From 15c6784f0f3638b9677aa4e4dadaef30776e901c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 12 Nov 2020 16:02:21 +1100 Subject: [PATCH 001/177] WIP --- .../Jobs/MessageReceiveJob.swift | 2 +- SessionMessagingKit/Jobs/MessageSendJob.swift | 2 +- .../Control Message/ClosedGroupUpdate.swift | 2 + .../Control Message/NullMessage.swift | 39 + .../Control Message/SessionRequest.swift | 4 +- .../Control Message/TypingIndicator.swift | 2 + .../Sending & Receiving/MessageSender.swift | 8 +- Signal.xcodeproj/project.pbxproj | 76 +- SignalUtilitiesKit/ClosedGroupPoller.swift | 7 +- SignalUtilitiesKit/ClosedGroupsProtocol.swift | 92 +- .../MessageSender+Promise.swift | 25 - .../MessageSenderJobQueue.swift | 256 --- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 4 - SignalUtilitiesKit/MultiDeviceProtocol.swift | 274 --- SignalUtilitiesKit/OWSMessageDecrypter.h | 47 - SignalUtilitiesKit/OWSMessageDecrypter.m | 686 ------- SignalUtilitiesKit/OWSMessageHandler.h | 24 - SignalUtilitiesKit/OWSMessageHandler.m | 183 -- SignalUtilitiesKit/OWSMessageManager.h | 33 - SignalUtilitiesKit/OWSMessageManager.m | 1735 ---------------- SignalUtilitiesKit/OWSMessageReceiver.h | 28 - SignalUtilitiesKit/OWSMessageReceiver.m | 513 ----- SignalUtilitiesKit/OWSMessageSend.swift | 96 - SignalUtilitiesKit/OWSMessageSender.h | 121 -- SignalUtilitiesKit/OWSMessageSender.m | 1744 ----------------- SignalUtilitiesKit/Poller.swift | 7 +- .../SessionManagementProtocol.swift | 15 +- SignalUtilitiesKit/SessionMetaProtocol.swift | 13 - SignalUtilitiesKit/SyncMessagesProtocol.swift | 14 +- SignalUtilitiesKit/TSConstants.h | 2 + SignalUtilitiesKit/TSConstants.m | 2 + SignalUtilitiesKit/TypingIndicators.swift | 21 +- .../Utilities/Destination+Conversion.swift | 21 + .../Utilities/MessageSender+Utilities.swift | 17 + 34 files changed, 201 insertions(+), 5914 deletions(-) create mode 100644 SessionMessagingKit/Messages/Control Message/NullMessage.swift delete mode 100644 SignalUtilitiesKit/MessageSender+Promise.swift delete mode 100644 SignalUtilitiesKit/MessageSenderJobQueue.swift delete mode 100644 SignalUtilitiesKit/MultiDeviceProtocol.swift delete mode 100644 SignalUtilitiesKit/OWSMessageDecrypter.h delete mode 100644 SignalUtilitiesKit/OWSMessageDecrypter.m delete mode 100644 SignalUtilitiesKit/OWSMessageHandler.h delete mode 100644 SignalUtilitiesKit/OWSMessageHandler.m delete mode 100644 SignalUtilitiesKit/OWSMessageManager.h delete mode 100644 SignalUtilitiesKit/OWSMessageManager.m delete mode 100644 SignalUtilitiesKit/OWSMessageReceiver.h delete mode 100644 SignalUtilitiesKit/OWSMessageReceiver.m delete mode 100644 SignalUtilitiesKit/OWSMessageSend.swift delete mode 100644 SignalUtilitiesKit/OWSMessageSender.h delete mode 100644 SignalUtilitiesKit/OWSMessageSender.m create mode 100644 SignalUtilitiesKit/Utilities/Destination+Conversion.swift create mode 100644 SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index e15593475..9b95f97ea 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -9,7 +9,7 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NS public static let maxFailureCount: UInt = 10 // MARK: Initialization - init(data: Data) { + public init(data: Data) { self.data = data } diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 53290e7fb..c0a2b5d33 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -14,7 +14,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi @objc public convenience init(message: Message, publicKey: String) { self.init(message: message, destination: .contact(publicKey: publicKey)) } @objc public convenience init(message: Message, groupPublicKey: String) { self.init(message: message, destination: .closedGroup(groupPublicKey: groupPublicKey)) } - init(message: Message, destination: Message.Destination) { + public init(message: Message, destination: Message.Destination) { self.message = message self.destination = destination } diff --git a/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift index 2d5fdf176..0d525a271 100644 --- a/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift @@ -14,6 +14,8 @@ public final class ClosedGroupUpdate : ControlMessage { } // MARK: Initialization + public override init() { super.init() } + internal init(kind: Kind) { super.init() self.kind = kind diff --git a/SessionMessagingKit/Messages/Control Message/NullMessage.swift b/SessionMessagingKit/Messages/Control Message/NullMessage.swift new file mode 100644 index 000000000..a66b93192 --- /dev/null +++ b/SessionMessagingKit/Messages/Control Message/NullMessage.swift @@ -0,0 +1,39 @@ +import SessionProtocolKit +import SessionUtilitiesKit + +@objc(SNNullMessage) +public final class NullMessage : ControlMessage { + + // MARK: Initialization + public override init() { super.init() } + + // MARK: Coding + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + public override func encode(with coder: NSCoder) { + super.encode(with: coder) + } + + // MARK: Proto Conversion + public override class func fromProto(_ proto: SNProtoContent) -> NullMessage? { + guard proto.nullMessage != nil else { return nil } + return NullMessage() + } + + public override func toProto() -> SNProtoContent? { + let nullMessageProto = SNProtoNullMessage.builder() + let paddingSize = UInt.random(in: 0..<512) // random(in:) uses the system's default random generator, which is cryptographically secure + let padding = Data.getSecureRandomData(ofSize: paddingSize)! + nullMessageProto.setPadding(padding) + let contentProto = SNProtoContent.builder() + do { + contentProto.setNullMessage(try nullMessageProto.build()) + return try contentProto.build() + } catch { + SNLog("Couldn't construct null message proto from: \(self).") + return nil + } + } +} diff --git a/SessionMessagingKit/Messages/Control Message/SessionRequest.swift b/SessionMessagingKit/Messages/Control Message/SessionRequest.swift index 36d1667e2..060ea1754 100644 --- a/SessionMessagingKit/Messages/Control Message/SessionRequest.swift +++ b/SessionMessagingKit/Messages/Control Message/SessionRequest.swift @@ -3,9 +3,11 @@ import SessionUtilitiesKit @objc(SNSessionRequest) public final class SessionRequest : ControlMessage { - private var preKeyBundle: PreKeyBundle? + public var preKeyBundle: PreKeyBundle? // MARK: Initialization + public override init() { super.init() } + internal init(preKeyBundle: PreKeyBundle) { super.init() self.preKeyBundle = preKeyBundle diff --git a/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift b/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift index 0e150ce73..e623868e0 100644 --- a/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift +++ b/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift @@ -29,6 +29,8 @@ public final class TypingIndicator : ControlMessage { public override var isValid: Bool { kind != nil } // MARK: Initialization + public override init() { super.init() } + internal init(kind: Kind) { super.init() self.kind = kind diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 93f7328c6..203169e2a 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -20,7 +20,7 @@ public enum MessageSender { } } - internal static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise { + public static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise { switch destination { case .contact(_), .closedGroup(_): return sendToSnodeDestination(destination, message: message, using: transaction) case .openGroup(_, _): return sendToOpenGroupDestination(destination, message: message, using: transaction) @@ -141,6 +141,12 @@ public enum MessageSender { } internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { + message.sentTimestamp = NSDate.millisecondTimestamp() + switch destination { + case .contact(_): preconditionFailure() + case .closedGroup(_): preconditionFailure() + case .openGroup(let channel, let server): message.recipient = "\(server).\(channel)" + } guard message.isValid else { return Promise(error: Error.invalidMessage) } let (channel, server) = { () -> (UInt64, String) in switch destination { diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 0a7ef7111..266471fa2 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -362,7 +362,6 @@ C33FDC21255A581F00E217F9 /* OWSPrimaryStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */; }; C33FDC23255A581F00E217F9 /* SSKPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA69255A57F900E217F9 /* SSKPreferences.swift */; }; - C33FDC24255A581F00E217F9 /* OWSMessageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6A255A57F900E217F9 /* OWSMessageManager.m */; }; C33FDC25255A581F00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */; }; C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */; }; C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */; }; @@ -401,7 +400,6 @@ C33FDC49255A581F00E217F9 /* NSTimer+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8F255A57FD00E217F9 /* NSTimer+OWS.m */; }; C33FDC4A255A582000E217F9 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; }; C33FDC4B255A582000E217F9 /* LKSyncOpenGroupsMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA91255A57FD00E217F9 /* LKSyncOpenGroupsMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC4C255A582000E217F9 /* OWSMessageSender.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA92255A57FE00E217F9 /* OWSMessageSender.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC4E255A582000E217F9 /* Data+Streaming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */; }; C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA96255A57FE00E217F9 /* OWSDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -426,7 +424,6 @@ C33FDC63255A582000E217F9 /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA9255A580000E217F9 /* Mnemonic.swift */; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; C33FDC65255A582000E217F9 /* OWSWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAB255A580000E217F9 /* OWSWebSocket.m */; }; - C33FDC66255A582000E217F9 /* OWSMessageHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAAC255A580000E217F9 /* OWSMessageHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC67255A582000E217F9 /* OWSDeviceProvisioner.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAAD255A580000E217F9 /* OWSDeviceProvisioner.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC68255A582000E217F9 /* OWSReceiptsForSenderMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAE255A580000E217F9 /* OWSReceiptsForSenderMessage.m */; }; C33FDC69255A582000E217F9 /* String+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAF255A580000E217F9 /* String+Trimming.swift */; }; @@ -434,7 +431,6 @@ C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; }; C33FDC6C255A582000E217F9 /* TSNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB2255A580000E217F9 /* TSNetworkManager.m */; }; C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB3255A580000E217F9 /* TSContactThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC6E255A582000E217F9 /* OWSMessageReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB4255A580000E217F9 /* OWSMessageReceiver.m */; }; C33FDC6F255A582000E217F9 /* TSNetworkManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB5255A580000E217F9 /* TSNetworkManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC70255A582000E217F9 /* SyncMessagesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB6255A580100E217F9 /* SyncMessagesProtocol.swift */; }; C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */; }; @@ -456,7 +452,6 @@ C33FDC83255A582000E217F9 /* OWSContact.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAC9255A580200E217F9 /* OWSContact.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC84255A582000E217F9 /* LokiMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACA255A580200E217F9 /* LokiMessage.swift */; }; C33FDC85255A582000E217F9 /* CDSSigningCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACB255A580200E217F9 /* CDSSigningCertificate.m */; }; - C33FDC86255A582000E217F9 /* OWSMessageSend.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACC255A580200E217F9 /* OWSMessageSend.swift */; }; C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; }; C33FDC88255A582000E217F9 /* OWSVerificationStateSyncMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACE255A580300E217F9 /* OWSVerificationStateSyncMessage.m */; }; C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -563,7 +558,6 @@ C33FDCF4255A582000E217F9 /* Poller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3A255A580B00E217F9 /* Poller.swift */; }; C33FDCF5255A582000E217F9 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCF7255A582000E217F9 /* OWSProfileKeyMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3D255A580B00E217F9 /* OWSProfileKeyMessage.m */; }; - C33FDCF8255A582000E217F9 /* OWSMessageSender.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3E255A580B00E217F9 /* OWSMessageSender.m */; }; C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3F255A580C00E217F9 /* String+SSK.swift */; }; C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */; }; C33FDCFB255A582000E217F9 /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */; }; @@ -623,7 +617,6 @@ C33FDD33255A582000E217F9 /* PhoneNumberUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB79255A581000E217F9 /* PhoneNumberUtil.m */; }; C33FDD34255A582000E217F9 /* NotificationsProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD36255A582000E217F9 /* OWSVerificationStateChangeMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7C255A581000E217F9 /* OWSVerificationStateChangeMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD37255A582000E217F9 /* OWSMessageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7D255A581100E217F9 /* OWSMessageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD38255A582000E217F9 /* TSPreKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */; }; C33FDD39255A582000E217F9 /* FullTextSearchFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */; }; C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB80255A581100E217F9 /* Notification+Loki.swift */; }; @@ -642,7 +635,6 @@ C33FDD47255A582000E217F9 /* DeviceLinkingSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8D255A581200E217F9 /* DeviceLinkingSessionDelegate.swift */; }; C33FDD48255A582000E217F9 /* OWSContact+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8E255A581200E217F9 /* OWSContact+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; }; - C33FDD4A255A582000E217F9 /* OWSMessageDecrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB90255A581200E217F9 /* OWSMessageDecrypter.m */; }; C33FDD4B255A582000E217F9 /* ProtoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB91255A581200E217F9 /* ProtoUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD4C255A582000E217F9 /* OWSDeviceProvisioningService.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB92255A581200E217F9 /* OWSDeviceProvisioningService.m */; }; C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */; }; @@ -653,7 +645,6 @@ C33FDD52255A582000E217F9 /* DeviceNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB98255A581300E217F9 /* DeviceNames.swift */; }; C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; }; C33FDD54255A582000E217F9 /* OWS2FAManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9A255A581300E217F9 /* OWS2FAManager.m */; }; - C33FDD55255A582000E217F9 /* MessageSenderJobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9B255A581300E217F9 /* MessageSenderJobQueue.swift */; }; C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD57255A582000E217F9 /* OWSCallMessageHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD58255A582000E217F9 /* TSAttachmentPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */; }; @@ -691,12 +682,10 @@ C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC2255A581700E217F9 /* SSKAsserts.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD7D255A582000E217F9 /* AnyPromise+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC3255A581700E217F9 /* AnyPromise+Conversion.swift */; }; C33FDD7E255A582000E217F9 /* TypingIndicatorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC4255A581700E217F9 /* TypingIndicatorMessage.swift */; }; - C33FDD80255A582000E217F9 /* OWSMessageReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC6255A581700E217F9 /* OWSMessageReceiver.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD82255A582000E217F9 /* OWSFingerprint.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC8255A581700E217F9 /* OWSFingerprint.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */; }; C33FDD84255A582000E217F9 /* LKGroupUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */; }; - C33FDD86255A582000E217F9 /* MultiDeviceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBCC255A581800E217F9 /* MultiDeviceProtocol.swift */; }; C33FDD88255A582000E217F9 /* OWSMessageServiceParams.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD89255A582000E217F9 /* OWSFingerprintBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCF255A581800E217F9 /* OWSFingerprintBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD8A255A582000E217F9 /* OnionRequestAPI+Encryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD0255A581800E217F9 /* OnionRequestAPI+Encryption.swift */; }; @@ -733,7 +722,6 @@ C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDAA255A582000E217F9 /* LokiDatabaseUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */; }; C33FDDAB255A582000E217F9 /* OWSIdentityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDAC255A582000E217F9 /* MessageSender+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF2255A581B00E217F9 /* MessageSender+Promise.swift */; }; C33FDDAD255A582000E217F9 /* OWSBlockedPhoneNumbersMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF3255A581B00E217F9 /* OWSBlockedPhoneNumbersMessage.h */; }; C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */; }; C33FDDAF255A582000E217F9 /* OWSDeviceProvisioningService.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF5255A581B00E217F9 /* OWSDeviceProvisioningService.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -743,7 +731,6 @@ C33FDDB3255A582000E217F9 /* OWSError.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF9255A581C00E217F9 /* OWSError.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB4255A582000E217F9 /* PhoneNumberUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBFA255A581C00E217F9 /* PhoneNumberUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB5255A582000E217F9 /* Storage+PublicChats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */; }; - C33FDDB6255A582000E217F9 /* OWSMessageHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFC255A581C00E217F9 /* OWSMessageHandler.m */; }; C33FDDB7255A582000E217F9 /* OWSPrimaryStorage+Calling.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */; }; C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB9255A582000E217F9 /* OWSOutgoingSyncMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFF255A581C00E217F9 /* OWSOutgoingSyncMessage.m */; }; @@ -761,7 +748,6 @@ C33FDDC5255A582000E217F9 /* OWSError.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0B255A581D00E217F9 /* OWSError.m */; }; C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */; }; C33FDDC7255A582000E217F9 /* OWSProvisioningMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC0D255A581E00E217F9 /* OWSProvisioningMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDC8255A582000E217F9 /* OWSMessageDecrypter.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC0E255A581E00E217F9 /* OWSMessageDecrypter.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDC9255A582000E217F9 /* LKDeviceLinkMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC0F255A581E00E217F9 /* LKDeviceLinkMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDCA255A582000E217F9 /* ProofOfWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC10255A581E00E217F9 /* ProofOfWork.swift */; }; C33FDDCB255A582000E217F9 /* TSSocketManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC11255A581E00E217F9 /* TSSocketManager.m */; }; @@ -1156,6 +1142,9 @@ C3CA3AB4255CDAE600F4C6D4 /* japanese.txt in Resources */ = {isa = PBXBuildFile; fileRef = C3CA3AB3255CDAE600F4C6D4 /* japanese.txt */; }; C3CA3ABE255CDB0D00F4C6D4 /* portuguese.txt in Resources */ = {isa = PBXBuildFile; fileRef = C3CA3ABD255CDB0D00F4C6D4 /* portuguese.txt */; }; C3CA3AC8255CDB2900F4C6D4 /* spanish.txt in Resources */ = {isa = PBXBuildFile; fileRef = C3CA3AC7255CDB2900F4C6D4 /* spanish.txt */; }; + C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */; }; + C3CA3B1D255CF3C800F4C6D4 /* MessageSender+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */; }; + C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; @@ -1728,7 +1717,6 @@ C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPrimaryStorage.h; sourceTree = ""; }; C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBlockingManager.m; sourceTree = ""; }; C33FDA69255A57F900E217F9 /* SSKPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKPreferences.swift; sourceTree = ""; }; - C33FDA6A255A57F900E217F9 /* OWSMessageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageManager.m; sourceTree = ""; }; C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingConfigurationUpdateInfoMessage.m; sourceTree = ""; }; C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoUtils.m; sourceTree = ""; }; C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "YapDatabase+Promise.swift"; sourceTree = ""; }; @@ -1767,7 +1755,6 @@ C33FDA8F255A57FD00E217F9 /* NSTimer+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+OWS.m"; sourceTree = ""; }; C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSYapDatabaseObject.m; sourceTree = ""; }; C33FDA91255A57FD00E217F9 /* LKSyncOpenGroupsMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKSyncOpenGroupsMessage.h; sourceTree = ""; }; - C33FDA92255A57FE00E217F9 /* OWSMessageSender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageSender.h; sourceTree = ""; }; C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Streaming.swift"; sourceTree = ""; }; C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSChunkedOutputStream.h; sourceTree = ""; }; C33FDA96255A57FE00E217F9 /* OWSDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDispatch.h; sourceTree = ""; }; @@ -1792,7 +1779,6 @@ C33FDAA9255A580000E217F9 /* Mnemonic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = ""; }; C33FDAAA255A580000E217F9 /* NSObject+Casting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Casting.m"; sourceTree = ""; }; C33FDAAB255A580000E217F9 /* OWSWebSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSWebSocket.m; sourceTree = ""; }; - C33FDAAC255A580000E217F9 /* OWSMessageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageHandler.h; sourceTree = ""; }; C33FDAAD255A580000E217F9 /* OWSDeviceProvisioner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioner.h; sourceTree = ""; }; C33FDAAE255A580000E217F9 /* OWSReceiptsForSenderMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSReceiptsForSenderMessage.m; sourceTree = ""; }; C33FDAAF255A580000E217F9 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = ""; }; @@ -1800,7 +1786,6 @@ C33FDAB1255A580000E217F9 /* OWSStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSStorage.m; sourceTree = ""; }; C33FDAB2255A580000E217F9 /* TSNetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSNetworkManager.m; sourceTree = ""; }; C33FDAB3255A580000E217F9 /* TSContactThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSContactThread.h; sourceTree = ""; }; - C33FDAB4255A580000E217F9 /* OWSMessageReceiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageReceiver.m; sourceTree = ""; }; C33FDAB5255A580000E217F9 /* TSNetworkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSNetworkManager.h; sourceTree = ""; }; C33FDAB6255A580100E217F9 /* SyncMessagesProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncMessagesProtocol.swift; sourceTree = ""; }; C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFailedMessagesJob.m; sourceTree = ""; }; @@ -1822,7 +1807,6 @@ C33FDAC9255A580200E217F9 /* OWSContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContact.h; sourceTree = ""; }; C33FDACA255A580200E217F9 /* LokiMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiMessage.swift; sourceTree = ""; }; C33FDACB255A580200E217F9 /* CDSSigningCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDSSigningCertificate.m; sourceTree = ""; }; - C33FDACC255A580200E217F9 /* OWSMessageSend.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMessageSend.swift; sourceTree = ""; }; C33FDACD255A580200E217F9 /* SSKJobRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKJobRecord.m; sourceTree = ""; }; C33FDACE255A580300E217F9 /* OWSVerificationStateSyncMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSVerificationStateSyncMessage.m; sourceTree = ""; }; C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAttachmentDownloads.h; sourceTree = ""; }; @@ -1929,7 +1913,6 @@ C33FDB3A255A580B00E217F9 /* Poller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poller.swift; sourceTree = ""; }; C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OWS.h"; sourceTree = ""; }; C33FDB3D255A580B00E217F9 /* OWSProfileKeyMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProfileKeyMessage.m; sourceTree = ""; }; - C33FDB3E255A580B00E217F9 /* OWSMessageSender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageSender.m; sourceTree = ""; }; C33FDB3F255A580C00E217F9 /* String+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SSK.swift"; sourceTree = ""; }; C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOSProto.swift; sourceTree = ""; }; C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIMETypeUtil.m; sourceTree = ""; }; @@ -1989,7 +1972,6 @@ C33FDB79255A581000E217F9 /* PhoneNumberUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhoneNumberUtil.m; sourceTree = ""; }; C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationsProtocol.h; sourceTree = ""; }; C33FDB7C255A581000E217F9 /* OWSVerificationStateChangeMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSVerificationStateChangeMessage.h; sourceTree = ""; }; - C33FDB7D255A581100E217F9 /* OWSMessageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageManager.h; sourceTree = ""; }; C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSPreKeyManager.m; sourceTree = ""; }; C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullTextSearchFinder.swift; sourceTree = ""; }; C33FDB80255A581100E217F9 /* Notification+Loki.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Notification+Loki.swift"; sourceTree = ""; }; @@ -2008,7 +1990,6 @@ C33FDB8D255A581200E217F9 /* DeviceLinkingSessionDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkingSessionDelegate.swift; sourceTree = ""; }; C33FDB8E255A581200E217F9 /* OWSContact+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSContact+Private.h"; sourceTree = ""; }; C33FDB8F255A581200E217F9 /* ParamParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParamParser.swift; sourceTree = ""; }; - C33FDB90255A581200E217F9 /* OWSMessageDecrypter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageDecrypter.m; sourceTree = ""; }; C33FDB91255A581200E217F9 /* ProtoUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProtoUtils.h; sourceTree = ""; }; C33FDB92255A581200E217F9 /* OWSDeviceProvisioningService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioningService.m; sourceTree = ""; }; C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PreKeyBundle+jsonDict.m"; sourceTree = ""; }; @@ -2019,7 +2000,6 @@ C33FDB98255A581300E217F9 /* DeviceNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceNames.swift; sourceTree = ""; }; C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+keyFromIntLong.m"; sourceTree = ""; }; C33FDB9A255A581300E217F9 /* OWS2FAManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FAManager.m; sourceTree = ""; }; - C33FDB9B255A581300E217F9 /* MessageSenderJobQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageSenderJobQueue.swift; sourceTree = ""; }; C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSIncomingMessage.h; sourceTree = ""; }; C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCallMessageHandler.h; sourceTree = ""; }; C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentPointer.m; sourceTree = ""; }; @@ -2057,12 +2037,10 @@ C33FDBC2255A581700E217F9 /* SSKAsserts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKAsserts.h; sourceTree = ""; }; C33FDBC3255A581700E217F9 /* AnyPromise+Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AnyPromise+Conversion.swift"; sourceTree = ""; }; C33FDBC4255A581700E217F9 /* TypingIndicatorMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorMessage.swift; sourceTree = ""; }; - C33FDBC6255A581700E217F9 /* OWSMessageReceiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageReceiver.h; sourceTree = ""; }; C33FDBC8255A581700E217F9 /* OWSFingerprint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSFingerprint.h; sourceTree = ""; }; C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreatePreKeysOperation.swift; sourceTree = ""; }; C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKGroupUtilities.h; sourceTree = ""; }; C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyReceivingErrorMessage.m; sourceTree = ""; }; - C33FDBCC255A581800E217F9 /* MultiDeviceProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiDeviceProtocol.swift; sourceTree = ""; }; C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageServiceParams.h; sourceTree = ""; }; C33FDBCF255A581800E217F9 /* OWSFingerprintBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSFingerprintBuilder.h; sourceTree = ""; }; C33FDBD0255A581800E217F9 /* OnionRequestAPI+Encryption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OnionRequestAPI+Encryption.swift"; sourceTree = ""; }; @@ -2099,7 +2077,6 @@ C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageKeys.h; sourceTree = ""; }; C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiDatabaseUtilities.swift; sourceTree = ""; }; C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIdentityManager.h; sourceTree = ""; }; - C33FDBF2255A581B00E217F9 /* MessageSender+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageSender+Promise.swift"; sourceTree = ""; }; C33FDBF3255A581B00E217F9 /* OWSBlockedPhoneNumbersMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockedPhoneNumbersMessage.h; sourceTree = ""; }; C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayNameUtilities2.swift; sourceTree = ""; }; C33FDBF5255A581B00E217F9 /* OWSDeviceProvisioningService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioningService.h; sourceTree = ""; }; @@ -2109,7 +2086,6 @@ C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = ""; }; C33FDBFA255A581C00E217F9 /* PhoneNumberUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhoneNumberUtil.h; sourceTree = ""; }; C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+PublicChats.swift"; sourceTree = ""; }; - C33FDBFC255A581C00E217F9 /* OWSMessageHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageHandler.m; sourceTree = ""; }; C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+Calling.m"; sourceTree = ""; }; C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+Functional.h"; sourceTree = ""; }; C33FDBFF255A581C00E217F9 /* OWSOutgoingSyncMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingSyncMessage.m; sourceTree = ""; }; @@ -2127,7 +2103,6 @@ C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = ""; }; C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInfoMessage.m; sourceTree = ""; }; C33FDC0D255A581E00E217F9 /* OWSProvisioningMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProvisioningMessage.h; sourceTree = ""; }; - C33FDC0E255A581E00E217F9 /* OWSMessageDecrypter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageDecrypter.h; sourceTree = ""; }; C33FDC0F255A581E00E217F9 /* LKDeviceLinkMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKDeviceLinkMessage.h; sourceTree = ""; }; C33FDC10255A581E00E217F9 /* ProofOfWork.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProofOfWork.swift; sourceTree = ""; }; C33FDC11255A581E00E217F9 /* TSSocketManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSSocketManager.m; sourceTree = ""; }; @@ -2525,6 +2500,9 @@ C3CA3AB3255CDAE600F4C6D4 /* japanese.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = japanese.txt; sourceTree = ""; }; C3CA3ABD255CDB0D00F4C6D4 /* portuguese.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = portuguese.txt; sourceTree = ""; }; C3CA3AC7255CDB2900F4C6D4 /* spanish.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = spanish.txt; sourceTree = ""; }; + C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Destination+Conversion.swift"; sourceTree = ""; }; + C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Utilities.swift"; sourceTree = ""; }; + C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NullMessage.swift; sourceTree = ""; }; C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = ""; }; C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = ""; }; C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; @@ -3230,6 +3208,7 @@ C3C2A7702553A41E00C340D1 /* ControlMessage.swift */, C300A5BC2554B00D00555489 /* ReadReceipt.swift */, C300A5C82554B04E00555489 /* SessionRequest.swift */, + C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */, C300A5D22554B05A00555489 /* TypingIndicator.swift */, C300A5DC2554B06600555489 /* ClosedGroupUpdate.swift */, C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */, @@ -3350,6 +3329,7 @@ C33FD9AC255A548A00E217F9 /* SignalUtilitiesKit */ = { isa = PBXGroup; children = ( + C3CA3B11255CF17200F4C6D4 /* Utilities */, C33FDC09255A581D00E217F9 /* AccountServiceClient.swift */, C33FDBC3255A581700E217F9 /* AnyPromise+Conversion.swift */, C33FDB8A255A581200E217F9 /* AppContext.h */, @@ -3609,13 +3589,10 @@ C33FDAFD255A580600E217F9 /* LRUCache.swift */, C33FDA7E255A57FB00E217F9 /* Mention.swift */, C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, - C33FDBF2255A581B00E217F9 /* MessageSender+Promise.swift */, - C33FDB9B255A581300E217F9 /* MessageSenderJobQueue.swift */, C33FDB82255A581100E217F9 /* MessageWrapper.swift */, C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */, C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */, C33FDAA9255A580000E217F9 /* Mnemonic.swift */, - C33FDBCC255A581800E217F9 /* MultiDeviceProtocol.swift */, C33FDA9F255A57FF00E217F9 /* NetworkManager.swift */, C33FDB80255A581100E217F9 /* Notification+Loki.swift */, C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */, @@ -3736,17 +3713,6 @@ C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */, C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */, C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */, - C33FDC0E255A581E00E217F9 /* OWSMessageDecrypter.h */, - C33FDB90255A581200E217F9 /* OWSMessageDecrypter.m */, - C33FDAAC255A580000E217F9 /* OWSMessageHandler.h */, - C33FDBFC255A581C00E217F9 /* OWSMessageHandler.m */, - C33FDB7D255A581100E217F9 /* OWSMessageManager.h */, - C33FDA6A255A57F900E217F9 /* OWSMessageManager.m */, - C33FDBC6255A581700E217F9 /* OWSMessageReceiver.h */, - C33FDAB4255A580000E217F9 /* OWSMessageReceiver.m */, - C33FDACC255A580200E217F9 /* OWSMessageSend.swift */, - C33FDA92255A57FE00E217F9 /* OWSMessageSender.h */, - C33FDB3E255A580B00E217F9 /* OWSMessageSender.m */, C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */, C33FDB70255A580F00E217F9 /* OWSMessageServiceParams.m */, C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, @@ -4364,6 +4330,15 @@ path = Mnemonic; sourceTree = ""; }; + C3CA3B11255CF17200F4C6D4 /* Utilities */ = { + isa = PBXGroup; + children = ( + C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */, + C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */, + ); + path = Utilities; + sourceTree = ""; + }; C3F0A58F255C8E3D007BE2A3 /* Meta */ = { isa = PBXGroup; children = ( @@ -4542,7 +4517,6 @@ C33FDD65255A582000E217F9 /* OWSFileSystem.h in Headers */, C33FDCD6255A582000E217F9 /* UIImage+OWS.h in Headers */, C38EF219255B6D3B007E1867 /* OWSConversationColor.h in Headers */, - C33FDD80255A582000E217F9 /* OWSMessageReceiver.h in Headers */, C38EF369255B6DCC007E1867 /* ViewControllerUtils.h in Headers */, C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */, C33FDD7A255A582000E217F9 /* OWSRequestFactory.h in Headers */, @@ -4572,7 +4546,6 @@ C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */, C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */, C33FDCBC255A582000E217F9 /* TSCall.h in Headers */, - C33FDD37255A582000E217F9 /* OWSMessageManager.h in Headers */, C38EF2C3255B6DA6007E1867 /* OWSContactOffersInteraction.h in Headers */, C33FDD95255A582000E217F9 /* OWSDevicesService.h in Headers */, C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */, @@ -4616,7 +4589,6 @@ C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */, C33FDD48255A582000E217F9 /* OWSContact+Private.h in Headers */, C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */, - C33FDC66255A582000E217F9 /* OWSMessageHandler.h in Headers */, C33FDDA1255A582000E217F9 /* NSTimer+OWS.h in Headers */, C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */, C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */, @@ -4629,7 +4601,6 @@ C33FDC83255A582000E217F9 /* OWSContact.h in Headers */, C33FDCB2255A582000E217F9 /* OWSSyncGroupsRequestMessage.h in Headers */, C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */, - C33FDDC8255A582000E217F9 /* OWSMessageDecrypter.h in Headers */, C38EF262255B6D6F007E1867 /* OWSContactsManager.h in Headers */, C33FDCC2255A582000E217F9 /* OWSProfileKeyMessage.h in Headers */, C33FDCDE255A582000E217F9 /* OWSOutgoingSentMessageTranscript.h in Headers */, @@ -4653,7 +4624,6 @@ C33FDDB3255A582000E217F9 /* OWSError.h in Headers */, C33FDD57255A582000E217F9 /* OWSCallMessageHandler.h in Headers */, C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */, - C33FDC4C255A582000E217F9 /* OWSMessageSender.h in Headers */, C38EF403255B6DF7007E1867 /* ContactCellView.h in Headers */, C33FDD6D255A582000E217F9 /* OWSOutgoingNullMessage.h in Headers */, C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */, @@ -5649,7 +5619,6 @@ C33FDDA8255A582000E217F9 /* ClosedGroupUpdateMessage.swift in Sources */, C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */, C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, - C33FDDAC255A582000E217F9 /* MessageSender+Promise.swift in Sources */, C38EF36A255B6DCC007E1867 /* NewNonContactConversationViewController.m in Sources */, C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */, C33FDD0A255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.m in Sources */, @@ -5664,7 +5633,6 @@ C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */, C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */, - C33FDDB6255A582000E217F9 /* OWSMessageHandler.m in Sources */, C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */, C33FDC80255A582000E217F9 /* Fingerprint.pb.swift in Sources */, C33FDD42255A582000E217F9 /* TSAccountManager.m in Sources */, @@ -5678,7 +5646,6 @@ C33FDD5F255A582000E217F9 /* SignalServiceProfile.swift in Sources */, C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */, C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */, - C33FDC6E255A582000E217F9 /* OWSMessageReceiver.m in Sources */, C33FDC7E255A582000E217F9 /* TSAttachmentStream.m in Sources */, C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */, C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */, @@ -5753,7 +5720,6 @@ C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */, C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */, C38EF3F3255B6DF7007E1867 /* ContactsViewHelper.m in Sources */, - C33FDC24255A581F00E217F9 /* OWSMessageManager.m in Sources */, C33FDC46255A581F00E217F9 /* PublicChatPoller.swift in Sources */, C38EF400255B6DF7007E1867 /* GalleryRailView.swift in Sources */, C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */, @@ -5796,6 +5762,7 @@ C38EF3FC255B6DF7007E1867 /* AvatarImageView.swift in Sources */, C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */, C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */, + C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */, C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */, C33FDC91255A582000E217F9 /* OWSDeviceProvisioner.m in Sources */, C33FDC6A255A582000E217F9 /* ProvisioningProto.swift in Sources */, @@ -5811,7 +5778,6 @@ C38EF310255B6DBF007E1867 /* DebugLogger.m in Sources */, C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */, C33FDD98255A582000E217F9 /* LokiPushNotificationManager.swift in Sources */, - C33FDCF8255A582000E217F9 /* OWSMessageSender.m in Sources */, C33FDD70255A582000E217F9 /* DataSource.m in Sources */, C33FDD2F255A582000E217F9 /* AppReadiness.m in Sources */, C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */, @@ -5824,7 +5790,6 @@ C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */, C33FDC49255A581F00E217F9 /* NSTimer+OWS.m in Sources */, C38EF260255B6D6F007E1867 /* OWSContactsManager.m in Sources */, - C33FDD55255A582000E217F9 /* MessageSenderJobQueue.swift in Sources */, C33FDCFD255A582000E217F9 /* YapDatabaseConnection+OWS.m in Sources */, C38EF3BC255B6DE7007E1867 /* ImageEditorPanGestureRecognizer.swift in Sources */, C33FDC23255A581F00E217F9 /* SSKPreferences.swift in Sources */, @@ -5867,7 +5832,6 @@ C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, C33FDDBB255A582000E217F9 /* TSGroupThread.m in Sources */, - C33FDD4A255A582000E217F9 /* OWSMessageDecrypter.m in Sources */, C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */, C33FDD14255A582000E217F9 /* OWSUDManager.swift in Sources */, C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */, @@ -5946,16 +5910,15 @@ C33FDCBA255A582000E217F9 /* OWSRequestBuilder.m in Sources */, C33FDC2B255A581F00E217F9 /* OWSReadReceiptManager.m in Sources */, C38EF326255B6DBF007E1867 /* ConversationStyle.swift in Sources */, - C33FDC86255A582000E217F9 /* OWSMessageSend.swift in Sources */, C38EF312255B6DBF007E1867 /* OWSGroupAvatarBuilder.m in Sources */, C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */, C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */, C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */, C33FDCF7255A582000E217F9 /* OWSProfileKeyMessage.m in Sources */, + C3CA3B1D255CF3C800F4C6D4 /* MessageSender+Utilities.swift in Sources */, C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */, C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */, C38EF362255B6DCC007E1867 /* ContactShareApprovalViewController.swift in Sources */, - C33FDD86255A582000E217F9 /* MultiDeviceProtocol.swift in Sources */, C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */, C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */, C33FDC92255A582000E217F9 /* OWSGroupsOutputStream.m in Sources */, @@ -6037,6 +6000,7 @@ C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */, C3A722802558C4E10043A11F /* AttachmentStream.swift in Sources */, C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */, + C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */, C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */, C352A32F2557549C00338F3E /* NotifyPNServerJob.swift in Sources */, C300A5F22554B09800555489 /* MessageSender.swift in Sources */, diff --git a/SignalUtilitiesKit/ClosedGroupPoller.swift b/SignalUtilitiesKit/ClosedGroupPoller.swift index c9ec1c9b5..0444b8656 100644 --- a/SignalUtilitiesKit/ClosedGroupPoller.swift +++ b/SignalUtilitiesKit/ClosedGroupPoller.swift @@ -27,7 +27,7 @@ public final class ClosedGroupPoller : NSObject { guard !isPolling else { return } isPolling = true timer = Timer.scheduledTimer(withTimeInterval: ClosedGroupPoller.pollInterval, repeats: true) { [weak self] _ in - self?.poll() + let _ = self?.poll() } } @@ -64,7 +64,10 @@ public final class ClosedGroupPoller : NSObject { guard let envelope = SSKProtoEnvelope.from(json) else { return } do { let data = try envelope.serializedData() - SSKEnvironment.shared.messageReceiver.handleReceivedEnvelopeData(data) + let job = MessageReceiveJob(data: data) + Storage.write { transaction in + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + } } catch { print("[Loki] Failed to deserialize envelope due to error: \(error).") } diff --git a/SignalUtilitiesKit/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/ClosedGroupsProtocol.swift index 0d62b1750..067bdfed6 100644 --- a/SignalUtilitiesKit/ClosedGroupsProtocol.swift +++ b/SignalUtilitiesKit/ClosedGroupsProtocol.swift @@ -37,7 +37,6 @@ public final class ClosedGroupsProtocol : NSObject { public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { // Prepare var members = members - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue let userPublicKey = getUserHexEncodedPublicKey() // Generate a key pair for the group let groupKeyPair = Curve25519.generateKeyPair() @@ -73,10 +72,12 @@ public final class ClosedGroupsProtocol : NSObject { guard member != userPublicKey else { continue } let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, groupPrivateKey: groupKeyPair.privateKey, senderKeys: senderKeys, members: membersAsData, admins: adminsAsData) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - promises.append(SSKEnvironment.shared.messageSender.sendPromise(message: closedGroupUpdateMessage)) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + let promise = MessageSender.sendNonDurably(closedGroupUpdate, in: thread, using: transaction) + promises.append(promise) } // Add the group to the user's set of public keys to poll for Storage.setClosedGroupPrivateKey(groupKeyPair.privateKey.toHexString(), for: groupPublicKey, using: transaction) @@ -92,7 +93,6 @@ public final class ClosedGroupsProtocol : NSObject { /// - Note: The returned promise is only relevant for group leaving. public static func update(_ groupPublicKey: String, with members: Set, name: String, transaction: YapDatabaseReadWriteTransaction) -> Promise { let (promise, seal) = Promise.pending() - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue let userPublicKey = getUserHexEncodedPublicKey() let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { @@ -124,13 +124,14 @@ public final class ClosedGroupsProtocol : NSObject { let promises: [Promise] = oldMembers.map { member in let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], members: membersAsData, admins: adminsAsData) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - return SSKEnvironment.shared.messageSender.sendPromise(message: closedGroupUpdateMessage) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + return MessageSender.sendNonDurably(closedGroupUpdate, in: thread, using: transaction) } when(resolved: promises).done2 { _ in seal.fulfill(()) }.catch2 { seal.reject($0) } - promise.done { + let _ = promise.done { Storage.writeSync { transaction in let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) for (senderPublicKey, oldRatchet) in allOldRatchets { @@ -144,16 +145,17 @@ public final class ClosedGroupsProtocol : NSObject { if isUserLeaving { Storage.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) // Notify the PN server - LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + let _ = LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) } else { // Send closed group update messages to any new members using established channels for member in newMembers { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [], members: membersAsData, admins: adminsAsData) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } // Send out the user's new ratchet to all members (minus the removed ones) using established channels let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) @@ -162,9 +164,10 @@ public final class ClosedGroupsProtocol : NSObject { guard member != userPublicKey else { continue } let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } } } @@ -177,10 +180,11 @@ public final class ClosedGroupsProtocol : NSObject { return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) } // Send a closed group update message to the existing members with the new members' ratchets (this message is aimed at the group) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: newSenderKeys, + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: newSenderKeys, members: membersAsData, admins: adminsAsData) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) // Establish sessions if needed establishSessionsIfNeeded(with: [String](newMembers), using: transaction) // Send closed group update messages to the new members using established channels @@ -189,18 +193,20 @@ public final class ClosedGroupsProtocol : NSObject { for member in newMembers { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } } else { seal.fulfill(()) let allSenderKeys = Storage.getAllClosedGroupSenderKeys(for: groupPublicKey) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } // Update the group let newGroupModel = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) @@ -240,10 +246,10 @@ public final class ClosedGroupsProtocol : NSObject { // Send the request let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKeyRequest(groupPublicKey: Data(hex: groupPublicKey)) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKeyRequest(groupPublicKey: Data(hex: groupPublicKey)) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } // MARK: - Receiving @@ -273,7 +279,6 @@ public final class ClosedGroupsProtocol : NSObject { } private static func handleNewGroupMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, using transaction: YapDatabaseReadWriteTransaction) { - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue // Unwrap the message let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let name = closedGroupUpdate.name @@ -298,9 +303,10 @@ public final class ClosedGroupsProtocol : NSObject { guard member != userPublicKey else { continue } let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } } for publicKey in missingSenderKeys.subtracting([ userPublicKey ]) { @@ -322,7 +328,7 @@ public final class ClosedGroupsProtocol : NSObject { // Add the group to the user's set of public keys to poll for Storage.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction) // Notify the PN server - LokiPushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) + let _ = LokiPushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) // Notify the user let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) infoMessage.save(with: transaction) @@ -335,7 +341,6 @@ public final class ClosedGroupsProtocol : NSObject { private static func handleInfoMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { // Unwrap the message - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let name = closedGroupUpdate.name let senderKeys = closedGroupUpdate.senderKeys @@ -377,7 +382,7 @@ public final class ClosedGroupsProtocol : NSObject { if wasUserRemoved { Storage.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) // Notify the PN server - LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + let _ = LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) } else { establishSessionsIfNeeded(with: members, using: transaction) // This internally takes care of multi device let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) @@ -386,9 +391,10 @@ public final class ClosedGroupsProtocol : NSObject { guard member != userPublicKey else { continue } let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // This internally takes care of multi device + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } } } @@ -406,7 +412,6 @@ public final class ClosedGroupsProtocol : NSObject { private static func handleSenderKeyRequestMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { // Prepare - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue let userPublicKey = getUserHexEncodedPublicKey() let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) @@ -431,9 +436,10 @@ public final class ClosedGroupsProtocol : NSObject { let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // This internally takes care of multi device + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } /// Invoked upon receiving a sender key from another user. diff --git a/SignalUtilitiesKit/MessageSender+Promise.swift b/SignalUtilitiesKit/MessageSender+Promise.swift deleted file mode 100644 index ac426fbb8..000000000 --- a/SignalUtilitiesKit/MessageSender+Promise.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - -public extension MessageSender { - - /** - * Wrap message sending in a Promise for easier callback chaining. - */ - func sendPromise(message: TSOutgoingMessage) -> Promise { - let promise: Promise = Promise { resolver in - self.send(message, success: { resolver.fulfill(()) }, failure: resolver.reject) - } - - // Ensure sends complete before they're GC'd. - // This *should* be redundant, since we should be calling retainUntilComplete - // at all call sites where the promise isn't otherwise retained. - promise.retainUntilComplete() - - return promise - } -} diff --git a/SignalUtilitiesKit/MessageSenderJobQueue.swift b/SignalUtilitiesKit/MessageSenderJobQueue.swift deleted file mode 100644 index c6136f0bd..000000000 --- a/SignalUtilitiesKit/MessageSenderJobQueue.swift +++ /dev/null @@ -1,256 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation - -/// Durably enqueues a message for sending. -/// -/// The queue's operations (`MessageSenderOperation`) uses `MessageSender` to send a message. -/// -/// ## Retry behavior -/// -/// Like all JobQueue's, MessageSenderJobQueue implements retry handling for operation errors. -/// -/// `MessageSender` also includes it's own retry logic necessary to encapsulate business logic around -/// a user changing their Registration ID, or adding/removing devices. That is, it is sometimes *normal* -/// for MessageSender to have to resend to a recipient multiple times before it is accepted, and doesn't -/// represent a "failure" from the application standpoint. -/// -/// So we have an inner non-durable retry (MessageSender) and an outer durable retry (MessageSenderJobQueue). -/// -/// Both respect the `error.isRetryable` convention to be sure we don't keep retrying in some situations -/// (e.g. rate limiting) - -@objc(SSKMessageSenderJobQueue) -public class MessageSenderJobQueue: NSObject, JobQueue { - - @objc - public override init() { - super.init() - - AppReadiness.runNowOrWhenAppWillBecomeReady { - self.setup() - } - } - - @objc(addMessage:transaction:) - public func add(message: TSOutgoingMessage, transaction: YapDatabaseReadWriteTransaction) { - self.add(message: message, removeMessageAfterSending: false, transaction: transaction) - } - - @objc(addMediaMessage:dataSource:contentType:sourceFilename:caption:albumMessageId:isTemporaryAttachment:) - public func add(mediaMessage: TSOutgoingMessage, dataSource: DataSource, contentType: String, sourceFilename: String?, caption: String?, albumMessageId: String?, isTemporaryAttachment: Bool) { - let attachmentInfo = OutgoingAttachmentInfo(dataSource: dataSource, contentType: contentType, sourceFilename: sourceFilename, caption: caption, albumMessageId: albumMessageId) - add(mediaMessage: mediaMessage, attachmentInfos: [attachmentInfo], isTemporaryAttachment: isTemporaryAttachment) - } - - @objc(addMediaMessage:attachmentInfos:isTemporaryAttachment:) - public func add(mediaMessage: TSOutgoingMessage, attachmentInfos: [OutgoingAttachmentInfo], isTemporaryAttachment: Bool) { - OutgoingMessagePreparer.prepareAttachments(attachmentInfos, - inMessage: mediaMessage, - completionHandler: { error in - if let error = error { - Storage.writeSync { transaction in - mediaMessage.update(sendingError: error, transaction: transaction) - } - } else { - Storage.writeSync { transaction in - self.add(message: mediaMessage, removeMessageAfterSending: isTemporaryAttachment, transaction: transaction) - } - } - }) - } - - private func add(message: TSOutgoingMessage, removeMessageAfterSending: Bool, transaction: YapDatabaseReadWriteTransaction) { - assert(AppReadiness.isAppReady() || CurrentAppContext().isRunningTests) - - let jobRecord: SSKMessageSenderJobRecord - do { - jobRecord = try SSKMessageSenderJobRecord(message: message, removeMessageAfterSending: false, label: self.jobRecordLabel) - } catch { - owsFailDebug("Failed to build job due to error: \(error).") - return - } - self.add(jobRecord: jobRecord, transaction: transaction) - } - - // MARK: JobQueue - - public typealias DurableOperationType = MessageSenderOperation - public static let jobRecordLabel: String = "MessageSender" - public static let maxRetries: UInt = 1 // Loki: We have our own retrying - public let requiresInternet: Bool = true - public var runningOperations: [MessageSenderOperation] = [] - - public var jobRecordLabel: String { - return type(of: self).jobRecordLabel - } - - @objc - public func setup() { - defaultSetup() - } - - public var isSetup: Bool = false - - /// Used when the user clears their database to cancel any outstanding jobs. - @objc public func clearAllJobs() { - Storage.writeSync { transaction in - let statuses: [SSKJobRecordStatus] = [ .unknown, .ready, .running, .permanentlyFailed ] - var records: [SSKJobRecord] = [] - statuses.forEach { - records += self.finder.allRecords(label: self.jobRecordLabel, status: $0, transaction: transaction) - } - records.forEach { $0.remove(with: transaction) } - } - } - - public func didMarkAsReady(oldJobRecord: SSKMessageSenderJobRecord, transaction: YapDatabaseReadWriteTransaction) { - if let messageId = oldJobRecord.messageId, let message = TSOutgoingMessage.fetch(uniqueId: messageId, transaction: transaction) { - message.updateWithMarkingAllUnsentRecipientsAsSending(with: transaction) - } - } - - public func buildOperation(jobRecord: SSKMessageSenderJobRecord, transaction: YapDatabaseReadTransaction) throws -> MessageSenderOperation { - let message: TSOutgoingMessage - if let invisibleMessage = jobRecord.invisibleMessage { - message = invisibleMessage - } else if let messageId = jobRecord.messageId, let fetchedMessage = TSOutgoingMessage.fetch(uniqueId: messageId, transaction: transaction) { - message = fetchedMessage - } else { - assert(jobRecord.messageId != nil) - throw JobError.obsolete(description: "Message no longer exists.") - } - - return MessageSenderOperation(message: message, jobRecord: jobRecord) - } - - var senderQueues: [String: OperationQueue] = [:] - let defaultQueue: OperationQueue = { - let operationQueue = OperationQueue() - operationQueue.name = "DefaultSendingQueue" - operationQueue.maxConcurrentOperationCount = 1 - operationQueue.qualityOfService = .userInitiated - - return operationQueue - }() - - // We use a per-thread serial OperationQueue to ensure messages are delivered to the - // service in the order the user sent them. - public func operationQueue(jobRecord: SSKMessageSenderJobRecord) -> OperationQueue { - guard let threadId = jobRecord.threadId else { - return defaultQueue - } - - guard let existingQueue = senderQueues[threadId] else { - let operationQueue = OperationQueue() - operationQueue.name = "SendingQueue:\(threadId)" - operationQueue.maxConcurrentOperationCount = 1 - operationQueue.qualityOfService = .userInitiated - - senderQueues[threadId] = operationQueue - - return operationQueue - } - - return existingQueue - } -} - -public class MessageSenderOperation: OWSOperation, DurableOperation { - - // MARK: DurableOperation - - public let jobRecord: SSKMessageSenderJobRecord - - weak public var durableOperationDelegate: MessageSenderJobQueue? - - public var operation: OWSOperation { - return self - } - - // MARK: Init - - let message: TSOutgoingMessage - - init(message: TSOutgoingMessage, jobRecord: SSKMessageSenderJobRecord) { - self.message = message - self.jobRecord = jobRecord - super.init() - } - - // MARK: Dependencies - - var messageSender: MessageSender { - return SSKEnvironment.shared.messageSender - } - - // MARK: OWSOperation - - override public func run() { - self.messageSender.send(message, success: reportSuccess, failure: reportError) - } - - override public func didSucceed() { - Storage.writeSync { transaction in - self.durableOperationDelegate?.durableOperationDidSucceed(self, transaction: transaction) - - if self.jobRecord.removeMessageAfterSending { - self.message.remove(with: transaction) - } - } - } - - override public func didReportError(_ error: Error) { - let message = self.message - var isFailedSessionRequest = false - if message is SessionRequestMessage, let publicKey = message.thread.contactIdentifier() { - isFailedSessionRequest = (Storage.getSessionRequestSentTimestamp(for: publicKey) == message.timestamp) - } - Storage.writeSync { transaction in - if isFailedSessionRequest, let publicKey = message.thread.contactIdentifier() { - Storage.setSessionRequestSentTimestamp(for: publicKey, to: 0, using: transaction) - } - - self.durableOperationDelegate?.durableOperation(self, didReportError: error, transaction: transaction) - } - } - - override public func retryInterval() -> TimeInterval { - // Arbitrary backoff factor... - // With backOffFactor of 1.9 - // try 1 delay: 0.00s - // try 2 delay: 0.19s - // ... - // try 5 delay: 1.30s - // ... - // try 11 delay: 61.31s - let backoffFactor = 1.9 - let maxBackoff = 15 * kMinuteInterval - - let seconds = 0.1 * min(maxBackoff, pow(backoffFactor, Double(self.jobRecord.failureCount))) - return seconds - } - - override public func didFail(error: Error) { - let message = self.message - var isFailedSessionRequest = false - if message is SessionRequestMessage, let publicKey = message.thread.contactIdentifier() { - isFailedSessionRequest = (Storage.getSessionRequestSentTimestamp(for: publicKey) == message.timestamp) - } - Storage.writeSync { transaction in - if isFailedSessionRequest, let publicKey = message.thread.contactIdentifier() { - Storage.setSessionRequestSentTimestamp(for: publicKey, to: 0, using: transaction) - } - - self.durableOperationDelegate?.durableOperation(self, didFailWithError: error, transaction: transaction) - - self.message.update(sendingError: error, transaction: transaction) - - if self.jobRecord.removeMessageAfterSending { - self.message.remove(with: transaction) - } - } - } -} diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index d6add33f3..309c405a0 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -64,10 +64,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import -#import -#import -#import #import #import #import diff --git a/SignalUtilitiesKit/MultiDeviceProtocol.swift b/SignalUtilitiesKit/MultiDeviceProtocol.swift deleted file mode 100644 index 64a283729..000000000 --- a/SignalUtilitiesKit/MultiDeviceProtocol.swift +++ /dev/null @@ -1,274 +0,0 @@ -import PromiseKit - -// A few notes about making changes in this file: -// -// • Don't use a database transaction if you can avoid it. -// • If you do need to use a database transaction, use a read transaction if possible. -// • For write transactions, consider making it the caller's responsibility to manage the database transaction (this helps avoid unnecessary transactions). -// • Think carefully about adding a function; there might already be one for what you need. -// • Document the expected cases in which a function will be used -// • Express those cases in tests. - -@objc(LKMultiDeviceProtocol) -public final class MultiDeviceProtocol : NSObject { - - /// A mapping from hex encoded public key to date updated. - /// - /// - Note: Should only be accessed from `LokiAPI.workQueue` to avoid race conditions. - public static var lastDeviceLinkUpdate: [String:Date] = [:] - - internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } - - // MARK: Settings - public static let deviceLinkUpdateInterval: TimeInterval = 60 - - // MARK: Multi Device Destination - public struct MultiDeviceDestination : Hashable { - public let publicKey: String - public let isMaster: Bool - } - - // MARK: - General - - @objc(isUnlinkDeviceMessage:) - public static func isUnlinkDeviceMessage(_ dataMessage: SSKProtoDataMessage) -> Bool { - let unlinkDeviceFlag = SSKProtoDataMessage.SSKProtoDataMessageFlags.unlinkDevice - return dataMessage.flags & UInt32(unlinkDeviceFlag.rawValue) != 0 - } - - public static func getUserLinkedDevices() -> Set { - var result: Set = [] - storage.dbReadConnection.read { transaction in - result = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: getUserHexEncodedPublicKey(), in: transaction) - } - return result - } - - @objc public static func isSlaveThread(_ thread: TSThread) -> Bool { - guard let thread = thread as? TSContactThread else { return false } - var isSlaveThread = false - storage.dbReadConnection.read { transaction in - isSlaveThread = storage.getMasterHexEncodedPublicKey(for: thread.contactIdentifier(), in: transaction) != nil - } - return isSlaveThread - } - - // MARK: - Sending (Part 1) - - @objc(isMultiDeviceRequiredForMessage:toPublicKey:) - public static func isMultiDeviceRequired(for message: TSOutgoingMessage, to publicKey: String) -> Bool { - return !(message is DeviceLinkMessage) && !(message is UnlinkDeviceMessage) && (message.thread as? TSGroupThread)?.groupModel.groupType != .openGroup - && !Storage.getUserClosedGroupPublicKeys().contains(publicKey) - } - - private static func copy(_ messageSend: OWSMessageSend, for destination: MultiDeviceDestination, with seal: Resolver) -> OWSMessageSend { - var recipient: SignalRecipient! - storage.dbReadConnection.read { transaction in - recipient = SignalRecipient.getOrBuildUnsavedRecipient(forRecipientId: destination.publicKey, transaction: transaction) - } - // TODO: Why is it okay that the thread, sender certificate, etc. don't get changed? - return OWSMessageSend(message: messageSend.message, thread: messageSend.thread, recipient: recipient, - senderCertificate: messageSend.senderCertificate, udAccess: messageSend.udAccess, localNumber: messageSend.localNumber, success: { - seal.fulfill(()) - }, failure: { error in - seal.reject(error) - }) - } - - private static func sendMessage(_ messageSend: OWSMessageSend, to destination: MultiDeviceDestination, in transaction: YapDatabaseReadTransaction) -> Promise { - let (threadPromise, threadPromiseSeal) = Promise.pending() - if messageSend.message.thread.isGroupThread() { - threadPromiseSeal.fulfill(messageSend.message.thread) - } else if let thread = TSContactThread.getWithContactId(destination.publicKey, transaction: transaction) { - threadPromiseSeal.fulfill(thread) - } else { - Storage.write { transaction in - let thread = TSContactThread.getOrCreateThread(withContactId: destination.publicKey, transaction: transaction) - threadPromiseSeal.fulfill(thread) - } - } - return threadPromise.then2 { thread -> Promise in - let message = messageSend.message - let messageSender = SSKEnvironment.shared.messageSender - let (promise, seal) = Promise.pending() - let messageSendCopy = copy(messageSend, for: destination, with: seal) - OWSDispatch.sendingQueue().async { - messageSender.sendMessage(messageSendCopy) - } - return promise - } - } - - /// See [Multi Device Message Sending](https://github.com/loki-project/session-protocol-docs/wiki/Multi-Device-Message-Sending) for more information. - @objc(sendMessageToDestinationAndLinkedDevices:transaction:) - public static func sendMessageToDestinationAndLinkedDevices(_ messageSend: OWSMessageSend, in transaction: YapDatabaseReadTransaction) { -// if !messageSend.isUDSend && messageSend.recipient.recipientId() != getUserHexEncodedPublicKey() { -// #if DEBUG -// preconditionFailure() -// #endif -// } - let message = messageSend.message - let messageSender = SSKEnvironment.shared.messageSender - if !isMultiDeviceRequired(for: message, to: messageSend.recipient.recipientId()) { - print("[Loki] sendMessageToDestinationAndLinkedDevices(_:in:) invoked for a message that doesn't require multi device routing.") - OWSDispatch.sendingQueue().async { - messageSender.sendMessage(messageSend) - } - return - } - print("[Loki] Sending \(type(of: message)) message using multi device routing.") - let publicKey = messageSend.recipient.recipientId() - getMultiDeviceDestinations(for: publicKey, in: transaction).done2 { destinations in - var promises: [Promise] = [] - let masterDestination = destinations.first { $0.isMaster } - if let masterDestination = masterDestination { - storage.dbReadConnection.read { transaction in - promises.append(sendMessage(messageSend, to: masterDestination, in: transaction)) - } - } - let slaveDestinations = destinations.filter { !$0.isMaster } - slaveDestinations.forEach { slaveDestination in - storage.dbReadConnection.read { transaction in - promises.append(sendMessage(messageSend, to: slaveDestination, in: transaction)) - } - } - when(resolved: promises).done(on: OWSDispatch.sendingQueue()) { results in - let errors = results.compactMap { result -> Error? in - if case PromiseKit.Result.rejected(let error) = result { - return error - } else { - return nil - } - } - if errors.isEmpty { - messageSend.success() - } else { - messageSend.failure(errors.first!) - } - } - }.catch2 { error in - // Proceed even if updating the recipient's device links failed, so that message sending - // is independent of whether the file server is online - OWSDispatch.sendingQueue().async { - messageSender.sendMessage(messageSend) - } - } - } - - @objc(updateDeviceLinksIfNeededForPublicKey:transaction:) - public static func updateDeviceLinksIfNeeded(for publicKey: String, in transaction: YapDatabaseReadTransaction) -> AnyPromise { - return AnyPromise.from(getMultiDeviceDestinations(for: publicKey, in: transaction)) - } - - // MARK: - Receiving - - @objc(handleDeviceLinkMessageIfNeeded:wrappedIn:transaction:) - public static func handleDeviceLinkMessageIfNeeded(_ protoContent: SSKProtoContent, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = envelope.source! // Set during UD decryption - guard let deviceLinkMessage = protoContent.lokiDeviceLinkMessage, let master = deviceLinkMessage.masterPublicKey, - let slave = deviceLinkMessage.slavePublicKey, let slaveSignature = deviceLinkMessage.slaveSignature else { - return print("[Loki] Received an invalid device link message.") - } - let deviceLinkingSession = DeviceLinkingSession.current - if let masterSignature = deviceLinkMessage.masterSignature { // Authorization - print("[Loki] Received a device link authorization from: \(publicKey).") // Intentionally not `master` - if let deviceLinkingSession = deviceLinkingSession { - deviceLinkingSession.processLinkingAuthorization(from: master, for: slave, masterSignature: masterSignature, slaveSignature: slaveSignature) - } else { - print("[Loki] Received a device link authorization without a session; ignoring.") - } - // Set any profile info (the device link authorization also includes the master device's profile info) - if let dataMessage = protoContent.dataMessage { - SessionMetaProtocol.updateDisplayNameIfNeeded(for: master, using: dataMessage, in: transaction) - SessionMetaProtocol.updateProfileKeyIfNeeded(for: master, using: dataMessage) - } - } else { // Request - print("[Loki] Received a device link request from: \(publicKey).") // Intentionally not `slave` - if let deviceLinkingSession = deviceLinkingSession { - deviceLinkingSession.processLinkingRequest(from: slave, to: master, with: slaveSignature) - } else { - NotificationCenter.default.post(name: .unexpectedDeviceLinkRequestReceived, object: nil) - } - } - } - - @objc(handleUnlinkDeviceMessage:wrappedIn:transaction:) - public static func handleUnlinkDeviceMessage(_ dataMessage: SSKProtoDataMessage, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = envelope.source! // Set during UD decryption - // Check that the request was sent by our master device - let userPublicKey = getUserHexEncodedPublicKey() - guard let userMasterPublicKey = storage.getMasterHexEncodedPublicKey(for: userPublicKey, in: transaction) else { return } - let wasSentByMasterDevice = (userMasterPublicKey == publicKey) - guard wasSentByMasterDevice else { return } - // Ignore the request if we don't know about the device link in question - let masterDeviceLinks = storage.getDeviceLinks(for: userMasterPublicKey, in: transaction) - if !masterDeviceLinks.contains(where: { - $0.master.publicKey == userMasterPublicKey && $0.slave.publicKey == userPublicKey - }) { - return - } - FileServerAPI.getDeviceLinks(associatedWith: userPublicKey).done2 { slaveDeviceLinks in - // Check that the device link IS present on the file server. - // Note that the device link as seen from the master device's perspective has been deleted at this point, but the - // device link as seen from the slave perspective hasn't. - if slaveDeviceLinks.contains(where: { - $0.master.publicKey == userMasterPublicKey && $0.slave.publicKey == userPublicKey - }) { - for deviceLink in slaveDeviceLinks { // In theory there should only be one - FileServerAPI.removeDeviceLink(deviceLink) // Attempt to clean up on the file server - } - UserDefaults.standard[.wasUnlinked] = true - DispatchQueue.main.async { - NotificationCenter.default.post(name: .dataNukeRequested, object: nil) - } - } - } - } -} - -// MARK: - Sending (Part 2) - -// Here (in a non-@objc extension) because it doesn't interoperate well with Obj-C -public extension MultiDeviceProtocol { - - fileprivate static func getMultiDeviceDestinations(for publicKey: String, in transaction: YapDatabaseReadTransaction) -> Promise> { - let (promise, seal) = Promise>.pending() - func getDestinations(in transaction: YapDatabaseReadTransaction? = nil) { - storage.dbReadConnection.read { transaction in - var destinations: Set = [] - let masterPublicKey = storage.getMasterHexEncodedPublicKey(for: publicKey, in: transaction) ?? publicKey - let masterDestination = MultiDeviceDestination(publicKey: masterPublicKey, isMaster: true) - destinations.insert(masterDestination) - let deviceLinks = storage.getDeviceLinks(for: masterPublicKey, in: transaction) - let slaveDestinations = deviceLinks.map { MultiDeviceDestination(publicKey: $0.slave.publicKey, isMaster: false) } - destinations.formUnion(slaveDestinations) - seal.fulfill(destinations) - } - } - let timeSinceLastUpdate: TimeInterval - if let lastDeviceLinkUpdate = lastDeviceLinkUpdate[publicKey] { - timeSinceLastUpdate = Date().timeIntervalSince(lastDeviceLinkUpdate) - } else { - timeSinceLastUpdate = .infinity - } - if timeSinceLastUpdate > deviceLinkUpdateInterval { - let masterPublicKey = storage.getMasterHexEncodedPublicKey(for: publicKey, in: transaction) ?? publicKey - FileServerAPI.getDeviceLinks(associatedWith: masterPublicKey).done2 { _ in - getDestinations() - lastDeviceLinkUpdate[publicKey] = Date() - }.catch2 { error in - if (error as? DotNetAPI.Error) == DotNetAPI.Error.parsingFailed { - // Don't immediately re-fetch in case of failure due to a parsing error - lastDeviceLinkUpdate[publicKey] = Date() - getDestinations() - } else { - print("[Loki] Failed to get device links due to error: \(error).") - seal.reject(error) - } - } - } else { - getDestinations() - } - return promise - } -} diff --git a/SignalUtilitiesKit/OWSMessageDecrypter.h b/SignalUtilitiesKit/OWSMessageDecrypter.h deleted file mode 100644 index 57cf87277..000000000 --- a/SignalUtilitiesKit/OWSMessageDecrypter.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSPrimaryStorage; -@class SSKProtoEnvelope; -@class YapDatabaseReadWriteTransaction; - -@interface OWSMessageDecryptResult : NSObject - -@property (nonatomic, readonly) NSData *envelopeData; -@property (nonatomic, readonly, nullable) NSData *plaintextData; -@property (nonatomic, readonly) NSString *source; -@property (nonatomic, readonly) UInt32 sourceDevice; -@property (nonatomic, readonly) BOOL isUDMessage; - -@end - -#pragma mark - - -// Decryption result includes the envelope since the envelope -// may be altered by the decryption process. -typedef void (^DecryptSuccessBlock)(OWSMessageDecryptResult *result, YapDatabaseReadWriteTransaction *transaction); -typedef void (^DecryptFailureBlock)(void); - -@interface OWSMessageDecrypter : OWSMessageHandler - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; - -// decryptEnvelope: can be called from any thread. -// successBlock & failureBlock will be called an arbitrary thread. -// -// Exactly one of successBlock & failureBlock will be called, -// once. -- (void)decryptEnvelope:(SSKProtoEnvelope *)envelope - envelopeData:(NSData *)envelopeData - successBlock:(DecryptSuccessBlock)successBlock - failureBlock:(DecryptFailureBlock)failureBlock; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageDecrypter.m b/SignalUtilitiesKit/OWSMessageDecrypter.m deleted file mode 100644 index 968fadf57..000000000 --- a/SignalUtilitiesKit/OWSMessageDecrypter.m +++ /dev/null @@ -1,686 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSMessageDecrypter.h" -#import "NSData+messagePadding.h" -#import "NSString+SSK.h" -#import "NotificationsProtocol.h" -#import "OWSAnalytics.h" -#import "OWSBlockingManager.h" -#import "OWSDevice.h" -#import "OWSError.h" -#import "OWSIdentityManager.h" -#import "OWSPrimaryStorage+PreKeyStore.h" -#import "OWSPrimaryStorage+SessionStore.h" -#import "OWSPrimaryStorage+SignedPreKeyStore.h" -#import "OWSPrimaryStorage.h" -#import "SSKEnvironment.h" -#import "SignalRecipient.h" -#import "TSAccountManager.h" -#import "TSContactThread.h" -#import "TSErrorMessage.h" -#import "TSPreKeyManager.h" -#import -#import -#import -#import -#import -#import -#import -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDescription) -{ - if (error) { - return error; - } - OWSCFailDebug(@"Caller should provide specific error"); - return OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptUDMessage, fallbackErrorDescription); -} - -#pragma mark - - -@interface OWSMessageDecryptResult () - -@property (nonatomic) NSData *envelopeData; -@property (nonatomic, nullable) NSData *plaintextData; -@property (nonatomic) NSString *source; -@property (nonatomic) UInt32 sourceDevice; -@property (nonatomic) BOOL isUDMessage; - -@end - -#pragma mark - - -@implementation OWSMessageDecryptResult - -+ (OWSMessageDecryptResult *)resultWithEnvelopeData:(NSData *)envelopeData - plaintextData:(nullable NSData *)plaintextData - source:(NSString *)source - sourceDevice:(UInt32)sourceDevice - isUDMessage:(BOOL)isUDMessage -{ - OWSAssertDebug(envelopeData); - OWSAssertDebug(source.length > 0); - OWSAssertDebug(sourceDevice > 0); - - OWSMessageDecryptResult *result = [OWSMessageDecryptResult new]; - result.envelopeData = envelopeData; - result.plaintextData = plaintextData; - result.source = source; - result.sourceDevice = sourceDevice; - result.isUDMessage = isUDMessage; - return result; -} - -@end - -#pragma mark - - -@interface OWSMessageDecrypter () - -@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage; -@property (nonatomic, readonly) SNSessionRestorationImplementation *sessionResetImplementation; -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@end - -#pragma mark - - -@implementation OWSMessageDecrypter - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - self = [super init]; - - if (!self) { - return self; - } - - _primaryStorage = primaryStorage; - _sessionResetImplementation = [SNSessionRestorationImplementation new]; - _dbConnection = primaryStorage.newDatabaseConnection; - - OWSSingletonAssert(); - - return self; -} - -#pragma mark - Dependencies - -- (OWSBlockingManager *)blockingManager -{ - OWSAssertDebug(SSKEnvironment.shared.blockingManager); - - return SSKEnvironment.shared.blockingManager; -} - -- (OWSIdentityManager *)identityManager -{ - OWSAssertDebug(SSKEnvironment.shared.identityManager); - - return SSKEnvironment.shared.identityManager; -} - -- (id)udManager -{ - OWSAssertDebug(SSKEnvironment.shared.udManager); - - return SSKEnvironment.shared.udManager; -} - -- (TSAccountManager *)tsAccountManager -{ - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - - return SSKEnvironment.shared.tsAccountManager; -} - -#pragma mark - Blocking - -- (BOOL)isEnvelopeSenderBlocked:(SSKProtoEnvelope *)envelope -{ - OWSAssertDebug(envelope); - - return [self.blockingManager.blockedPhoneNumbers containsObject:envelope.source]; -} - -#pragma mark - Decryption - -- (void)decryptEnvelope:(SSKProtoEnvelope *)envelope - envelopeData:(NSData *)envelopeData - successBlock:(DecryptSuccessBlock)successBlockParameter - failureBlock:(DecryptFailureBlock)failureBlockParameter -{ - OWSAssertDebug(envelope); - OWSAssertDebug(envelopeData); - OWSAssertDebug(successBlockParameter); - OWSAssertDebug(failureBlockParameter); - OWSAssertDebug([self.tsAccountManager isRegistered]); - - // successBlock is called synchronously so that we can avail ourselves of - // the transaction. - // - // Ensure that failureBlock is called on a worker queue. - DecryptFailureBlock failureBlock = ^() { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - failureBlockParameter(); - }); - }; - - NSString *localRecipientId = self.tsAccountManager.localNumber; - uint32_t localDeviceId = OWSDevicePrimaryDeviceId; - DecryptSuccessBlock successBlock = ^( - OWSMessageDecryptResult *result, YapDatabaseReadWriteTransaction *transaction) { - // Ensure all blocked messages are discarded. - if ([self isEnvelopeSenderBlocked:envelope]) { - OWSLogInfo(@"Ignoring blocked envelope from: %@.", envelope.source); - return failureBlock(); - } - - if ([result.source isEqualToString:localRecipientId] && result.sourceDevice == localDeviceId) { - // Self-sent messages should be discarded during the decryption process. - OWSFailDebug(@"Unexpected self-sent sync message."); - return failureBlock(); - } - - // Having received a valid (decryptable) message from this user, - // make note of the fact that they have a valid Signal account. - [SignalRecipient markRecipientAsRegistered:result.source deviceId:result.sourceDevice transaction:transaction]; - - successBlockParameter(result, transaction); - }; - - @try { - OWSLogInfo(@"Decrypting envelope: %@.", [self descriptionForEnvelope:envelope]); - - if (envelope.type != SSKProtoEnvelopeTypeUnidentifiedSender) { - if (!envelope.hasSource || envelope.source.length < 1 || ![ECKeyPair isValidHexEncodedPublicKeyWithCandidate:envelope.source]) { - OWSFailDebug(@"Incoming envelope with invalid source."); - return failureBlock(); - } - if (!envelope.hasSourceDevice || envelope.sourceDevice < 1) { - OWSFailDebug(@"Incoming envelope with invalid source device."); - return failureBlock(); - } - - // We block UD messages later, after they are decrypted. - if ([self isEnvelopeSenderBlocked:envelope]) { - OWSLogInfo(@"Ignoring blocked envelope from: %@.", envelope.source); - return failureBlock(); - } - } - - switch (envelope.type) { - case SSKProtoEnvelopeTypeCiphertext: { - [self throws_decryptSecureMessage:envelope - envelopeData:envelopeData - successBlock:^(OWSMessageDecryptResult *result, YapDatabaseReadWriteTransaction *transaction) { - OWSLogDebug(@"Decrypted secure message."); - successBlock(result, transaction); - } - failureBlock:^(NSError *_Nullable error) { - OWSLogError(@"Decrypting secure message from: %@ failed with error: %@.", - envelopeAddress(envelope), - error); - OWSProdError([OWSAnalyticsEvents messageManagerErrorCouldNotHandleSecureMessage]); - failureBlock(); - }]; - // Return to avoid double-acknowledging. - return; - } - case SSKProtoEnvelopeTypePrekeyBundle: { - [self throws_decryptPreKeyBundle:envelope - envelopeData:envelopeData - successBlock:^(OWSMessageDecryptResult *result, YapDatabaseReadWriteTransaction *transaction) { - OWSLogDebug(@"Decrypted pre key bundle message."); - successBlock(result, transaction); - } - failureBlock:^(NSError *_Nullable error) { - OWSLogError(@"Decrypting pre key bundle message from: %@ failed with error: %@.", - envelopeAddress(envelope), - error); - OWSProdError([OWSAnalyticsEvents messageManagerErrorCouldNotHandlePrekeyBundle]); - failureBlock(); - }]; - // Return to avoid double-acknowledging. - return; - } - // These message types don't have a payload to decrypt. - case SSKProtoEnvelopeTypeReceipt: - case SSKProtoEnvelopeTypeKeyExchange: - case SSKProtoEnvelopeTypeUnknown: { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSMessageDecryptResult *result = - [OWSMessageDecryptResult resultWithEnvelopeData:envelopeData - plaintextData:nil - source:envelope.source - sourceDevice:envelope.sourceDevice - isUDMessage:NO]; - successBlock(result, transaction); - }]; - // Return to avoid double-acknowledging. - return; - } - case SSKProtoEnvelopeTypeClosedGroupCiphertext: { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - NSError *error = nil; - NSArray *plaintextAndSenderPublicKey = [LKClosedGroupUtilities decryptEnvelope:envelope transaction:transaction error:&error]; - if (error != nil) { return failureBlock(); } - NSData *plaintext = plaintextAndSenderPublicKey[0]; - NSString *senderPublicKey = plaintextAndSenderPublicKey[1]; - SSKProtoEnvelopeBuilder *newEnvelope = [envelope asBuilder]; - [newEnvelope setSource:senderPublicKey]; - NSData *newEnvelopeAsData = [newEnvelope buildSerializedDataAndReturnError:&error]; - if (error != nil) { return failureBlock(); } - NSString *userPublicKey = [OWSIdentityManager.sharedManager.identityKeyPair hexEncodedPublicKey]; - if ([senderPublicKey isEqual:userPublicKey]) { return failureBlock(); } - OWSMessageDecryptResult *result = [OWSMessageDecryptResult resultWithEnvelopeData:newEnvelopeAsData - plaintextData:[plaintext removePadding] - source:senderPublicKey - sourceDevice:OWSDevicePrimaryDeviceId - isUDMessage:NO]; - successBlock(result, transaction); - }]; - return; - } - case SSKProtoEnvelopeTypeUnidentifiedSender: { - [self decryptUnidentifiedSender:envelope - successBlock:^(OWSMessageDecryptResult *result, YapDatabaseReadWriteTransaction *transaction) { - OWSLogDebug(@"Decrypted unidentified sender message."); - successBlock(result, transaction); - } - failureBlock:^(NSError *_Nullable error) { - OWSLogError(@"Decrypting unidentified sender message from: %@ failed with error: %@.", - envelopeAddress(envelope), - error); - OWSProdError([OWSAnalyticsEvents messageManagerErrorCouldNotHandleUnidentifiedSenderMessage]); - failureBlock(); - }]; - // Return to avoid double-acknowledging. - return; - } - default: - OWSLogWarn(@"Received unhandled envelope type: %d.", (int)envelope.type); - break; - } - } @catch (NSException *exception) { - OWSFailDebug(@"Received an invalid envelope: %@.", exception.debugDescription); - OWSProdFail([OWSAnalyticsEvents messageManagerErrorInvalidProtocolMessage]); - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSErrorMessage *errorMessage = [TSErrorMessage corruptedMessageInUnknownThread]; - [SSKEnvironment.shared.notificationsManager notifyUserForThreadlessErrorMessage:errorMessage - transaction:transaction]; - }]; - } - - failureBlock(); -} - -- (void)throws_decryptSecureMessage:(SSKProtoEnvelope *)envelope - envelopeData:(NSData *)envelopeData - successBlock:(DecryptSuccessBlock)successBlock - failureBlock:(void (^)(NSError *_Nullable error))failureBlock -{ - OWSAssertDebug(envelope); - OWSAssertDebug(envelopeData); - OWSAssertDebug(successBlock); - OWSAssertDebug(failureBlock); - - [self decryptEnvelope:envelope - envelopeData:envelopeData - cipherTypeName:@"Secure Message" - cipherMessageBlock:^(NSData *encryptedData) { - return [[WhisperMessage alloc] init_throws_withData:encryptedData]; - } - successBlock:successBlock - failureBlock:failureBlock]; -} - -- (void)throws_decryptPreKeyBundle:(SSKProtoEnvelope *)envelope - envelopeData:(NSData *)envelopeData - successBlock:(DecryptSuccessBlock)successBlock - failureBlock:(void (^)(NSError *_Nullable error))failureBlock -{ - OWSAssertDebug(envelope); - OWSAssertDebug(envelopeData); - OWSAssertDebug(successBlock); - OWSAssertDebug(failureBlock); - - // Check whether we need to refresh our PreKeys every time we receive a PreKeyWhisperMessage. - [TSPreKeyManager checkPreKeys]; - - [self decryptEnvelope:envelope - envelopeData:envelopeData - cipherTypeName:@"PreKey Bundle" - cipherMessageBlock:^(NSData *encryptedData) { - return [[PreKeyWhisperMessage alloc] init_throws_withData:encryptedData]; - } - successBlock:successBlock - failureBlock:failureBlock]; -} - -- (void)decryptEnvelope:(SSKProtoEnvelope *)envelope - envelopeData:(NSData *)envelopeData - cipherTypeName:(NSString *)cipherTypeName - cipherMessageBlock:(id (^_Nonnull)(NSData *))cipherMessageBlock - successBlock:(DecryptSuccessBlock)successBlock - failureBlock:(void (^)(NSError *_Nullable error))failureBlock -{ - OWSAssertDebug(envelope); - OWSAssertDebug(envelopeData); - OWSAssertDebug(cipherTypeName.length > 0); - OWSAssertDebug(cipherMessageBlock); - OWSAssertDebug(successBlock); - OWSAssertDebug(failureBlock); - - NSString *recipientId = envelope.source; - int deviceId = envelope.sourceDevice; - - // DEPRECATED - Remove `legacyMessage` after all clients have been upgraded. - NSData *encryptedData = envelope.content ?: envelope.legacyMessage; - if (!encryptedData) { - OWSProdFail([OWSAnalyticsEvents messageManagerErrorMessageEnvelopeHasNoContent]); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, @"Envelope has no content."); - return failureBlock(error); - } - - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - @try { - id cipherMessage = cipherMessageBlock(encryptedData); - SNSessionCipher *cipher = [[SNSessionCipher alloc] - initWithSessionResetImplementation:self.sessionResetImplementation - sessionStore:self.primaryStorage - preKeyStore:self.primaryStorage - signedPreKeyStore:self.primaryStorage - identityKeyStore:self.identityManager - recipientID:recipientId - deviceID:deviceId]; - - // plaintextData may be nil for some envelope types. - NSError *error = nil; - NSData *_Nullable decryptedData = [cipher decrypt:cipherMessage protocolContext:transaction error:&error]; - // Throw if we got an error - SCKRaiseIfExceptionWrapperError(error); - NSData *_Nullable plaintextData = decryptedData != nil ? [decryptedData removePadding] : nil; - - OWSMessageDecryptResult *result = [OWSMessageDecryptResult resultWithEnvelopeData:envelopeData - plaintextData:plaintextData - source:envelope.source - sourceDevice:envelope.sourceDevice - isUDMessage:NO]; - successBlock(result, transaction); - } @catch (NSException *exception) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self processException:exception envelope:envelope]; - NSString *errorDescription = [NSString - stringWithFormat:@"Exception while decrypting %@: %@.", cipherTypeName, exception.description]; - OWSLogError(@"%@", errorDescription); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription); - failureBlock(error); - }); - } - }]; -} - -- (void)decryptUnidentifiedSender:(SSKProtoEnvelope *)envelope - successBlock:(DecryptSuccessBlock)successBlock - failureBlock:(void (^)(NSError *_Nullable error))failureBlock -{ - OWSAssertDebug(envelope); - OWSAssertDebug(successBlock); - OWSAssertDebug(failureBlock); - - // NOTE: We don't need to bother with `legacyMessage` for UD messages. - NSData *encryptedData = envelope.content; - if (!encryptedData) { - NSString *errorDescription = @"UD Envelope is missing content."; - OWSFailDebug(@"%@", errorDescription); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptUDMessage, errorDescription); - return failureBlock(error); - } - - UInt64 serverTimestamp = envelope.timestamp; - - id certificateValidator = - [[SMKCertificateDefaultValidator alloc] initWithTrustRoot:self.udManager.trustRoot]; - - NSString *localRecipientId = self.tsAccountManager.localNumber; - uint32_t localDeviceId = OWSDevicePrimaryDeviceId; - - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - NSError *cipherError; - SMKSecretSessionCipher *_Nullable cipher = - [[SMKSecretSessionCipher alloc] initWithSessionResetImplementation:self.sessionResetImplementation - sessionStore:self.primaryStorage - preKeyStore:self.primaryStorage - signedPreKeyStore:self.primaryStorage - identityStore:self.identityManager - error:&cipherError]; - - if (cipherError || !cipher) { - OWSFailDebug(@"Could not create secret session cipher: %@.", cipherError); - cipherError = EnsureDecryptError(cipherError, @"Could not create secret session cipher."); - return failureBlock(cipherError); - } - - NSError *decryptError; - SMKDecryptResult *_Nullable decryptResult = - [cipher throwswrapped_decryptMessageWithCertificateValidator:certificateValidator - cipherTextData:encryptedData - timestamp:serverTimestamp - localRecipientId:localRecipientId - localDeviceId:localDeviceId - protocolContext:transaction - error:&decryptError]; - - if (!decryptResult) { - if (!decryptError) { - OWSFailDebug(@"Caller should provide specific error."); - NSError *error = OWSErrorWithCodeDescription( - OWSErrorCodeFailedToDecryptUDMessage, @"Could not decrypt UD message."); - return failureBlock(error); - } - - // Decrypt Failure Part 1: Unwrap failure details - - NSError *_Nullable underlyingError; - SSKProtoEnvelope *_Nullable identifiedEnvelope; - - if (![decryptError.domain isEqualToString:@"SessionMetadataKit.SecretSessionKnownSenderError"]) { - underlyingError = decryptError; - identifiedEnvelope = envelope; - } else { - underlyingError = decryptError.userInfo[NSUnderlyingErrorKey]; - - NSString *senderRecipientId - = decryptError.userInfo[SecretSessionKnownSenderError.kSenderRecipientIdKey]; - OWSAssert(senderRecipientId); - - NSNumber *senderDeviceId = decryptError.userInfo[SecretSessionKnownSenderError.kSenderDeviceIdKey]; - OWSAssert(senderDeviceId); - - SSKProtoEnvelopeBuilder *identifiedEnvelopeBuilder = envelope.asBuilder; - identifiedEnvelopeBuilder.source = senderRecipientId; - identifiedEnvelopeBuilder.sourceDevice = senderDeviceId.unsignedIntValue; - NSError *identifiedEnvelopeBuilderError; - - identifiedEnvelope = [identifiedEnvelopeBuilder buildAndReturnError:&identifiedEnvelopeBuilderError]; - if (identifiedEnvelopeBuilderError) { - OWSFailDebug(@"identifiedEnvelopeBuilderError: %@", identifiedEnvelopeBuilderError); - } - } - OWSAssert(underlyingError); - OWSAssert(identifiedEnvelope); - - NSException *_Nullable underlyingException; - if ([underlyingError.domain isEqualToString:SCKExceptionWrapperErrorDomain] - && underlyingError.code == SCKExceptionWrapperErrorThrown) { - - underlyingException = underlyingError.userInfo[SCKExceptionWrapperUnderlyingExceptionKey]; - OWSAssert(underlyingException); - } - - // Decrypt Failure Part 2: Handle unwrapped failure details - - if (underlyingException) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self processException:underlyingException envelope:identifiedEnvelope]; - NSString *errorDescription = [NSString - stringWithFormat:@"Exception while decrypting UD message: %@.", underlyingException.description]; - OWSLogError(@"%@", errorDescription); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription); - failureBlock(error); - }); - return; - } - - if ([underlyingError.domain isEqualToString:@"SessionMetadataKit.SMKSecretSessionCipherError"] - && underlyingError.code == SMKSecretSessionCipherErrorSelfSentMessage) { - // Self-sent messages can be safely discarded. - failureBlock(underlyingError); - return; - } - - // Attempt to recover automatically - if ([decryptError userInfo][NSUnderlyingErrorKey] != nil) { - NSDictionary *underlyingErrorUserInfo = [[decryptError userInfo][NSUnderlyingErrorKey] userInfo]; - if (underlyingErrorUserInfo[SCKExceptionWrapperUnderlyingExceptionKey] != nil) { - NSException *underlyingUnderlyingError = underlyingErrorUserInfo[SCKExceptionWrapperUnderlyingExceptionKey]; - if ([[underlyingUnderlyingError reason] hasPrefix:@"Bad Mac!"]) { - if ([underlyingError userInfo][@"kSenderRecipientIdKey"] != nil) { - NSString *senderPublicKey = [underlyingError userInfo][@"kSenderRecipientIdKey"]; - TSContactThread *thread = [TSContactThread getThreadWithContactId:senderPublicKey transaction:transaction]; - if (thread != nil) { - [thread addSessionRestoreDevice:senderPublicKey transaction:transaction]; - [LKSessionManagementProtocol startSessionResetInThread:thread transaction:transaction]; - } - } - } - } - } - - failureBlock(underlyingError); - return; - } - - if (decryptResult.messageType == SMKMessageTypePrekey) { - [TSPreKeyManager checkPreKeys]; - } - - NSString *source = decryptResult.senderRecipientId; - if (source.length < 1) { - NSString *errorDescription = @"Invalid UD sender."; - OWSFailDebug(@"%@", errorDescription); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptUDMessage, errorDescription); - return failureBlock(error); - } - - long sourceDeviceId = decryptResult.senderDeviceId; - if (sourceDeviceId < 1 || sourceDeviceId > UINT32_MAX) { - NSString *errorDescription = @"Invalid UD sender device ID."; - OWSFailDebug(@"%@", errorDescription); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptUDMessage, errorDescription); - return failureBlock(error); - } - NSData *plaintextData = [decryptResult.paddedPayload removePadding]; - - SSKProtoEnvelopeBuilder *envelopeBuilder = [envelope asBuilder]; - [envelopeBuilder setSource:source]; - [envelopeBuilder setSourceDevice:(uint32_t)sourceDeviceId]; - if (decryptResult.messageType == SMKMessageTypeFallback) { - [envelopeBuilder setType:SSKProtoEnvelopeTypeFallbackMessage]; - OWSLogInfo(@"SMKMessageTypeFallback"); - } - NSError *envelopeBuilderError; - NSData *_Nullable newEnvelopeData = [envelopeBuilder buildSerializedDataAndReturnError:&envelopeBuilderError]; - if (envelopeBuilderError || !newEnvelopeData) { - OWSFailDebug(@"Could not update UD envelope data: %@", envelopeBuilderError); - NSError *error = EnsureDecryptError(envelopeBuilderError, @"Could not update UD envelope data"); - return failureBlock(error); - } - - OWSMessageDecryptResult *result = [OWSMessageDecryptResult resultWithEnvelopeData:newEnvelopeData - plaintextData:plaintextData - source:source - sourceDevice:(uint32_t)sourceDeviceId - isUDMessage:YES]; - successBlock(result, transaction); - }]; -} - -- (void)processException:(NSException *)exception envelope:(SSKProtoEnvelope *)envelope -{ - OWSLogError( - @"Got exception: %@ of type: %@ with reason: %@", exception.description, exception.name, exception.reason); - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSErrorMessage *errorMessage; - - if (envelope.source.length == 0) { - TSErrorMessage *errorMessage = [TSErrorMessage corruptedMessageInUnknownThread]; - [SSKEnvironment.shared.notificationsManager notifyUserForThreadlessErrorMessage:errorMessage - transaction:transaction]; - return; - } - - if ([exception.name isEqualToString:NoSessionException]) { - OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorNoSession], envelope); - errorMessage = [TSErrorMessage missingSessionWithEnvelope:envelope withTransaction:transaction]; - } else if ([exception.name isEqualToString:InvalidKeyException]) { - OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKey], envelope); - errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction]; - } else if ([exception.name isEqualToString:InvalidKeyIdException]) { - OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKeyId], envelope); - errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction]; - } else if ([exception.name isEqualToString:DuplicateMessageException]) { - // Duplicate messages are silently discarded. - return; - } else if ([exception.name isEqualToString:InvalidVersionException]) { - OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidMessageVersion], envelope); - errorMessage = [TSErrorMessage invalidVersionWithEnvelope:envelope withTransaction:transaction]; - } else if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { - // Should no longer get here, since we now record the new identity for incoming messages. - OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorUntrustedIdentityKeyException], envelope); - OWSFailDebug(@"Failed to trust identity on incoming message from: %@", envelopeAddress(envelope)); - return; - } else { - OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorCorruptMessage], envelope); - errorMessage = [TSErrorMessage corruptedMessageWithEnvelope:envelope withTransaction:transaction]; - } - - OWSAssertDebug(errorMessage); - if (errorMessage != nil) { - [LKSessionManagementProtocol handleDecryptionError:errorMessage forPublicKey:envelope.source transaction:transaction]; - if (![LKSessionMetaProtocol isErrorMessageFromBeforeRestoration:errorMessage]) { - [errorMessage saveWithTransaction:transaction]; - [self notifyUserForErrorMessage:errorMessage envelope:envelope transaction:transaction]; - } else { - // Show the thread if it exists before restoration - NSString *masterPublicKey = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:envelope.source in:transaction] ?: envelope.source; - TSThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:masterPublicKey transaction:transaction]; - contactThread.shouldThreadBeVisible = true; - [contactThread saveWithTransaction:transaction]; - } - } - }]; -} - -- (void)notifyUserForErrorMessage:(TSErrorMessage *)errorMessage - envelope:(SSKProtoEnvelope *)envelope - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - NSString *masterPublicKey = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:envelope.source in:transaction] ?: envelope.source; - TSThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:masterPublicKey transaction:transaction]; - [SSKEnvironment.shared.notificationsManager notifyUserForErrorMessage:errorMessage - thread:contactThread - transaction:transaction]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageHandler.h b/SignalUtilitiesKit/OWSMessageHandler.h deleted file mode 100644 index 8722028b7..000000000 --- a/SignalUtilitiesKit/OWSMessageHandler.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class SSKProtoContent; -@class SSKProtoDataMessage; -@class SSKProtoEnvelope; - -NSString *envelopeAddress(SSKProtoEnvelope *envelope); - -@interface OWSMessageHandler : NSObject - -- (NSString *)descriptionForEnvelopeType:(SSKProtoEnvelope *)envelope; -- (NSString *)descriptionForEnvelope:(SSKProtoEnvelope *)envelope; -- (NSString *)descriptionForContent:(SSKProtoContent *)content; -- (NSString *)descriptionForDataMessage:(SSKProtoDataMessage *)dataMessage; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageHandler.m b/SignalUtilitiesKit/OWSMessageHandler.m deleted file mode 100644 index 892540eae..000000000 --- a/SignalUtilitiesKit/OWSMessageHandler.m +++ /dev/null @@ -1,183 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSMessageHandler.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -// used in log formatting -NSString *envelopeAddress(SSKProtoEnvelope *envelope) -{ - return [NSString stringWithFormat:@"%@.%d", envelope.source, (unsigned int)envelope.sourceDevice]; -} - -@implementation OWSMessageHandler - -- (NSString *)descriptionForEnvelopeType:(SSKProtoEnvelope *)envelope -{ - OWSAssertDebug(envelope != nil); - - switch (envelope.type) { - case SSKProtoEnvelopeTypeReceipt: - return @"DeliveryReceipt"; - case SSKProtoEnvelopeTypeUnknown: - // Shouldn't happen - return @"Unknown"; - case SSKProtoEnvelopeTypeCiphertext: - return @"SignalEncryptedMessage"; - case SSKProtoEnvelopeTypeKeyExchange: - // Unsupported - return @"KeyExchange"; - case SSKProtoEnvelopeTypePrekeyBundle: - return @"PreKeyEncryptedMessage"; - case SSKProtoEnvelopeTypeUnidentifiedSender: - return @"UnidentifiedSender"; - case SSKProtoEnvelopeTypeFallbackMessage: - return @"FallbackMessage"; - case SSKProtoEnvelopeTypeClosedGroupCiphertext: - return @"ClosedGroupCiphertext"; - default: - // Shouldn't happen - return @"Other"; - } -} - -- (NSString *)descriptionForEnvelope:(SSKProtoEnvelope *)envelope -{ - OWSAssertDebug(envelope != nil); - - return [NSString stringWithFormat:@"", - [self descriptionForEnvelopeType:envelope], - envelopeAddress(envelope), - envelope.timestamp, - (unsigned long)envelope.content.length]; -} - -/** - * We don't want to just log `content.description` because we'd potentially log message bodies for dataMesssages and - * sync transcripts - */ -- (NSString *)descriptionForContent:(SSKProtoContent *)content -{ - if (content.syncMessage) { - return [NSString stringWithFormat:@"", [self descriptionForSyncMessage:content.syncMessage]]; - } else if (content.dataMessage) { - return [NSString stringWithFormat:@"", [self descriptionForDataMessage:content.dataMessage]]; - } else if (content.callMessage) { - NSString *callMessageDescription = [self descriptionForCallMessage:content.callMessage]; - return [NSString stringWithFormat:@"", callMessageDescription]; - } else if (content.nullMessage) { - return [NSString stringWithFormat:@"", content.nullMessage]; - } else if (content.receiptMessage) { - return [NSString stringWithFormat:@"", content.receiptMessage]; - } else if (content.typingMessage) { - return [NSString stringWithFormat:@"", content.typingMessage]; - } else { - // Don't fire an analytics event; if we ever add a new content type, we'd generate a ton of - // analytics traffic. - return @"UnknownContent"; - } -} - -- (NSString *)descriptionForCallMessage:(SSKProtoCallMessage *)callMessage -{ - NSString *messageType; - UInt64 callId; - - if (callMessage.offer) { - messageType = @"Offer"; - callId = callMessage.offer.id; - } else if (callMessage.busy) { - messageType = @"Busy"; - callId = callMessage.busy.id; - } else if (callMessage.answer) { - messageType = @"Answer"; - callId = callMessage.answer.id; - } else if (callMessage.hangup) { - messageType = @"Hangup"; - callId = callMessage.hangup.id; - } else if (callMessage.iceUpdate.count > 0) { - messageType = [NSString stringWithFormat:@"Ice Updates (%lu)", (unsigned long)callMessage.iceUpdate.count]; - callId = callMessage.iceUpdate.firstObject.id; - } else { - OWSFailDebug(@"failure: unexpected call message type: %@", callMessage); - messageType = @"Unknown"; - callId = 0; - } - - return [NSString stringWithFormat:@"type: %@, id: %llu", messageType, callId]; -} - -/** - * We don't want to just log `dataMessage.description` because we'd potentially log message contents - */ -- (NSString *)descriptionForDataMessage:(SSKProtoDataMessage *)dataMessage -{ - NSMutableString *description = [NSMutableString new]; - - if (dataMessage.group) { - [description appendString:@"(Group:YES) "]; - } - - if ((dataMessage.flags & SSKProtoDataMessageFlagsEndSession) != 0) { - [description appendString:@"EndSession"]; - } else if ((dataMessage.flags & SSKProtoDataMessageFlagsExpirationTimerUpdate) != 0) { - [description appendString:@"ExpirationTimerUpdate"]; - } else if ((dataMessage.flags & SSKProtoDataMessageFlagsProfileKeyUpdate) != 0) { - [description appendString:@"ProfileKey"]; - } else if (dataMessage.attachments.count > 0) { - [description appendString:@"MessageWithAttachment"]; - } else { - [description appendString:@"Plain"]; - } - - return [NSString stringWithFormat:@"<%@ />", description]; -} - -/** - * We don't want to just log `syncMessage.description` because we'd potentially log message contents in sent transcripts - */ -- (NSString *)descriptionForSyncMessage:(SSKProtoSyncMessage *)syncMessage -{ - NSMutableString *description = [NSMutableString new]; - if (syncMessage.sent) { - [description appendString:@"SentTranscript"]; - } else if (syncMessage.request) { - if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeContacts) { - [description appendString:@"ContactRequest"]; - } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeGroups) { - [description appendString:@"GroupRequest"]; - } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeBlocked) { - [description appendString:@"BlockedRequest"]; - } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeConfiguration) { - [description appendString:@"ConfigurationRequest"]; - } else { - OWSFailDebug(@"Unknown sync message request type"); - [description appendString:@"UnknownRequest"]; - } - } else if (syncMessage.blocked) { - [description appendString:@"Blocked"]; - } else if (syncMessage.read.count > 0) { - [description appendString:@"ReadReceipt"]; - } else if (syncMessage.verified) { - NSString *verifiedString = - [NSString stringWithFormat:@"Verification for: %@", syncMessage.verified.destination]; - [description appendString:verifiedString]; - } else if (syncMessage.contacts) { - [description appendString:@"Contacts"]; - } else if (syncMessage.groups) { - [description appendString:@"ClosedGroups"]; - } else if (syncMessage.openGroups) { - [description appendString:@"OpenGroups"]; - } else { - [description appendString:@"Unknown"]; - } - - return description; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageManager.h b/SignalUtilitiesKit/OWSMessageManager.h deleted file mode 100644 index f8624d0a5..000000000 --- a/SignalUtilitiesKit/OWSMessageManager.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSPrimaryStorage; -@class SSKProtoEnvelope; -@class TSThread; -@class YapDatabaseReadWriteTransaction; - -@interface OWSMessageManager : OWSMessageHandler - -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)sharedManager; - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; - -// processEnvelope: can be called from any thread. -- (void)throws_processEnvelope:(SSKProtoEnvelope *)envelope - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction - serverID:(uint64_t)serverID; - -// This should be invoked by the main app when the app is ready. -- (void)startObserving; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageManager.m b/SignalUtilitiesKit/OWSMessageManager.m deleted file mode 100644 index d839a282e..000000000 --- a/SignalUtilitiesKit/OWSMessageManager.m +++ /dev/null @@ -1,1735 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSMessageManager.h" -#import "AppContext.h" -#import "AppReadiness.h" -#import "ContactsManagerProtocol.h" -#import "MimeTypeUtil.h" -#import "NSNotificationCenter+OWS.h" -#import "NSString+SSK.h" -#import "NotificationsProtocol.h" -#import "OWSAttachmentDownloads.h" -#import "OWSBlockingManager.h" -#import "OWSCallMessageHandler.h" -#import "OWSContact.h" -#import "OWSDevice.h" -#import "OWSDevicesService.h" -#import "OWSDisappearingConfigurationUpdateInfoMessage.h" -#import "OWSDisappearingMessagesConfiguration.h" -#import "OWSDisappearingMessagesJob.h" -#import "LKDeviceLinkMessage.h" -#import "OWSIdentityManager.h" -#import "OWSIncomingMessageFinder.h" -#import "OWSIncomingSentMessageTranscript.h" -#import "OWSMessageSender.h" -#import "OWSMessageUtils.h" -#import "OWSOutgoingNullMessage.h" -#import "OWSOutgoingReceiptManager.h" -#import "OWSPrimaryStorage+SessionStore.h" -#import "OWSPrimaryStorage+Loki.h" -#import "OWSPrimaryStorage.h" -#import "OWSReadReceiptManager.h" -#import "OWSRecordTranscriptJob.h" -#import "OWSSyncGroupsMessage.h" -#import "OWSSyncGroupsRequestMessage.h" -#import "ProfileManagerProtocol.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "SSKAsserts.h" -#import "TSAttachment.h" -#import "TSAttachmentPointer.h" -#import "TSAttachmentStream.h" -#import "TSContactThread.h" -#import "TSDatabaseView.h" -#import "TSGroupModel.h" -#import "TSGroupThread.h" -#import "TSIncomingMessage.h" -#import "TSInfoMessage.h" -#import "TSNetworkManager.h" -#import "TSOutgoingMessage.h" -#import "TSQuotedMessage.h" -#import -#import -#import -#import -#import -#import -#import "OWSDispatch.h" -#import "OWSBatchMessageProcessor.h" -#import "OWSQueues.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSMessageManager () - -@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage; -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -@property (nonatomic, readonly) OWSIncomingMessageFinder *incomingMessageFinder; - -@end - -#pragma mark - - -@implementation OWSMessageManager - -+ (instancetype)sharedManager -{ - OWSAssertDebug(SSKEnvironment.shared.messageManager); - - return SSKEnvironment.shared.messageManager; -} - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - self = [super init]; - - if (!self) { - return self; - } - - _primaryStorage = primaryStorage; - _dbConnection = primaryStorage.newDatabaseConnection; - _incomingMessageFinder = [[OWSIncomingMessageFinder alloc] initWithPrimaryStorage:primaryStorage]; - - OWSSingletonAssert(); - - return self; -} - -- (void)dealloc { - [NSNotificationCenter.defaultCenter removeObserver:self]; -} - -#pragma mark - - -- (id)callMessageHandler -{ - OWSAssertDebug(SSKEnvironment.shared.callMessageHandler); - - return SSKEnvironment.shared.callMessageHandler; -} - -- (id)contactsManager -{ - OWSAssertDebug(SSKEnvironment.shared.contactsManager); - - return SSKEnvironment.shared.contactsManager; -} - -- (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return SSKEnvironment.shared.messageSenderJobQueue; -} - -- (OWSBlockingManager *)blockingManager -{ - OWSAssertDebug(SSKEnvironment.shared.blockingManager); - - return SSKEnvironment.shared.blockingManager; -} - -- (OWSIdentityManager *)identityManager -{ - OWSAssertDebug(SSKEnvironment.shared.identityManager); - - return SSKEnvironment.shared.identityManager; -} - -- (TSNetworkManager *)networkManager -{ - OWSAssertDebug(SSKEnvironment.shared.networkManager); - - return SSKEnvironment.shared.networkManager; -} - -- (OWSOutgoingReceiptManager *)outgoingReceiptManager -{ - OWSAssertDebug(SSKEnvironment.shared.outgoingReceiptManager); - - return SSKEnvironment.shared.outgoingReceiptManager; -} - -- (id)syncManager -{ - OWSAssertDebug(SSKEnvironment.shared.syncManager); - - return SSKEnvironment.shared.syncManager; -} - -- (TSAccountManager *)tsAccountManager -{ - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - - return SSKEnvironment.shared.tsAccountManager; -} - -- (id)profileManager -{ - return SSKEnvironment.shared.profileManager; -} - -- (id)typingIndicators -{ - return SSKEnvironment.shared.typingIndicators; -} - -- (OWSAttachmentDownloads *)attachmentDownloads -{ - return SSKEnvironment.shared.attachmentDownloads; -} - -#pragma mark - - -- (void)startObserving -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(yapDatabaseModified:) - name:YapDatabaseModifiedNotification - object:OWSPrimaryStorage.sharedManager.dbNotificationObject]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(yapDatabaseModified:) - name:YapDatabaseModifiedExternallyNotification - object:nil]; -} - -- (void)yapDatabaseModified:(NSNotification *)notification -{ - if (AppReadiness.isAppReady) { - [OWSMessageUtils.sharedManager updateApplicationBadgeCount]; - } else { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - [OWSMessageUtils.sharedManager updateApplicationBadgeCount]; - }]; - }); - } -} - -#pragma mark - - -- (BOOL)isEnvelopeSenderBlocked:(SSKProtoEnvelope *)envelope -{ - OWSAssertDebug(envelope); - - return [self.blockingManager isRecipientIdBlocked:envelope.source]; -} - -- (BOOL)isDataMessageBlocked:(SSKProtoDataMessage *)dataMessage envelope:(SSKProtoEnvelope *)envelope -{ - OWSAssertDebug(dataMessage); - OWSAssertDebug(envelope); - - if (dataMessage.group) { - return [self.blockingManager isGroupIdBlocked:dataMessage.group.id]; - } else { - BOOL senderBlocked = [self isEnvelopeSenderBlocked:envelope]; - - // If the envelopeSender was blocked, we never should have gotten as far as decrypting the dataMessage. - OWSAssertDebug(!senderBlocked); - - return senderBlocked; - } -} - -#pragma mark - - -- (void)throws_processEnvelope:(SSKProtoEnvelope *)envelope - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction - serverID:(uint64_t)serverID -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - if (!self.tsAccountManager.isRegistered) { - OWSFailDebug(@"Not registered."); - return; - } - - OWSLogInfo(@"Handling decrypted envelope: %@.", [self descriptionForEnvelope:envelope]); - - if (!envelope.hasSource || envelope.source.length < 1) { - OWSFailDebug(@"Incoming envelope with invalid source."); - return; - } - if (!envelope.hasSourceDevice || envelope.sourceDevice < 1) { - OWSFailDebug(@"Incoming envelope with invalid source device."); - return; - } - - if ([self isEnvelopeSenderBlocked:envelope]) { - return; - } - - [self checkForUnknownLinkedDevice:envelope transaction:transaction]; - - switch (envelope.type) { - case SSKProtoEnvelopeTypeFallbackMessage: - case SSKProtoEnvelopeTypeCiphertext: - case SSKProtoEnvelopeTypePrekeyBundle: - case SSKProtoEnvelopeTypeClosedGroupCiphertext: - case SSKProtoEnvelopeTypeUnidentifiedSender: - if (!plaintextData) { - OWSFailDebug(@"missing decrypted data for envelope: %@", [self descriptionForEnvelope:envelope]); - return; - } - [self throws_handleEnvelope:envelope - plaintextData:plaintextData - wasReceivedByUD:wasReceivedByUD - transaction:transaction - serverID:serverID]; - break; - case SSKProtoEnvelopeTypeReceipt: - OWSAssertDebug(!plaintextData); - [self handleDeliveryReceipt:envelope transaction:transaction]; - break; - // Other messages are just dismissed for now. - case SSKProtoEnvelopeTypeKeyExchange: - OWSLogWarn(@"Received Key Exchange Message, not supported"); - break; - case SSKProtoEnvelopeTypeUnknown: - OWSLogWarn(@"Received an unknown message type"); - break; - default: - OWSLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type); - break; - } -} - -- (void)handleDeliveryReceipt:(SSKProtoEnvelope *)envelope transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - // Old-style delivery notices don't include a "delivery timestamp". - [self processDeliveryReceiptsFromRecipientId:envelope.source - sentTimestamps:@[ - @(envelope.timestamp), - ] - deliveryTimestamp:nil - transaction:transaction]; -} - -// deliveryTimestamp is an optional parameter, since legacy -// delivery receipts don't have a "delivery timestamp". Those -// messages repurpose the "timestamp" field to indicate when the -// corresponding message was originally sent. -- (void)processDeliveryReceiptsFromRecipientId:(NSString *)recipientId - sentTimestamps:(NSArray *)sentTimestamps - deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (recipientId.length < 1) { - OWSFailDebug(@"Empty recipientId."); - return; - } - if (sentTimestamps.count < 1) { - OWSFailDebug(@"Missing sentTimestamps."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - for (NSNumber *nsTimestamp in sentTimestamps) { - uint64_t timestamp = [nsTimestamp unsignedLongLongValue]; - - NSArray *messages - = (NSArray *)[TSInteraction interactionsWithTimestamp:timestamp - ofClass:[TSOutgoingMessage class] - withTransaction:transaction]; - if (messages.count < 1) { - // The service sends delivery receipts for "unpersisted" messages - // like group updates, so these errors are expected to a certain extent. - // - // TODO: persist "early" delivery receipts. - OWSLogInfo(@"Missing message for delivery receipt: %llu", timestamp); - } else { - if (messages.count > 1) { - OWSLogInfo(@"More than one message (%lu) for delivery receipt: %llu", - (unsigned long)messages.count, - timestamp); - } - for (TSOutgoingMessage *outgoingMessage in messages) { - [outgoingMessage updateWithDeliveredRecipient:recipientId - deliveryTimestamp:deliveryTimestamp - transaction:transaction]; - } - } - } -} - -- (void)throws_handleEnvelope:(SSKProtoEnvelope *)envelope - plaintextData:(NSData *)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction - serverID:(uint64_t)serverID -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!plaintextData) { - OWSFailDebug(@"Missing plaintextData."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - if (envelope.timestamp < 1) { - OWSFailDebug(@"Invalid timestamp."); - return; - } - if (envelope.source.length < 1) { - OWSFailDebug(@"Missing source."); - return; - } - if (envelope.sourceDevice < 1) { - OWSFailDebug(@"Invalid source device."); - return; - } - - OWSPrimaryStorage *storage = OWSPrimaryStorage.sharedManager; - __block NSSet *senderLinkedDevices; - [storage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - senderLinkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:envelope.source in:transaction]; - }]; - - BOOL duplicateEnvelope = NO; - for (NSString *publicKey in senderLinkedDevices) { - duplicateEnvelope = duplicateEnvelope - || [self.incomingMessageFinder existsMessageWithTimestamp:envelope.timestamp - sourceId:publicKey - sourceDeviceId:envelope.sourceDevice - transaction:transaction]; - } - - if (duplicateEnvelope) { - OWSLogInfo(@"Ignoring previously received envelope from: %@ with timestamp: %llu.", - envelopeAddress(envelope), - envelope.timestamp); - return; - } - - if (envelope.content != nil) { - NSError *error; - SSKProtoContent *_Nullable contentProto = [SSKProtoContent parseData:plaintextData error:&error]; - if (error != nil || contentProto == nil) { - OWSFailDebug(@"Couldn't parse proto due to error: %@.", error); - return; - } - OWSLogInfo(@"Handling content: .", [self descriptionForContent:contentProto]); - - if ([LKSyncMessagesProtocol isDuplicateSyncMessage:contentProto fromPublicKey:envelope.source]) { - [LKLogger print:@"[Loki] Ignoring duplicate sync transcript."]; - return; - } - - [LKSessionManagementProtocol handlePreKeyBundleMessageIfNeeded:contentProto wrappedIn:envelope transaction:transaction]; - - if (contentProto.lokiDeviceLinkMessage != nil) { - [LKMultiDeviceProtocol handleDeviceLinkMessageIfNeeded:contentProto wrappedIn:envelope transaction:transaction]; - } else if (contentProto.syncMessage) { - [self throws_handleIncomingEnvelope:envelope - withSyncMessage:contentProto.syncMessage - transaction:transaction - serverID:serverID]; - - [[OWSDeviceManager sharedManager] setHasReceivedSyncMessage]; - } else if (contentProto.dataMessage) { - [self handleIncomingEnvelope:envelope - withDataMessage:contentProto.dataMessage - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; - } else if (contentProto.callMessage) { - [self handleIncomingEnvelope:envelope withCallMessage:contentProto.callMessage]; - } else if (contentProto.typingMessage) { - [self handleIncomingEnvelope:envelope withTypingMessage:contentProto.typingMessage transaction:transaction]; - } else if (contentProto.receiptMessage) { - [self handleIncomingEnvelope:envelope - withReceiptMessage:contentProto.receiptMessage - transaction:transaction]; - } else { - OWSLogWarn(@"Ignoring envelope. Content with no known payload"); - } - } else if (envelope.legacyMessage != nil) { // DEPRECATED - Remove after all clients have been upgraded. - NSError *error; - SSKProtoDataMessage *_Nullable dataMessageProto = [SSKProtoDataMessage parseData:plaintextData error:&error]; - if (error || !dataMessageProto) { - OWSFailDebug(@"could not parse proto: %@", error); - return; - } - OWSLogInfo(@"handling message: ", [self descriptionForDataMessage:dataMessageProto]); - - [self handleIncomingEnvelope:envelope - withDataMessage:dataMessageProto - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; - } else { - - } -} - -- (void)handleIncomingEnvelope:(SSKProtoEnvelope *)envelope - withDataMessage:(SSKProtoDataMessage *)dataMessage - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - if ([self isDataMessageBlocked:dataMessage envelope:envelope]) { - NSString *logMessage = [NSString stringWithFormat:@"Ignoring blocked message from sender: %@.", envelope.source]; - if (dataMessage.group) { - logMessage = [logMessage stringByAppendingFormat:@" in group: %@", dataMessage.group.id]; - } - OWSLogError(@"%@", logMessage); - return; - } - - if (dataMessage.hasTimestamp) { - if (dataMessage.timestamp <= 0) { - OWSFailDebug(@"Ignoring data message with invalid timestamp: %@.", envelope.source); - return; - } - // This prevents replay attacks by the service. - if (dataMessage.timestamp != envelope.timestamp) { - OWSFailDebug(@"Ignoring data message with non-matching timestamp: %@.", envelope.source); - return; - } - } - - [LKClosedGroupsProtocol handleSharedSenderKeysUpdateIfNeeded:dataMessage from:envelope.source transaction:transaction]; - - if (dataMessage.group) { - TSGroupThread *_Nullable groupThread = - [TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction]; - - if (groupThread) { - if (groupThread.groupModel.groupType == closedGroup) { - if ([LKClosedGroupsProtocol shouldIgnoreClosedGroupMessage:dataMessage inThread:groupThread wrappedIn:envelope]) { return; } - } - - if (dataMessage.group.type != SSKProtoGroupContextTypeUpdate) { - if (![groupThread isCurrentUserInGroupWithTransaction:transaction]) { - OWSLogInfo(@"Ignoring messages for left group."); - return; - } - } - } else { - // Unknown group - if (dataMessage.group.type == SSKProtoGroupContextTypeUpdate) { - // Accept group updates for unknown groups - } else if (dataMessage.group.type == SSKProtoGroupContextTypeDeliver) { - [self sendGroupInfoRequest:dataMessage.group.id envelope:envelope transaction:transaction]; - return; - } else { - OWSLogInfo(@"Ignoring group message for unknown group from: %@.", envelope.source); - return; - } - } - } - - if ((dataMessage.flags & SSKProtoDataMessageFlagsEndSession) != 0) { - [self handleEndSessionMessageWithEnvelope:envelope dataMessage:dataMessage transaction:transaction]; - } else if ((dataMessage.flags & SSKProtoDataMessageFlagsExpirationTimerUpdate) != 0) { - [self handleExpirationTimerUpdateMessageWithEnvelope:envelope dataMessage:dataMessage transaction:transaction]; - } else if ((dataMessage.flags & SSKProtoDataMessageFlagsProfileKeyUpdate) != 0) { - [self handleProfileKeyMessageWithEnvelope:envelope dataMessage:dataMessage]; - } else if ([LKMultiDeviceProtocol isUnlinkDeviceMessage:dataMessage]) { - [LKMultiDeviceProtocol handleUnlinkDeviceMessage:dataMessage wrappedIn:envelope transaction:transaction]; - } else if (dataMessage.attachments.count > 0) { - [self handleReceivedMediaWithEnvelope:envelope - dataMessage:dataMessage - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; - } else { - [self handleReceivedTextMessageWithEnvelope:envelope - dataMessage:dataMessage - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; - - if ([self isDataMessageGroupAvatarUpdate:dataMessage]) { - OWSLogVerbose(@"Data message had group avatar attachment"); - [self handleReceivedGroupAvatarUpdateWithEnvelope:envelope dataMessage:dataMessage transaction:transaction]; - } - } - - // Send delivery receipts for "valid data" messages received via UD. - if (wasReceivedByUD) { - [self.outgoingReceiptManager enqueueDeliveryReceiptForEnvelope:envelope]; - } -} - -- (void)sendGroupInfoRequest:(NSData *)groupId - envelope:(SSKProtoEnvelope *)envelope - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - if (groupId.length < 1) { - OWSFailDebug(@"Invalid groupId."); - return; - } - - // FIXME: https://github.com/signalapp/Signal-iOS/issues/1340 - OWSLogInfo(@"Sending group info request: %@", envelopeAddress(envelope)); - - NSString *recipientId = envelope.source; - - TSThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; - - OWSSyncGroupsRequestMessage *syncGroupsRequestMessage = - [[OWSSyncGroupsRequestMessage alloc] initWithThread:thread groupId:groupId]; - - [self.messageSenderJobQueue addMessage:syncGroupsRequestMessage transaction:transaction]; -} - -- (void)handleIncomingEnvelope:(SSKProtoEnvelope *)envelope - withReceiptMessage:(SSKProtoReceiptMessage *)receiptMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!receiptMessage) { - OWSFailDebug(@"Missing receiptMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - NSArray *sentTimestamps = receiptMessage.timestamp; - - switch (receiptMessage.type) { - case SSKProtoReceiptMessageTypeDelivery: - OWSLogVerbose(@"Processing receipt message with delivery receipts."); - [self processDeliveryReceiptsFromRecipientId:envelope.source - sentTimestamps:sentTimestamps - deliveryTimestamp:@(envelope.timestamp) - transaction:transaction]; - return; - case SSKProtoReceiptMessageTypeRead: - OWSLogVerbose(@"Processing receipt message with read receipts."); - [OWSReadReceiptManager.sharedManager processReadReceiptsFromRecipientId:envelope.source - sentTimestamps:sentTimestamps - readTimestamp:envelope.timestamp]; - break; - default: - OWSLogInfo(@"Ignoring receipt message of unknown type: %d.", (int)receiptMessage.type); - return; - } -} - -- (void)handleIncomingEnvelope:(SSKProtoEnvelope *)envelope - withCallMessage:(SSKProtoCallMessage *)callMessage -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!callMessage) { - OWSFailDebug(@"Missing callMessage."); - return; - } - - if ([callMessage hasProfileKey]) { - NSData *profileKey = [callMessage profileKey]; - NSString *recipientId = envelope.source; - [self.profileManager setProfileKeyData:profileKey forRecipientId:recipientId]; - } - - // By dispatching async, we introduce the possibility that these messages might be lost - // if the app exits before this block is executed. This is fine, since the call by - // definition will end if the app exits. - dispatch_async(dispatch_get_main_queue(), ^{ - if (callMessage.offer) { - [self.callMessageHandler receivedOffer:callMessage.offer fromCallerId:envelope.source]; - } else if (callMessage.answer) { - [self.callMessageHandler receivedAnswer:callMessage.answer fromCallerId:envelope.source]; - } else if (callMessage.iceUpdate.count > 0) { - for (SSKProtoCallMessageIceUpdate *iceUpdate in callMessage.iceUpdate) { - [self.callMessageHandler receivedIceUpdate:iceUpdate fromCallerId:envelope.source]; - } - } else if (callMessage.hangup) { - OWSLogVerbose(@"Received CallMessage with Hangup."); - [self.callMessageHandler receivedHangup:callMessage.hangup fromCallerId:envelope.source]; - } else if (callMessage.busy) { - [self.callMessageHandler receivedBusy:callMessage.busy fromCallerId:envelope.source]; - } else { - - } - }); -} - -- (void)handleIncomingEnvelope:(SSKProtoEnvelope *)envelope - withTypingMessage:(SSKProtoTypingMessage *)typingMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!typingMessage) { - OWSFailDebug(@"Missing typingMessage."); - return; - } - if (typingMessage.timestamp != envelope.timestamp) { - OWSFailDebug(@"typingMessage has invalid timestamp."); - return; - } - NSString *localNumber = self.tsAccountManager.localNumber; - if ([localNumber isEqualToString:envelope.source]) { - OWSLogVerbose(@"Ignoring typing indicators from self or linked device."); - return; - } else if ([self.blockingManager isRecipientIdBlocked:envelope.source] - || (typingMessage.hasGroupID && [self.blockingManager isGroupIdBlocked:typingMessage.groupID])) { - NSString *logMessage = [NSString stringWithFormat:@"Ignoring blocked message from sender: %@", envelope.source]; - if (typingMessage.hasGroupID) { - logMessage = [logMessage stringByAppendingFormat:@" in group: %@", typingMessage.groupID]; - } - OWSLogError(@"%@", logMessage); - return; - } - - TSThread *_Nullable thread; - if (typingMessage.hasGroupID) { - TSGroupThread *groupThread = [TSGroupThread threadWithGroupId:typingMessage.groupID transaction:transaction]; - - if (![groupThread isCurrentUserInGroupWithTransaction:transaction]) { - OWSLogInfo(@"Ignoring messages for left group."); - return; - } - - thread = groupThread; - } else { - thread = [TSContactThread getThreadWithContactId:envelope.source transaction:transaction]; - } - - if (!thread) { - // This isn't neccesarily an error. We might not yet know about the thread, - // in which case we don't need to display the typing indicators. - OWSLogWarn(@"Could not locate thread for typingMessage."); - return; - } - - dispatch_async(dispatch_get_main_queue(), ^{ - switch (typingMessage.action) { - case SSKProtoTypingMessageActionStarted: - [self.typingIndicators didReceiveTypingStartedMessageInThread:thread - recipientId:envelope.source - deviceId:envelope.sourceDevice]; - break; - case SSKProtoTypingMessageActionStopped: - [self.typingIndicators didReceiveTypingStoppedMessageInThread:thread - recipientId:envelope.source - deviceId:envelope.sourceDevice]; - break; - default: - OWSFailDebug(@"Typing message has unexpected action."); - break; - } - }); -} - -- (void)handleReceivedGroupAvatarUpdateWithEnvelope:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - TSGroupThread *_Nullable groupThread = - [TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction]; - if (!groupThread) { - OWSFailDebug(@"Missing group for group avatar update"); - return; - } - - TSAttachmentPointer *_Nullable avatarPointer = - [TSAttachmentPointer attachmentPointerFromProto:dataMessage.group.avatar albumMessage:nil]; - - if (!avatarPointer) { - OWSLogWarn(@"received unsupported group avatar envelope"); - return; - } - [self.attachmentDownloads downloadAttachmentPointer:avatarPointer - success:^(NSArray *attachmentStreams) { - OWSAssertDebug(attachmentStreams.count == 1); - TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; - [groupThread updateAvatarWithAttachmentStream:attachmentStream]; - } - failure:^(NSError *error) { - OWSLogError(@"failed to fetch attachments for group avatar sent at: %llu. with error: %@", - envelope.timestamp, - error); - }]; -} - -- (void)handleReceivedMediaWithEnvelope:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - TSThread *_Nullable thread = [self threadForEnvelope:envelope dataMessage:dataMessage transaction:transaction]; - - if (!thread) { - OWSFailDebug(@"Ignoring media message for unknown group."); - return; - } - - TSIncomingMessage *_Nullable message = [self handleReceivedEnvelope:envelope - withDataMessage:dataMessage - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; - - if (!message) { - return; - } - - [message saveWithTransaction:transaction]; - - OWSLogDebug(@"Incoming attachment message: %@.", message.debugDescription); - - [self.attachmentDownloads downloadAttachmentsForMessage:message - transaction:transaction - success:^(NSArray *attachmentStreams) { - OWSLogDebug(@"Successfully fetched attachments: %lu for message: %@.", - (unsigned long)attachmentStreams.count, - message); - } - failure:^(NSError *error) { - OWSLogError(@"Failed to fetch attachments for message: %@ with error: %@.", message, error); - }]; -} - -- (void)throws_handleIncomingEnvelope:(SSKProtoEnvelope *)envelope - withSyncMessage:(SSKProtoSyncMessage *)syncMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction - serverID:(uint64_t)serverID -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!syncMessage) { - OWSFailDebug(@"Missing syncMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - if (![LKSyncMessagesProtocol isValidSyncMessage:envelope transaction:transaction]) { - return; - } - - if (syncMessage.sent) { - OWSIncomingSentMessageTranscript *transcript = - [[OWSIncomingSentMessageTranscript alloc] initWithProto:syncMessage.sent transaction:transaction]; - - SSKProtoDataMessage *_Nullable dataMessage = syncMessage.sent.message; - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - - // Loki: Update profile if needed (i.e. if the sync message came from the master device) - [LKSyncMessagesProtocol updateProfileFromSyncMessageIfNeeded:dataMessage wrappedIn:envelope transaction:transaction]; - - NSString *destination = syncMessage.sent.destination; - if (dataMessage && destination.length > 0 && dataMessage.hasProfileKey) { - // If we observe a linked device sending our profile key to another - // user, we can infer that that user belongs in our profile whitelist. - if (dataMessage.group) { - [self.profileManager addGroupIdToProfileWhitelist:dataMessage.group.id]; - } else { - [self.profileManager addUserToProfileWhitelist:destination]; - } - } - - if ([self isDataMessageGroupAvatarUpdate:syncMessage.sent.message] && !syncMessage.sent.isRecipientUpdate) { - [OWSRecordTranscriptJob - processIncomingSentMessageTranscript:transcript - serverID:0 - serverTimestamp:0 - attachmentHandler:^(NSArray *attachmentStreams) { - OWSAssertDebug(attachmentStreams.count == 1); - TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; - [LKStorage writeSyncWithBlock:^( - YapDatabaseReadWriteTransaction *transaction) { - TSGroupThread *_Nullable groupThread = - [TSGroupThread threadWithGroupId:dataMessage.group.id - transaction:transaction]; - if (!groupThread) { - OWSFailDebug(@"ignoring sync group avatar update for unknown group."); - return; - } - - [groupThread updateAvatarWithAttachmentStream:attachmentStream - transaction:transaction]; - }]; - } - transaction:transaction - ]; - } else { - if (transcript.isGroupUpdate) { - [LKSyncMessagesProtocol handleClosedGroupUpdateSyncMessageIfNeeded:transcript wrappedIn:envelope transaction:transaction]; - } else if (transcript.isGroupQuit) { - [LKSyncMessagesProtocol handleClosedGroupQuitSyncMessageIfNeeded:transcript wrappedIn:envelope transaction:transaction]; - } else { - [OWSRecordTranscriptJob - processIncomingSentMessageTranscript:transcript - serverID:(serverID ?: 0) - serverTimestamp:(uint64_t)envelope.serverTimestamp - attachmentHandler:^(NSArray *attachmentStreams) { - OWSLogDebug(@"successfully fetched transcript attachments: %lu", - (unsigned long)attachmentStreams.count); - } - transaction:transaction]; - } - } - } else if (syncMessage.request) { - if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeContacts) { - // We respond asynchronously because populating the sync message will - // create transactions and it's not practical (due to locking in the OWSIdentityManager) - // to plumb our transaction through. - // - // In rare cases this means we won't respond to the sync request, but that's - // acceptable. - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[self.syncManager syncAllContacts] retainUntilComplete]; - }); - } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeGroups) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[self.syncManager syncAllGroups] retainUntilComplete]; - }); - } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeBlocked) { - OWSLogInfo(@"Received request for block list"); - [self.blockingManager syncBlockList]; - } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeConfiguration) { - [SSKEnvironment.shared.syncManager sendConfigurationSyncMessage]; - } else { - OWSLogWarn(@"ignoring unsupported sync request message"); - } - } else if (syncMessage.blocked) { - NSArray *blockedPhoneNumbers = [syncMessage.blocked.numbers copy]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self.blockingManager setBlockedPhoneNumbers:blockedPhoneNumbers sendSyncMessage:NO]; - dispatch_async(dispatch_get_main_queue(), ^{ - [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.blockedContactsUpdated object:nil]; - }); - }); - } else if (syncMessage.read.count > 0) { - OWSLogInfo(@"Received %lu read receipt(s)", (unsigned long)syncMessage.read.count); - [OWSReadReceiptManager.sharedManager processReadReceiptsFromLinkedDevice:syncMessage.read - readTimestamp:envelope.timestamp - transaction:transaction]; - } else if (syncMessage.verified) { - OWSLogInfo(@"Received verification state for %@", syncMessage.verified.destination); - [self.identityManager throws_processIncomingSyncMessage:syncMessage.verified transaction:transaction]; - } else if (syncMessage.contacts != nil) { - [LKSyncMessagesProtocol handleContactSyncMessageIfNeeded:syncMessage wrappedIn:envelope transaction:transaction]; - } else if (syncMessage.groups != nil) { - [LKSyncMessagesProtocol handleClosedGroupSyncMessageIfNeeded:syncMessage wrappedIn:envelope transaction:transaction]; - } else if (syncMessage.openGroups != nil) { - [LKSyncMessagesProtocol handleOpenGroupSyncMessageIfNeeded:syncMessage wrappedIn:envelope transaction:transaction]; - } else { - OWSLogWarn(@"Ignoring unsupported sync message."); - } -} - -- (void)handleEndSessionMessageWithEnvelope:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction]; - [LKSessionManagementProtocol handleEndSessionMessageReceivedInThread:thread using:transaction]; -} - -- (void)handleExpirationTimerUpdateMessageWithEnvelope:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - TSThread *_Nullable thread = [self threadForEnvelope:envelope dataMessage:dataMessage transaction:transaction]; - if (!thread) { - OWSFailDebug(@"Ignoring expiring messages update for unknown group."); - return; - } - - OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration; - if (dataMessage.hasExpireTimer && dataMessage.expireTimer > 0) { - OWSLogInfo( - @"Expiring messages duration turned to %u for thread %@", (unsigned int)dataMessage.expireTimer, thread); - disappearingMessagesConfiguration = - [[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId - enabled:YES - durationSeconds:dataMessage.expireTimer]; - } else { - OWSLogInfo(@"Expiring messages have been turned off for thread %@", thread); - disappearingMessagesConfiguration = [[OWSDisappearingMessagesConfiguration alloc] - initWithThreadId:thread.uniqueId - enabled:NO - durationSeconds:OWSDisappearingMessagesConfigurationDefaultExpirationDuration]; - } - OWSAssertDebug(disappearingMessagesConfiguration); - [disappearingMessagesConfiguration saveWithTransaction:transaction]; - NSString *name = [dataMessage.profile displayName] ?: [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:envelope.source transaction:transaction] ?: envelope.source; - - // MJK TODO - safe to remove senderTimestamp - OWSDisappearingConfigurationUpdateInfoMessage *message = - [[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - configuration:disappearingMessagesConfiguration - createdByRemoteName:name - createdInExistingGroup:NO]; - [message saveWithTransaction:transaction]; -} - -- (void)handleProfileKeyMessageWithEnvelope:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - - NSString *recipientId = envelope.source; - if (!dataMessage.hasProfileKey) { - OWSFailDebug(@"Received a profile key message without a profile key from: %@.", envelopeAddress(envelope)); - return; - } - - NSData *profileKey = dataMessage.profileKey; - if (profileKey.length != kAES256_KeyByteLength) { - OWSFailDebug(@"received profile key of unexpected length: %lu, from: %@", - (unsigned long)profileKey.length, - envelopeAddress(envelope)); - return; - } - - if (dataMessage.profile == nil) { - OWSFailDebug(@"received profile key message without loki profile attached from: %@", envelopeAddress(envelope)); - return; - } - - id profileManager = SSKEnvironment.shared.profileManager; - [profileManager setProfileKeyData:profileKey forRecipientId:recipientId avatarURL:dataMessage.profile.profilePicture]; -} - -- (void)handleReceivedTextMessageWithEnvelope:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - [self handleReceivedEnvelope:envelope - withDataMessage:dataMessage - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; -} - -- (void)handleGroupInfoRequest:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - if (dataMessage.group.type != SSKProtoGroupContextTypeRequestInfo) { - OWSFailDebug(@"Unexpected group message type."); - return; - } - - NSData *groupId = dataMessage.group ? dataMessage.group.id : nil; - if (!groupId) { - OWSFailDebug(@"Group info request is missing group id."); - return; - } - - OWSLogInfo(@"Received 'Request Group Info' message for group: %@ from: %@", groupId, envelope.source); - - TSGroupThread *_Nullable gThread = [TSGroupThread threadWithGroupId:dataMessage.group.id transaction:transaction]; - if (!gThread) { - OWSLogWarn(@"Unknown group: %@", groupId); - return; - } - - // Ensure sender is in the group. - if (![gThread isUserMemberInGroup:envelope.source transaction:transaction]) { - OWSLogWarn(@"Ignoring 'Request Group Info' message for non-member of group. %@ not in %@", - envelope.source, - gThread.groupModel.groupMemberIds); - return; - } - - // Ensure we are in the group. - if (![gThread isCurrentUserInGroupWithTransaction:transaction]) { - OWSLogWarn(@"Ignoring 'Request Group Info' message for group we no longer belong to."); - return; - } - - NSString *updateGroupInfo = - [gThread.groupModel getInfoStringAboutUpdateTo:gThread.groupModel contactsManager:self.contactsManager]; - - uint32_t expiresInSeconds = [gThread disappearingMessagesDurationWithTransaction:transaction]; - TSOutgoingMessage *message = [TSOutgoingMessage outgoingMessageInThread:gThread - groupMetaMessage:TSGroupMetaMessageUpdate - expiresInSeconds:expiresInSeconds]; - - [message updateWithCustomMessage:updateGroupInfo transaction:transaction]; - // Only send this group update to the requester. - [message updateWithSendingToSingleGroupRecipient:envelope.source transaction:transaction]; - - if (gThread.groupModel.groupImage) { - NSData *_Nullable data = UIImagePNGRepresentation(gThread.groupModel.groupImage); - OWSAssertDebug(data); - if (data) { - DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; - [self.messageSenderJobQueue addMediaMessage:message - dataSource:dataSource - contentType:OWSMimeTypeImagePng - sourceFilename:nil - caption:nil - albumMessageId:nil - isTemporaryAttachment:YES]; - } - } else { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - } -} - -- (TSIncomingMessage *_Nullable)handleReceivedEnvelope:(SSKProtoEnvelope *)envelope - withDataMessage:(SSKProtoDataMessage *)dataMessage - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return nil; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return nil; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return nil; - } - - uint64_t timestamp = envelope.timestamp; - NSString *body = dataMessage.body; - NSData *groupId = dataMessage.group ? dataMessage.group.id : nil; - OWSContact *_Nullable contact = [OWSContacts contactForDataMessage:dataMessage transaction:transaction]; - NSNumber *_Nullable serverTimestamp = (envelope.hasServerTimestamp ? @(envelope.serverTimestamp) : nil); - - if (dataMessage.group.type == SSKProtoGroupContextTypeRequestInfo) { - [self handleGroupInfoRequest:envelope dataMessage:dataMessage transaction:transaction]; - return nil; - } - - /* - // Loki: Update device links in a blocking way - // FIXME: This is horrible for performance - // FIXME: ======== - // The envelope source is set during UD decryption - if ([ECKeyPair isValidHexEncodedPublicKeyWithCandidate:envelope.source] && dataMessage.publicChatInfo == nil // Handled in LokiPublicChatPoller for open group messages - && envelope.type != SSKProtoEnvelopeTypeClosedGroupCiphertext) { - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - [[LKMultiDeviceProtocol updateDeviceLinksIfNeededForPublicKey:envelope.source transaction:transaction].ensureOn(queue, ^() { - dispatch_semaphore_signal(semaphore); - }).catchOn(queue, ^(NSError *error) { - dispatch_semaphore_signal(semaphore); - }) retainUntilComplete]; - dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC)); - } - // FIXME: ======== - */ - - if (groupId.length > 0) { - NSMutableSet *newMemberIds = [NSMutableSet setWithArray:dataMessage.group.members]; - NSMutableSet *removedMemberIds = [NSMutableSet new]; - for (NSString *recipientId in newMemberIds) { - if (![ECKeyPair isValidHexEncodedPublicKeyWithCandidate:recipientId]) { - OWSLogVerbose(@"Incoming group update has invalid group member: %@", [self descriptionForEnvelope:envelope]); - OWSFailDebug(@"Incoming group update has invalid group member"); - return nil; - } - } - - NSString *senderMasterPublicKey = ([LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:envelope.source in:transaction] ?: envelope.source); - NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; - NSString *userMasterPublicKey = ([LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:userPublicKey in:transaction] ?: userPublicKey); - - // Group messages create the group if it doesn't already exist. - // - // We distinguish between the old group state (if any) and the new group state. - TSGroupThread *_Nullable oldGroupThread = [TSGroupThread threadWithGroupId:groupId transaction:transaction]; - if (oldGroupThread) { - // Loki: Determine removed members - removedMemberIds = [NSMutableSet setWithArray:oldGroupThread.groupModel.groupMemberIds]; - [removedMemberIds minusSet:newMemberIds]; - // TODO: Below is the original code. Is it safe that we modified it like this? - // ======== - // Don't trust other clients; ensure all known group members remain in the - // group unless it is a "quit" message in which case we should only remove - // the quiting member below. -// [newMemberIds addObjectsFromArray:oldGroupThread.groupModel.groupMemberIds]; - // ======== - } - - [LKSessionMetaProtocol updateProfileKeyIfNeededForPublicKey:senderMasterPublicKey using:dataMessage]; - - [LKSessionMetaProtocol updateDisplayNameIfNeededForPublicKey:senderMasterPublicKey using:dataMessage transaction:transaction]; - - switch (dataMessage.group.type) { - case SSKProtoGroupContextTypeUpdate: { - if (oldGroupThread != nil && oldGroupThread.groupModel.groupType == closedGroup - && [LKClosedGroupsProtocol shouldIgnoreClosedGroupUpdateMessage:dataMessage inThread:oldGroupThread wrappedIn:envelope]) { - return nil; - } - // Ensures that the thread exists but don't update it. - TSGroupThread *newGroupThread = - [TSGroupThread getOrCreateThreadWithGroupId:groupId groupType:oldGroupThread.groupModel.groupType transaction:transaction]; - - TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name - memberIds:newMemberIds.allObjects - image:oldGroupThread.groupModel.groupImage - groupId:dataMessage.group.id - groupType:oldGroupThread.groupModel.groupType - adminIds:dataMessage.group.admins]; - newGroupModel.removedMembers = removedMemberIds; - NSString *updateGroupInfo = [newGroupThread.groupModel getInfoStringAboutUpdateTo:newGroupModel - contactsManager:self.contactsManager]; - - [newGroupThread setGroupModel:newGroupModel withTransaction:transaction]; - - BOOL wasCurrentUserRemovedFromGroup = [removedMemberIds containsObject:userMasterPublicKey]; - if (!wasCurrentUserRemovedFromGroup) { - [LKClosedGroupsProtocol establishSessionsIfNeededWithClosedGroupMembers:newMemberIds.allObjects transaction:transaction]; - } - - [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer - thread:newGroupThread - createdByRemoteRecipientId:nil - createdInExistingGroup:YES - transaction:transaction]; - - // MJK TODO - should be safe to remove senderTimestamp - TSInfoMessage *infoMessage = [[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:newGroupThread - messageType:TSInfoMessageTypeGroupUpdate - customMessage:updateGroupInfo]; - [infoMessage saveWithTransaction:transaction]; - - // If we were the one that was removed then we need to leave the group - if (wasCurrentUserRemovedFromGroup) { - [newGroupThread leaveGroupWithTransaction:transaction]; - } - - return nil; - } - case SSKProtoGroupContextTypeQuit: { - if (!oldGroupThread) { - OWSLogWarn(@"Ignoring quit group message from unknown group."); - return nil; - } - newMemberIds = [NSMutableSet setWithArray:oldGroupThread.groupModel.groupMemberIds]; - [newMemberIds removeObject:senderMasterPublicKey]; - oldGroupThread.groupModel.groupMemberIds = [newMemberIds.allObjects mutableCopy]; - [oldGroupThread saveWithTransaction:transaction]; - - NSString *nameString = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:senderMasterPublicKey transaction:transaction] ?: - [self.contactsManager displayNameForPhoneIdentifier:senderMasterPublicKey transaction:transaction]; - NSString *updateGroupInfo = - [NSString stringWithFormat:NSLocalizedString(@"GROUP_MEMBER_LEFT", @""), nameString]; - // MJK TODO - should be safe to remove senderTimestamp - [[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:oldGroupThread - messageType:TSInfoMessageTypeGroupUpdate - customMessage:updateGroupInfo] saveWithTransaction:transaction]; - - // If we were the one that quit then we need to leave the group (only relevant for slave - // devices in a multi device context) - // TODO: This needs more documentation - if (![newMemberIds containsObject:userMasterPublicKey]) { - [oldGroupThread leaveGroupWithTransaction:transaction]; - } - - return nil; - } - case SSKProtoGroupContextTypeDeliver: { - if (!oldGroupThread) { - OWSFailDebug(@"Ignoring deliver group message from unknown group."); - return nil; - } - - [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer - thread:oldGroupThread - createdByRemoteRecipientId:senderMasterPublicKey - createdInExistingGroup:NO - transaction:transaction]; - - TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage - thread:oldGroupThread - transaction:transaction]; - - NSError *linkPreviewError; - OWSLinkPreview *_Nullable linkPreview = - [OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:dataMessage - body:body - transaction:transaction - error:&linkPreviewError]; - if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) { - OWSLogError(@"linkPreviewError: %@", linkPreviewError); - } - - OWSLogDebug(@"Incoming message from: %@ for group: %@ with timestamp: %lu", - envelopeAddress(envelope), - groupId, - (unsigned long)timestamp); - - // Legit usage of senderTimestamp when creating an incoming group message record - TSIncomingMessage *incomingMessage = - [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp - inThread:oldGroupThread - authorId:senderMasterPublicKey - sourceDeviceId:envelope.sourceDevice - messageBody:body - attachmentIds:@[] - expiresInSeconds:dataMessage.expireTimer - quotedMessage:quotedMessage - contactShare:contact - linkPreview:linkPreview - serverTimestamp:serverTimestamp - wasReceivedByUD:wasReceivedByUD]; - - // For open group messages, use the server timestamp as the received timestamp - if (oldGroupThread.isPublicChat) { - [incomingMessage setServerTimestampToReceivedTimestamp:(uint64_t)envelope.serverTimestamp]; - } - - // Loki: Set open group server ID if needed - if (dataMessage.publicChatInfo != nil && dataMessage.publicChatInfo.hasServerID) { - incomingMessage.openGroupServerMessageID = dataMessage.publicChatInfo.serverID; - } - - NSArray *attachmentPointers = - [TSAttachmentPointer attachmentPointersFromProtos:dataMessage.attachments - albumMessage:incomingMessage]; - for (TSAttachmentPointer *pointer in attachmentPointers) { - [pointer saveWithTransaction:transaction]; - [incomingMessage.attachmentIds addObject:pointer.uniqueId]; - } - - if (body.length == 0 && attachmentPointers.count < 1 && !contact) { - OWSLogWarn(@"Ignoring empty incoming message from: %@ for group: %@ with timestamp: %lu.", - senderMasterPublicKey, - groupId, - (unsigned long)timestamp); - return nil; - } - - // Loki: Cache the user public key (for mentions) - dispatch_async(dispatch_get_main_queue(), ^{ - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [LKMentionsManager populateUserPublicKeyCacheIfNeededFor:oldGroupThread.uniqueId in:transaction]; - [LKMentionsManager cache:incomingMessage.authorId for:oldGroupThread.uniqueId]; - }]; - }); - - [self finalizeIncomingMessage:incomingMessage - thread:oldGroupThread - masterThread:oldGroupThread - envelope:envelope - transaction:transaction]; - - // Loki: Map the message ID to the message server ID if needed - if (dataMessage.publicChatInfo != nil && dataMessage.publicChatInfo.hasServerID) { - [self.primaryStorage setIDForMessageWithServerID:dataMessage.publicChatInfo.serverID to:incomingMessage.uniqueId in:transaction]; - } - - return incomingMessage; - } - default: { - OWSLogWarn(@"Ignoring unknown group message type: %d.", (int)dataMessage.group.type); - return nil; - } - } - } else { - - // Loki: A message from a slave device should appear as if it came from the master device; the underlying - // friend request logic, however, should still be specific to the slave device. - - NSString *publicKey = envelope.source; - NSString *masterPublicKey = ([LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:envelope.source in:transaction] ?: envelope.source); - TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:publicKey transaction:transaction]; - TSContactThread *masterThread = [TSContactThread getOrCreateThreadWithContactId:masterPublicKey transaction:transaction]; - - OWSLogDebug(@"Incoming message from: %@ with timestamp: %lu.", publicKey, (unsigned long)timestamp); - - [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer - thread:masterThread - createdByRemoteRecipientId:publicKey - createdInExistingGroup:NO - transaction:transaction]; - - TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage - thread:masterThread - transaction:transaction]; - - NSError *linkPreviewError; - OWSLinkPreview *_Nullable linkPreview = - [OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:dataMessage - body:body - transaction:transaction - error:&linkPreviewError]; - if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) { - OWSLogError(@"linkPreviewError: %@", linkPreviewError); - } - - // Legit usage of senderTimestamp when creating incoming message from received envelope - TSIncomingMessage *incomingMessage = - [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp - inThread:masterThread - authorId:masterThread.contactIdentifier - sourceDeviceId:envelope.sourceDevice - messageBody:body - attachmentIds:@[] - expiresInSeconds:dataMessage.expireTimer - quotedMessage:quotedMessage - contactShare:contact - linkPreview:linkPreview - serverTimestamp:serverTimestamp - wasReceivedByUD:wasReceivedByUD]; - - [LKSessionMetaProtocol updateProfileKeyIfNeededForPublicKey:masterPublicKey using:dataMessage]; - - [LKSessionMetaProtocol updateDisplayNameIfNeededForPublicKey:masterPublicKey using:dataMessage transaction:transaction]; - - NSArray *attachmentPointers = - [TSAttachmentPointer attachmentPointersFromProtos:dataMessage.attachments albumMessage:incomingMessage]; - for (TSAttachmentPointer *pointer in attachmentPointers) { - [pointer saveWithTransaction:transaction]; - [incomingMessage.attachmentIds addObject:pointer.uniqueId]; - } - - if (body.length == 0 && attachmentPointers.count < 1 && !contact) { return nil; } - - [self finalizeIncomingMessage:incomingMessage - thread:thread - masterThread:thread - envelope:envelope - transaction:transaction]; - - return incomingMessage; - } -} - -- (void)finalizeIncomingMessage:(TSIncomingMessage *)incomingMessage - thread:(TSThread *)thread - masterThread:(TSThread *)masterThread - envelope:(SSKProtoEnvelope *)envelope - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return; - } - if (!thread) { - OWSFailDebug(@"Missing thread."); - return; - } - if (!incomingMessage) { - OWSFailDebug(@"Missing incomingMessage."); - return; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return; - } - - [incomingMessage saveWithTransaction:transaction]; - - // Any messages sent from the current user - from this device or another - should be automatically marked as read. - if ([(masterThread.contactIdentifier ?: envelope.source) isEqualToString:self.tsAccountManager.localNumber]) { - // Don't send a read receipt for messages sent by ourselves. - [incomingMessage markAsReadAtTimestamp:envelope.timestamp sendReadReceipt:NO transaction:transaction]; - } - - // Download the "non-message body" attachments. - NSMutableArray *otherAttachmentIds = [incomingMessage.allAttachmentIds mutableCopy]; - if (incomingMessage.attachmentIds) { - [otherAttachmentIds removeObjectsInArray:incomingMessage.attachmentIds]; - } - for (NSString *attachmentId in otherAttachmentIds) { - TSAttachment *_Nullable attachment = - [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; - if (![attachment isKindOfClass:[TSAttachmentPointer class]]) { - OWSLogInfo(@"Skipping attachment stream."); - continue; - } - TSAttachmentPointer *_Nullable attachmentPointer = (TSAttachmentPointer *)attachment; - - OWSLogDebug(@"Downloading attachment for message: %lu", (unsigned long)incomingMessage.timestamp); - - // Use a separate download for each attachment so that: - // - // * We update the message as each comes in. - // * Failures don't interfere with successes. - [self.attachmentDownloads downloadAttachmentPointer:attachmentPointer - success:^(NSArray *attachmentStreams) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSAttachmentStream *_Nullable attachmentStream = attachmentStreams.firstObject; - OWSAssertDebug(attachmentStream); - if (attachmentStream && incomingMessage.quotedMessage.thumbnailAttachmentPointerId.length > 0 && - [attachmentStream.uniqueId - isEqualToString:incomingMessage.quotedMessage.thumbnailAttachmentPointerId]) { - [incomingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream]; - [incomingMessage saveWithTransaction:transaction]; - } else { - // We touch the message to trigger redraw of any views displaying it, - // since the attachment might be a contact avatar, etc. - [incomingMessage touchWithTransaction:transaction]; - } - }]; - } - failure:^(NSError *error) { - OWSLogWarn(@"Failed to download attachment for message: %lu with error: %@.", - (unsigned long)incomingMessage.timestamp, - error); - }]; - } - - // In case we already have a read receipt for this new message (this happens sometimes). - [OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage - transaction:transaction]; - - // Update thread preview in inbox - [masterThread touchWithTransaction:transaction]; - - if (CurrentAppContext().isMainApp) { - [SSKEnvironment.shared.notificationsManager notifyUserForIncomingMessage:incomingMessage inThread:masterThread transaction:transaction]; - } - - dispatch_async(dispatch_get_main_queue(), ^{ - [self.typingIndicators didReceiveIncomingMessageInThread:masterThread - recipientId:(masterThread.contactIdentifier ?: envelope.source) - deviceId:envelope.sourceDevice]; - }); -} - -#pragma mark - helpers - -- (BOOL)isDataMessageGroupAvatarUpdate:(SSKProtoDataMessage *)dataMessage -{ - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return NO; - } - - return (dataMessage.group != nil && dataMessage.group.type == SSKProtoGroupContextTypeUpdate - && dataMessage.group.avatar != nil); -} - -/** - * @returns - * Group or Contact thread for message, creating a new contact thread if necessary, - * but never creating a new group thread. - */ -- (nullable TSThread *)threadForEnvelope:(SSKProtoEnvelope *)envelope - dataMessage:(SSKProtoDataMessage *)dataMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (!envelope) { - OWSFailDebug(@"Missing envelope."); - return nil; - } - if (!dataMessage) { - OWSFailDebug(@"Missing dataMessage."); - return nil; - } - if (!transaction) { - OWSFail(@"Missing transaction."); - return nil; - } - - if (dataMessage.group) { - NSData *groupId = dataMessage.group.id; - OWSAssertDebug(groupId.length > 0); - TSGroupThread *_Nullable groupThread = [TSGroupThread threadWithGroupId:groupId transaction:transaction]; - // This method should only be called from a code path that has already verified - // that this is a "known" group. - OWSAssertDebug(groupThread); - return groupThread; - } else { - return [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction]; - } -} - -#pragma mark - - -- (void)checkForUnknownLinkedDevice:(SSKProtoEnvelope *)envelope - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(envelope); - OWSAssertDebug(transaction); - - NSString *localNumber = self.tsAccountManager.localNumber; - if (![localNumber isEqualToString:envelope.source]) { - return; - } - - // Consult the device list cache we use for message sending - // whether or not we know about this linked device. - SignalRecipient *_Nullable recipient = - [SignalRecipient registeredRecipientForRecipientId:localNumber mustHaveDevices:NO transaction:transaction]; - if (!recipient) { - - } else { - BOOL isRecipientDevice = [recipient.devices containsObject:@(envelope.sourceDevice)]; - if (!isRecipientDevice) { - OWSLogInfo(@"Message received from unknown linked device; adding to local SignalRecipient: %lu.", - (unsigned long) envelope.sourceDevice); - - [recipient updateRegisteredRecipientWithDevicesToAdd:@[ @(envelope.sourceDevice) ] - devicesToRemove:nil - transaction:transaction]; - } - } - - // Consult the device list cache we use for the "linked device" UI - // whether or not we know about this linked device. - NSMutableSet *deviceIdSet = [NSMutableSet new]; - for (OWSDevice *device in [OWSDevice currentDevicesWithTransaction:transaction]) { - [deviceIdSet addObject:@(device.deviceId)]; - } - BOOL isInDeviceList = [deviceIdSet containsObject:@(envelope.sourceDevice)]; - if (!isInDeviceList) { - OWSLogInfo(@"Message received from unknown linked device; refreshing device list: %lu.", - (unsigned long) envelope.sourceDevice); - - [OWSDevicesService refreshDevices]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self.profileManager fetchLocalUsersProfile]; - }); - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageReceiver.h b/SignalUtilitiesKit/OWSMessageReceiver.h deleted file mode 100644 index f8946d0f2..000000000 --- a/SignalUtilitiesKit/OWSMessageReceiver.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSPrimaryStorage; -@class OWSStorage; - -// This class is used to write incoming (encrypted, unprocessed) -// messages to a durable queue and then decrypt them in the order -// in which they were received. Successfully decrypted messages -// are forwarded to OWSBatchMessageProcessor. -@interface OWSMessageReceiver : NSObject - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; - -+ (NSString *)databaseExtensionName; -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage; - -- (void)handleReceivedEnvelopeData:(NSData *)envelopeData; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageReceiver.m b/SignalUtilitiesKit/OWSMessageReceiver.m deleted file mode 100644 index ecf4abba6..000000000 --- a/SignalUtilitiesKit/OWSMessageReceiver.m +++ /dev/null @@ -1,513 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSMessageReceiver.h" -#import "AppContext.h" -#import "AppReadiness.h" -#import "NSArray+OWS.h" -#import "NotificationsProtocol.h" -#import "OWSBackgroundTask.h" -#import "OWSBatchMessageProcessor.h" -#import "OWSMessageDecrypter.h" -#import "OWSPrimaryStorage+Loki.h" -#import "OWSQueues.h" -#import "OWSStorage.h" -#import "OWSIdentityManager.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "TSDatabaseView.h" -#import "TSErrorMessage.h" -#import "TSYapDatabaseObject.h" -#import -#import -#import -#import -#import -#import -#import - -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSMessageDecryptJob : TSYapDatabaseObject - -@property (nonatomic, readonly) NSDate *createdAt; -@property (nonatomic, readonly) NSData *envelopeData; -@property (nonatomic, readonly, nullable) SSKProtoEnvelope *envelopeProto; - -- (instancetype)initWithEnvelopeData:(NSData *)envelopeData NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithUniqueId:(NSString *_Nullable)uniqueId NS_UNAVAILABLE; - -@end - -#pragma mark - - -@implementation OWSMessageDecryptJob - -+ (NSString *)collection -{ - return @"OWSMessageProcessingJob"; -} - -- (instancetype)initWithEnvelopeData:(NSData *)envelopeData -{ - OWSAssertDebug(envelopeData); - - self = [super initWithUniqueId:[NSUUID new].UUIDString]; - if (!self) { - return self; - } - - _envelopeData = envelopeData; - _createdAt = [NSDate new]; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoEnvelope *)envelopeProto -{ - NSError *error; - SSKProtoEnvelope *_Nullable envelope = [SSKProtoEnvelope parseData:self.envelopeData error:&error]; - if (error || envelope == nil) { - OWSFailDebug(@"failed to parse envelope with error: %@", error); - return nil; - } - - return envelope; -} - -@end - -#pragma mark - Finder - -NSString *const OWSMessageDecryptJobFinderExtensionName = @"OWSMessageProcessingJobFinderExtensionName2"; -NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessingJobFinderExtensionGroup2"; - -@interface OWSMessageDecryptJobFinder : NSObject - -@end - -#pragma mark - - -@interface OWSMessageDecryptJobFinder () - -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@end - -#pragma mark - - -@implementation OWSMessageDecryptJobFinder - -- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection -{ - OWSSingletonAssert(); - - self = [super init]; - if (!self) { - return self; - } - - _dbConnection = dbConnection; - - [OWSMessageDecryptJobFinder registerLegacyClasses]; - - return self; -} - -- (OWSMessageDecryptJob *_Nullable)nextJob -{ - __block OWSMessageDecryptJob *_Nullable job = nil; - - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - YapDatabaseViewTransaction *viewTransaction = [transaction ext:OWSMessageDecryptJobFinderExtensionName]; - OWSAssertDebug(viewTransaction != nil); - job = [viewTransaction firstObjectInGroup:OWSMessageDecryptJobFinderExtensionGroup]; - }]; - - return job; -} - -- (void)addJobForEnvelopeData:(NSData *)envelopeData -{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - OWSMessageDecryptJob *job = [[OWSMessageDecryptJob alloc] initWithEnvelopeData:envelopeData]; - [job saveWithTransaction:transaction]; - }]; -} - -- (void)removeJobWithId:(NSString *)uniqueId -{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [transaction removeObjectForKey:uniqueId inCollection:[OWSMessageDecryptJob collection]]; - }]; -} - -+ (YapDatabaseView *)databaseExtension -{ - YapDatabaseViewSorting *sorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - - if (![object1 isKindOfClass:[OWSMessageDecryptJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - OWSMessageDecryptJob *job1 = (OWSMessageDecryptJob *)object1; - - if (![object2 isKindOfClass:[OWSMessageDecryptJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - OWSMessageDecryptJob *job2 = (OWSMessageDecryptJob *)object2; - - return [job1.createdAt compare:job2.createdAt]; - }]; - - YapDatabaseViewGrouping *grouping = - [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable(YapDatabaseReadTransaction *_Nonnull transaction, - NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object) { - if (![object isKindOfClass:[OWSMessageDecryptJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", object, collection); - return nil; - } - - // Arbitrary string - all in the same group. We're only using the view for sorting. - return OWSMessageDecryptJobFinderExtensionGroup; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageDecryptJob collection]]]; - - return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; -} - -+ (void)registerLegacyClasses -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - // We've renamed OWSMessageProcessingJob to OWSMessageDecryptJob. - [NSKeyedUnarchiver setClass:[OWSMessageDecryptJob class] forClassName:[OWSMessageDecryptJob collection]]; - }); -} - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage -{ - [self registerLegacyClasses]; - - YapDatabaseView *existingView = [storage registeredExtension:OWSMessageDecryptJobFinderExtensionName]; - if (existingView) { - OWSFailDebug(@"%@ was already initialized.", OWSMessageDecryptJobFinderExtensionName); - // already initialized - return; - } - [storage asyncRegisterExtension:[self databaseExtension] withName:OWSMessageDecryptJobFinderExtensionName]; -} - -@end - -#pragma mark - Queue Processing - -@interface OWSMessageDecryptQueue : NSObject - -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -@property (nonatomic, readonly) OWSMessageDecryptJobFinder *finder; -@property (nonatomic) BOOL isDrainingQueue; - -- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection - finder:(OWSMessageDecryptJobFinder *)finder NS_DESIGNATED_INITIALIZER; -- (instancetype)init NS_UNAVAILABLE; - -@end - -#pragma mark - - -@implementation OWSMessageDecryptQueue - -- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection finder:(OWSMessageDecryptJobFinder *)finder -{ - OWSSingletonAssert(); - - self = [super init]; - if (!self) { - return self; - } - - _dbConnection = dbConnection; - _finder = finder; - _isDrainingQueue = NO; - - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - if (CurrentAppContext().isMainApp) { - [self drainQueue]; - } - }]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(registrationStateDidChange:) - name:RegistrationStateDidChangeNotification - object:nil]; - - return self; -} - -#pragma mark - Singletons - -- (OWSMessageDecrypter *)messageDecrypter -{ - OWSAssertDebug(SSKEnvironment.shared.messageDecrypter); - - return SSKEnvironment.shared.messageDecrypter; -} - -- (OWSBatchMessageProcessor *)batchMessageProcessor -{ - OWSAssertDebug(SSKEnvironment.shared.batchMessageProcessor); - - return SSKEnvironment.shared.batchMessageProcessor; -} - -- (TSAccountManager *)tsAccountManager -{ - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - - return SSKEnvironment.shared.tsAccountManager; -} - -#pragma mark - Notifications - -- (void)registrationStateDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - if (CurrentAppContext().isMainApp) { - [self drainQueue]; - } - }]; -} - -#pragma mark - Instance methods - -- (dispatch_queue_t)serialQueue -{ - static dispatch_queue_t queue = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - queue = dispatch_queue_create("org.whispersystems.message.decrypt", DISPATCH_QUEUE_SERIAL); - }); - return queue; -} - -- (void)enqueueEnvelopeData:(NSData *)envelopeData -{ - [self.finder addJobForEnvelopeData:envelopeData]; -} - -- (void)drainQueue -{ - OWSAssertDebug(AppReadiness.isAppReady); - - if (!CurrentAppContext().isMainApp) { return; } - if (!self.tsAccountManager.isRegisteredAndReady) { return; } - - dispatch_async(self.serialQueue, ^{ - if (self.isDrainingQueue) { return; } - self.isDrainingQueue = YES; - [self drainQueueWorkStep]; - }); -} - -- (void)drainQueueWorkStep -{ - AssertOnDispatchQueue(self.serialQueue); - - OWSMessageDecryptJob *_Nullable job = [self.finder nextJob]; - - if (!job) { - self.isDrainingQueue = NO; - OWSLogVerbose(@"Queue is drained."); - return; - } - - __block OWSBackgroundTask *_Nullable backgroundTask = - [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - - [self processJob:job - completion:^(BOOL success) { - [self.finder removeJobWithId:job.uniqueId]; - OWSLogVerbose(@"%@ job. %lu jobs left.", - success ? @"decrypted" : @"failed to decrypt", - (unsigned long)[OWSMessageDecryptJob numberOfKeysInCollection]); - [self drainQueueWorkStep]; - OWSAssertDebug(backgroundTask); - backgroundTask = nil; - }]; -} - -- (BOOL)wasReceivedByUD:(SSKProtoEnvelope *)envelope -{ - return (envelope.type == SSKProtoEnvelopeTypeUnidentifiedSender && (!envelope.hasSource || envelope.source.length < 1)); -} - -- (void)processJob:(OWSMessageDecryptJob *)job completion:(void (^)(BOOL))completion -{ - AssertOnDispatchQueue(self.serialQueue); - OWSAssertDebug(job); - - SSKProtoEnvelope *_Nullable envelope = job.envelopeProto; - - if (!envelope) { - OWSFailDebug(@"Couldn't parse proto."); - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSErrorMessage *errorMessage = [TSErrorMessage corruptedMessageInUnknownThread]; - [SSKEnvironment.shared.notificationsManager notifyUserForThreadlessErrorMessage:errorMessage - transaction:transaction]; - }]; - - dispatch_async(self.serialQueue, ^{ - completion(NO); - }); - - return; - } - - // We use the original envelope for this check; - // the decryption process might rewrite the envelope. - BOOL wasReceivedByUD = [self wasReceivedByUD:envelope]; - - [self.messageDecrypter decryptEnvelope:envelope - envelopeData:job.envelopeData - successBlock:^(OWSMessageDecryptResult *result, YapDatabaseReadWriteTransaction *transaction) { - OWSAssertDebug(transaction); - - if ([LKSessionMetaProtocol shouldSkipMessageDecryptResult:result wrappedIn:envelope]) { - dispatch_async(self.serialQueue, ^{ - completion(YES); - }); - return; - } - - // We persist the decrypted envelope data in the same transaction within which - // it was decrypted to prevent data loss. If the new job isn't persisted, - // the session state side effects of its decryption are also rolled back. - // - // NOTE: We use envelopeData from the decrypt result, not job.envelopeData, - // since the envelope may be altered by the decryption process in the UD case. - [self.batchMessageProcessor enqueueEnvelopeData:result.envelopeData - plaintextData:result.plaintextData - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; - - dispatch_async(self.serialQueue, ^{ - completion(YES); - }); - } - failureBlock:^{ - dispatch_async(self.serialQueue, ^{ - completion(NO); - }); - }]; -} - -@end - -#pragma mark - OWSMessageReceiver - -@interface OWSMessageReceiver () - -@property (nonatomic, readonly) OWSMessageDecryptQueue *processingQueue; -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@end - -#pragma mark - - -@implementation OWSMessageReceiver - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - OWSSingletonAssert(); - - self = [super init]; - - if (!self) { - return self; - } - - // For coherency we use the same dbConnection to persist and read the unprocessed envelopes - YapDatabaseConnection *dbConnection = [primaryStorage newDatabaseConnection]; - OWSMessageDecryptJobFinder *finder = [[OWSMessageDecryptJobFinder alloc] initWithDBConnection:dbConnection]; - OWSMessageDecryptQueue *processingQueue = [[OWSMessageDecryptQueue alloc] initWithDBConnection:dbConnection finder:finder]; - - _processingQueue = processingQueue; - - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - if (CurrentAppContext().isMainApp) { - [self.processingQueue drainQueue]; - } - }]; - - return self; -} - -#pragma mark - class methods - -+ (NSString *)databaseExtensionName -{ - return OWSMessageDecryptJobFinderExtensionName; -} - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage -{ - [OWSMessageDecryptJobFinder asyncRegisterDatabaseExtension:storage]; -} - -#pragma mark - instance methods - -- (void)handleReceivedEnvelopeData:(NSData *)envelopeData -{ - if (envelopeData.length < 1) { - OWSFailDebug(@"Received an empty envelope."); - return; - } - - // Drop any too-large messages on the floor. Well behaving clients should never send them. - NSUInteger kMaxEnvelopeByteCount = 250 * 1024; - if (envelopeData.length > kMaxEnvelopeByteCount) { - OWSFailDebug(@"Received an oversized message."); - return; - } - - // Take note of any messages larger than we expect, but still process them. - // This likely indicates a misbehaving sending client. - NSUInteger kLargeEnvelopeWarningByteCount = 25 * 1024; - if (envelopeData.length > kLargeEnvelopeWarningByteCount) { - OWSFailDebug(@"Received an unexpectedly large message."); - } - - [self.processingQueue enqueueEnvelopeData:envelopeData]; - [self.processingQueue drainQueue]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageSend.swift b/SignalUtilitiesKit/OWSMessageSend.swift deleted file mode 100644 index 36dd9241f..000000000 --- a/SignalUtilitiesKit/OWSMessageSend.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - - -// Corresponds to a single effort to send a message to a given recipient, -// which may span multiple attempts. Note that group messages may be sent -// to multiple recipients and therefore require multiple instances of -// OWSMessageSend. -@objc -public class OWSMessageSend: NSObject { - @objc - public let message: TSOutgoingMessage - - // thread may be nil if message is an OWSOutgoingSyncMessage. - @objc - public let thread: TSThread? - - @objc - public let recipient: SignalRecipient - - private static let kMaxRetriesPerRecipient: Int = 1 // Loki: We have our own retrying - - @objc - public var remainingAttempts = OWSMessageSend.kMaxRetriesPerRecipient - - // We "fail over" to REST sends after _any_ error sending - // via the web socket. - @objc - public var hasWebsocketSendFailed = false - - @objc - public var udAccess: OWSUDAccess? - - @objc - public var senderCertificate: SMKSenderCertificate? - - @objc - public let localNumber: String - - @objc - public let isLocalNumber: Bool - - @objc - public let success: () -> Void - - @objc - public let failure: (Error) -> Void - - @objc - public init(message: TSOutgoingMessage, - thread: TSThread?, - recipient: SignalRecipient, - senderCertificate: SMKSenderCertificate?, - udAccess: OWSUDAccess?, - localNumber: String, - success: @escaping () -> Void, - failure: @escaping (Error) -> Void) { - self.message = message - self.thread = thread - self.recipient = recipient - self.localNumber = localNumber - self.senderCertificate = senderCertificate - self.udAccess = udAccess - - if let recipientId = recipient.uniqueId { - self.isLocalNumber = localNumber == recipientId - } else { - owsFailDebug("SignalRecipient missing recipientId") - self.isLocalNumber = false - } - - self.success = success - self.failure = failure - } - - @objc - public var isUDSend: Bool { - return udAccess != nil && senderCertificate != nil - } - - @objc - public func disableUD() { - Logger.verbose("\(recipient.recipientId)") - udAccess = nil - } - - @objc - public func setHasUDAuthFailed() { - Logger.verbose("\(recipient.recipientId)") - // We "fail over" to non-UD sends after auth errors sending via UD. - disableUD() - } -} diff --git a/SignalUtilitiesKit/OWSMessageSender.h b/SignalUtilitiesKit/OWSMessageSender.h deleted file mode 100644 index ed52d2019..000000000 --- a/SignalUtilitiesKit/OWSMessageSender.h +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -extern const NSUInteger kOversizeTextMessageSizeThreshold; - -@class OWSBlockingManager; -@class OWSPrimaryStorage; -@class TSAttachmentStream; -@class TSInvalidIdentityKeySendingErrorMessage; -@class TSNetworkManager; -@class TSOutgoingMessage; -@class TSThread; -@class YapDatabaseReadWriteTransaction; -@class OWSMessageSend; - -@protocol ContactsManagerProtocol; - -/** - * Useful for when you *sometimes* want to retry before giving up and calling the failure handler - * but *sometimes* we don't want to retry when we know it's a terminal failure, so we allow the - * caller to indicate this with isRetryable=NO. - */ -typedef void (^RetryableFailureHandler)(NSError *_Nonnull error); - -// Message send error handling is slightly different for contact and group messages. -// -// For example, If one member of a group deletes their account, the group should -// ignore errors when trying to send messages to this ex-member. - -#pragma mark - - -NS_SWIFT_NAME(OutgoingAttachmentInfo) -@interface OWSOutgoingAttachmentInfo : NSObject - -@property (nonatomic, readonly) DataSource *dataSource; -@property (nonatomic, readonly) NSString *contentType; -@property (nonatomic, readonly, nullable) NSString *sourceFilename; -@property (nonatomic, readonly, nullable) NSString *caption; -@property (nonatomic, readonly, nullable) NSString *albumMessageId; - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithDataSource:(DataSource *)dataSource - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId NS_DESIGNATED_INITIALIZER; - -@end - -#pragma mark - - -NS_SWIFT_NAME(MessageSender) -@interface OWSMessageSender : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; - -/** - * Send and resend text messages or resend messages with existing attachments. - * If you haven't yet created the attachment, see the `sendAttachment:` variants. - */ -- (void)sendMessage:(TSOutgoingMessage *)message - success:(void (^)(void))successHandler - failure:(void (^)(NSError *error))failureHandler; - -/** - * Takes care of allocating and uploading the attachment, then sends the message. - * Only necessary to call once. If sending fails, retry with `sendMessage:`. - */ -- (void)sendAttachment:(DataSource *)dataSource - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - albumMessageId:(nullable NSString *)albumMessageId - inMessage:(TSOutgoingMessage *)outgoingMessage - success:(void (^)(void))successHandler - failure:(void (^)(NSError *error))failureHandler; - -- (void)sendAttachments:(NSArray *)attachmentInfos - inMessage:(TSOutgoingMessage *)message - success:(void (^)(void))successHandler - failure:(void (^)(NSError *error))failureHandler; - -/** - * Same as `sendAttachment:`, but deletes the local copy of the attachment after sending. - * Used for sending sync request data, not for user visible attachments. - */ -- (void)sendTemporaryAttachment:(DataSource *)dataSource - contentType:(NSString *)contentType - inMessage:(TSOutgoingMessage *)outgoingMessage - success:(void (^)(void))successHandler - failure:(void (^)(NSError *error))failureHandler; - -- (void)sendMessage:(OWSMessageSend *)messageSend; - -@end - -#pragma mark - - -@interface OutgoingMessagePreparer : NSObject - -/// Persists all necessary data to disk before sending, e.g. generate thumbnails -+ (NSArray *)prepareMessageForSending:(TSOutgoingMessage *)message - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -/// Writes attachment to disk and applies original filename to message attributes -+ (void)prepareAttachments:(NSArray *)attachmentInfos - inMessage:(TSOutgoingMessage *)outgoingMessage - completionHandler:(void (^)(NSError *_Nullable error))completionHandler - NS_SWIFT_NAME(prepareAttachments(_:inMessage:completionHandler:)); - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageSender.m b/SignalUtilitiesKit/OWSMessageSender.m deleted file mode 100644 index a0f889952..000000000 --- a/SignalUtilitiesKit/OWSMessageSender.m +++ /dev/null @@ -1,1744 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSMessageSender.h" -#import "AppContext.h" -#import "NSData+keyVersionByte.h" -#import "NSData+messagePadding.h" -#import "NSError+MessageSending.h" -#import "OWSBackgroundTask.h" -#import "OWSBlockingManager.h" -#import "OWSContact.h" -#import "OWSDevice.h" -#import "OWSDisappearingMessagesJob.h" -#import "OWSDispatch.h" -#import "OWSEndSessionMessage.h" -#import "OWSError.h" -#import "OWSIdentityManager.h" -#import "OWSMessageServiceParams.h" -#import "OWSOperation.h" -#import "OWSOutgoingSentMessageTranscript.h" -#import "OWSOutgoingSyncMessage.h" -#import "OWSPrimaryStorage+PreKeyStore.h" -#import "OWSPrimaryStorage+SignedPreKeyStore.h" -#import "OWSPrimaryStorage+sessionStore.h" -#import "OWSPrimaryStorage+Loki.h" -#import "OWSPrimaryStorage.h" -#import "OWSRequestFactory.h" -#import "OWSUploadOperation.h" -#import "PreKeyBundle+jsonDict.h" -#import "SSKEnvironment.h" -#import "SignalRecipient.h" -#import "TSAccountManager.h" -#import "TSAttachmentStream.h" -#import "TSContactThread.h" -#import "TSGroupThread.h" -#import "TSIncomingMessage.h" -#import "TSInfoMessage.h" -#import "TSInvalidIdentityKeySendingErrorMessage.h" -#import "TSNetworkManager.h" -#import "TSOutgoingMessage.h" -#import "TSPreKeyManager.h" -#import "TSQuotedMessage.h" -#import "TSRequest.h" -#import "TSSocketManager.h" -#import "TSThread.h" -#import "TSContactThread.h" -#import "LKDeviceLinkMessage.h" -#import "LKUnlinkDeviceMessage.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import "SSKAsserts.h" -#import "SignalRecipient.h" - -NS_ASSUME_NONNULL_BEGIN - -NSString *NoSessionForTransientMessageException = @"NoSessionForTransientMessageException"; - -const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; - -NSError *SSKEnsureError(NSError *_Nullable error, OWSErrorCode fallbackCode, NSString *fallbackErrorDescription) -{ - if (error) { - return error; - } - OWSCFailDebug(@"Using fallback error."); - return OWSErrorWithCodeDescription(fallbackCode, fallbackErrorDescription); -} - -#pragma mark - - -void AssertIsOnSendingQueue() -{ -#ifdef DEBUG - if (@available(iOS 10.0, *)) { - dispatch_assert_queue([OWSDispatch sendingQueue]); - } // else, skip assert as it's a development convenience. -#endif -} - -#pragma mark - - -@implementation OWSOutgoingAttachmentInfo - -- (instancetype)initWithDataSource:(DataSource *)dataSource - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption - albumMessageId:(nullable NSString *)albumMessageId -{ - self = [super init]; - if (!self) { - return self; - } - - _dataSource = dataSource; - _contentType = contentType; - _sourceFilename = sourceFilename; - _caption = caption; - _albumMessageId = albumMessageId; - - return self; -} - -@end - -#pragma mark - - -/** - * OWSSendMessageOperation encapsulates all the work associated with sending a message, e.g. uploading attachments, - * getting proper keys, and retrying upon failure. - * - * Used by `OWSMessageSender` to serialize message sending, ensuring that messages are emitted in the order they - * were sent. - */ -@interface OWSSendMessageOperation : OWSOperation - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithMessage:(TSOutgoingMessage *)message - messageSender:(OWSMessageSender *)messageSender - dbConnection:(YapDatabaseConnection *)dbConnection - success:(void (^)(void))aSuccessHandler - failure:(void (^)(NSError * error))aFailureHandler NS_DESIGNATED_INITIALIZER; - -@end - -#pragma mark - - -@interface OWSMessageSender (OWSSendMessageOperation) - -- (void)sendMessageToService:(TSOutgoingMessage *)message - success:(void (^)(void))successHandler - failure:(RetryableFailureHandler)failureHandler; - -@end - -#pragma mark - - -@interface OWSSendMessageOperation () - -@property (nonatomic, readonly) TSOutgoingMessage *message; -@property (nonatomic, readonly) OWSMessageSender *messageSender; -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -@property (nonatomic, readonly) void (^successHandler)(void); -@property (nonatomic, readonly) void (^failureHandler)(NSError *error); - -@end - -#pragma mark - - -@implementation OWSSendMessageOperation - -- (instancetype)initWithMessage:(TSOutgoingMessage *)message - messageSender:(OWSMessageSender *)messageSender - dbConnection:(YapDatabaseConnection *)dbConnection - success:(void (^)(void))successHandler - failure:(void (^)(NSError * error))failureHandler -{ - self = [super init]; - - if (!self) { - return self; - } - - _message = message; - _messageSender = messageSender; - _dbConnection = dbConnection; - _successHandler = successHandler; - _failureHandler = failureHandler; - - return self; -} - -#pragma mark - OWSOperation overrides - -- (nullable NSError *)checkForPreconditionError -{ - __block NSError *_Nullable error = [super checkForPreconditionError]; - if (error) { return error; } - - if (self.message.hasAttachments) { - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - for (TSAttachment *attachment in [self.message attachmentsWithTransaction:transaction]) { - if (![attachment isKindOfClass:[TSAttachmentStream class]]) { - error = OWSErrorMakeFailedToSendOutgoingMessageError(); - break; - } - - TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; - OWSAssertDebug(attachmentStream); - OWSAssertDebug(attachmentStream.serverId); - OWSAssertDebug(attachmentStream.isUploaded); - } - }]; - } - - return error; -} - -- (void)run -{ - if (self.message.shouldBeSaved && ![TSOutgoingMessage fetchObjectWithUniqueID:self.message.uniqueId]) { - OWSLogInfo(@"Aborting message send; message deleted."); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageDeletedBeforeSent, @"Message was deleted before it could be sent."); - error.isFatal = YES; - [self reportError:error]; - return; - } - - [self.messageSender sendMessageToService:self.message - success:^{ - [self reportSuccess]; - } - failure:^(NSError *error) { - [self reportError:error]; - }]; -} - -- (void)didSucceed -{ - if (self.message.messageState != TSOutgoingMessageStateSent) { - [LKLogger print:@"[Loki] Succeeded with sending a message, but the message state isn't TSOutgoingMessageStateSent."]; - } - - self.successHandler(); -} - -- (void)didFailWithError:(NSError *)error -{ - OWSLogError(@"Message failed to send due to error: %@.", error); - self.failureHandler(error); -} - -@end - -#pragma mark - - -NSString *const OWSMessageSenderInvalidDeviceException = @"InvalidDeviceException"; -NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; - -@interface OWSMessageSender () - -@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage; -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -@property (atomic, readonly) NSMutableDictionary *sendingQueueMap; - -@end - -#pragma mark - - -@implementation OWSMessageSender - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - self = [super init]; - if (!self) { - return self; - } - - _primaryStorage = primaryStorage; - _sendingQueueMap = [NSMutableDictionary new]; - _dbConnection = primaryStorage.newDatabaseConnection; - - OWSSingletonAssert(); - - return self; -} - -#pragma mark - Dependencies - -- (id)contactsManager -{ - OWSAssertDebug(SSKEnvironment.shared.contactsManager); - - return SSKEnvironment.shared.contactsManager; -} - -- (OWSBlockingManager *)blockingManager -{ - OWSAssertDebug(SSKEnvironment.shared.blockingManager); - - return SSKEnvironment.shared.blockingManager; -} - -- (TSNetworkManager *)networkManager -{ - OWSAssertDebug(SSKEnvironment.shared.networkManager); - - return SSKEnvironment.shared.networkManager; -} - -- (id)udManager -{ - OWSAssertDebug(SSKEnvironment.shared.udManager); - - return SSKEnvironment.shared.udManager; -} - -- (TSAccountManager *)tsAccountManager -{ - return TSAccountManager.sharedInstance; -} - -- (OWSIdentityManager *)identityManager -{ - return SSKEnvironment.shared.identityManager; -} - -#pragma mark - - -- (NSOperationQueue *)sendingQueueForMessage:(TSOutgoingMessage *)message -{ - OWSAssertDebug(message); - - - NSString *kDefaultQueueKey = @"kDefaultQueueKey"; - NSString *queueKey = message.uniqueThreadId ?: kDefaultQueueKey; - OWSAssertDebug(queueKey.length > 0); - - if ([kDefaultQueueKey isEqualToString:queueKey]) { - // when do we get here? - OWSLogDebug(@"using default message queue"); - } - - @synchronized(self) - { - NSOperationQueue *sendingQueue = self.sendingQueueMap[queueKey]; - - if (!sendingQueue) { - sendingQueue = [NSOperationQueue new]; - sendingQueue.qualityOfService = NSOperationQualityOfServiceUserInitiated; - sendingQueue.maxConcurrentOperationCount = 1; - sendingQueue.name = [NSString stringWithFormat:@"%@:%@", self.logTag, queueKey]; - self.sendingQueueMap[queueKey] = sendingQueue; - } - - return sendingQueue; - } -} - -- (void)sendMessage:(TSOutgoingMessage *)message - success:(void (^)(void))successHandler - failure:(void (^)(NSError *error))failureHandler -{ - OWSAssertDebug(message); - - if (message.body.length > 0) { - OWSAssertDebug([message.body lengthOfBytesUsingEncoding:NSUTF8StringEncoding] <= kOversizeTextMessageSizeThreshold); - } - - if (message.shouldBeSaved && !message.thread.isGroupThread && ![LKSessionMetaProtocol isThreadNoteToSelf:message.thread]) { - // Loki: Not strictly true but nice from a UI point of view - [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.calculatingPoW object:[[NSNumber alloc] initWithUnsignedLongLong:message.timestamp]]; - } - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - NSMutableArray *allAttachmentIds = [NSMutableArray new]; - - // This method will use a read/write transaction. This transaction - // will block until any open read/write transactions are complete. - // - // That's key - we don't want to send any messages in response - // to an incoming message until processing of that batch of messages - // is complete. For example, we wouldn't want to auto-reply to a - // group info request before that group info request's batch was - // finished processing. Otherwise, we might receive a delivery - // notice for a group update we hadn't yet saved to the database. - // - // So we're using YDB behavior to ensure this invariant, which is a bit - // unorthodox. - if (message.allAttachmentIds.count > 0) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [allAttachmentIds addObjectsFromArray:[OutgoingMessagePreparer prepareMessageForSending:message transaction:transaction]]; - }]; - } - - NSOperationQueue *sendingQueue = [self sendingQueueForMessage:message]; - - OWSSendMessageOperation *sendMessageOperation = - [[OWSSendMessageOperation alloc] initWithMessage:message - messageSender:self - dbConnection:self.dbConnection - success:successHandler - failure:failureHandler]; - - for (NSString *attachmentId in allAttachmentIds) { - OWSUploadOperation *uploadAttachmentOperation = - [[OWSUploadOperation alloc] initWithAttachmentId:attachmentId - threadID:message.thread.uniqueId - dbConnection:self.dbConnection]; - - [sendMessageOperation addDependency:uploadAttachmentOperation]; - [sendingQueue addOperation:uploadAttachmentOperation]; - } - - [sendingQueue addOperation:sendMessageOperation]; - }); -} - -- (void)sendTemporaryAttachment:(DataSource *)dataSource - contentType:(NSString *)contentType - inMessage:(TSOutgoingMessage *)message - success:(void (^)(void))successHandler - failure:(void (^)(NSError *error))failureHandler -{ - OWSAssertDebug(dataSource); - - void (^successWithDeleteHandler)(void) = ^() { - successHandler(); - - OWSLogDebug(@"Removing successful temporary attachment message with attachment ids: %@", message.attachmentIds); - [message remove]; - }; - - void (^failureWithDeleteHandler)(NSError *error) = ^(NSError *error) { - failureHandler(error); - - OWSLogDebug(@"Removing failed temporary attachment message with attachment ids: %@", message.attachmentIds); - [message remove]; - }; - - [self sendAttachment:dataSource - contentType:contentType - sourceFilename:nil - albumMessageId:nil - inMessage:message - success:successWithDeleteHandler - failure:failureWithDeleteHandler]; -} - -- (void)sendAttachment:(DataSource *)dataSource - contentType:(NSString *)contentType - sourceFilename:(nullable NSString *)sourceFilename - albumMessageId:(nullable NSString *)albumMessageId - inMessage:(TSOutgoingMessage *)message - success:(void (^)(void))success - failure:(void (^)(NSError *error))failure -{ - OWSAssertDebug(dataSource); - - OWSOutgoingAttachmentInfo *attachmentInfo = [[OWSOutgoingAttachmentInfo alloc] initWithDataSource:dataSource - contentType:contentType - sourceFilename:sourceFilename - caption:nil - albumMessageId:albumMessageId]; - [self sendAttachments:@[ attachmentInfo, ] - inMessage:message - success:success - failure:failure]; -} - -- (void)sendAttachments:(NSArray *)attachmentInfos - inMessage:(TSOutgoingMessage *)message - success:(void (^)(void))success - failure:(void (^)(NSError *error))failure -{ - OWSAssertDebug(attachmentInfos.count > 0); - - [OutgoingMessagePreparer prepareAttachments:attachmentInfos - inMessage:message - completionHandler:^(NSError *_Nullable error) { - if (error) { - failure(error); - return; - } - [self sendMessage:message success:success failure:failure]; - }]; -} - -- (void)sendMessageToService:(TSOutgoingMessage *)message - success:(void (^)(void))success - failure:(RetryableFailureHandler)failure -{ - [self.udManager ensureSenderCertificateWithSuccess:^(SMKSenderCertificate *senderCertificate) { - OWSAssertDebug(senderCertificate != nil); - dispatch_async(OWSDispatch.sendingQueue, ^{ - [self sendMessageToService:message senderCertificate:senderCertificate success:success failure:failure]; - }); - } - failure:^(NSError *error) { // Should never occur - dispatch_async(OWSDispatch.sendingQueue, ^{ - [self sendMessageToService:message senderCertificate:nil success:success failure:failure]; - }); - }]; -} - -- (nullable NSArray *)unsentRecipientsForMessage:(TSOutgoingMessage *)message - thread:(nullable TSThread *)thread - error:(NSError **)errorHandle -{ - OWSAssertDebug(message); - OWSAssertDebug(errorHandle); - - NSString *userPublicKey = self.tsAccountManager.localNumber; - - __block NSMutableSet *recipientIds = [NSMutableSet new]; - if ([message isKindOfClass:OWSOutgoingSyncMessage.class]) { - recipientIds = [LKSessionMetaProtocol getDestinationsForOutgoingSyncMessage]; - } else if (thread.isGroupThread) { - TSGroupThread *groupThread = (TSGroupThread *)thread; - recipientIds = [LKSessionMetaProtocol getDestinationsForOutgoingGroupMessage:message inThread:thread]; - __block NSString *userMasterPublicKey; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - userMasterPublicKey = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:userPublicKey in:transaction] ?: userPublicKey; - }]; - if ([recipientIds containsObject:userMasterPublicKey]) { - OWSFailDebug(@"Message send recipients should not include self."); - } - } else if ([thread isKindOfClass:TSContactThread.class]) { - NSString *recipientContactId = ((TSContactThread *)thread).contactIdentifier; - - // Treat 1:1 sends to blocked contacts as failures. - // If we block a user, don't send 1:1 messages to them. The UI - // should prevent this from occurring, but in some edge cases - // you might, for example, have a pending outgoing message when - // you block them. - OWSAssertDebug(recipientContactId.length > 0); - if ([self.blockingManager isRecipientIdBlocked:recipientContactId]) { - OWSLogInfo(@"Skipping 1:1 send to blocked contact: %@", recipientContactId); - NSError *error = OWSErrorMakeMessageSendFailedDueToBlockListError(); - [error setIsRetryable:NO]; - *errorHandle = error; - return nil; - } - - [recipientIds addObject:recipientContactId]; - } else { - OWSFailDebug(@"Unknown message type: %@", [message class]); - NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); - [error setIsRetryable:NO]; - *errorHandle = error; - return nil; - } - - [recipientIds minusSet:[NSSet setWithArray:self.blockingManager.blockedPhoneNumbers]]; - return recipientIds.allObjects; -} - -- (NSArray *)recipientsForRecipientIds:(NSArray *)recipientIds -{ - OWSAssertDebug(recipientIds.count > 0); - - NSMutableArray *recipients = [NSMutableArray new]; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - for (NSString *recipientId in recipientIds) { - SignalRecipient *recipient = - [SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction]; - [recipients addObject:recipient]; - } - }]; - return [recipients copy]; -} - -- (AnyPromise *)sendPromiseForRecipients:(NSArray *)recipients - message:(TSOutgoingMessage *)message - thread:(nullable TSThread *)thread - senderCertificate:(nullable SMKSenderCertificate *)senderCertificate - sendErrors:(NSMutableArray *)sendErrors -{ - OWSAssertDebug(recipients.count > 0); - OWSAssertDebug(message); - OWSAssertDebug(sendErrors); - - NSMutableArray *sendPromises = [NSMutableArray array]; - - for (SignalRecipient *recipient in recipients) { - AnyPromise *sendPromise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - NSString *localNumber = self.tsAccountManager.localNumber; - - OWSUDAccess *_Nullable theirUDAccess; - if (senderCertificate != nil && ![recipient.recipientId isEqualToString:localNumber]) { - theirUDAccess = [self.udManager udAccessForRecipientId:recipient.recipientId requireSyncAccess:YES]; - } - - OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:message - thread:thread - recipient:recipient - senderCertificate:senderCertificate - udAccess:theirUDAccess - localNumber:self.tsAccountManager.localNumber - success:^{ - // The value doesn't matter, we just need any non-NSError value. - resolve(@(1)); - } - failure:^(NSError *error) { - @synchronized(sendErrors) { - [sendErrors addObject:error]; - } - resolve(error); - }]; - -// NSString *publicKey = recipients.firstObject.recipientId; -// if ([LKMultiDeviceProtocol isMultiDeviceRequiredForMessage:message toPublicKey:publicKey]) { // Avoid the write transaction if possible -// [self.primaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { -// [LKMultiDeviceProtocol sendMessageToDestinationAndLinkedDevices:messageSend transaction:transaction]; -// }]; -// } else { - [self sendMessage:messageSend]; -// } - }]; - [sendPromises addObject:sendPromise]; - } - - // We use PMKJoin(), not PMKWhen(), because we don't want the - // completion promise to execute until _all_ send promises - // have either succeeded or failed. PMKWhen() executes as - // soon as any of its input promises fail. - return PMKJoin(sendPromises); -} - -- (void)sendMessageToService:(TSOutgoingMessage *)message - senderCertificate:(nullable SMKSenderCertificate *)senderCertificate - success:(void (^)(void))successHandlerParam - failure:(RetryableFailureHandler)failureHandlerParam -{ - AssertIsOnSendingQueue(); - OWSAssert(senderCertificate); - - void (^successHandler)(void) = ^() { - dispatch_async(OWSDispatch.sendingQueue, ^{ - [self handleMessageSentLocally:message - success:^{ - successHandlerParam(); - } - failure:^(NSError *error) { - OWSLogError(@"Error sending sync message for message: %@ timestamp: %llu.", - message.class, - message.timestamp); - - failureHandlerParam(error); - }]; - }); - }; - void (^failureHandler)(NSError *) = ^(NSError *error) { - if (message.wasSentToAnyRecipient) { - dispatch_async(OWSDispatch.sendingQueue, ^{ - [self handleMessageSentLocally:message - success:^{ - failureHandlerParam(error); - } - failure:^(NSError *syncError) { - OWSLogError(@"Error sending sync message for message: %@ timestamp: %llu, %@.", - message.class, - message.timestamp, - syncError); - - // Discard the sync message error in favor of the original error - failureHandlerParam(error); - }]; - }); - return; - } - - failureHandlerParam(error); - }; - - TSThread *_Nullable thread = message.thread; - - BOOL isSyncMessage = [message isKindOfClass:[OWSOutgoingSyncMessage class]]; - if (thread == nil && !isSyncMessage) { - - // The thread has been deleted since the message was enqueued. - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients, - NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS", @"Error indicating that an outgoing message had no valid recipients.")); - [error setIsRetryable:NO]; - return failureHandler(error); - } - - // In the "self-send" special case, we ony need to send a sync message with a delivery receipt - // Loki: Take into account multi device - if ([LKSessionMetaProtocol isThreadNoteToSelf:thread] - && !([message isKindOfClass:LKDeviceLinkMessage.class]) && !([message isKindOfClass:SNClosedGroupUpdate.class])) { - // Don't mark self-sent messages as read (or sent) until the sync transcript is sent - successHandler(); - return; - } - - if (thread.isGroupThread) { - [self saveInfoMessageForGroupMessage:message inThread:thread]; - } - - NSError *error; - NSArray *_Nullable recipientIds = [self unsentRecipientsForMessage:message thread:thread error:&error]; - if (error || !recipientIds) { - error = SSKEnsureError( - error, OWSErrorCodeMessageSendNoValidRecipients, @"Couldn't build recipient list for message."); - [error setIsRetryable:NO]; - return failureHandler(error); - } - - // Mark skipped recipients as such. We skip because: - // - // * Recipient is no longer in the group. - // * Recipient is blocked. - // - // Elsewhere, we skip recipient if their Signal account has been deactivated. - NSMutableSet *obsoleteRecipientIds = [NSMutableSet setWithArray:message.sendingRecipientIds]; - [obsoleteRecipientIds minusSet:[NSSet setWithArray:recipientIds]]; - if (obsoleteRecipientIds.count > 0) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSString *recipientId in obsoleteRecipientIds) { - [message updateWithSkippedRecipient:recipientId transaction:transaction]; - } - }]; - } - - if (recipientIds.count < 1) { - successHandler(); - return; - } - - NSArray *recipients = [self recipientsForRecipientIds:recipientIds]; - - BOOL isGroupSend = (thread && thread.isGroupThread); - NSMutableArray *sendErrors = [NSMutableArray array]; - AnyPromise *sendPromise = [self sendPromiseForRecipients:recipients - message:message - thread:thread - senderCertificate:senderCertificate - sendErrors:sendErrors] - .then(^(id value) { - successHandler(); - }); - - sendPromise.catch(^(id failure) { - NSError *firstRetryableError = nil; - NSError *firstNonRetryableError = nil; - - NSArray *sendErrorsCopy; - @synchronized(sendErrors) { - sendErrorsCopy = [sendErrors copy]; - } - - for (NSError *error in sendErrorsCopy) { - // Some errors should be ignored when sending messages - // to groups. See discussion on - // NSError (OWSMessageSender) category. - if (isGroupSend && error.shouldBeIgnoredForGroups) { - continue; - } - - // Some errors should never be retried, in order to avoid - // hitting rate limits, for example. Unfortunately, since - // group send retry is all-or-nothing, we need to fail - // immediately even if some of the other recipients had - // retryable errors. - if (error.isFatal) { - failureHandler(error); - return; - } - - if ([error isRetryable] && !firstRetryableError) { - firstRetryableError = error; - } else if (![error isRetryable] && !firstNonRetryableError) { - firstNonRetryableError = error; - } - } - - // If any of the send errors are retryable, we want to retry. - // Therefore, prefer to propagate a retryable error. - if (firstRetryableError) { - return failureHandler(firstRetryableError); - } else if (firstNonRetryableError) { - return failureHandler(firstNonRetryableError); - } else { - // If we only received errors that we should ignore, - // consider this send a success, unless the message could - // not be sent to any recipient. - if (message.sentRecipientsCount == 0) { - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients, - NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS", @"Error indicating that an outgoing message had no valid recipients.")); - [error setIsRetryable:NO]; - failureHandler(error); - } else { - successHandler(); - } - } - }); - - [sendPromise retainUntilComplete]; -} - -- (nullable NSArray *)deviceMessagesForMessageSend:(OWSMessageSend *)messageSend - error:(NSError **)errorHandle -{ - OWSAssertDebug(messageSend); - OWSAssertDebug(errorHandle); - AssertIsOnSendingQueue(); - - SignalRecipient *recipient = messageSend.recipient; - - NSArray *deviceMessages; - @try { - deviceMessages = [self throws_deviceMessagesForMessageSend:messageSend]; - } @catch (NSException *exception) { - if ([exception.name isEqualToString:NoSessionForTransientMessageException]) { - // When users re-register, we don't want transient messages (like typing - // indicators) to cause users to hit the prekey fetch rate limit. So - // we silently discard these message if there is no pre-existing session - // for the recipient. - NSError *error = OWSErrorWithCodeDescription( - OWSErrorCodeNoSessionForTransientMessage, @"No session for transient message."); - [error setIsRetryable:NO]; - [error setIsFatal:YES]; - *errorHandle = error; - return nil; - } else if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { - NSString *localizedErrorDescriptionFormat - = NSLocalizedString(@"FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY", - @"action sheet header when re-sending message which failed because of untrusted identity keys"); - - NSString *localizedErrorDescription = - [NSString stringWithFormat:localizedErrorDescriptionFormat, - [self.contactsManager displayNameForPhoneIdentifier:recipient.recipientId]]; - NSError *error = OWSErrorMakeUntrustedIdentityError(localizedErrorDescription, recipient.recipientId); - - // Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request - // rate limit - [error setIsRetryable:NO]; - // Avoid the "Too many failures with this contact" error rate limiting. - [error setIsFatal:YES]; - *errorHandle = error; - - PreKeyBundle *_Nullable newKeyBundle = exception.userInfo[TSInvalidPreKeyBundleKey]; - if (newKeyBundle == nil) { - return nil; - } - - if (![newKeyBundle isKindOfClass:[PreKeyBundle class]]) { - return nil; - } - - NSData *newIdentityKeyWithVersion = newKeyBundle.identityKey; - - if (![newIdentityKeyWithVersion isKindOfClass:[NSData class]]) { - return nil; - } - - // TODO migrate to storing the full 33 byte representation of the identity key. - if (newIdentityKeyWithVersion.length != kIdentityKeyLength) { - return nil; - } - - NSData *newIdentityKey = [newIdentityKeyWithVersion throws_removeKeyType]; - [self.identityManager saveRemoteIdentity:newIdentityKey recipientId:recipient.recipientId]; - - return nil; - } - - if ([exception.name isEqualToString:OWSMessageSenderRateLimitedException]) { - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceRateLimited, - NSLocalizedString(@"FAILED_SENDING_BECAUSE_RATE_LIMIT", - @"action sheet header when re-sending message which failed because of too many attempts")); - // We're already rate-limited. No need to exacerbate the problem. - [error setIsRetryable:NO]; - // Avoid exacerbating the rate limiting. - [error setIsFatal:YES]; - *errorHandle = error; - return nil; - } - - OWSLogWarn(@"Could not build device messages: %@", exception); - NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); - [error setIsRetryable:YES]; - *errorHandle = error; - return nil; - } - - return deviceMessages; -} - -- (void)sendMessage:(OWSMessageSend *)messageSend -{ - OWSAssertDebug(messageSend); - OWSAssertDebug(messageSend.thread || [messageSend.message isKindOfClass:[OWSOutgoingSyncMessage class]]); - NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; - if (!messageSend.isUDSend && ![messageSend.recipient.recipientId isEqual:userPublicKey]) { - [LKLogger print:@"[Loki] Non-UD send"]; - } - - TSOutgoingMessage *message = messageSend.message; - SignalRecipient *recipient = messageSend.recipient; - - BOOL notifyPNServer = ((message.body != nil && message.body.length > 0) || message.hasAttachments); - - OWSLogInfo(@"Attempting to send message: %@, timestamp: %llu, recipient: %@.", - message.class, - message.timestamp, - recipient.uniqueId); - - AssertIsOnSendingQueue(); - - if ([TSPreKeyManager isAppLockedDueToPreKeyUpdateFailures]) { - // Retry pre key update every time user tries to send a message while the app - // is disabled due to pre key update failures. - // - // Only try to update the signed pre key; updating it is sufficient to - // re-enable message sending. - [TSPreKeyManager - rotateSignedPreKeyWithSuccess:^{ - OWSLogInfo(@"New pre keys registered with server."); - NSError *error = OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError(); - [error setIsRetryable:YES]; - return messageSend.failure(error); - } - failure:^(NSError *error) { - OWSLogWarn(@"Failed to update pre keys with the server due to error: %@.", error); - return messageSend.failure(error); - }]; - } - - if (messageSend.remainingAttempts <= 0) { - // We should always fail with a specific error. - NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); - [error setIsRetryable:YES]; - return messageSend.failure(error); - } - - // Consume an attempt. - messageSend.remainingAttempts = messageSend.remainingAttempts - 1; - - // We need to disable UD for sync messages before we build the device messages, - // since we don't want to build a device message for the local device in the - // non-UD auth case. - if ([message isKindOfClass:[OWSOutgoingSyncMessage class]] - && ![message isKindOfClass:[OWSOutgoingSentMessageTranscript class]]) { - [messageSend disableUD]; - } - - NSError *deviceMessagesError; - NSArray *_Nullable deviceMessages; - if (message.thread.isGroupThread && ((TSGroupThread *)message.thread).isPublicChat) { - deviceMessages = @[]; - } else { - deviceMessages = [self deviceMessagesForMessageSend:messageSend error:&deviceMessagesError]; - - // Loki: Remove this when we have shared sender keys - // ======== - if (deviceMessages.count == 0) { - return messageSend.success(); - } - // ======== - } - - if (deviceMessagesError || !deviceMessages) { - OWSAssertDebug(deviceMessagesError); - return messageSend.failure(deviceMessagesError); - } - - for (NSDictionary *deviceMessage in deviceMessages) { - NSNumber *_Nullable messageType = deviceMessage[@"type"]; - OWSAssertDebug(messageType); - BOOL hasValidMessageType; - if (messageSend.isUDSend) { - hasValidMessageType = [messageType isEqualToNumber:@(TSUnidentifiedSenderMessageType)]; - } else { - NSArray *validMessageTypes = @[ @(TSEncryptedWhisperMessageType), @(TSPreKeyWhisperMessageType), @(TSFallbackMessageType), @(TSClosedGroupCiphertextMessageType) ]; - hasValidMessageType = [validMessageTypes containsObject:messageType]; - } - - if (!hasValidMessageType) { - OWSFailDebug(@"Invalid message type: %@.", messageType); - NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); - [error setIsRetryable:NO]; - return messageSend.failure(error); - } - } - - if (deviceMessages.count == 0 && !(message.thread.isGroupThread && ((TSGroupThread *)message.thread).isPublicChat)) { - // This might happen: - // - // * The first (after upgrading?) time we send a sync message to our linked devices. - // * After unlinking all linked devices. - // * After trying and failing to link a device. - // * The first time we send a message to a user, if they don't have their - // default device. For example, if they have unregistered - // their primary but still have a linked device. Or later, when they re-register. - // - // When we're not sure if we have linked devices, we need to try - // to send self-sync messages even if they have no device messages - // so that we can learn from the service whether or not there are - // linked devices that we don't know about. - OWSLogWarn(@"Sending a message with no device messages."); - - NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); - [error setIsRetryable:NO]; - return messageSend.failure(error); - } - - void (^failedMessageSend)(NSError *error) = ^(NSError *error) { - NSUInteger statusCode = 0; - NSData *_Nullable responseData = nil; - if ([error.domain isEqualToString:TSNetworkManagerErrorDomain]) { - statusCode = error.code; - NSError *_Nullable underlyingError = error.userInfo[NSUnderlyingErrorKey]; - if (underlyingError) { - responseData = underlyingError.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; - } else { - OWSFailDebug(@"Missing underlying error: %@.", error); - } - } - [self messageSendDidFail:messageSend deviceMessages:deviceMessages statusCode:statusCode error:error responseData:responseData]; - }; - - __block SNOpenGroup *publicChat; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChat = [LKDatabaseUtilities getPublicChatForThreadID:message.uniqueThreadId transaction: transaction]; - }]; - if (publicChat != nil) { - NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; - NSString *displayName = SSKEnvironment.shared.profileManager.localProfileName; - if (displayName == nil) { displayName = @"Anonymous"; } - TSQuotedMessage *quote = message.quotedMessage; - uint64_t quoteID = quote.timestamp; - NSString *quoteePublicKey = quote.authorId; - __block uint64_t quotedMessageServerID = 0; - if (quoteID != 0) { - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - quotedMessageServerID = [LKDatabaseUtilities getServerIDForQuoteWithID:quoteID quoteeHexEncodedPublicKey:quoteePublicKey threadID:messageSend.thread.uniqueId transaction:transaction]; - }]; - } - NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body - SNOpenGroupMessage *groupMessage = [[SNOpenGroupMessage alloc] initWithSenderPublicKey:userPublicKey displayName:displayName body:body type:SNOpenGroupAPI.openGroupMessageType - timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteePublicKey:quoteePublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0 serverTimestamp:0]; - OWSLinkPreview *linkPreview = message.linkPreview; - if (linkPreview != nil) { - TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:linkPreview.imageAttachmentId]; - if (attachment != nil) { - [groupMessage addAttachmentWithKind:@"preview" server:publicChat.server serverID:attachment.serverId contentType:attachment.contentType size:attachment.byteCount fileName:attachment.sourceFilename flags:0 width:@(attachment.imageSize.width).unsignedIntegerValue height:@(attachment.imageSize.height).unsignedIntegerValue caption:attachment.caption url:attachment.downloadURL linkPreviewURL:linkPreview.urlString linkPreviewTitle:linkPreview.title]; - } - } - for (NSString *attachmentID in message.attachmentIds) { - TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID]; - if (attachment == nil) { continue; } - NSUInteger width = attachment.shouldHaveImageSize ? @(attachment.imageSize.width).unsignedIntegerValue : 0; - NSUInteger height = attachment.shouldHaveImageSize ? @(attachment.imageSize.height).unsignedIntegerValue : 0; - [groupMessage addAttachmentWithKind:@"attachment" server:publicChat.server serverID:attachment.serverId contentType:attachment.contentType size:attachment.byteCount fileName:attachment.sourceFilename flags:0 width:width height:height caption:attachment.caption url:attachment.downloadURL linkPreviewURL:nil linkPreviewTitle:nil]; - } - message.actualSenderHexEncodedPublicKey = userPublicKey; - [[SNOpenGroupAPI sendMessage:groupMessage toGroup:publicChat.channel onServer:publicChat.server] - .thenOn(OWSDispatch.sendingQueue, ^(SNOpenGroupMessage *groupMessage) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [message saveOpenGroupServerMessageID:groupMessage.serverID in:transaction]; - [self.primaryStorage setIDForMessageWithServerID:groupMessage.serverID to:message.uniqueId in:transaction]; - }]; - [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false]; - }) - .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { - failedMessageSend(error); - }) retainUntilComplete]; - } else { - NSString *targetPublicKey = recipient.recipientId; - NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; - __block BOOL isUserLinkedDevice; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - isUserLinkedDevice = [LKDatabaseUtilities isUserLinkedDevice:targetPublicKey in:transaction]; - }]; - BOOL isSSKBasedClosedGroup = [messageSend.thread isKindOfClass:TSGroupThread.class] && ((TSGroupThread *)messageSend.thread).usesSharedSenderKeys; - if (isSSKBasedClosedGroup) { - [LKLogger print:[NSString stringWithFormat:@"[Loki] Sending %@ to SSK based closed group.", message.class]]; - } else if ([targetPublicKey isEqual:userPublicKey]) { - [LKLogger print:[NSString stringWithFormat:@"[Loki] Sending %@ to self.", message.class]]; - } else if (isUserLinkedDevice) { - [LKLogger print:[NSString stringWithFormat:@"[Loki] Sending %@ to %@ (one of the current user's linked devices).", message.class, recipient.recipientId]]; - } else { - [LKLogger print:[NSString stringWithFormat:@"[Loki] Sending %@ to %@.", message.class, recipient.recipientId]]; - } - NSDictionary *signalMessageInfo = deviceMessages.firstObject; - SSKProtoEnvelopeType type = ((NSNumber *)signalMessageInfo[@"type"]).integerValue; - uint32_t senderDeviceID = (type == SSKProtoEnvelopeTypeUnidentifiedSender) ? 0 : OWSDevicePrimaryDeviceId; - NSString *content = signalMessageInfo[@"content"]; - NSString *recipientID = signalMessageInfo[@"destination"]; - uint64_t ttl = ((NSNumber *)signalMessageInfo[@"ttl"]).unsignedIntegerValue; - BOOL isPing = ((NSNumber *)signalMessageInfo[@"isPing"]).boolValue; - uint64_t timestamp = message.timestamp; - NSString *senderID; - if (type == SSKProtoEnvelopeTypeClosedGroupCiphertext) { - senderID = recipientID; - } else if (type == SSKProtoEnvelopeTypeUnidentifiedSender) { - senderID = @""; - } else { - senderID = userPublicKey; - [LKLogger print:@"[Loki] Non-UD send"]; - } - LKSignalMessage *signalMessage = [[LKSignalMessage alloc] initWithType:type timestamp:timestamp senderID:senderID senderDeviceID:senderDeviceID content:content recipientID:recipientID ttl:ttl isPing:isPing]; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - if (!message.skipSave) { - // Update the PoW calculation status - [message saveIsCalculatingProofOfWork:YES withTransaction:transaction]; - } - }]; - // Convenience - void (^handleError)(NSError *error) = ^(NSError *error) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - if (!message.skipSave) { - // Update the PoW calculation status - [message saveIsCalculatingProofOfWork:NO withTransaction:transaction]; - } - }]; - // Handle the error - failedMessageSend(error); - }; - // Send the message - [[LKSnodeAPI sendSignalMessage:signalMessage] - .thenOn(OWSDispatch.sendingQueue, ^(id result) { - NSSet *promises = (NSSet *)result; - __block BOOL isSuccess = NO; - NSUInteger promiseCount = promises.count; - __block NSUInteger errorCount = 0; - for (AnyPromise *promise in promises) { - [promise - .thenOn(OWSDispatch.sendingQueue, ^(id result) { - if (isSuccess) { return; } // Succeed as soon as the first promise succeeds - [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.messageSent object:[[NSNumber alloc] initWithUnsignedLongLong:signalMessage.timestamp]]; - isSuccess = YES; - if (notifyPNServer) { - [LKPushNotificationManager notifyForMessage:signalMessage]; - } - [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false]; - }) - .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { - errorCount += 1; - if (errorCount != promiseCount) { return; } // Only error out if all promises failed - [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.messageFailed object:[[NSNumber alloc] initWithUnsignedLongLong:signalMessage.timestamp]]; - handleError(error); - }) retainUntilComplete]; - } - }) - .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { - handleError(error); - }) retainUntilComplete]; - } -} - -- (void)messageSendDidSucceed:(OWSMessageSend *)messageSend - deviceMessages:(NSArray *)deviceMessages - wasSentByUD:(BOOL)wasSentByUD - wasSentByWebsocket:(BOOL)wasSentByWebsocket -{ - OWSAssertDebug(messageSend); - OWSAssertDebug(deviceMessages); - - SignalRecipient *recipient = messageSend.recipient; - - OWSLogInfo(@"Successfully sent message: %@ timestamp: %llu, wasSentByUD: %d.", - messageSend.message.class, messageSend.message.timestamp, wasSentByUD); - - if (messageSend.isLocalNumber && deviceMessages.count == 0) { - OWSLogInfo(@"Sent a message with no device messages; clearing 'mayHaveLinkedDevices'."); - // In order to avoid skipping necessary sync messages, the default value - // for mayHaveLinkedDevices is YES. Once we've successfully sent a - // sync message with no device messages (e.g. the service has confirmed - // that we have no linked devices), we can set mayHaveLinkedDevices to NO - // to avoid unnecessary message sends for sync messages until we learn - // of a linked device (e.g. through the device linking UI or by receiving - // a sync message, etc.). - [OWSDeviceManager.sharedManager clearMayHaveLinkedDevices]; - } - - dispatch_async(OWSDispatch.sendingQueue, ^{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [messageSend.message updateWithSentRecipient:messageSend.recipient.uniqueId - wasSentByUD:wasSentByUD - transaction:transaction]; - - // If we've just delivered a message to a user, we know they - // have a valid Signal account. - [SignalRecipient markRecipientAsRegisteredAndGet:recipient.recipientId transaction:transaction]; - }]; - - messageSend.success(); - }); -} - -- (void)messageSendDidFail:(OWSMessageSend *)messageSend - deviceMessages:(NSArray *)deviceMessages - statusCode:(NSInteger)statusCode - error:(NSError *)responseError - responseData:(nullable NSData *)responseData -{ - OWSAssertDebug(messageSend); - OWSAssertDebug(messageSend.thread || [messageSend.message isKindOfClass:[OWSOutgoingSyncMessage class]]); - OWSAssertDebug(deviceMessages); - OWSAssertDebug(responseError); - - TSOutgoingMessage *message = messageSend.message; - SignalRecipient *recipient = messageSend.recipient; - - OWSLogInfo(@"Failed to send message: %@, timestamp: %llu, to recipient: %@.", - message.class, - message.timestamp, - recipient.uniqueId); - - void (^retrySend)(void) = ^void() { - if (messageSend.remainingAttempts <= 0) { - return messageSend.failure(responseError); - } - - dispatch_async(OWSDispatch.sendingQueue, ^{ - OWSLogDebug(@"Retrying: %@.", message.debugDescription); - [self sendMessage:messageSend]; - }); - }; - - switch (statusCode) { - case 0: { // Loki - NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); - [error setIsRetryable:NO]; - return messageSend.failure(error); - } - case 401: { - OWSLogWarn(@"Unable to send due to invalid credentials. Did the user's client get de-authed by " - @"registering elsewhere?"); - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure, - NSLocalizedString(@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message")); - // No need to retry if we've been de-authed. - [error setIsRetryable:NO]; - return messageSend.failure(error); - } - default: - retrySend(); - break; - } -} - -- (void)handleMessageSentLocally:(TSOutgoingMessage *)message - success:(void (^)(void))successParam - failure:(RetryableFailureHandler)failure -{ - dispatch_block_t success = ^{ - // Don't mark self-sent messages as read (or sent) until the sync transcript is sent - // Loki: Take into account multi device - BOOL isNoteToSelf = [LKSessionMetaProtocol isThreadNoteToSelf:message.thread]; - if (isNoteToSelf && !([message isKindOfClass:LKDeviceLinkMessage.class]) - && ![message isKindOfClass:SNClosedGroupUpdate.class]) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSString *recipientId in message.sendingRecipientIds) { - [message updateWithReadRecipientId:recipientId readTimestamp:message.timestamp transaction:transaction]; - } - }]; - } - - successParam(); - }; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:message - expirationStartedAt:[NSDate ows_millisecondTimeStamp] - transaction:transaction]; - }]; - - if (!message.shouldSyncTranscript) { - return success(); - } - - BOOL shouldSendTranscript = [LKSessionMetaProtocol shouldSendTranscriptForMessage:message inThread:message.thread]; - if (!shouldSendTranscript) { - return success(); - } - - BOOL isRecipientUpdate = message.hasSyncedTranscript; - [self - sendSyncTranscriptForMessage:message - isRecipientUpdate:isRecipientUpdate - success:^{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [message updateWithHasSyncedTranscript:YES transaction:transaction]; - }]; - - success(); - } - failure:failure]; -} - -- (void)sendSyncTranscriptForMessage:(TSOutgoingMessage *)message - isRecipientUpdate:(BOOL)isRecipientUpdate - success:(void (^)(void))success - failure:(RetryableFailureHandler)failure -{ - OWSOutgoingSentMessageTranscript *sentMessageTranscript = - [[OWSOutgoingSentMessageTranscript alloc] initWithOutgoingMessage:message isRecipientUpdate:isRecipientUpdate]; - - NSString *userPublicKey = self.tsAccountManager.localNumber; - - // Loki: Send to the user's other device - __block NSSet *userLinkedDevices; - [self.primaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - userLinkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:userPublicKey in:transaction]; - }]; - NSString *otherUserDevice; - for (NSString *device in userLinkedDevices) { - if (![device isEqual:userPublicKey]) { - otherUserDevice = device; - break; - } - } - - NSString *recipientId = otherUserDevice ?: userPublicKey; - __block SignalRecipient *recipient; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - recipient = [SignalRecipient markRecipientAsRegisteredAndGet:recipientId transaction:transaction]; - }]; - - SMKSenderCertificate *senderCertificate = [self.udManager getSenderCertificate]; - OWSUDAccess *recipientUDAccess = nil; - if (senderCertificate != nil) { - recipientUDAccess = [self.udManager udAccessForRecipientId:recipient.recipientId requireSyncAccess:YES]; - } - - // Loki: If the message was aimed at an SSK based closed group, aim the sync transcript at - // the contact thread with the other device rather than also sending it to the group. - __block TSThread *thread = message.thread; - if ([thread isKindOfClass:TSGroupThread.class] && ((TSGroupThread *)thread).usesSharedSenderKeys) { - [LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) { - thread = [TSContactThread getThreadWithContactId:otherUserDevice transaction:transaction]; - }]; - } - - OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:sentMessageTranscript - thread:thread - recipient:recipient - senderCertificate:senderCertificate - udAccess:recipientUDAccess - localNumber:self.tsAccountManager.localNumber - success:^{ - OWSLogInfo(@"Successfully sent sync transcript."); - - success(); - } - failure:^(NSError *error) { - OWSLogInfo(@"Failed to send sync transcript: %@ (isRetryable: %d).", error, error.isRetryable); - - failure(error); - }]; - - [self sendMessage:messageSend]; -} - -- (NSArray *)throws_deviceMessagesForMessageSend:(OWSMessageSend *)messageSend -{ - // Loki: Multi device is handled elsewhere so just send to the provided recipient ID (Signal used - // to send to each of the recipient's devices here) - OWSAssertDebug(messageSend.message != nil); - OWSAssertDebug(messageSend.recipient != nil); - - SignalRecipient *recipient = messageSend.recipient; - NSMutableArray *messagesArray = [NSMutableArray new]; - - NSData *_Nullable plainText = [messageSend.message buildPlainTextData:recipient]; - if (!plainText) { - OWSRaiseException(InvalidMessageException, @"Failed to build message proto."); - } - OWSLogDebug(@"Built message: %@ plainTextData.length: %lu", [messageSend.message class], (unsigned long)plainText.length); - - NSString *recipientID = recipient.recipientId; - - OWSLogVerbose(@"Building device messages for: %@ %@ (isLocalNumber: %d, isUDSend: %d).", - recipientID, - recipient.devices, - messageSend.isLocalNumber, - messageSend.isUDSend); - - @try { - __block BOOL isSessionRequired; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - isSessionRequired = [LKSessionManagementProtocol isSessionRequiredForMessage:messageSend.message recipientID:recipientID transaction:transaction]; - }]; - if (isSessionRequired) { - BOOL hasSession = [self throws_ensureRecipientHasSessionForMessageSend:messageSend recipientID:recipientID deviceId:@(OWSDevicePrimaryDeviceId)]; - - // Loki: Remove this when shared sender keys has been widely rolled out - // ======== - if (!hasSession && [LKSessionManagementProtocol shouldIgnoreMissingPreKeyBundleExceptionForMessage:messageSend.message to:recipientID]) { - return @[ [NSDictionary new] ]; - } - // ======== - } - - __block NSDictionary *_Nullable messageDict; - __block NSException *encryptionException; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - @try { - messageDict = [self throws_encryptedMessageForMessageSend:messageSend - recipientID:recipientID - plainText:plainText - transaction:transaction]; - } @catch (NSException *exception) { - encryptionException = exception; - } - }]; - - if (encryptionException) { - OWSLogInfo(@"Exception during encryption: %@.", encryptionException); - @throw encryptionException; - } - - if (messageDict) { - [messagesArray addObject:messageDict]; - } else { - OWSRaiseException(InvalidMessageException, @"Failed to encrypt message."); - } - } @catch (NSException *exception) { - if ([exception.name isEqualToString:OWSMessageSenderInvalidDeviceException]) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [recipient updateRegisteredRecipientWithDevicesToAdd:nil - devicesToRemove:@[ @(OWSDevicePrimaryDeviceId) ] - transaction:transaction]; - }]; - } else { - @throw exception; - } - } - - return [messagesArray copy]; -} - -- (BOOL)throws_ensureRecipientHasSessionForMessageSend:(OWSMessageSend *)messageSend recipientID:(NSString *)recipientID deviceId:(NSNumber *)deviceId -{ - OWSAssertDebug(messageSend); - OWSAssertDebug(deviceId); - - OWSPrimaryStorage *storage = self.primaryStorage; - SignalRecipient *recipient = messageSend.recipient; - OWSAssertDebug(recipientID.length > 0); - - // Discard "typing indicator" messages if there is no existing session with the user. - BOOL canSafelyBeDiscarded = messageSend.message.isOnline; - if (canSafelyBeDiscarded) { - OWSRaiseException(NoSessionForTransientMessageException, @"No session for transient message."); - } - - PreKeyBundle *_Nullable bundle = [storage getPreKeyBundleForContact:recipientID]; - __block NSException *exception; - - if (!bundle) { - __block BOOL hasSession; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - hasSession = [storage containsSession:recipientID deviceId:[deviceId intValue] protocolContext:transaction]; - }]; - if (hasSession) { return YES; } - - TSOutgoingMessage *message = messageSend.message; - // Loki: Remove this when we have shared sender keys - // ======== - if ([LKSessionManagementProtocol shouldIgnoreMissingPreKeyBundleExceptionForMessage:message to:recipientID]) { return NO; } - // ======== - NSString *missingPrekeyBundleException = @"missingPrekeyBundleException"; - OWSRaiseException(missingPrekeyBundleException, @"Missing pre key bundle for: %@.", recipientID); - } else { - SessionBuilder *builder = [[SessionBuilder alloc] initWithSessionStore:storage - preKeyStore:storage - signedPreKeyStore:storage - identityKeyStore:self.identityManager - recipientId:recipientID - deviceId:[deviceId intValue]]; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - @try { - [builder throws_processPrekeyBundle:bundle protocolContext:transaction]; - - // Loki: Discard the pre key bundle as the session has now been established - [storage removePreKeyBundleForContact:recipientID transaction:transaction]; - } @catch (NSException *caughtException) { - exception = caughtException; - } - }]; - if (exception) { - if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { - OWSRaiseExceptionWithUserInfo(UntrustedIdentityKeyException, (@{ TSInvalidPreKeyBundleKey : bundle, TSInvalidRecipientKey : recipientID }), @""); - } - @throw exception; - } - return YES; - } -} - -- (nullable NSDictionary *)throws_encryptedMessageForMessageSend:(OWSMessageSend *)messageSend - recipientID:(NSString *)recipientID - plainText:(NSData *)plainText - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(messageSend); - OWSAssertDebug(recipientID); - OWSAssertDebug(plainText); - OWSAssertDebug(transaction); - - OWSPrimaryStorage *storage = self.primaryStorage; - TSOutgoingMessage *message = messageSend.message; - - SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storage - preKeyStore:storage - signedPreKeyStore:storage - identityKeyStore:self.identityManager - recipientId:recipientID - deviceId:@(OWSDevicePrimaryDeviceId).intValue]; - - NSData *_Nullable serializedMessage; - TSWhisperMessageType messageType; - if ([LKSharedSenderKeysImplementation.shared isClosedGroup:recipientID]) { - NSError *error; - serializedMessage = [LKClosedGroupUtilities encryptData:plainText.paddedMessageBody usingGroupPublicKey:recipientID transaction:transaction error:&error]; - - if (error != nil) { - OWSFailDebug(@"Couldn't encrypt message for SSK based closed group due to error: %@.", error); - return nil; - } - - messageType = TSClosedGroupCiphertextMessageType; - - messageSend.udAccess = nil; - } else if (messageSend.isUDSend) { - NSError *error; - SNSessionRestorationImplementation *sessionResetImplementation = [SNSessionRestorationImplementation new]; - - SMKSecretSessionCipher *_Nullable secretCipher = - [[SMKSecretSessionCipher alloc] initWithSessionResetImplementation:sessionResetImplementation - sessionStore:self.primaryStorage - preKeyStore:self.primaryStorage - signedPreKeyStore:self.primaryStorage - identityStore:self.identityManager - error:&error]; - if (error || !secretCipher) { - OWSRaiseException(@"SecretSessionCipherFailure", @"Can't create secret session cipher."); - } - - // Loki: The way this works is: - // • Alice sends a session request (i.e. a pre key bundle) to Bob using fallback encryption. - // • She may send any number of subsequent messages also encrypted using fallback encryption. - // • When Bob receives the session request, he sets up his Signal cipher session locally and sends back a null message, - // now encrypted using Signal encryption. - // • Alice receives this, sets up her Signal cipher session locally, and sends any subsequent messages - // using Signal encryption. - - BOOL shouldUseFallbackEncryption = [LKSessionManagementProtocol shouldUseFallbackEncryptionForMessage:message recipientID:recipientID transaction:transaction]; - - if (shouldUseFallbackEncryption) { - [LKLogger print:@"[Loki] Using fallback encryption"]; - } else { - [LKLogger print:@"[Loki] Using Signal Encryption"]; - } - - serializedMessage = [secretCipher throwswrapped_encryptMessageWithRecipientPublicKey:recipientID - deviceID:@(OWSDevicePrimaryDeviceId).intValue - paddedPlaintext:plainText.paddedMessageBody - senderCertificate:messageSend.senderCertificate - protocolContext:transaction - useFallbackSessionCipher:shouldUseFallbackEncryption - error:&error]; - - SCKRaiseIfExceptionWrapperError(error); - if (serializedMessage == nil || error != nil) { - OWSFailDebug(@"Error while UD encrypting message: %@.", error); - return nil; - } - messageType = TSUnidentifiedSenderMessageType; - } else { - id encryptedMessage = - [cipher throws_encryptMessage:[plainText paddedMessageBody] protocolContext:transaction]; - serializedMessage = encryptedMessage.serialized; - messageType = [self messageTypeForCipherMessage:encryptedMessage]; - } - - BOOL isSilent = message.isSilent; - BOOL isOnline = message.isOnline; - - OWSMessageServiceParams *messageParams = - [[OWSMessageServiceParams alloc] initWithType:messageType - recipientId:recipientID - device:@(OWSDevicePrimaryDeviceId).intValue - content:serializedMessage - isSilent:isSilent - isOnline:isOnline - registrationId:[cipher throws_remoteRegistrationId:transaction] - ttl:message.ttl - isPing:NO]; - - NSError *error; - NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error]; - - if (error != nil) { - return nil; - } - - return jsonDict; -} - -- (TSWhisperMessageType)messageTypeForCipherMessage:(id)cipherMessage -{ - switch (cipherMessage.cipherMessageType) { - case CipherMessageType_Whisper: - return TSEncryptedWhisperMessageType; - case CipherMessageType_Prekey: - return TSPreKeyWhisperMessageType; - default: - return TSUnknownMessageType; - } -} - -- (void)saveInfoMessageForGroupMessage:(TSOutgoingMessage *)message inThread:(TSThread *)thread -{ - OWSAssertDebug(message); - OWSAssertDebug(thread); - - if (message.groupMetaMessage == TSGroupMetaMessageDeliver) { - // TODO: Why is this necessary? - [message save]; - } else if (message.groupMetaMessage == TSGroupMetaMessageQuit) { - // MJK TODO - remove senderTimestamp - [[[TSInfoMessage alloc] initWithTimestamp:message.timestamp - inThread:thread - messageType:TSInfoMessageTypeGroupQuit - customMessage:message.customMessage] save]; - } else { - // MJK TODO - remove senderTimestamp - [[[TSInfoMessage alloc] initWithTimestamp:message.timestamp - inThread:thread - messageType:TSInfoMessageTypeGroupUpdate - customMessage:message.customMessage] save]; - } -} - -@end - -@implementation OutgoingMessagePreparer - -#pragma mark - Dependencies - -+ (YapDatabaseConnection *)dbConnection -{ - return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection; -} - -#pragma mark - - -+ (NSArray *)prepareMessageForSending:(TSOutgoingMessage *)message - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(message); - OWSAssertDebug(transaction); - - NSMutableArray *attachmentIds = [NSMutableArray new]; - - if (message.attachmentIds) { - [attachmentIds addObjectsFromArray:message.attachmentIds]; - } - - if (message.quotedMessage) { - // Though we currently only ever expect at most one thumbnail, the proto data model - // suggests this could change. The logic is intended to work with multiple, but - // if we ever actually want to send multiple, we should do more testing. - NSArray *quotedThumbnailAttachments = - [message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction]; - for (TSAttachmentStream *attachment in quotedThumbnailAttachments) { - [attachmentIds addObject:attachment.uniqueId]; - } - } - - if (message.contactShare.avatarAttachmentId != nil) { - TSAttachment *attachment = [message.contactShare avatarAttachmentWithTransaction:transaction]; - if ([attachment isKindOfClass:[TSAttachmentStream class]]) { - [attachmentIds addObject:attachment.uniqueId]; - } else { - OWSFailDebug(@"Unexpected avatarAttachment: %@.", attachment); - } - } - - if (message.linkPreview.imageAttachmentId != nil) { - TSAttachment *attachment = - [TSAttachment fetchObjectWithUniqueID:message.linkPreview.imageAttachmentId transaction:transaction]; - if ([attachment isKindOfClass:[TSAttachmentStream class]]) { - [attachmentIds addObject:attachment.uniqueId]; - } else { - OWSFailDebug(@"Unexpected attachment: %@.", attachment); - } - } - - // All outgoing messages should be saved at the time they are enqueued. - [message saveWithTransaction:transaction]; - // When we start a message send, all "failed" recipients should be marked as "sending". - [message updateWithMarkingAllUnsentRecipientsAsSendingWithTransaction:transaction]; - - return attachmentIds; -} - -+ (void)prepareAttachments:(NSArray *)attachmentInfos - inMessage:(TSOutgoingMessage *)outgoingMessage - completionHandler:(void (^)(NSError *_Nullable error))completionHandler -{ - OWSAssertDebug(attachmentInfos.count > 0); - OWSAssertDebug(outgoingMessage); - - dispatch_async([OWSDispatch attachmentsQueue], ^{ - NSMutableArray *attachmentStreams = [NSMutableArray new]; - for (OWSOutgoingAttachmentInfo *attachmentInfo in attachmentInfos) { - TSAttachmentStream *attachmentStream = - [[TSAttachmentStream alloc] initWithContentType:attachmentInfo.contentType - byteCount:(UInt32)attachmentInfo.dataSource.dataLength - sourceFilename:attachmentInfo.sourceFilename - caption:attachmentInfo.caption - albumMessageId:attachmentInfo.albumMessageId]; - - if (outgoingMessage.isVoiceMessage) { - attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage; - } - - if (![attachmentStream writeDataSource:attachmentInfo.dataSource]) { - NSError *error = OWSErrorMakeWriteAttachmentDataError(); - completionHandler(error); - return; - } - - [attachmentStreams addObject:attachmentStream]; - } - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - for (TSAttachmentStream *attachmentStream in attachmentStreams) { - [outgoingMessage.attachmentIds addObject:attachmentStream.uniqueId]; - if (attachmentStream.sourceFilename) { - outgoingMessage.attachmentFilenameMap[attachmentStream.uniqueId] = attachmentStream.sourceFilename; - } - } - [outgoingMessage saveWithTransaction:transaction]; - for (TSAttachmentStream *attachmentStream in attachmentStreams) { - [attachmentStream saveWithTransaction:transaction]; - } - }]; - - completionHandler(nil); - }); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Poller.swift b/SignalUtilitiesKit/Poller.swift index 1f5ef36c9..8387361ca 100644 --- a/SignalUtilitiesKit/Poller.swift +++ b/SignalUtilitiesKit/Poller.swift @@ -44,7 +44,7 @@ public final class Poller : NSObject { // MARK: Private API private func setUpPolling() { guard isPolling else { return } - SnodeAPI.getSwarm(for: getUserHexEncodedPublicKey(), isForcedReload: true).then2 { [weak self] _ -> Promise in + let _ = SnodeAPI.getSwarm(for: getUserHexEncodedPublicKey(), isForcedReload: true).then2 { [weak self] _ -> Promise in guard let strongSelf = self else { return Promise { $0.fulfill(()) } } strongSelf.usedSnodes.removeAll() let (promise, seal) = Promise.pending() @@ -96,7 +96,10 @@ public final class Poller : NSObject { guard let envelope = SSKProtoEnvelope.from(json) else { return } do { let data = try envelope.serializedData() - SSKEnvironment.shared.messageReceiver.handleReceivedEnvelopeData(data) + let job = MessageReceiveJob(data: data) + Storage.write { transaction in + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + } } catch { print("[Loki] Failed to deserialize envelope due to error: \(error).") } diff --git a/SignalUtilitiesKit/SessionManagementProtocol.swift b/SignalUtilitiesKit/SessionManagementProtocol.swift index 17fdabd77..f8f5b13a4 100644 --- a/SignalUtilitiesKit/SessionManagementProtocol.swift +++ b/SignalUtilitiesKit/SessionManagementProtocol.swift @@ -105,20 +105,17 @@ public final class SessionManagementProtocol : NSObject { // Send the session request print("[Loki] Sending session request to: \(publicKey).") Storage.setSessionRequestSentTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) - let sessionRequestMessage = SessionRequestMessage(thread: thread) - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue - messageSenderJobQueue.add(message: sessionRequestMessage, transaction: transaction) + let sessionRequest = SessionRequest() + sessionRequest.preKeyBundle = storage.generatePreKeyBundle(forContact: publicKey) + MessageSender.send(sessionRequest, in: thread, using: transaction) } @objc(sendNullMessageToPublicKey:transaction:) public static func sendNullMessage(to publicKey: String, in transaction: YapDatabaseReadWriteTransaction) { let thread = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) thread.save(with: transaction) - let nullMessage = OWSOutgoingNullMessage(outgoingMessageWithTimestamp: NSDate.millisecondTimestamp(), in: thread, messageBody: nil, - attachmentIds: [], expiresInSeconds: 0, expireStartedAt: 0, isVoiceMessage: false, groupMetaMessage: .unspecified, quotedMessage: nil, - contactShare: nil, linkPreview: nil) - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue - messageSenderJobQueue.add(message: nullMessage, transaction: transaction) + let nullMessage = NullMessage() + MessageSender.send(nullMessage, in: thread, using: transaction) } /// - Note: Deprecated. @@ -147,9 +144,11 @@ public final class SessionManagementProtocol : NSObject { guard ECKeyPair.isValidHexEncodedPublicKey(candidate: device) else { continue } let thread = TSContactThread.getOrCreateThread(withContactId: device, transaction: transaction) thread.save(with: transaction) + /* let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread) let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue messageSenderJobQueue.add(message: endSessionMessage, transaction: transaction) + */ } thread.removeAllSessionRestoreDevices(with: transaction) // Notify the user diff --git a/SignalUtilitiesKit/SessionMetaProtocol.swift b/SignalUtilitiesKit/SessionMetaProtocol.swift index dde938992..d15e4802b 100644 --- a/SignalUtilitiesKit/SessionMetaProtocol.swift +++ b/SignalUtilitiesKit/SessionMetaProtocol.swift @@ -101,19 +101,6 @@ public final class SessionMetaProtocol : NSObject { return errorMessage.timestamp < restorationTimeInMs } - @objc(shouldSkipMessageDecryptResult:wrappedIn:) - public static func shouldSkipMessageDecryptResult(_ result: OWSMessageDecryptResult, wrappedIn envelope: SSKProtoEnvelope) -> Bool { - return result.source == getUserHexEncodedPublicKey() - /* - if result.source == getUserHexEncodedPublicKey() { return true } - var isLinkedDevice = false - Storage.read { transaction in - isLinkedDevice = LokiDatabaseUtilities.isUserLinkedDevice(result.source, transaction: transaction) - } - return isLinkedDevice && envelope.type == .closedGroupCiphertext - */ - } - @objc(updateDisplayNameIfNeededForPublicKey:using:transaction:) public static func updateDisplayNameIfNeeded(for publicKey: String, using dataMessage: SSKProtoDataMessage, in transaction: YapDatabaseReadWriteTransaction) { guard let profile = dataMessage.profile, let displayName = profile.displayName, !displayName.isEmpty else { return } diff --git a/SignalUtilitiesKit/SyncMessagesProtocol.swift b/SignalUtilitiesKit/SyncMessagesProtocol.swift index ba159ef62..077354442 100644 --- a/SignalUtilitiesKit/SyncMessagesProtocol.swift +++ b/SignalUtilitiesKit/SyncMessagesProtocol.swift @@ -28,6 +28,7 @@ public final class SyncMessagesProtocol : NSObject { // MARK: - Sending @objc public static func syncProfile() { + /* Storage.writeSync { transaction in let userPublicKey = getUserHexEncodedPublicKey() let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: userPublicKey, in: transaction) @@ -41,6 +42,7 @@ public final class SyncMessagesProtocol : NSObject { messageSenderJobQueue.add(message: syncMessage, transaction: transaction) } } + */ } @objc(syncContactWithPublicKey:) @@ -73,6 +75,7 @@ public final class SyncMessagesProtocol : NSObject { @objc(syncClosedGroup:transaction:) public static func syncClosedGroup(_ thread: TSGroupThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + /* // Prepare let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue let group = thread.groupModel @@ -113,6 +116,7 @@ public final class SyncMessagesProtocol : NSObject { messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // This internally takes care of multi device } sendMessageToLinkedDevices() + */ // Return a dummy promise return AnyPromise.from(Promise { $0.fulfill(()) }) } @@ -132,15 +136,7 @@ public final class SyncMessagesProtocol : NSObject { } @objc public static func syncAllOpenGroups() -> AnyPromise { - let openGroupSyncMessage = SyncOpenGroupsMessage() - let (promise, seal) = Promise.pending() - let messageSender = SSKEnvironment.shared.messageSender - messageSender.send(openGroupSyncMessage, success: { - seal.fulfill(()) - }, failure: { error in - seal.reject(error) - }) - return AnyPromise.from(promise) + fatalError("Not implemented.") } // MARK: - Receiving diff --git a/SignalUtilitiesKit/TSConstants.h b/SignalUtilitiesKit/TSConstants.h index 26962c8cc..8ddac95c1 100644 --- a/SignalUtilitiesKit/TSConstants.h +++ b/SignalUtilitiesKit/TSConstants.h @@ -9,6 +9,8 @@ NS_ASSUME_NONNULL_BEGIN #ifndef TextSecureKit_Constants_h #define TextSecureKit_Constants_h +extern const NSUInteger kOversizeTextMessageSizeThreshold; + typedef NS_ENUM(NSInteger, TSWhisperMessageType) { TSUnknownMessageType = 0, TSEncryptedWhisperMessageType = 1, diff --git a/SignalUtilitiesKit/TSConstants.m b/SignalUtilitiesKit/TSConstants.m index b82b9e0e7..fbd6607e9 100644 --- a/SignalUtilitiesKit/TSConstants.m +++ b/SignalUtilitiesKit/TSConstants.m @@ -6,6 +6,8 @@ NS_ASSUME_NONNULL_BEGIN +const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; + BOOL IsUsingProductionService() { #ifdef USING_PRODUCTION_SERVICE diff --git a/SignalUtilitiesKit/TypingIndicators.swift b/SignalUtilitiesKit/TypingIndicators.swift index d0e7ebd73..e05cb43ff 100644 --- a/SignalUtilitiesKit/TypingIndicators.swift +++ b/SignalUtilitiesKit/TypingIndicators.swift @@ -226,12 +226,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { self.thread = thread } - // MARK: - Dependencies - - private var messageSender: MessageSender { - return SSKEnvironment.shared.messageSender - } - // MARK: - func didStartTypingOutgoingInput() { @@ -325,8 +319,19 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { if !SessionMetaProtocol.shouldSendTypingIndicator(in: thread) { return } - let message = TypingIndicatorMessage(thread: thread, action: action) - messageSender.sendPromise(message: message).retainUntilComplete() + let typingIndicator = TypingIndicator() + typingIndicator.kind = { + switch action { + case .started: return .started + case .stopped: return .stopped + } + }() + typingIndicator.threadID = thread.uniqueId! + let destination = Message.Destination.from(thread) + let job = MessageSendJob(message: typingIndicator, destination: destination) + Storage.write { transaction in + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + } } } diff --git a/SignalUtilitiesKit/Utilities/Destination+Conversion.swift b/SignalUtilitiesKit/Utilities/Destination+Conversion.swift new file mode 100644 index 000000000..f0de30135 --- /dev/null +++ b/SignalUtilitiesKit/Utilities/Destination+Conversion.swift @@ -0,0 +1,21 @@ + +public extension Message.Destination { + + static func from(_ thread: TSThread) -> Message.Destination { + if let thread = thread as? TSContactThread { + return .contact(publicKey: thread.uniqueId!) + } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys { + let groupID = thread.groupModel.groupId + let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) + return .closedGroup(groupPublicKey: groupPublicKey) + } else if let thread = thread as? TSGroupThread, thread.isPublicChat { + var openGroup: OpenGroup! + Storage.read { transaction in + openGroup = LokiDatabaseUtilities.getPublicChat(for: thread.uniqueId!, in: transaction) + } + return .openGroup(channel: openGroup.channel, server: openGroup.server) + } else { + preconditionFailure("TODO: Handle legacy closed groups.") + } + } +} diff --git a/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift b/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift new file mode 100644 index 000000000..a0d635917 --- /dev/null +++ b/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift @@ -0,0 +1,17 @@ +import PromiseKit + +public extension MessageSender { + + static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + message.threadID = thread.uniqueId! + let destination = Message.Destination.from(thread) + let job = MessageSendJob(message: message, destination: destination) + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + } + + static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + message.threadID = thread.uniqueId! + let destination = Message.Destination.from(thread) + return MessageSender.send(message, to: destination, using: transaction) + } +} From aba4cda14379381f1f1a88723ca9b0ecd0cfca67 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 12 Nov 2020 16:23:34 +1100 Subject: [PATCH 002/177] WIP --- .../Jobs/MessageReceiveJob.swift | 8 +- .../Sending & Receiving/MessageReceiver.swift | 2 +- Signal.xcodeproj/project.pbxproj | 8 - SignalUtilitiesKit/FullTextSearchFinder.swift | 2 +- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 1 - SignalUtilitiesKit/PublicChatPoller.swift | 5 +- .../SharingThreadPickerViewController.m | 2 - SignalUtilitiesKit/SignalAttachment.swift | 18 +- ...SInvalidIdentityKeyReceivingErrorMessage.m | 3 - SignalUtilitiesKit/TSOutgoingMessage.m | 1 - SignalUtilitiesKit/TSThread.h | 1 - SignalUtilitiesKit/TSThread.m | 5 - SignalUtilitiesKit/ThreadUtil.h | 144 ---- SignalUtilitiesKit/ThreadUtil.m | 797 ------------------ 14 files changed, 21 insertions(+), 976 deletions(-) delete mode 100644 SignalUtilitiesKit/ThreadUtil.h delete mode 100644 SignalUtilitiesKit/ThreadUtil.m diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 9b95f97ea..1c6f9503a 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -3,25 +3,29 @@ import SessionUtilitiesKit public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? private let data: Data + private let messageServerID: UInt64? public var failureCount: UInt = 0 // MARK: Settings public static let maxFailureCount: UInt = 10 // MARK: Initialization - public init(data: Data) { + public init(data: Data, messageServerID: UInt64? = nil) { self.data = data + self.messageServerID = messageServerID } // MARK: Coding public init?(coder: NSCoder) { guard let data = coder.decodeObject(forKey: "data") as! Data? else { return nil } self.data = data + self.messageServerID = coder.decodeObject(forKey: "messageServerUD") as! UInt64? self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(data, forKey: "data") + coder.encode(messageServerID, forKey: "messageServerID") coder.encode(failureCount, forKey: "failureCount") } @@ -30,7 +34,7 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NS Configuration.shared.storage.with { transaction in // Intentionally capture self Threading.workQueue.async { do { - let _ = try MessageReceiver.parse(self.data, using: transaction) + let _ = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) self.handleSuccess() } catch { SNLog("Couldn't parse message due to error: \(error).") diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 759136062..a874a701f 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -30,7 +30,7 @@ internal enum MessageReceiver { } } - internal static func parse(_ data: Data, using transaction: Any) throws -> Message { + internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> Message { // Parse the envelope let envelope = try MessageWrapper.unwrap(data: data) // Decrypt the contents diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 266471fa2..5a89d3c8c 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -880,7 +880,6 @@ C38EF31B255B6DBF007E1867 /* OWSPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F2255B6DBC007E1867 /* Searcher.swift */; }; C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */; }; - C38EF31E255B6DBF007E1867 /* ThreadUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F4255B6DBC007E1867 /* ThreadUtil.m */; }; C38EF320255B6DBF007E1867 /* OWSScrubbingLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */; }; C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */; }; C38EF322255B6DBF007E1867 /* DebugLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F8255B6DBC007E1867 /* DebugLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -890,7 +889,6 @@ C38EF326255B6DBF007E1867 /* ConversationStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */; }; C38EF327255B6DBF007E1867 /* BlockListUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */; }; C38EF328255B6DBF007E1867 /* OWSContactAvatarBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FE255B6DBD007E1867 /* OWSContactAvatarBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF329255B6DBF007E1867 /* ThreadUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FF255B6DBD007E1867 /* ThreadUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF300255B6DBD007E1867 /* UIUtil.m */; }; C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF301255B6DBD007E1867 /* OWSFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF32D255B6DBF007E1867 /* BlockListUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -2225,7 +2223,6 @@ C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSPreferences.h; path = SignalUtilitiesKit/OWSPreferences.h; sourceTree = SOURCE_ROOT; }; C38EF2F2255B6DBC007E1867 /* Searcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Searcher.swift; path = SignalUtilitiesKit/Searcher.swift; sourceTree = SOURCE_ROOT; }; C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+OWS.swift"; path = "SignalUtilitiesKit/UIImage+OWS.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2F4255B6DBC007E1867 /* ThreadUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadUtil.m; path = SignalUtilitiesKit/ThreadUtil.m; sourceTree = SOURCE_ROOT; }; C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SignalUtilitiesKit/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; }; C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSScrubbingLogFormatter.m; path = SignalUtilitiesKit/OWSScrubbingLogFormatter.m; sourceTree = SOURCE_ROOT; }; C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAudioPlayer.m; path = SignalUtilitiesKit/OWSAudioPlayer.m; sourceTree = SOURCE_ROOT; }; @@ -2236,7 +2233,6 @@ C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationStyle.swift; path = SignalUtilitiesKit/ConversationStyle.swift; sourceTree = SOURCE_ROOT; }; C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BlockListUIUtils.m; path = SignalUtilitiesKit/BlockListUIUtils.m; sourceTree = SOURCE_ROOT; }; C38EF2FE255B6DBD007E1867 /* OWSContactAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSContactAvatarBuilder.h; path = SignalUtilitiesKit/OWSContactAvatarBuilder.h; sourceTree = SOURCE_ROOT; }; - C38EF2FF255B6DBD007E1867 /* ThreadUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadUtil.h; path = SignalUtilitiesKit/ThreadUtil.h; sourceTree = SOURCE_ROOT; }; C38EF300255B6DBD007E1867 /* UIUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UIUtil.m; path = SignalUtilitiesKit/UIUtil.m; sourceTree = SOURCE_ROOT; }; C38EF301255B6DBD007E1867 /* OWSFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSFormat.h; path = SignalUtilitiesKit/OWSFormat.h; sourceTree = SOURCE_ROOT; }; C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.h; sourceTree = SOURCE_ROOT; }; @@ -3468,8 +3464,6 @@ C38EF306255B6DBE007E1867 /* OWSWindowManager.m */, C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */, - C38EF2FF255B6DBD007E1867 /* ThreadUtil.h */, - C38EF2F4255B6DBC007E1867 /* ThreadUtil.m */, C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */, C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */, C38EF30A255B6DBE007E1867 /* UIUtil.h */, @@ -4562,7 +4556,6 @@ C33FDC6F255A582000E217F9 /* TSNetworkManager.h in Headers */, C33FDD4B255A582000E217F9 /* ProtoUtils.h in Headers */, C33FDD19255A582000E217F9 /* YapDatabaseConnection+OWS.h in Headers */, - C38EF329255B6DBF007E1867 /* ThreadUtil.h in Headers */, C33FDD1F255A582000E217F9 /* OWSSyncConfigurationMessage.h in Headers */, C38EF216255B6D3B007E1867 /* Theme.h in Headers */, C38EF31B255B6DBF007E1867 /* OWSPreferences.h in Headers */, @@ -5827,7 +5820,6 @@ C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */, C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */, C33FDC5E255A582000E217F9 /* SSKProto.swift in Sources */, - C38EF31E255B6DBF007E1867 /* ThreadUtil.m in Sources */, C38EF39E255B6DDA007E1867 /* OWSQuotedReplyModel.m in Sources */, C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, diff --git a/SignalUtilitiesKit/FullTextSearchFinder.swift b/SignalUtilitiesKit/FullTextSearchFinder.swift index 5ead04baf..1fcd44e96 100644 --- a/SignalUtilitiesKit/FullTextSearchFinder.swift +++ b/SignalUtilitiesKit/FullTextSearchFinder.swift @@ -216,7 +216,7 @@ public class FullTextSearchFinder: NSObject { if let groupThread = object as? TSGroupThread { return self.groupThreadIndexer.index(groupThread, transaction: transaction) } else if let contactThread = object as? TSContactThread { - guard contactThread.shouldThreadBeVisible && !contactThread.isSlaveThread else { + guard contactThread.shouldThreadBeVisible else { // If we've never sent/received a message in a TSContactThread, // then we want it to appear in the "Other Contacts" section rather // than in the "Conversations" section. diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 309c405a0..18c71fc06 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -102,7 +102,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import diff --git a/SignalUtilitiesKit/PublicChatPoller.swift b/SignalUtilitiesKit/PublicChatPoller.swift index dfd03a974..9d1dbf10c 100644 --- a/SignalUtilitiesKit/PublicChatPoller.swift +++ b/SignalUtilitiesKit/PublicChatPoller.swift @@ -178,7 +178,10 @@ public final class PublicChatPoller : NSObject { Storage.writeSync { transaction in transaction.setObject(senderDisplayName, forKey: senderPublicKey, inCollection: publicChat.id) let messageServerID = message.serverID - SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction, serverID: messageServerID ?? 0) + let job = MessageReceiveJob(data: try! envelope.buildSerializedData(), messageServerID: messageServerID) + Storage.write { transaction in + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + } // If we got a message from our master device then we should use its profile picture if let profilePicture = message.profilePicture, masterPublicKey == message.senderPublicKey { if (message.displayName.count > 0) { diff --git a/SignalUtilitiesKit/SharingThreadPickerViewController.m b/SignalUtilitiesKit/SharingThreadPickerViewController.m index 5f8fcc8c0..9a85d0f96 100644 --- a/SignalUtilitiesKit/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/SharingThreadPickerViewController.m @@ -4,14 +4,12 @@ #import "SharingThreadPickerViewController.h" #import "SignalApp.h" -#import "ThreadUtil.h" #import "UIColor+OWS.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" #import #import #import -#import #import #import diff --git a/SignalUtilitiesKit/SignalAttachment.swift b/SignalUtilitiesKit/SignalAttachment.swift index 42f48edd3..0a9aa7385 100644 --- a/SignalUtilitiesKit/SignalAttachment.swift +++ b/SignalUtilitiesKit/SignalAttachment.swift @@ -244,15 +244,15 @@ public class SignalAttachment: NSObject { return errorDescription } - @objc - public func buildOutgoingAttachmentInfo(message: TSMessage) -> OutgoingAttachmentInfo { - assert(message.uniqueId != nil) - return OutgoingAttachmentInfo(dataSource: dataSource, - contentType: mimeType, - sourceFilename: filenameOrDefault, - caption: captionText, - albumMessageId: message.uniqueId) - } +// @objc +// public func buildOutgoingAttachmentInfo(message: TSMessage) -> OutgoingAttachmentInfo { +// assert(message.uniqueId != nil) +// return OutgoingAttachmentInfo(dataSource: dataSource, +// contentType: mimeType, +// sourceFilename: filenameOrDefault, +// caption: captionText, +// albumMessageId: message.uniqueId) +// } @objc public func staticThumbnail() -> UIImage? { diff --git a/SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.m b/SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.m index caf7ccbdb..034853307 100644 --- a/SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -5,8 +5,6 @@ #import "TSInvalidIdentityKeyReceivingErrorMessage.h" #import "OWSFingerprint.h" #import "OWSIdentityManager.h" -#import "OWSMessageManager.h" -#import "OWSMessageReceiver.h" #import "OWSPrimaryStorage+SessionStore.h" #import "OWSPrimaryStorage.h" #import "SSKEnvironment.h" @@ -108,7 +106,6 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage [self.thread receivedMessagesForInvalidKey:newKey]; for (TSInvalidIdentityKeyReceivingErrorMessage *errorMessage in messagesToDecrypt) { - [SSKEnvironment.shared.messageReceiver handleReceivedEnvelopeData:errorMessage.envelopeData]; // Here we remove the existing error message because handleReceivedEnvelope will either // 1.) succeed and create a new successful message in the thread or... diff --git a/SignalUtilitiesKit/TSOutgoingMessage.m b/SignalUtilitiesKit/TSOutgoingMessage.m index b30739593..f681ccb6b 100644 --- a/SignalUtilitiesKit/TSOutgoingMessage.m +++ b/SignalUtilitiesKit/TSOutgoingMessage.m @@ -7,7 +7,6 @@ #import "TSOutgoingMessage.h" #import "NSString+SSK.h" #import "OWSContact.h" -#import "OWSMessageSender.h" #import "OWSOutgoingSyncMessage.h" #import "OWSPrimaryStorage.h" #import "ProfileManagerProtocol.h" diff --git a/SignalUtilitiesKit/TSThread.h b/SignalUtilitiesKit/TSThread.h index 6eaef5ca4..bcf077447 100644 --- a/SignalUtilitiesKit/TSThread.h +++ b/SignalUtilitiesKit/TSThread.h @@ -38,7 +38,6 @@ extern ConversationColorName const kConversationColorName_Default; @property (nonatomic, readonly) NSDate *creationDate; @property (nonatomic, readonly) BOOL isArchivedByLegacyTimestampForSorting; @property (nonatomic, readonly) TSInteraction *lastInteraction; -@property (nonatomic, readonly) BOOL isSlaveThread; /** * Whether the object is a group thread or not. diff --git a/SignalUtilitiesKit/TSThread.m b/SignalUtilitiesKit/TSThread.m index 3ef2ecaf7..773c00a1c 100644 --- a/SignalUtilitiesKit/TSThread.m +++ b/SignalUtilitiesKit/TSThread.m @@ -730,11 +730,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa }]; } -- (BOOL)isSlaveThread -{ - return [LKMultiDeviceProtocol isSlaveThread:self]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ThreadUtil.h b/SignalUtilitiesKit/ThreadUtil.h deleted file mode 100644 index ec5070d1f..000000000 --- a/SignalUtilitiesKit/ThreadUtil.h +++ /dev/null @@ -1,144 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class LKDeviceLinkMessage; -@class LKUnlinkDeviceMessage; -@class OWSBlockingManager; -@class OWSContact; -@class OWSContactsManager; -@class OWSLinkPreviewDraft; -@class OWSMessageSender; -@class OWSQuotedReplyModel; -@class OWSUnreadIndicator; -@class SignalAttachment; -@class TSContactThread; -@class TSGroupThread; -@class TSInteraction; -@class TSOutgoingMessage; -@class TSThread; -@class YapDatabaseConnection; -@class YapDatabaseReadTransaction; -@class YapDatabaseReadWriteTransaction; - -@interface ThreadDynamicInteractions : NSObject - -// Represents the "reverse index" of the focus message, if any. -// The "reverse index" is the distance of this interaction from -// the last interaction in the thread. Therefore the last interaction -// will have a "reverse index" of zero. -// -// We use "reverse indices" because (among other uses) we use this to -// determine the initial load window size. -@property (nonatomic, nullable, readonly) NSNumber *focusMessagePosition; - -@property (nonatomic, nullable, readonly) OWSUnreadIndicator *unreadIndicator; - -- (void)clearUnreadIndicatorState; - -@end - -#pragma mark - - -@interface ThreadUtil : NSObject - -#pragma mark - Durable Message Enqueue - -+ (void)enqueueDeviceLinkMessage:(LKDeviceLinkMessage *)message; - -+ (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)fullMessageText - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft - transaction:(YapDatabaseReadTransaction *)transaction; - -+ (TSOutgoingMessage *)enqueueMessageWithText:(nullable NSString *)fullMessageText - mediaAttachments:(NSArray *)attachments - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft - transaction:(YapDatabaseReadTransaction *)transaction; - -+ (TSOutgoingMessage *)enqueueMessageWithContactShare:(OWSContact *)contactShare inThread:(TSThread *)thread; -+ (void)enqueueLeaveGroupMessageInThread:(TSGroupThread *)thread; - -#pragma mark - Non-Durable Sending - -// Used by SAE and "reply from lockscreen", otherwise we should use the durable `enqueue` counterpart -+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - transaction:(YapDatabaseReadTransaction *)transaction - messageSender:(OWSMessageSender *)messageSender - completion:(void (^)(NSError *_Nullable error))completion; - -// Used by SAE, otherwise we should use the durable `enqueue` counterpart -+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText - mediaAttachments:(NSArray *)attachments - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - transaction:(YapDatabaseReadTransaction *)transaction - messageSender:(OWSMessageSender *)messageSender - completion:(void (^)(NSError *_Nullable error))completion; - -// Used by SAE, otherwise we should use the durable `enqueue` counterpart -+ (TSOutgoingMessage *)sendMessageNonDurablyWithContactShare:(OWSContact *)contactShare - inThread:(TSThread *)thread - messageSender:(OWSMessageSender *)messageSender - completion:(void (^)(NSError *_Nullable error))completion; - - -#pragma mark - dynamic interactions - -// This method will create and/or remove any offers and indicators -// necessary for this thread. This includes: -// -// * Block offers. -// * "Add to contacts" offers. -// * Unread indicators. -// -// Parameters: -// -// * hideUnreadMessagesIndicator: If YES, the "unread indicator" has -// been cleared and should not be shown. -// * firstUnseenInteractionTimestamp: A snapshot of unseen message state -// when we entered the conversation view. See comments on -// ThreadOffersAndIndicators. -// * maxRangeSize: Loading a lot of messages in conversation view is -// slow and unwieldy. This number represents the maximum current -// size of the "load window" in that view. The unread indicator should -// always be inserted within that window. -+ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread - contactsManager:(OWSContactsManager *)contactsManager - blockingManager:(OWSBlockingManager *)blockingManager - dbConnection:(YapDatabaseConnection *)dbConnection - hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator - lastUnreadIndicator:(nullable OWSUnreadIndicator *)lastUnreadIndicator - focusMessageId:(nullable NSString *)focusMessageId - maxRangeSize:(int)maxRangeSize; - -+ (BOOL)shouldShowGroupProfileBannerInThread:(TSThread *)thread blockingManager:(OWSBlockingManager *)blockingManager; - -// This method should be called right _before_ we send a message to a thread, -// since we want to auto-add contact threads to the profile whitelist if the -// conversation was initiated by the local user. -// -// Returns YES IFF the thread was just added to the profile whitelist. -+ (BOOL)addThreadToProfileWhitelistIfEmptyContactThread:(TSThread *)thread; - -#pragma mark - Delete Content - -+ (void)deleteAllContent; - -#pragma mark - Find Content - -+ (nullable TSInteraction *)findInteractionInThreadByTimestamp:(uint64_t)timestamp - authorId:(NSString *)authorId - threadUniqueId:(NSString *)threadUniqueId - transaction:(YapDatabaseReadTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ThreadUtil.m b/SignalUtilitiesKit/ThreadUtil.m deleted file mode 100644 index 37b57b6cd..000000000 --- a/SignalUtilitiesKit/ThreadUtil.m +++ /dev/null @@ -1,797 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "ThreadUtil.h" -#import "OWSContactOffersInteraction.h" -#import "OWSContactsManager.h" -#import "OWSQuotedReplyModel.h" -#import "OWSUnreadIndicator.h" -#import "TSUnreadIndicatorInteraction.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - - -NS_ASSUME_NONNULL_BEGIN - -@interface ThreadDynamicInteractions () - -@property (nonatomic, nullable) NSNumber *focusMessagePosition; - -@property (nonatomic, nullable) OWSUnreadIndicator *unreadIndicator; - -@end - -#pragma mark - - -@implementation ThreadDynamicInteractions - -- (void)clearUnreadIndicatorState -{ - self.unreadIndicator = nil; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) { - return YES; - } - - if (![object isKindOfClass:[ThreadDynamicInteractions class]]) { - return NO; - } - - ThreadDynamicInteractions *other = (ThreadDynamicInteractions *)object; - return ([NSObject isNullableObject:self.focusMessagePosition equalTo:other.focusMessagePosition] && - [NSObject isNullableObject:self.unreadIndicator equalTo:other.unreadIndicator]); -} - -@end - -#pragma mark - - -typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMessage, - NSMutableArray *attachmentInfos, - YapDatabaseReadWriteTransaction *writeTransaction); - -@implementation ThreadUtil - -#pragma mark - Dependencies - -+ (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return SSKEnvironment.shared.messageSenderJobQueue; -} - -+ (YapDatabaseConnection *)dbConnection -{ - return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection; -} - -#pragma mark - Durable Message Enqueue - -+ (void)enqueueDeviceLinkMessage:(LKDeviceLinkMessage *)message -{ - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; -} - -+ (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)fullMessageText - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft - transaction:(YapDatabaseReadTransaction *)transaction -{ - return [self enqueueMessageWithText:fullMessageText - mediaAttachments:@[] - inThread:thread - quotedReplyModel:quotedReplyModel - linkPreviewDraft:linkPreviewDraft - transaction:transaction]; -} - -+ (TSOutgoingMessage *)enqueueMessageWithText:(nullable NSString *)fullMessageText - mediaAttachments:(NSArray *)mediaAttachments - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(thread); - - return [self - buildOutgoingMessageWithText:fullMessageText - mediaAttachments:mediaAttachments - thread:thread - quotedReplyModel:quotedReplyModel - linkPreviewDraft:linkPreviewDraft - transaction:transaction - completion:^(TSOutgoingMessage *savedMessage, - NSMutableArray *attachmentInfos, - YapDatabaseReadWriteTransaction *writeTransaction) { - if (attachmentInfos.count == 0) { - [self.messageSenderJobQueue addMessage:savedMessage transaction:writeTransaction]; - } else { - [self.messageSenderJobQueue addMediaMessage:savedMessage - attachmentInfos:attachmentInfos - isTemporaryAttachment:NO]; - } - }]; -} - -+ (TSOutgoingMessage *)buildOutgoingMessageWithText:(nullable NSString *)fullMessageText - mediaAttachments:(NSArray *)mediaAttachments - thread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - linkPreviewDraft:(nullable OWSLinkPreviewDraft *)linkPreviewDraft - transaction:(YapDatabaseReadTransaction *)transaction - completion:(BuildOutgoingMessageCompletionBlock)completionBlock; -{ - NSString *_Nullable truncatedText; - NSArray *attachments = mediaAttachments; - if ([fullMessageText lengthOfBytesUsingEncoding:NSUTF8StringEncoding] <= kOversizeTextMessageSizeThreshold) { - truncatedText = fullMessageText; - } else { - if (SSKFeatureFlags.sendingMediaWithOversizeText) { - truncatedText = [fullMessageText ows_truncatedToByteCount:kOversizeTextMessageSizeThreshold]; - } else { - // Legacy iOS clients already support receiving long text, but they assume _any_ body - // text is the _full_ body text. So until we consider "rollout" complete, we maintain - // the legacy sending behavior, which does not include the truncated text in the - // websocket proto. - truncatedText = nil; - } - DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:fullMessageText]; - if (dataSource) { - SignalAttachment *oversizeTextAttachment = - [SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI]; - attachments = [mediaAttachments arrayByAddingObject:oversizeTextAttachment]; - } else { - OWSFailDebug(@"dataSource was unexpectedly nil."); - } - } - - OWSDisappearingMessagesConfiguration *configuration = - [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction]; - - uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0); - - for (SignalAttachment *attachment in attachments) { - OWSAssertDebug(!attachment.hasError); - OWSAssertDebug(attachment.mimeType.length > 0); - } - - BOOL isVoiceMessage = (attachments.count == 1 && attachments.lastObject.isVoiceMessage); - - TSOutgoingMessage *message = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:truncatedText - attachmentIds:[NSMutableArray new] - expiresInSeconds:expiresInSeconds - expireStartedAt:0 - isVoiceMessage:isVoiceMessage - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:[quotedReplyModel buildQuotedMessageForSending] - contactShare:nil - linkPreview:nil]; - [message save]; - - [BenchManager - benchAsyncWithTitle:@"Saving outgoing message" - block:^(void (^benchmarkCompletion)(void)) { - // To avoid blocking the send flow, we dispatch an async write from within this read - // transaction - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull writeTransaction) { - - OWSLinkPreview *_Nullable linkPreview = - [self linkPreviewForLinkPreviewDraft:linkPreviewDraft - transaction:writeTransaction]; - if (linkPreview) { - [message updateWithLinkPreview:linkPreview transaction:writeTransaction]; - } - - NSMutableArray *attachmentInfos = [NSMutableArray new]; - for (SignalAttachment *attachment in attachments) { - OWSOutgoingAttachmentInfo *attachmentInfo = [attachment buildOutgoingAttachmentInfoWithMessage:message]; - [attachmentInfos addObject:attachmentInfo]; - } - completionBlock(message, attachmentInfos, writeTransaction); - } completion:benchmarkCompletion]; - }]; - - return message; -} - -+ (TSOutgoingMessage *)enqueueMessageWithContactShare:(OWSContact *)contactShare inThread:(TSThread *)thread; -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - OWSAssertDebug(contactShare.ows_isValid); - OWSAssertDebug(thread); - - OWSDisappearingMessagesConfiguration *configuration = - [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId]; - - uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0); - TSOutgoingMessage *message = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:expiresInSeconds - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:contactShare - linkPreview:nil]; - - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [message saveWithTransaction:transaction]; - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; - - return message; -} - -+ (void)enqueueLeaveGroupMessageInThread:(TSGroupThread *)thread -{ - OWSAssertDebug([thread isKindOfClass:[TSGroupThread class]]); - - TSOutgoingMessage *message = - [TSOutgoingMessage outgoingMessageInThread:thread groupMetaMessage:TSGroupMetaMessageQuit expiresInSeconds:0]; - - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; -} - -// MARK: Non-Durable Sending - -// We might want to generate a link preview here. -+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - transaction:(YapDatabaseReadTransaction *)transaction - messageSender:(OWSMessageSender *)messageSender - completion:(void (^)(NSError *_Nullable error))completion -{ - OWSAssertDebug(completion); - - return [self sendMessageNonDurablyWithText:fullMessageText - mediaAttachments:@[] - inThread:thread - quotedReplyModel:quotedReplyModel - transaction:transaction - messageSender:messageSender - completion:completion]; -} - -+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText - mediaAttachments:(NSArray *)mediaAttachments - inThread:(TSThread *)thread - quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel - transaction:(YapDatabaseReadTransaction *)transaction - messageSender:(OWSMessageSender *)messageSender - completion:(void (^)(NSError *_Nullable error))completion -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(thread); - OWSAssertDebug(completion); - - return - [self buildOutgoingMessageWithText:fullMessageText - mediaAttachments:mediaAttachments - thread:thread - quotedReplyModel:quotedReplyModel - linkPreviewDraft:nil - transaction:transaction - completion:^(TSOutgoingMessage *_Nonnull savedMessage, - NSMutableArray *_Nonnull attachmentInfos, - YapDatabaseReadWriteTransaction *_Nonnull writeTransaction) { - if (attachmentInfos.count == 0) { - [messageSender sendMessage:savedMessage - success:^{ - dispatch_async(dispatch_get_main_queue(), ^(void) { - completion(nil); - }); - } - failure:^(NSError *error) { - dispatch_async(dispatch_get_main_queue(), ^(void) { - completion(error); - }); - }]; - } else { - [messageSender sendAttachments:attachmentInfos - inMessage:savedMessage - success:^{ - dispatch_async(dispatch_get_main_queue(), ^(void) { - completion(nil); - }); - } - failure:^(NSError *error) { - dispatch_async(dispatch_get_main_queue(), ^(void) { - completion(error); - }); - }]; - } - }]; -} - -+ (TSOutgoingMessage *)sendMessageNonDurablyWithContactShare:(OWSContact *)contactShare - inThread:(TSThread *)thread - messageSender:(OWSMessageSender *)messageSender - completion:(void (^)(NSError *_Nullable error))completion -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - OWSAssertDebug(contactShare.ows_isValid); - OWSAssertDebug(thread); - OWSAssertDebug(messageSender); - OWSAssertDebug(completion); - - OWSDisappearingMessagesConfiguration *configuration = - [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId]; - - uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0); - // MJK TODO - remove senderTimestamp - TSOutgoingMessage *message = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:expiresInSeconds - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:contactShare - linkPreview:nil]; - - [messageSender sendMessage:message - success:^{ - OWSLogDebug(@"Successfully sent contact share."); - dispatch_async(dispatch_get_main_queue(), ^(void) { - completion(nil); - }); - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send contact share with error: %@", error); - dispatch_async(dispatch_get_main_queue(), ^(void) { - completion(error); - }); - }]; - - return message; -} - -+ (nullable OWSLinkPreview *)linkPreviewForLinkPreviewDraft:(nullable OWSLinkPreviewDraft *)linkPreviewDraft - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - if (!linkPreviewDraft) { - return nil; - } - NSError *linkPreviewError; - OWSLinkPreview *_Nullable linkPreview = [OWSLinkPreview buildValidatedLinkPreviewFromInfo:linkPreviewDraft - transaction:transaction - error:&linkPreviewError]; - if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) { - OWSLogError(@"linkPreviewError: %@", linkPreviewError); - } - return linkPreview; -} - -#pragma mark - Dynamic Interactions - -+ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread - contactsManager:(OWSContactsManager *)contactsManager - blockingManager:(OWSBlockingManager *)blockingManager - dbConnection:(YapDatabaseConnection *)dbConnection - hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator - lastUnreadIndicator:(nullable OWSUnreadIndicator *)lastUnreadIndicator - focusMessageId:(nullable NSString *)focusMessageId - maxRangeSize:(int)maxRangeSize -{ - OWSAssertDebug(thread); - OWSAssertDebug(dbConnection); - OWSAssertDebug(contactsManager); - OWSAssertDebug(blockingManager); - OWSAssertDebug(maxRangeSize > 0); - - ThreadDynamicInteractions *result = [ThreadDynamicInteractions new]; - - [dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - // Find any "dynamic" interactions and safety number changes. - // - // We use different views for performance reasons. - NSMutableArray *blockingSafetyNumberChanges = [NSMutableArray new]; - NSMutableArray *nonBlockingSafetyNumberChanges = [NSMutableArray new]; - [[TSDatabaseView threadSpecialMessagesDatabaseView:transaction] - enumerateKeysAndObjectsInGroup:thread.uniqueId - usingBlock:^( - NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { - if ([object isKindOfClass:[TSInvalidIdentityKeyErrorMessage class]]) { - [blockingSafetyNumberChanges addObject:object]; - } else if ([object isKindOfClass:[TSErrorMessage class]]) { - TSErrorMessage *errorMessage = (TSErrorMessage *)object; - OWSAssertDebug( - errorMessage.errorType == TSErrorMessageNonBlockingIdentityChange); - [nonBlockingSafetyNumberChanges addObject:errorMessage]; - } else { - OWSFailDebug(@"Unexpected dynamic interaction type: %@", [object class]); - } - }]; - - // Determine if there are "unread" messages in this conversation. - // If we've been passed a firstUnseenInteractionTimestampParameter, - // just use that value in order to preserve continuity of the - // unread messages indicator after all messages in the conversation - // have been marked as read. - // - // IFF this variable is non-null, there are unseen messages in the thread. - NSNumber *_Nullable firstUnseenSortId = nil; - if (lastUnreadIndicator) { - firstUnseenSortId = @(lastUnreadIndicator.firstUnseenSortId); - } else { - TSInteraction *_Nullable firstUnseenInteraction = - [[TSDatabaseView unseenDatabaseViewExtension:transaction] firstObjectInGroup:thread.uniqueId]; - if (firstUnseenInteraction && firstUnseenInteraction.sortId != NULL) { - firstUnseenSortId = @(firstUnseenInteraction.sortId); - } - } - - [self ensureUnreadIndicator:result - thread:thread - transaction:transaction - maxRangeSize:maxRangeSize - blockingSafetyNumberChanges:blockingSafetyNumberChanges - nonBlockingSafetyNumberChanges:nonBlockingSafetyNumberChanges - hideUnreadMessagesIndicator:hideUnreadMessagesIndicator - firstUnseenSortId:firstUnseenSortId]; - - // Determine the position of the focus message _after_ performing any mutations - // around dynamic interactions. - if (focusMessageId != nil) { - result.focusMessagePosition = - [self focusMessagePositionForThread:thread transaction:transaction focusMessageId:focusMessageId]; - } - }]; - - return result; -} - -+ (void)ensureUnreadIndicator:(ThreadDynamicInteractions *)dynamicInteractions - thread:(TSThread *)thread - transaction:(YapDatabaseReadTransaction *)transaction - maxRangeSize:(int)maxRangeSize - blockingSafetyNumberChanges:(NSArray *)blockingSafetyNumberChanges - nonBlockingSafetyNumberChanges:(NSArray *)nonBlockingSafetyNumberChanges - hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator - firstUnseenSortId:(nullable NSNumber *)firstUnseenSortId -{ - OWSAssertDebug(dynamicInteractions); - OWSAssertDebug(thread); - OWSAssertDebug(transaction); - OWSAssertDebug(blockingSafetyNumberChanges); - OWSAssertDebug(nonBlockingSafetyNumberChanges); - - if (hideUnreadMessagesIndicator) { - return; - } - if (!firstUnseenSortId) { - // If there are no unseen interactions, don't show an unread indicator. - return; - } - - YapDatabaseViewTransaction *threadMessagesTransaction = [transaction ext:TSMessageDatabaseViewExtensionName]; - OWSAssertDebug([threadMessagesTransaction isKindOfClass:[YapDatabaseViewTransaction class]]); - - // Determine unread indicator position, if necessary. - // - // Enumerate in reverse to count the number of messages - // after the unseen messages indicator. Not all of - // them are unnecessarily unread, but we need to tell - // the messages view the position of the unread indicator, - // so that it can widen its "load window" to always show - // the unread indicator. - __block long visibleUnseenMessageCount = 0; - __block TSInteraction *interactionAfterUnreadIndicator = nil; - __block BOOL hasMoreUnseenMessages = NO; - [threadMessagesTransaction - enumerateKeysAndObjectsInGroup:thread.uniqueId - withOptions:NSEnumerationReverse - usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { - if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Expected a TSInteraction: %@", [object class]); - return; - } - - TSInteraction *interaction = (TSInteraction *)object; - - if (interaction.isDynamicInteraction) { - // Ignore dynamic interactions, if any. - return; - } - - if (interaction.sortId < firstUnseenSortId.unsignedLongLongValue) { - // By default we want the unread indicator to appear just before - // the first unread message. - *stop = YES; - return; - } - - visibleUnseenMessageCount++; - - interactionAfterUnreadIndicator = interaction; - - if (visibleUnseenMessageCount + 1 >= maxRangeSize) { - // If there are more unseen messages than can be displayed in the - // messages view, show the unread indicator at the top of the - // displayed messages. - *stop = YES; - hasMoreUnseenMessages = YES; - } - }]; - - if (!interactionAfterUnreadIndicator) { - // If we can't find an interaction after the unread indicator, - // don't show it. All unread messages may have been deleted or - // expired. - return; - } - OWSAssertDebug(visibleUnseenMessageCount > 0); - - NSUInteger missingUnseenSafetyNumberChangeCount = 0; - if (hasMoreUnseenMessages) { - NSMutableSet *missingUnseenSafetyNumberChanges = [NSMutableSet set]; - for (TSInvalidIdentityKeyErrorMessage *safetyNumberChange in blockingSafetyNumberChanges) { - BOOL isUnseen = safetyNumberChange.sortId >= firstUnseenSortId.unsignedLongLongValue; - if (!isUnseen) { - continue; - } - - BOOL isMissing = safetyNumberChange.sortId < interactionAfterUnreadIndicator.sortId; - if (!isMissing) { - continue; - } - - @try { - NSData *_Nullable newIdentityKey = [safetyNumberChange throws_newIdentityKey]; - if (newIdentityKey == nil) { - OWSFailDebug(@"Safety number change was missing it's new identity key."); - continue; - } - - [missingUnseenSafetyNumberChanges addObject:newIdentityKey]; - } @catch (NSException *exception) { - OWSFailDebug(@"exception: %@", exception); - } - } - - // Count the de-duplicated "blocking" safety number changes and all - // of the "non-blocking" safety number changes. - missingUnseenSafetyNumberChangeCount - = (missingUnseenSafetyNumberChanges.count + nonBlockingSafetyNumberChanges.count); - } - - NSInteger unreadIndicatorPosition = visibleUnseenMessageCount; - - dynamicInteractions.unreadIndicator = - [[OWSUnreadIndicator alloc] initWithFirstUnseenSortId:firstUnseenSortId.unsignedLongLongValue - hasMoreUnseenMessages:hasMoreUnseenMessages - missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount - unreadIndicatorPosition:unreadIndicatorPosition]; - OWSLogInfo(@"Creating Unread Indicator: %llu", dynamicInteractions.unreadIndicator.firstUnseenSortId); -} - -+ (nullable NSNumber *)focusMessagePositionForThread:(TSThread *)thread - transaction:(YapDatabaseReadTransaction *)transaction - focusMessageId:(NSString *)focusMessageId -{ - OWSAssertDebug(thread); - OWSAssertDebug(transaction); - OWSAssertDebug(focusMessageId); - - YapDatabaseViewTransaction *databaseView = [transaction ext:TSMessageDatabaseViewExtensionName]; - - NSString *_Nullable group = nil; - NSUInteger index; - BOOL success = - [databaseView getGroup:&group index:&index forKey:focusMessageId inCollection:TSInteraction.collection]; - if (!success) { - // This might happen if the focus message has disappeared - // before this view could appear. - OWSFailDebug(@"failed to find focus message index."); - return nil; - } - if (![group isEqualToString:thread.uniqueId]) { - OWSFailDebug(@"focus message has invalid group."); - return nil; - } - NSUInteger count = [databaseView numberOfItemsInGroup:thread.uniqueId]; - if (index >= count) { - OWSFailDebug(@"focus message has invalid index."); - return nil; - } - NSUInteger position = (count - index) - 1; - return @(position); -} - -+ (BOOL)shouldShowGroupProfileBannerInThread:(TSThread *)thread blockingManager:(OWSBlockingManager *)blockingManager -{ - OWSAssertDebug(thread); - OWSAssertDebug(blockingManager); - - if (!thread.isGroupThread) { - return NO; - } - if ([OWSProfileManager.sharedManager isThreadInProfileWhitelist:thread]) { - return NO; - } - if (![OWSProfileManager.sharedManager hasLocalProfile]) { - return NO; - } - if ([blockingManager isThreadBlocked:thread]) { - return NO; - } - - BOOL hasUnwhitelistedMember = NO; - NSArray *blockedPhoneNumbers = [blockingManager blockedPhoneNumbers]; - for (NSString *recipientId in thread.recipientIdentifiers) { - if (![blockedPhoneNumbers containsObject:recipientId] - && ![OWSProfileManager.sharedManager isUserInProfileWhitelist:recipientId]) { - hasUnwhitelistedMember = YES; - break; - } - } - if (!hasUnwhitelistedMember) { - return NO; - } - return YES; -} - -+ (BOOL)addThreadToProfileWhitelistIfEmptyContactThread:(TSThread *)thread -{ - OWSAssertDebug(thread); - - if (thread.isGroupThread) { - return NO; - } - if ([OWSProfileManager.sharedManager isThreadInProfileWhitelist:thread]) { - return NO; - } - if (!thread.shouldThreadBeVisible) { - [OWSProfileManager.sharedManager addThreadToProfileWhitelist:thread]; - return YES; - } else { - return NO; - } -} - -#pragma mark - Delete Content - -+ (void)deleteAllContent -{ - OWSLogInfo(@""); - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self removeAllObjectsInCollection:[TSThread collection] - class:[TSThread class] - transaction:transaction]; - [self removeAllObjectsInCollection:[TSInteraction collection] - class:[TSInteraction class] - transaction:transaction]; - [self removeAllObjectsInCollection:[TSAttachment collection] - class:[TSAttachment class] - transaction:transaction]; - @try { - [self removeAllObjectsInCollection:[SignalRecipient collection] - class:[SignalRecipient class] - transaction:transaction]; - } @catch (NSException *exception) { - // Do nothing - } - }]; - [TSAttachmentStream deleteAttachments]; -} - -+ (void)removeAllObjectsInCollection:(NSString *)collection - class:(Class) class - transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(collection.length > 0); - OWSAssertDebug(class); - OWSAssertDebug(transaction); - - NSArray *_Nullable uniqueIds = [transaction allKeysInCollection:collection]; - if (!uniqueIds) { - OWSFailDebug(@"couldn't load uniqueIds for collection: %@.", collection); - return; - } - OWSLogInfo(@"Deleting %lu objects from: %@", (unsigned long)uniqueIds.count, collection); - NSUInteger count = 0; - for (NSString *uniqueId in uniqueIds) { - // We need to fetch each object, since [TSYapDatabaseObject removeWithTransaction:] sometimes does important - // work. - TSYapDatabaseObject *_Nullable object = [class fetchObjectWithUniqueID:uniqueId transaction:transaction]; - if (!object) { - OWSFailDebug(@"couldn't load object for deletion: %@.", collection); - continue; - } - [object removeWithTransaction:transaction]; - count++; - }; - OWSLogInfo(@"Deleted %lu/%lu objects from: %@", (unsigned long)count, (unsigned long)uniqueIds.count, collection); -} - -#pragma mark - Find Content - -+ (nullable TSInteraction *)findInteractionInThreadByTimestamp:(uint64_t)timestamp - authorId:(NSString *)authorId - threadUniqueId:(NSString *)threadUniqueId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(timestamp > 0); - OWSAssertDebug(authorId.length > 0); - - NSString *localNumber = [TSAccountManager localNumber]; - if (localNumber.length < 1) { - OWSFailDebug(@"missing long number."); - return nil; - } - - NSArray *interactions = - [TSInteraction interactionsWithTimestamp:timestamp - filter:^(TSInteraction *interaction) { - NSString *_Nullable messageAuthorId = nil; - if ([interaction isKindOfClass:[TSIncomingMessage class]]) { - TSIncomingMessage *incomingMessage = (TSIncomingMessage *)interaction; - messageAuthorId = incomingMessage.authorId; - } else if ([interaction isKindOfClass:[TSOutgoingMessage class]]) { - messageAuthorId = localNumber; - } - if (messageAuthorId.length < 1) { - return NO; - } - - if (![authorId isEqualToString:messageAuthorId]) { - return NO; - } - if (![interaction.uniqueThreadId isEqualToString:threadUniqueId]) { - return NO; - } - return YES; - } - withTransaction:transaction]; - if (interactions.count < 1) { - return nil; - } - if (interactions.count > 1) { - // In case of collision, take the first. - OWSLogError(@"more than one matching interaction in thread."); - } - return interactions.firstObject; -} - -@end - -NS_ASSUME_NONNULL_END From f36f447bec996a32af139b056997e40968669d97 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 16 Nov 2020 10:34:47 +1100 Subject: [PATCH 003/177] Ditch unused Signal code --- .../Components/ConversationTitleView.swift | 23 +- Session/Meta/Signal-Bridging-Header.h | 31 +- Session/Meta/Signal-Prefix.pch | 1 - Session/Signal/AccountManager.swift | 28 - ...ShareToExistingContactViewController.swift | 145 -- Session/Signal/AddToBlockListViewController.m | 15 +- Session/Signal/AddToGroupViewController.m | 48 +- .../AdvancedSettingsTableViewController.h | 9 - .../AdvancedSettingsTableViewController.m | 312 ---- Session/Signal/AppDelegate.m | 93 +- Session/Signal/AppEnvironment.swift | 6 - Session/Signal/AppNotifications.swift | 235 +-- Session/Signal/AvatarTableViewCell.swift | 12 +- Session/Signal/AvatarViewHelper.m | 4 +- Session/Signal/BlockListViewController.h | 13 - Session/Signal/BlockListViewController.m | 175 -- .../Signal/ColorPickerViewController.swift | 532 ------ Session/Signal/ContactCell.swift | 162 -- Session/Signal/ContactShareViewHelper.swift | 215 --- Session/Signal/ContactViewController.swift | 679 ------- Session/Signal/ContactsPicker.swift | 404 ---- ...nversationConfigurationSyncOperation.swift | 97 - .../Cells/ConversationViewCell.h | 18 - .../Cells/OWSContactOffersCell.h | 19 - .../Cells/OWSContactOffersCell.m | 263 --- .../Cells/OWSContactShareButtonsView.h | 33 - .../Cells/OWSContactShareButtonsView.m | 169 -- .../Cells/OWSContactShareView.h | 22 - .../Cells/OWSContactShareView.m | 165 -- .../Cells/OWSGenericAttachmentView.m | 4 +- .../Cells/OWSMessageBubbleView.h | 9 - .../Cells/OWSMessageBubbleView.m | 200 +- .../ConversationView/Cells/OWSMessageCell.m | 3 +- .../Cells/OWSMessageFooterView.m | 3 +- .../Cells/OWSMessageTimerView.m | 2 +- .../Cells/OWSQuotedMessageView.m | 5 +- .../Cells/OWSSystemMessageCell.m | 67 +- .../Cells/TypingIndicatorCell.swift | 49 +- .../ConversationHeaderView.swift | 131 -- .../ConversationInputToolbar.m | 3 - .../ConversationViewController.m | 1039 ++--------- .../ConversationView/ConversationViewItem.h | 3 - .../ConversationView/ConversationViewItem.m | 103 +- .../ConversationView/ConversationViewModel.h | 2 - .../ConversationView/ConversationViewModel.m | 56 +- .../DomainFrontingCountryViewController.h | 13 - .../DomainFrontingCountryViewController.m | 98 - Session/Signal/FingerprintViewController.h | 15 - Session/Signal/FingerprintViewController.m | 558 ------ .../Signal/FingerprintViewScanController.h | 27 - .../Signal/FingerprintViewScanController.m | 258 --- Session/Signal/GifPickerViewController.swift | 4 +- Session/Signal/GroupTableViewCell.swift | 18 +- Session/Signal/InviteFlow.swift | 271 --- .../Signal/LegacyNotificationsAdaptee.swift | 2 +- Session/Signal/MediaPageViewController.swift | 5 - Session/Signal/MessageActions.swift | 13 +- .../Signal/MessageDetailViewController.swift | 31 +- Session/Signal/MessageFetcherJob.swift | 175 -- .../Signal/MessageRecipientStatusUtils.swift | 4 - .../Signal/OWSAddToContactViewController.h | 15 - .../Signal/OWSAddToContactViewController.m | 212 --- Session/Signal/OWSAnalytics.swift | 22 - Session/Signal/OWSBackupExportJob.m | 20 +- .../Signal/OWSBackupSettingsViewController.m | 2 +- .../OWSConversationSettingsViewController.m | 333 +--- Session/Signal/OWSDeviceTableViewCell.h | 20 - Session/Signal/OWSDeviceTableViewCell.m | 85 - Session/Signal/OWSOrphanDataCleaner.m | 2 +- Session/Signal/Pastelog.h | 18 - Session/Signal/Pastelog.m | 647 ------- Session/Signal/PinEntryView.h | 32 - Session/Signal/PinEntryView.m | 227 --- .../PrivacySettingsTableViewController.m | 220 +-- Session/Signal/PushRegistrationManager.swift | 83 +- .../SafetyNumberConfirmationAlert.swift | 117 -- Session/Signal/SessionResetJob.swift | 19 +- .../Signal/ShowGroupMembersViewController.h | 13 - .../Signal/ShowGroupMembersViewController.m | 478 ----- Session/Signal/SignalApp.m | 4 +- Session/Signal/SignalsNavigationController.h | 9 - Session/Signal/SignalsNavigationController.m | 123 -- Session/Signal/UpdateGroupViewController.h | 29 - Session/Signal/UpdateGroupViewController.m | 558 ------ Session/Signal/UserNotificationsAdaptee.swift | 2 +- Session/Signal/WebRTCCallMessageHandler.swift | 53 - Session/Utilities/BackgroundPoller.swift | 3 +- Session/View Controllers/BaseVC.swift | 10 - .../View Controllers/DeviceLinkingModal.swift | 256 --- .../DeviceLinkingModalDelegate.swift | 12 - Session/View Controllers/DeviceLinksVC.swift | 234 --- .../View Controllers/DeviceNameModal.swift | 103 -- .../DeviceNameModalDelegate.swift | 5 - Session/View Controllers/HomeVC.swift | 18 +- .../View Controllers/JoinPublicChatVC.swift | 4 +- Session/View Controllers/LandingVC.swift | 73 +- .../View Controllers/NewClosedGroupVC.swift | 74 +- .../View Controllers/NewPrivateChatVC.swift | 14 +- Session/View Controllers/QRCodeVC.swift | 12 +- Session/View Controllers/SettingsVC.swift | 47 +- .../Notification+MessageSender.swift | 9 + .../Shared Sender Keys/SharedSenderKeys.swift | 2 +- SessionProtocolKit/Storage.swift | 1 + .../NotificationServiceExtension.swift | 11 +- .../SignalShareExtension-Bridging-Header.h | 3 +- .../ShareViewController.swift | 20 +- .../AnyPromise+Retaining.swift | 13 - SessionUtilitiesKit/Promise+Retaining.swift | 46 + Signal.xcodeproj/project.pbxproj | 1638 +++++------------ .../xcschemes/Signal-Internal.xcscheme | 99 - .../xcschemes/SignalMessaging.xcscheme | 67 - SignalUtilitiesKit/AccountServiceClient.swift | 34 - .../AnyPromise+Conversion.swift | 10 - SignalUtilitiesKit/AppContext.h | 3 +- SignalUtilitiesKit/AppContext.m | 1 - SignalUtilitiesKit/AppReadiness.m | 1 - SignalUtilitiesKit/AppSetup.m | 62 +- SignalUtilitiesKit/Array+Description.swift | 7 - .../{ => Attachments}/SignalAttachment.swift | 10 - .../{ => Attachments}/TSAttachment.h | 0 .../{ => Attachments}/TSAttachment.m | 0 .../{ => Attachments}/TSAttachmentPointer.h | 0 .../{ => Attachments}/TSAttachmentPointer.m | 2 +- .../{ => Attachments}/TSAttachmentStream.h | 0 .../{ => Attachments}/TSAttachmentStream.m | 0 SignalUtilitiesKit/AvatarImageView.swift | 264 --- SignalUtilitiesKit/CDSQuote.h | 34 - SignalUtilitiesKit/CDSQuote.m | 192 -- SignalUtilitiesKit/CDSSigningCertificate.h | 32 - SignalUtilitiesKit/CDSSigningCertificate.m | 391 ---- SignalUtilitiesKit/ClosedGroupParser.swift | 30 - SignalUtilitiesKit/ClosedGroupPoller.swift | 2 +- .../ClosedGroupUpdateMessage.swift | 132 -- SignalUtilitiesKit/ClosedGroupUtilities.swift | 70 - SignalUtilitiesKit/ClosedGroupsProtocol.swift | 81 +- SignalUtilitiesKit/Contact.h | 58 - SignalUtilitiesKit/Contact.m | 434 ----- SignalUtilitiesKit/ContactDiscoveryService.h | 65 - SignalUtilitiesKit/ContactDiscoveryService.m | 774 -------- SignalUtilitiesKit/ContactFieldView.swift | 205 --- SignalUtilitiesKit/ContactParser.swift | 28 - .../ContactShareApprovalViewController.swift | 513 ------ .../ContactShareViewModel.swift | 168 -- SignalUtilitiesKit/ContactsUpdater.h | 25 - SignalUtilitiesKit/ContactsUpdater.m | 120 -- SignalUtilitiesKit/ContactsViewHelper.h | 90 - SignalUtilitiesKit/ContactsViewHelper.m | 463 ----- .../CreatePreKeysOperation.swift | 28 - SignalUtilitiesKit/Data+SecureRandom.swift | 12 - .../{ => Database}/OWSDatabaseMigration.h | 0 .../{ => Database}/OWSDatabaseMigration.m | 0 .../OWSDatabaseMigrationRunner.h | 0 .../OWSDatabaseMigrationRunner.m | 0 .../OWSPrimaryStorage+Calling.h | 0 .../OWSPrimaryStorage+Calling.m | 0 .../OWSPrimaryStorage+PreKeyStore.h | 0 .../OWSPrimaryStorage+PreKeyStore.m | 0 .../OWSPrimaryStorage+SessionStore.h | 0 .../OWSPrimaryStorage+SessionStore.m | 0 .../OWSPrimaryStorage+SignedPreKeyStore.h | 0 .../OWSPrimaryStorage+SignedPreKeyStore.m | 0 .../OWSPrimaryStorage+keyFromIntLong.h | 0 .../OWSPrimaryStorage+keyFromIntLong.m | 0 .../{ => Database}/OWSPrimaryStorage.h | 0 .../{ => Database}/OWSPrimaryStorage.m | 10 - .../OWSResaveCollectionDBMigration.h | 0 .../OWSResaveCollectionDBMigration.m | 0 .../{ => Database}/OWSStorage.h | 0 .../{ => Database}/OWSStorage.m | 0 .../{ => Database}/SSKKeychainStorage.swift | 0 .../{ => Database}/TSYapDatabaseObject.h | 0 .../{ => Database}/TSYapDatabaseObject.m | 0 .../{ => Database}/YapDatabase+Promise.swift | 0 .../YapDatabaseConnection+OWS.h | 0 .../YapDatabaseConnection+OWS.m | 0 .../YapDatabaseTransaction+OWS.h | 0 .../YapDatabaseTransaction+OWS.m | 3 + SignalUtilitiesKit/DecryptionUtilities.swift | 18 - SignalUtilitiesKit/DeviceLink.swift | 96 - SignalUtilitiesKit/DeviceLinkIndex.swift | 43 - SignalUtilitiesKit/DeviceLinkingSession.swift | 69 - .../DeviceLinkingSessionDelegate.swift | 6 - .../DeviceLinkingUtilities.swift | 57 - SignalUtilitiesKit/DeviceNames.swift | 218 --- .../EditContactShareNameViewController.swift | 332 ---- SignalUtilitiesKit/EncryptionUtilities.swift | 38 - SignalUtilitiesKit/Environment.h | 2 - SignalUtilitiesKit/Environment.m | 9 +- .../FileServerAPI+Deprecated.swift | 148 -- SignalUtilitiesKit/FullTextSearchFinder.swift | 23 +- SignalUtilitiesKit/FullTextSearcher.swift | 9 +- SignalUtilitiesKit/GroupUtilities.swift | 4 +- SignalUtilitiesKit/LKDeviceLinkMessage.h | 19 - SignalUtilitiesKit/LKDeviceLinkMessage.m | 89 - SignalUtilitiesKit/LKGroupUtilities.h | 3 - SignalUtilitiesKit/LKGroupUtilities.m | 15 +- SignalUtilitiesKit/LKSyncOpenGroupsMessage.h | 14 - SignalUtilitiesKit/LKSyncOpenGroupsMessage.m | 43 - SignalUtilitiesKit/LKUnlinkDeviceMessage.h | 12 - SignalUtilitiesKit/LKUnlinkDeviceMessage.m | 27 - SignalUtilitiesKit/LKUserDefaults.swift | 34 +- .../LokiDatabaseUtilities.swift | 45 - SignalUtilitiesKit/LokiMessage.swift | 75 - .../LokiPushNotificationManager.swift | 30 +- ...okiSessionRestorationImplementation.swift} | 4 +- SignalUtilitiesKit/MentionsManager.swift | 2 +- SignalUtilitiesKit/MessageWrapper.swift | 72 - .../{ => Messages}/TSErrorMessage.h | 0 .../{ => Messages}/TSErrorMessage.m | 7 +- .../TSErrorMessage_privateConstructor.h | 0 .../{ => Messages}/TSIncomingMessage.h | 0 .../{ => Messages}/TSIncomingMessage.m | 0 .../{ => Messages}/TSInfoMessage.h | 1 - .../{ => Messages}/TSInfoMessage.m | 7 +- .../{ => Messages}/TSInteraction.h | 0 .../{ => Messages}/TSInteraction.m | 2 +- .../TSInvalidIdentityKeyErrorMessage.h | 0 .../TSInvalidIdentityKeyErrorMessage.m | 0 ...SInvalidIdentityKeyReceivingErrorMessage.h | 0 ...SInvalidIdentityKeyReceivingErrorMessage.m | 1 - .../TSInvalidIdentityKeySendingErrorMessage.h | 0 .../TSInvalidIdentityKeySendingErrorMessage.m | 1 - SignalUtilitiesKit/{ => Messages}/TSMessage.h | 8 +- SignalUtilitiesKit/{ => Messages}/TSMessage.m | 23 +- .../{ => Messages}/TSOutgoingMessage.h | 6 - .../{ => Messages}/TSOutgoingMessage.m | 53 +- .../{ => Messages}/TSQuotedMessage.h | 0 .../{ => Messages}/TSQuotedMessage.m | 0 SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 34 +- SignalUtilitiesKit/Mnemonic.swift | 161 -- .../OWSPrimaryStorage+Loki.h | 0 .../OWSPrimaryStorage+Loki.m | 4 +- .../OWSPrimaryStorage+Loki.swift | 8 - .../Storage+ClosedGroups.swift | 0 .../Storage+Collections.swift | 0 .../Storage+OnionRequests.swift | 0 .../Storage+PublicChats.swift | 0 .../Storage+SessionManagement.swift | 0 .../Storage+SnodeAPI.swift | 0 .../{ => Move to main app}/Storage.swift | 0 SignalUtilitiesKit/NSTimer+OWS.h | 21 - SignalUtilitiesKit/NSTimer+OWS.m | 70 - SignalUtilitiesKit/NetworkManager.swift | 53 - .../NewNonContactConversationViewController.h | 19 - .../NewNonContactConversationViewController.m | 101 - SignalUtilitiesKit/Notification+Loki.swift | 52 +- SignalUtilitiesKit/OWS2FAManager.h | 47 - SignalUtilitiesKit/OWS2FAManager.m | 271 --- .../OWSAddToContactsOfferMessage.h | 21 - .../OWSAddToContactsOfferMessage.m | 56 - .../OWSAddToProfileWhitelistOfferMessage.h | 19 - .../OWSAddToProfileWhitelistOfferMessage.m | 40 - SignalUtilitiesKit/OWSAnalytics.h | 165 -- SignalUtilitiesKit/OWSAnalytics.m | 426 ----- SignalUtilitiesKit/OWSAnalyticsEvents.h | 239 --- SignalUtilitiesKit/OWSAnalyticsEvents.m | 549 ------ SignalUtilitiesKit/OWSAttachmentDownloads.m | 20 +- SignalUtilitiesKit/OWSAvatarBuilder.h | 35 - SignalUtilitiesKit/OWSAvatarBuilder.m | 296 --- SignalUtilitiesKit/OWSBackgroundTask.m | 1 - SignalUtilitiesKit/OWSBatchMessageProcessor.h | 40 - SignalUtilitiesKit/OWSBatchMessageProcessor.m | 546 ------ .../OWSBlockedPhoneNumbersMessage.h | 19 - .../OWSBlockedPhoneNumbersMessage.m | 57 - SignalUtilitiesKit/OWSBlockingManager.m | 21 +- .../OWSCensorshipConfiguration.h | 35 - .../OWSCensorshipConfiguration.m | 247 --- SignalUtilitiesKit/OWSContact+Private.h | 60 - SignalUtilitiesKit/OWSContact.h | 183 -- SignalUtilitiesKit/OWSContact.m | 1126 ----------- SignalUtilitiesKit/OWSContactAvatarBuilder.h | 32 - SignalUtilitiesKit/OWSContactAvatarBuilder.m | 227 --- .../OWSContactDiscoveryOperation.swift | 537 ------ SignalUtilitiesKit/OWSContactsManager.h | 107 -- SignalUtilitiesKit/OWSContactsManager.m | 1133 ------------ SignalUtilitiesKit/OWSContactsOutputStream.m | 29 +- SignalUtilitiesKit/OWSConversationColor.h | 82 - SignalUtilitiesKit/OWSConversationColor.m | 359 ---- SignalUtilitiesKit/OWSCountryMetadata.h | 23 - SignalUtilitiesKit/OWSCountryMetadata.m | 379 ---- SignalUtilitiesKit/OWSDevice.h | 78 - SignalUtilitiesKit/OWSDevice.m | 353 ---- SignalUtilitiesKit/OWSDeviceProvisioner.h | 38 - SignalUtilitiesKit/OWSDeviceProvisioner.m | 123 -- .../OWSDeviceProvisioningCodeService.h | 18 - .../OWSDeviceProvisioningCodeService.m | 62 - .../OWSDeviceProvisioningService.h | 22 - .../OWSDeviceProvisioningService.m | 57 - SignalUtilitiesKit/OWSDevicesService.h | 25 - SignalUtilitiesKit/OWSDevicesService.m | 126 -- ...DisappearingMessagesConfigurationMessage.h | 30 - ...DisappearingMessagesConfigurationMessage.m | 72 - .../OWSDisappearingMessagesJob.m | 11 +- .../OWSDynamicOutgoingMessage.h | 36 - .../OWSDynamicOutgoingMessage.m | 64 - SignalUtilitiesKit/OWSEndSessionMessage.h | 30 - SignalUtilitiesKit/OWSEndSessionMessage.m | 74 - SignalUtilitiesKit/OWSFingerprint.h | 52 - SignalUtilitiesKit/OWSFingerprint.m | 334 ---- SignalUtilitiesKit/OWSFingerprintBuilder.h | 32 - SignalUtilitiesKit/OWSFingerprintBuilder.m | 66 - SignalUtilitiesKit/OWSGroupAvatarBuilder.h | 21 - SignalUtilitiesKit/OWSGroupAvatarBuilder.m | 101 - SignalUtilitiesKit/OWSGroupsOutputStream.m | 24 - SignalUtilitiesKit/OWSIdentityManager.h | 15 - SignalUtilitiesKit/OWSIdentityManager.m | 214 +-- .../OWSIncomingSentMessageTranscript.h | 52 - .../OWSIncomingSentMessageTranscript.m | 108 -- .../OWSLinkedDeviceReadReceipt.h | 26 - .../OWSLinkedDeviceReadReceipt.m | 77 - SignalUtilitiesKit/OWSMessageServiceParams.h | 10 +- SignalUtilitiesKit/OWSMessageServiceParams.m | 4 - SignalUtilitiesKit/OWSMessageUtils.m | 2 +- SignalUtilitiesKit/OWSOperation.m | 1 - SignalUtilitiesKit/OWSOutgoingCallMessage.h | 48 - SignalUtilitiesKit/OWSOutgoingCallMessage.m | 196 -- SignalUtilitiesKit/OWSOutgoingNullMessage.h | 31 - SignalUtilitiesKit/OWSOutgoingNullMessage.m | 107 -- .../OWSOutgoingReceiptManager.m | 16 +- .../OWSOutgoingSentMessageTranscript.h | 25 - .../OWSOutgoingSentMessageTranscript.m | 118 -- SignalUtilitiesKit/OWSOutgoingSyncMessage.h | 35 - SignalUtilitiesKit/OWSOutgoingSyncMessage.m | 125 -- SignalUtilitiesKit/OWSPreferences.m | 2 - SignalUtilitiesKit/OWSProfileKeyMessage.h | 28 - SignalUtilitiesKit/OWSProfileKeyMessage.m | 78 - SignalUtilitiesKit/OWSProvisioningMessage.h | 23 - SignalUtilitiesKit/OWSProvisioningMessage.m | 93 - SignalUtilitiesKit/OWSQuotedReplyModel.m | 22 +- SignalUtilitiesKit/OWSReadReceiptManager.m | 29 +- .../OWSReadReceiptsForLinkedDevicesMessage.h | 20 - .../OWSReadReceiptsForLinkedDevicesMessage.m | 56 - .../OWSReceiptsForSenderMessage.h | 33 - .../OWSReceiptsForSenderMessage.m | 139 -- SignalUtilitiesKit/OWSRecordTranscriptJob.m | 26 +- SignalUtilitiesKit/OWSRequestBuilder.h | 17 - SignalUtilitiesKit/OWSRequestBuilder.m | 43 - SignalUtilitiesKit/OWSRequestFactory.h | 117 -- SignalUtilitiesKit/OWSRequestFactory.m | 543 ------ SignalUtilitiesKit/OWSRequestMaker.swift | 247 --- SignalUtilitiesKit/OWSSignalService.h | 37 - SignalUtilitiesKit/OWSSignalService.m | 328 ---- .../OWSSyncConfigurationMessage.h | 22 - .../OWSSyncConfigurationMessage.m | 66 - SignalUtilitiesKit/OWSSyncContactsMessage.h | 28 - SignalUtilitiesKit/OWSSyncContactsMessage.m | 157 -- SignalUtilitiesKit/OWSSyncGroupsMessage.h | 24 - SignalUtilitiesKit/OWSSyncGroupsMessage.m | 104 -- .../OWSSyncGroupsRequestMessage.h | 27 - .../OWSSyncGroupsRequestMessage.m | 85 - SignalUtilitiesKit/OWSSyncManager.h | 25 - SignalUtilitiesKit/OWSSyncManager.m | 337 ---- SignalUtilitiesKit/OWSUDManager.swift | 32 +- .../OWSUnknownContactBlockOfferMessage.h | 17 - .../OWSUnknownContactBlockOfferMessage.m | 38 - SignalUtilitiesKit/OWSUploadOperation.m | 82 +- .../OWSVerificationStateChangeMessage.h | 26 - .../OWSVerificationStateChangeMessage.m | 35 - .../OWSVerificationStateSyncMessage.h | 27 - .../OWSVerificationStateSyncMessage.m | 111 -- SignalUtilitiesKit/OWSWebSocket.h | 55 - SignalUtilitiesKit/OWSWebSocket.m | 1141 ------------ SignalUtilitiesKit/OldSnodeAPI.swift | 44 - .../OnionRequestAPI+Encryption.swift | 72 - SignalUtilitiesKit/OutageDetection.swift | 5 +- SignalUtilitiesKit/PhoneNumber.h | 52 - SignalUtilitiesKit/PhoneNumber.m | 584 ------ SignalUtilitiesKit/PhoneNumberUtil.h | 44 - SignalUtilitiesKit/PhoneNumberUtil.m | 610 ------ SignalUtilitiesKit/Poller.swift | 2 +- .../PreKeyRefreshOperation.swift | 59 +- SignalUtilitiesKit/ProfileFetcherJob.swift | 241 --- .../Promise+retainUntilComplete.swift | 63 - SignalUtilitiesKit/ProofOfWork.swift | 109 -- SignalUtilitiesKit/PublicChatPoller.swift | 243 +-- .../{ => Remove Later}/ContactCellView.h | 0 .../{ => Remove Later}/ContactCellView.m | 12 +- .../{ => Remove Later}/ContactTableViewCell.h | 0 .../{ => Remove Later}/ContactTableViewCell.m | 0 .../{ => Remove Later}/OWSProfileManager.h | 0 .../{ => Remove Later}/OWSProfileManager.m | 107 -- .../{ => Remove Later}/OWSUserProfile.h | 0 .../{ => Remove Later}/OWSUserProfile.m | 15 - .../ProfileManagerProtocol.h | 12 - .../SessionManagementProtocol.swift | 159 +- .../SessionMetaProtocol.swift | 4 +- .../ReturnToCallViewController.swift | 88 - .../RotateSignedKeyOperation.swift | 46 +- SignalUtilitiesKit/SSKEnvironment.h | 51 +- SignalUtilitiesKit/SSKEnvironment.m | 96 +- SignalUtilitiesKit/SSKPreferences.swift | 2 - .../SSKProtoPrekeyBundleMessage+Loki.swift | 23 - SignalUtilitiesKit/SSKWebSocket.swift | 185 -- .../SessionRequestMessage.swift | 51 - .../SharedSenderKeysImplementation.swift | 220 --- SignalUtilitiesKit/SignalAccount.h | 2 - SignalUtilitiesKit/SignalAccount.m | 7 +- SignalUtilitiesKit/SignalRecipient.m | 27 +- SignalUtilitiesKit/SignalServiceClient.swift | 94 - SignalUtilitiesKit/SyncMessagesProtocol.swift | 293 --- .../SystemContactsFetcher.swift | 411 ----- SignalUtilitiesKit/TSAccountManager.m | 183 +- SignalUtilitiesKit/TSConstants.h | 2 +- SignalUtilitiesKit/TSDatabaseView.h | 2 - SignalUtilitiesKit/TSDatabaseView.m | 53 +- SignalUtilitiesKit/TSNetworkManager.h | 45 - SignalUtilitiesKit/TSNetworkManager.m | 588 ------ SignalUtilitiesKit/TSPreKeyManager.m | 2 +- SignalUtilitiesKit/TSSocketManager.h | 50 - SignalUtilitiesKit/TSSocketManager.m | 80 - SignalUtilitiesKit/TTLUtilities.swift | 32 - SignalUtilitiesKit/ThreadUtil.h | 83 + SignalUtilitiesKit/ThreadUtil.m | 409 ++++ SignalUtilitiesKit/ThreadViewHelper.m | 4 +- .../{ => Threads}/TSContactThread.h | 15 +- .../{ => Threads}/TSContactThread.m | 54 +- .../{ => Threads}/TSGroupModel.h | 7 +- .../{ => Threads}/TSGroupModel.m | 2 +- .../{ => Threads}/TSGroupThread.h | 12 +- .../{ => Threads}/TSGroupThread.m | 70 +- SignalUtilitiesKit/{ => Threads}/TSThread.h | 26 - SignalUtilitiesKit/{ => Threads}/TSThread.m | 222 +-- .../TypingIndicatorMessage.swift | 122 -- SignalUtilitiesKit/TypingIndicators.swift | 17 +- .../{ => UI}/ApprovalRailCellView.swift | 0 ...AttachmentApprovalInputAccessoryView.swift | 0 .../AttachmentApprovalViewController.swift | 0 .../{ => UI}/AttachmentCaptionToolbar.swift | 0 .../AttachmentCaptionViewController.swift | 0 .../{ => UI}/AttachmentItemCollection.swift | 0 .../AttachmentPrepViewController.swift | 0 .../{ => UI}/AttachmentTextToolbar.swift | 0 .../{ => UI}/AttachmentTextView.swift | 0 .../{ => UI}/BlockListUIUtils.h | 9 - .../{ => UI}/BlockListUIUtils.m | 27 +- SignalUtilitiesKit/UI/CircleView.swift | 82 + .../{ => UI}/ConversationStyle.swift | 16 +- .../DirectionalPanGestureRecognizer.swift | 0 .../DisappearingTimerConfigurationView.swift | 0 .../{ => UI}/DisplayableText.swift | 0 .../{ => UI}/GalleryRailView.swift | 0 .../{ => UI}/GradientView.swift | 0 .../{ => UI}/Identicon+ObjC.swift | 0 .../ImageEditorBrushViewController.swift | 0 .../{ => UI}/ImageEditorCanvasView.swift | 0 .../{ => UI}/ImageEditorContents.swift | 0 .../ImageEditorCropViewController.swift | 0 .../{ => UI}/ImageEditorItem.swift | 0 .../{ => UI}/ImageEditorModel.swift | 0 .../{ => UI}/ImageEditorPaletteView.swift | 0 .../ImageEditorPanGestureRecognizer.swift | 0 .../ImageEditorPinchGestureRecognizer.swift | 0 .../{ => UI}/ImageEditorStrokeItem.swift | 0 .../{ => UI}/ImageEditorTextItem.swift | 0 .../ImageEditorTextViewController.swift | 0 .../{ => UI}/ImageEditorTransform.swift | 0 .../{ => UI}/ImageEditorView.swift | 0 .../{ => UI}/MediaMessageView.swift | 0 .../MessageApprovalViewController.swift | 16 +- ...ModalActivityIndicatorViewController.swift | 0 SignalUtilitiesKit/{ => UI}/OWSAlerts.swift | 0 .../{ => UI}/OWSAnyTouchGestureRecognizer.h | 0 .../{ => UI}/OWSAnyTouchGestureRecognizer.m | 0 SignalUtilitiesKit/{ => UI}/OWSButton.swift | 0 .../{ => UI}/OWSFlatButton.swift | 0 .../{ => UI}/OWSLayerView.swift | 0 .../{ => UI}/OWSNavigationBar.swift | 25 - .../{ => UI}/OWSNavigationController.h | 0 .../{ => UI}/OWSNavigationController.m | 0 SignalUtilitiesKit/{ => UI}/OWSSearchBar.h | 0 SignalUtilitiesKit/{ => UI}/OWSSearchBar.m | 0 .../{ => UI}/OWSTableViewController.h | 0 .../{ => UI}/OWSTableViewController.m | 0 SignalUtilitiesKit/{ => UI}/OWSTextField.h | 0 SignalUtilitiesKit/{ => UI}/OWSTextField.m | 0 SignalUtilitiesKit/{ => UI}/OWSTextView.h | 0 SignalUtilitiesKit/{ => UI}/OWSTextView.m | 0 .../OWSViewController+ImageEditor.swift | 0 .../{ => UI}/OWSViewController.h | 0 .../{ => UI}/OWSViewController.m | 0 .../{ => UI}/OWSWindowManager.h | 0 .../{ => UI}/OWSWindowManager.m | 89 +- .../{ => UI}/PlaceholderIcon.swift | 0 .../{ => UI}/ProfilePictureView.swift | 3 +- .../{ => UI}/ScreenLockViewController.h | 0 .../{ => UI}/ScreenLockViewController.m | 0 .../{ => UI}/SelectRecipientViewController.h | 0 .../{ => UI}/SelectRecipientViewController.m | 273 +-- .../{ => UI}/SelectThreadViewController.h | 0 .../{ => UI}/SelectThreadViewController.m | 132 +- .../SharingThreadPickerViewController.h | 0 .../SharingThreadPickerViewController.m | 242 +-- .../{ => UI}/SheetViewController.swift | 0 .../{ => UI}/TappableStackView.swift | 0 .../{ => UI}/TappableView.swift | 0 SignalUtilitiesKit/{ => UI}/Theme.h | 0 SignalUtilitiesKit/{ => UI}/Theme.m | 0 SignalUtilitiesKit/{ => UI}/Toast.swift | 0 SignalUtilitiesKit/{ => UI}/UIColor+OWS.h | 0 SignalUtilitiesKit/{ => UI}/UIColor+OWS.m | 0 SignalUtilitiesKit/{ => UI}/UIFont+OWS.h | 0 SignalUtilitiesKit/{ => UI}/UIFont+OWS.m | 0 .../{ => UI}/UIGestureRecognizer+OWS.swift | 0 SignalUtilitiesKit/{ => UI}/UIImage+OWS.swift | 0 SignalUtilitiesKit/{ => UI}/UIUtil.h | 0 SignalUtilitiesKit/{ => UI}/UIUtil.m | 0 SignalUtilitiesKit/{ => UI}/UIView+OWS.h | 0 SignalUtilitiesKit/{ => UI}/UIView+OWS.m | 0 SignalUtilitiesKit/{ => UI}/UIView+OWS.swift | 0 .../{ => UI}/UIView+Utilities.swift | 0 .../{ => UI}/UIViewController+OWS.h | 0 .../{ => UI}/UIViewController+OWS.m | 0 .../{ => UI}/UIViewController+Utilities.swift | 0 .../{ => UI}/VideoPlayerView.swift | 0 .../{ => Utilities}/AttachmentSharing.h | 0 .../{ => Utilities}/AttachmentSharing.m | 13 +- .../{ => Utilities}/Bench.swift | 0 .../{ => Utilities}/BuildConfiguration.swift | 0 .../{ => Utilities}/ByteParser.h | 0 .../{ => Utilities}/ByteParser.m | 0 .../{ => Utilities}/Collection+OWS.swift | 3 +- .../{ => Utilities}/DebugLogger.h | 0 .../{ => Utilities}/DebugLogger.m | 0 .../{ => Utilities}/Debugging.swift | 0 .../Utilities/Destination+Conversion.swift | 2 +- .../{ => Utilities}/LRUCache.swift | 0 .../{ => Utilities}/MIMETypeUtil.h | 0 .../{ => Utilities}/MIMETypeUtil.m | 0 .../{ => Utilities}/NSArray+Functional.h | 0 .../{ => Utilities}/NSArray+Functional.m | 0 .../{ => Utilities}/NSArray+OWS.h | 0 .../{ => Utilities}/NSArray+OWS.m | 0 .../{ => Utilities}/NSAttributedString+OWS.m | 0 .../{ => Utilities}/NSData+Image.h | 0 .../{ => Utilities}/NSData+Image.m | 0 .../{ => Utilities}/NSObject+Casting.h | 0 .../{ => Utilities}/NSObject+Casting.m | 0 .../NSRegularExpression+SSK.swift | 6 +- .../{ => Utilities}/NSSet+Functional.h | 0 .../{ => Utilities}/NSSet+Functional.m | 0 .../{ => Utilities}/NSString+SSK.h | 0 .../{ => Utilities}/NSString+SSK.m | 0 .../NSURLSessionDataTask+StatusCode.h | 0 .../NSURLSessionDataTask+StatusCode.m | 0 .../{ => Utilities}/NSUserDefaults+OWS.h | 0 .../{ => Utilities}/NSUserDefaults+OWS.m | 0 .../{ => Utilities}/OWSAudioPlayer.h | 0 .../{ => Utilities}/OWSAudioPlayer.m | 0 .../{ => Utilities}/OWSAudioSession.swift | 0 .../{ => Utilities}/OWSFormat.h | 0 .../{ => Utilities}/OWSFormat.m | 0 SignalUtilitiesKit/{ => Utilities}/OWSMath.h | 0 .../{ => Utilities}/OWSMediaUtils.swift | 0 .../OWSScrubbingLogFormatter.h | 0 .../OWSScrubbingLogFormatter.m | 0 .../{ => Utilities}/OWSVideoPlayer.swift | 0 .../{ => Utilities}/OrderedDictionary.swift | 0 .../{ => Utilities}/ProtoUtils.h | 0 .../{ => Utilities}/ProtoUtils.m | 30 +- .../ReverseDispatchQueue.swift | 0 .../SNProtoEnvelope+Conversion.swift} | 4 +- .../{ => Utilities}/SSKAsserts.h | 0 .../{ => Utilities}/ShareViewDelegate.swift | 0 .../{ => Utilities}/String+SSK.swift | 0 .../{ => Utilities}/String+Trimming.swift | 0 .../UIAlertController+OWS.swift | 0 .../UIDevice+featureSupport.swift | 0 .../{ => Utilities}/UIImage+OWS.h | 0 .../{ => Utilities}/UIImage+OWS.m | 0 SignalUtilitiesKit/{ => Utilities}/Weak.swift | 0 .../{ => Utilities}/WeakTimer.swift | 0 SignalUtilitiesKit/VersionMigrations.m | 25 +- SignalUtilitiesKit/ViewControllerUtils.h | 35 - SignalUtilitiesKit/ViewControllerUtils.m | 158 -- 574 files changed, 1866 insertions(+), 40001 deletions(-) delete mode 100644 Session/Signal/AddContactShareToExistingContactViewController.swift delete mode 100644 Session/Signal/AdvancedSettingsTableViewController.h delete mode 100644 Session/Signal/AdvancedSettingsTableViewController.m delete mode 100644 Session/Signal/BlockListViewController.h delete mode 100644 Session/Signal/BlockListViewController.m delete mode 100644 Session/Signal/ColorPickerViewController.swift delete mode 100644 Session/Signal/ContactCell.swift delete mode 100644 Session/Signal/ContactShareViewHelper.swift delete mode 100644 Session/Signal/ContactViewController.swift delete mode 100644 Session/Signal/ContactsPicker.swift delete mode 100644 Session/Signal/ConversationConfigurationSyncOperation.swift delete mode 100644 Session/Signal/ConversationView/Cells/OWSContactOffersCell.h delete mode 100644 Session/Signal/ConversationView/Cells/OWSContactOffersCell.m delete mode 100644 Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.h delete mode 100644 Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.m delete mode 100644 Session/Signal/ConversationView/Cells/OWSContactShareView.h delete mode 100644 Session/Signal/ConversationView/Cells/OWSContactShareView.m delete mode 100644 Session/Signal/ConversationView/ConversationHeaderView.swift delete mode 100644 Session/Signal/DomainFrontingCountryViewController.h delete mode 100644 Session/Signal/DomainFrontingCountryViewController.m delete mode 100644 Session/Signal/FingerprintViewController.h delete mode 100644 Session/Signal/FingerprintViewController.m delete mode 100644 Session/Signal/FingerprintViewScanController.h delete mode 100644 Session/Signal/FingerprintViewScanController.m delete mode 100644 Session/Signal/InviteFlow.swift delete mode 100644 Session/Signal/MessageFetcherJob.swift delete mode 100644 Session/Signal/OWSAddToContactViewController.h delete mode 100644 Session/Signal/OWSAddToContactViewController.m delete mode 100644 Session/Signal/OWSAnalytics.swift delete mode 100644 Session/Signal/OWSDeviceTableViewCell.h delete mode 100644 Session/Signal/OWSDeviceTableViewCell.m delete mode 100644 Session/Signal/Pastelog.h delete mode 100644 Session/Signal/Pastelog.m delete mode 100644 Session/Signal/PinEntryView.h delete mode 100644 Session/Signal/PinEntryView.m delete mode 100644 Session/Signal/SafetyNumberConfirmationAlert.swift delete mode 100644 Session/Signal/ShowGroupMembersViewController.h delete mode 100644 Session/Signal/ShowGroupMembersViewController.m delete mode 100644 Session/Signal/SignalsNavigationController.h delete mode 100644 Session/Signal/SignalsNavigationController.m delete mode 100644 Session/Signal/UpdateGroupViewController.h delete mode 100644 Session/Signal/UpdateGroupViewController.m delete mode 100644 Session/View Controllers/DeviceLinkingModal.swift delete mode 100644 Session/View Controllers/DeviceLinkingModalDelegate.swift delete mode 100644 Session/View Controllers/DeviceLinksVC.swift delete mode 100644 Session/View Controllers/DeviceNameModal.swift delete mode 100644 Session/View Controllers/DeviceNameModalDelegate.swift delete mode 100644 SessionUtilitiesKit/AnyPromise+Retaining.swift create mode 100644 SessionUtilitiesKit/Promise+Retaining.swift delete mode 100644 Signal.xcodeproj/xcshareddata/xcschemes/Signal-Internal.xcscheme delete mode 100644 Signal.xcodeproj/xcshareddata/xcschemes/SignalMessaging.xcscheme delete mode 100644 SignalUtilitiesKit/AccountServiceClient.swift delete mode 100644 SignalUtilitiesKit/AnyPromise+Conversion.swift delete mode 100644 SignalUtilitiesKit/Array+Description.swift rename SignalUtilitiesKit/{ => Attachments}/SignalAttachment.swift (98%) rename SignalUtilitiesKit/{ => Attachments}/TSAttachment.h (100%) rename SignalUtilitiesKit/{ => Attachments}/TSAttachment.m (100%) rename SignalUtilitiesKit/{ => Attachments}/TSAttachmentPointer.h (100%) rename SignalUtilitiesKit/{ => Attachments}/TSAttachmentPointer.m (99%) rename SignalUtilitiesKit/{ => Attachments}/TSAttachmentStream.h (100%) rename SignalUtilitiesKit/{ => Attachments}/TSAttachmentStream.m (100%) delete mode 100644 SignalUtilitiesKit/AvatarImageView.swift delete mode 100644 SignalUtilitiesKit/CDSQuote.h delete mode 100644 SignalUtilitiesKit/CDSQuote.m delete mode 100644 SignalUtilitiesKit/CDSSigningCertificate.h delete mode 100644 SignalUtilitiesKit/CDSSigningCertificate.m delete mode 100644 SignalUtilitiesKit/ClosedGroupParser.swift delete mode 100644 SignalUtilitiesKit/ClosedGroupUpdateMessage.swift delete mode 100644 SignalUtilitiesKit/ClosedGroupUtilities.swift delete mode 100644 SignalUtilitiesKit/Contact.h delete mode 100644 SignalUtilitiesKit/Contact.m delete mode 100644 SignalUtilitiesKit/ContactDiscoveryService.h delete mode 100644 SignalUtilitiesKit/ContactDiscoveryService.m delete mode 100644 SignalUtilitiesKit/ContactFieldView.swift delete mode 100644 SignalUtilitiesKit/ContactParser.swift delete mode 100644 SignalUtilitiesKit/ContactShareApprovalViewController.swift delete mode 100644 SignalUtilitiesKit/ContactShareViewModel.swift delete mode 100644 SignalUtilitiesKit/ContactsUpdater.h delete mode 100644 SignalUtilitiesKit/ContactsUpdater.m delete mode 100644 SignalUtilitiesKit/ContactsViewHelper.h delete mode 100644 SignalUtilitiesKit/ContactsViewHelper.m delete mode 100644 SignalUtilitiesKit/Data+SecureRandom.swift rename SignalUtilitiesKit/{ => Database}/OWSDatabaseMigration.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSDatabaseMigration.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSDatabaseMigrationRunner.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSDatabaseMigrationRunner.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+Calling.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+Calling.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+PreKeyStore.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+PreKeyStore.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+SessionStore.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+SessionStore.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+SignedPreKeyStore.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+SignedPreKeyStore.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+keyFromIntLong.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage+keyFromIntLong.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSPrimaryStorage.m (97%) rename SignalUtilitiesKit/{ => Database}/OWSResaveCollectionDBMigration.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSResaveCollectionDBMigration.m (100%) rename SignalUtilitiesKit/{ => Database}/OWSStorage.h (100%) rename SignalUtilitiesKit/{ => Database}/OWSStorage.m (100%) rename SignalUtilitiesKit/{ => Database}/SSKKeychainStorage.swift (100%) rename SignalUtilitiesKit/{ => Database}/TSYapDatabaseObject.h (100%) rename SignalUtilitiesKit/{ => Database}/TSYapDatabaseObject.m (100%) rename SignalUtilitiesKit/{ => Database}/YapDatabase+Promise.swift (100%) rename SignalUtilitiesKit/{ => Database}/YapDatabaseConnection+OWS.h (100%) rename SignalUtilitiesKit/{ => Database}/YapDatabaseConnection+OWS.m (100%) rename SignalUtilitiesKit/{ => Database}/YapDatabaseTransaction+OWS.h (100%) rename SignalUtilitiesKit/{ => Database}/YapDatabaseTransaction+OWS.m (98%) delete mode 100644 SignalUtilitiesKit/DecryptionUtilities.swift delete mode 100644 SignalUtilitiesKit/DeviceLink.swift delete mode 100644 SignalUtilitiesKit/DeviceLinkIndex.swift delete mode 100644 SignalUtilitiesKit/DeviceLinkingSession.swift delete mode 100644 SignalUtilitiesKit/DeviceLinkingSessionDelegate.swift delete mode 100644 SignalUtilitiesKit/DeviceLinkingUtilities.swift delete mode 100644 SignalUtilitiesKit/DeviceNames.swift delete mode 100644 SignalUtilitiesKit/EditContactShareNameViewController.swift delete mode 100644 SignalUtilitiesKit/EncryptionUtilities.swift delete mode 100644 SignalUtilitiesKit/FileServerAPI+Deprecated.swift delete mode 100644 SignalUtilitiesKit/LKDeviceLinkMessage.h delete mode 100644 SignalUtilitiesKit/LKDeviceLinkMessage.m delete mode 100644 SignalUtilitiesKit/LKSyncOpenGroupsMessage.h delete mode 100644 SignalUtilitiesKit/LKSyncOpenGroupsMessage.m delete mode 100644 SignalUtilitiesKit/LKUnlinkDeviceMessage.h delete mode 100644 SignalUtilitiesKit/LKUnlinkDeviceMessage.m delete mode 100644 SignalUtilitiesKit/LokiMessage.swift rename SignalUtilitiesKit/{LokiSessionResetImplementation.swift => LokiSessionRestorationImplementation.swift} (95%) delete mode 100644 SignalUtilitiesKit/MessageWrapper.swift rename SignalUtilitiesKit/{ => Messages}/TSErrorMessage.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSErrorMessage.m (94%) rename SignalUtilitiesKit/{ => Messages}/TSErrorMessage_privateConstructor.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSIncomingMessage.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSIncomingMessage.m (100%) rename SignalUtilitiesKit/{ => Messages}/TSInfoMessage.h (98%) rename SignalUtilitiesKit/{ => Messages}/TSInfoMessage.m (91%) rename SignalUtilitiesKit/{ => Messages}/TSInteraction.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSInteraction.m (99%) rename SignalUtilitiesKit/{ => Messages}/TSInvalidIdentityKeyErrorMessage.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSInvalidIdentityKeyErrorMessage.m (100%) rename SignalUtilitiesKit/{ => Messages}/TSInvalidIdentityKeyReceivingErrorMessage.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSInvalidIdentityKeyReceivingErrorMessage.m (99%) rename SignalUtilitiesKit/{ => Messages}/TSInvalidIdentityKeySendingErrorMessage.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSInvalidIdentityKeySendingErrorMessage.m (98%) rename SignalUtilitiesKit/{ => Messages}/TSMessage.h (93%) rename SignalUtilitiesKit/{ => Messages}/TSMessage.m (94%) rename SignalUtilitiesKit/{ => Messages}/TSOutgoingMessage.h (97%) rename SignalUtilitiesKit/{ => Messages}/TSOutgoingMessage.m (96%) rename SignalUtilitiesKit/{ => Messages}/TSQuotedMessage.h (100%) rename SignalUtilitiesKit/{ => Messages}/TSQuotedMessage.m (100%) delete mode 100644 SignalUtilitiesKit/Mnemonic.swift rename SignalUtilitiesKit/{ => Move to main app}/OWSPrimaryStorage+Loki.h (100%) rename SignalUtilitiesKit/{ => Move to main app}/OWSPrimaryStorage+Loki.m (99%) rename SignalUtilitiesKit/{ => Move to main app}/OWSPrimaryStorage+Loki.swift (85%) rename SignalUtilitiesKit/{ => Move to main app}/Storage+ClosedGroups.swift (100%) rename SignalUtilitiesKit/{ => Move to main app}/Storage+Collections.swift (100%) rename SignalUtilitiesKit/{ => Move to main app}/Storage+OnionRequests.swift (100%) rename SignalUtilitiesKit/{ => Move to main app}/Storage+PublicChats.swift (100%) rename SignalUtilitiesKit/{ => Move to main app}/Storage+SessionManagement.swift (100%) rename SignalUtilitiesKit/{ => Move to main app}/Storage+SnodeAPI.swift (100%) rename SignalUtilitiesKit/{ => Move to main app}/Storage.swift (100%) delete mode 100644 SignalUtilitiesKit/NSTimer+OWS.h delete mode 100644 SignalUtilitiesKit/NSTimer+OWS.m delete mode 100644 SignalUtilitiesKit/NetworkManager.swift delete mode 100644 SignalUtilitiesKit/NewNonContactConversationViewController.h delete mode 100644 SignalUtilitiesKit/NewNonContactConversationViewController.m delete mode 100644 SignalUtilitiesKit/OWS2FAManager.h delete mode 100644 SignalUtilitiesKit/OWS2FAManager.m delete mode 100644 SignalUtilitiesKit/OWSAddToContactsOfferMessage.h delete mode 100644 SignalUtilitiesKit/OWSAddToContactsOfferMessage.m delete mode 100644 SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.h delete mode 100644 SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.m delete mode 100755 SignalUtilitiesKit/OWSAnalytics.h delete mode 100755 SignalUtilitiesKit/OWSAnalytics.m delete mode 100755 SignalUtilitiesKit/OWSAnalyticsEvents.h delete mode 100755 SignalUtilitiesKit/OWSAnalyticsEvents.m delete mode 100644 SignalUtilitiesKit/OWSAvatarBuilder.h delete mode 100644 SignalUtilitiesKit/OWSAvatarBuilder.m delete mode 100644 SignalUtilitiesKit/OWSBatchMessageProcessor.h delete mode 100644 SignalUtilitiesKit/OWSBatchMessageProcessor.m delete mode 100644 SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.h delete mode 100644 SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.m delete mode 100644 SignalUtilitiesKit/OWSCensorshipConfiguration.h delete mode 100644 SignalUtilitiesKit/OWSCensorshipConfiguration.m delete mode 100644 SignalUtilitiesKit/OWSContact+Private.h delete mode 100644 SignalUtilitiesKit/OWSContact.h delete mode 100644 SignalUtilitiesKit/OWSContact.m delete mode 100644 SignalUtilitiesKit/OWSContactAvatarBuilder.h delete mode 100644 SignalUtilitiesKit/OWSContactAvatarBuilder.m delete mode 100644 SignalUtilitiesKit/OWSContactDiscoveryOperation.swift delete mode 100644 SignalUtilitiesKit/OWSContactsManager.h delete mode 100644 SignalUtilitiesKit/OWSContactsManager.m delete mode 100644 SignalUtilitiesKit/OWSConversationColor.h delete mode 100644 SignalUtilitiesKit/OWSConversationColor.m delete mode 100644 SignalUtilitiesKit/OWSCountryMetadata.h delete mode 100644 SignalUtilitiesKit/OWSCountryMetadata.m delete mode 100644 SignalUtilitiesKit/OWSDevice.h delete mode 100644 SignalUtilitiesKit/OWSDevice.m delete mode 100644 SignalUtilitiesKit/OWSDeviceProvisioner.h delete mode 100644 SignalUtilitiesKit/OWSDeviceProvisioner.m delete mode 100644 SignalUtilitiesKit/OWSDeviceProvisioningCodeService.h delete mode 100644 SignalUtilitiesKit/OWSDeviceProvisioningCodeService.m delete mode 100644 SignalUtilitiesKit/OWSDeviceProvisioningService.h delete mode 100644 SignalUtilitiesKit/OWSDeviceProvisioningService.m delete mode 100644 SignalUtilitiesKit/OWSDevicesService.h delete mode 100644 SignalUtilitiesKit/OWSDevicesService.m delete mode 100644 SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.h delete mode 100644 SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.m delete mode 100644 SignalUtilitiesKit/OWSDynamicOutgoingMessage.h delete mode 100644 SignalUtilitiesKit/OWSDynamicOutgoingMessage.m delete mode 100644 SignalUtilitiesKit/OWSEndSessionMessage.h delete mode 100644 SignalUtilitiesKit/OWSEndSessionMessage.m delete mode 100644 SignalUtilitiesKit/OWSFingerprint.h delete mode 100644 SignalUtilitiesKit/OWSFingerprint.m delete mode 100644 SignalUtilitiesKit/OWSFingerprintBuilder.h delete mode 100644 SignalUtilitiesKit/OWSFingerprintBuilder.m delete mode 100644 SignalUtilitiesKit/OWSGroupAvatarBuilder.h delete mode 100644 SignalUtilitiesKit/OWSGroupAvatarBuilder.m delete mode 100644 SignalUtilitiesKit/OWSIncomingSentMessageTranscript.h delete mode 100644 SignalUtilitiesKit/OWSIncomingSentMessageTranscript.m delete mode 100644 SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.h delete mode 100644 SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.m delete mode 100644 SignalUtilitiesKit/OWSOutgoingCallMessage.h delete mode 100644 SignalUtilitiesKit/OWSOutgoingCallMessage.m delete mode 100644 SignalUtilitiesKit/OWSOutgoingNullMessage.h delete mode 100644 SignalUtilitiesKit/OWSOutgoingNullMessage.m delete mode 100644 SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.h delete mode 100644 SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.m delete mode 100644 SignalUtilitiesKit/OWSOutgoingSyncMessage.h delete mode 100644 SignalUtilitiesKit/OWSOutgoingSyncMessage.m delete mode 100644 SignalUtilitiesKit/OWSProfileKeyMessage.h delete mode 100644 SignalUtilitiesKit/OWSProfileKeyMessage.m delete mode 100644 SignalUtilitiesKit/OWSProvisioningMessage.h delete mode 100644 SignalUtilitiesKit/OWSProvisioningMessage.m delete mode 100644 SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.h delete mode 100644 SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.m delete mode 100644 SignalUtilitiesKit/OWSReceiptsForSenderMessage.h delete mode 100644 SignalUtilitiesKit/OWSReceiptsForSenderMessage.m delete mode 100644 SignalUtilitiesKit/OWSRequestBuilder.h delete mode 100644 SignalUtilitiesKit/OWSRequestBuilder.m delete mode 100644 SignalUtilitiesKit/OWSRequestFactory.h delete mode 100644 SignalUtilitiesKit/OWSRequestFactory.m delete mode 100644 SignalUtilitiesKit/OWSRequestMaker.swift delete mode 100644 SignalUtilitiesKit/OWSSignalService.h delete mode 100644 SignalUtilitiesKit/OWSSignalService.m delete mode 100644 SignalUtilitiesKit/OWSSyncConfigurationMessage.h delete mode 100644 SignalUtilitiesKit/OWSSyncConfigurationMessage.m delete mode 100644 SignalUtilitiesKit/OWSSyncContactsMessage.h delete mode 100644 SignalUtilitiesKit/OWSSyncContactsMessage.m delete mode 100644 SignalUtilitiesKit/OWSSyncGroupsMessage.h delete mode 100644 SignalUtilitiesKit/OWSSyncGroupsMessage.m delete mode 100644 SignalUtilitiesKit/OWSSyncGroupsRequestMessage.h delete mode 100644 SignalUtilitiesKit/OWSSyncGroupsRequestMessage.m delete mode 100644 SignalUtilitiesKit/OWSSyncManager.h delete mode 100644 SignalUtilitiesKit/OWSSyncManager.m delete mode 100644 SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.h delete mode 100644 SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.m delete mode 100644 SignalUtilitiesKit/OWSVerificationStateChangeMessage.h delete mode 100644 SignalUtilitiesKit/OWSVerificationStateChangeMessage.m delete mode 100644 SignalUtilitiesKit/OWSVerificationStateSyncMessage.h delete mode 100644 SignalUtilitiesKit/OWSVerificationStateSyncMessage.m delete mode 100644 SignalUtilitiesKit/OWSWebSocket.h delete mode 100644 SignalUtilitiesKit/OWSWebSocket.m delete mode 100644 SignalUtilitiesKit/OldSnodeAPI.swift delete mode 100644 SignalUtilitiesKit/OnionRequestAPI+Encryption.swift delete mode 100644 SignalUtilitiesKit/PhoneNumber.h delete mode 100644 SignalUtilitiesKit/PhoneNumber.m delete mode 100644 SignalUtilitiesKit/PhoneNumberUtil.h delete mode 100644 SignalUtilitiesKit/PhoneNumberUtil.m delete mode 100644 SignalUtilitiesKit/ProfileFetcherJob.swift delete mode 100644 SignalUtilitiesKit/Promise+retainUntilComplete.swift delete mode 100644 SignalUtilitiesKit/ProofOfWork.swift rename SignalUtilitiesKit/{ => Remove Later}/ContactCellView.h (100%) rename SignalUtilitiesKit/{ => Remove Later}/ContactCellView.m (96%) rename SignalUtilitiesKit/{ => Remove Later}/ContactTableViewCell.h (100%) rename SignalUtilitiesKit/{ => Remove Later}/ContactTableViewCell.m (100%) rename SignalUtilitiesKit/{ => Remove Later}/OWSProfileManager.h (100%) rename SignalUtilitiesKit/{ => Remove Later}/OWSProfileManager.m (94%) rename SignalUtilitiesKit/{ => Remove Later}/OWSUserProfile.h (100%) rename SignalUtilitiesKit/{ => Remove Later}/OWSUserProfile.m (96%) rename SignalUtilitiesKit/{ => Remove Later}/ProfileManagerProtocol.h (79%) rename SignalUtilitiesKit/{ => Remove Later}/SessionManagementProtocol.swift (61%) rename SignalUtilitiesKit/{ => Remove Later}/SessionMetaProtocol.swift (98%) delete mode 100644 SignalUtilitiesKit/ReturnToCallViewController.swift delete mode 100644 SignalUtilitiesKit/SSKProtoPrekeyBundleMessage+Loki.swift delete mode 100644 SignalUtilitiesKit/SSKWebSocket.swift delete mode 100644 SignalUtilitiesKit/SessionRequestMessage.swift delete mode 100644 SignalUtilitiesKit/SharedSenderKeysImplementation.swift delete mode 100644 SignalUtilitiesKit/SignalServiceClient.swift delete mode 100644 SignalUtilitiesKit/SyncMessagesProtocol.swift delete mode 100644 SignalUtilitiesKit/SystemContactsFetcher.swift delete mode 100644 SignalUtilitiesKit/TSNetworkManager.h delete mode 100644 SignalUtilitiesKit/TSNetworkManager.m delete mode 100644 SignalUtilitiesKit/TSSocketManager.h delete mode 100644 SignalUtilitiesKit/TSSocketManager.m delete mode 100644 SignalUtilitiesKit/TTLUtilities.swift create mode 100644 SignalUtilitiesKit/ThreadUtil.h create mode 100644 SignalUtilitiesKit/ThreadUtil.m rename SignalUtilitiesKit/{ => Threads}/TSContactThread.h (59%) rename SignalUtilitiesKit/{ => Threads}/TSContactThread.m (53%) rename SignalUtilitiesKit/{ => Threads}/TSGroupModel.h (84%) rename SignalUtilitiesKit/{ => Threads}/TSGroupModel.m (99%) rename SignalUtilitiesKit/{ => Threads}/TSGroupThread.h (81%) rename SignalUtilitiesKit/{ => Threads}/TSGroupThread.m (78%) rename SignalUtilitiesKit/{ => Threads}/TSThread.h (78%) rename SignalUtilitiesKit/{ => Threads}/TSThread.m (68%) delete mode 100644 SignalUtilitiesKit/TypingIndicatorMessage.swift rename SignalUtilitiesKit/{ => UI}/ApprovalRailCellView.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentApprovalInputAccessoryView.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentApprovalViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentCaptionToolbar.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentCaptionViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentItemCollection.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentPrepViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentTextToolbar.swift (100%) rename SignalUtilitiesKit/{ => UI}/AttachmentTextView.swift (100%) rename SignalUtilitiesKit/{ => UI}/BlockListUIUtils.h (82%) rename SignalUtilitiesKit/{ => UI}/BlockListUIUtils.m (95%) create mode 100644 SignalUtilitiesKit/UI/CircleView.swift rename SignalUtilitiesKit/{ => UI}/ConversationStyle.swift (92%) rename SignalUtilitiesKit/{ => UI}/DirectionalPanGestureRecognizer.swift (100%) rename SignalUtilitiesKit/{ => UI}/DisappearingTimerConfigurationView.swift (100%) rename SignalUtilitiesKit/{ => UI}/DisplayableText.swift (100%) rename SignalUtilitiesKit/{ => UI}/GalleryRailView.swift (100%) rename SignalUtilitiesKit/{ => UI}/GradientView.swift (100%) rename SignalUtilitiesKit/{ => UI}/Identicon+ObjC.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorBrushViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorCanvasView.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorContents.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorCropViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorItem.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorModel.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorPaletteView.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorPanGestureRecognizer.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorPinchGestureRecognizer.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorStrokeItem.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorTextItem.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorTextViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorTransform.swift (100%) rename SignalUtilitiesKit/{ => UI}/ImageEditorView.swift (100%) rename SignalUtilitiesKit/{ => UI}/MediaMessageView.swift (100%) rename SignalUtilitiesKit/{ => UI}/MessageApprovalViewController.swift (92%) rename SignalUtilitiesKit/{ => UI}/ModalActivityIndicatorViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/OWSAlerts.swift (100%) rename SignalUtilitiesKit/{ => UI}/OWSAnyTouchGestureRecognizer.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSAnyTouchGestureRecognizer.m (100%) rename SignalUtilitiesKit/{ => UI}/OWSButton.swift (100%) rename SignalUtilitiesKit/{ => UI}/OWSFlatButton.swift (100%) rename SignalUtilitiesKit/{ => UI}/OWSLayerView.swift (100%) rename SignalUtilitiesKit/{ => UI}/OWSNavigationBar.swift (86%) rename SignalUtilitiesKit/{ => UI}/OWSNavigationController.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSNavigationController.m (100%) rename SignalUtilitiesKit/{ => UI}/OWSSearchBar.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSSearchBar.m (100%) rename SignalUtilitiesKit/{ => UI}/OWSTableViewController.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSTableViewController.m (100%) rename SignalUtilitiesKit/{ => UI}/OWSTextField.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSTextField.m (100%) rename SignalUtilitiesKit/{ => UI}/OWSTextView.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSTextView.m (100%) rename SignalUtilitiesKit/{ => UI}/OWSViewController+ImageEditor.swift (100%) rename SignalUtilitiesKit/{ => UI}/OWSViewController.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSViewController.m (100%) rename SignalUtilitiesKit/{ => UI}/OWSWindowManager.h (100%) rename SignalUtilitiesKit/{ => UI}/OWSWindowManager.m (87%) rename SignalUtilitiesKit/{ => UI}/PlaceholderIcon.swift (100%) rename SignalUtilitiesKit/{ => UI}/ProfilePictureView.swift (97%) rename SignalUtilitiesKit/{ => UI}/ScreenLockViewController.h (100%) rename SignalUtilitiesKit/{ => UI}/ScreenLockViewController.m (100%) rename SignalUtilitiesKit/{ => UI}/SelectRecipientViewController.h (100%) rename SignalUtilitiesKit/{ => UI}/SelectRecipientViewController.m (51%) rename SignalUtilitiesKit/{ => UI}/SelectThreadViewController.h (100%) rename SignalUtilitiesKit/{ => UI}/SelectThreadViewController.m (67%) rename SignalUtilitiesKit/{ => UI}/SharingThreadPickerViewController.h (100%) rename SignalUtilitiesKit/{ => UI}/SharingThreadPickerViewController.m (65%) rename SignalUtilitiesKit/{ => UI}/SheetViewController.swift (100%) rename SignalUtilitiesKit/{ => UI}/TappableStackView.swift (100%) rename SignalUtilitiesKit/{ => UI}/TappableView.swift (100%) rename SignalUtilitiesKit/{ => UI}/Theme.h (100%) rename SignalUtilitiesKit/{ => UI}/Theme.m (100%) rename SignalUtilitiesKit/{ => UI}/Toast.swift (100%) rename SignalUtilitiesKit/{ => UI}/UIColor+OWS.h (100%) rename SignalUtilitiesKit/{ => UI}/UIColor+OWS.m (100%) rename SignalUtilitiesKit/{ => UI}/UIFont+OWS.h (100%) rename SignalUtilitiesKit/{ => UI}/UIFont+OWS.m (100%) rename SignalUtilitiesKit/{ => UI}/UIGestureRecognizer+OWS.swift (100%) rename SignalUtilitiesKit/{ => UI}/UIImage+OWS.swift (100%) rename SignalUtilitiesKit/{ => UI}/UIUtil.h (100%) rename SignalUtilitiesKit/{ => UI}/UIUtil.m (100%) rename SignalUtilitiesKit/{ => UI}/UIView+OWS.h (100%) rename SignalUtilitiesKit/{ => UI}/UIView+OWS.m (100%) rename SignalUtilitiesKit/{ => UI}/UIView+OWS.swift (100%) rename SignalUtilitiesKit/{ => UI}/UIView+Utilities.swift (100%) rename SignalUtilitiesKit/{ => UI}/UIViewController+OWS.h (100%) rename SignalUtilitiesKit/{ => UI}/UIViewController+OWS.m (100%) rename SignalUtilitiesKit/{ => UI}/UIViewController+Utilities.swift (100%) rename SignalUtilitiesKit/{ => UI}/VideoPlayerView.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/AttachmentSharing.h (100%) rename SignalUtilitiesKit/{ => Utilities}/AttachmentSharing.m (91%) rename SignalUtilitiesKit/{ => Utilities}/Bench.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/BuildConfiguration.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/ByteParser.h (100%) rename SignalUtilitiesKit/{ => Utilities}/ByteParser.m (100%) rename SignalUtilitiesKit/{ => Utilities}/Collection+OWS.swift (90%) rename SignalUtilitiesKit/{ => Utilities}/DebugLogger.h (100%) rename SignalUtilitiesKit/{ => Utilities}/DebugLogger.m (100%) rename SignalUtilitiesKit/{ => Utilities}/Debugging.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/LRUCache.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/MIMETypeUtil.h (100%) rename SignalUtilitiesKit/{ => Utilities}/MIMETypeUtil.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSArray+Functional.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSArray+Functional.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSArray+OWS.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSArray+OWS.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSAttributedString+OWS.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSData+Image.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSData+Image.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSObject+Casting.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSObject+Casting.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSRegularExpression+SSK.swift (92%) rename SignalUtilitiesKit/{ => Utilities}/NSSet+Functional.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSSet+Functional.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSString+SSK.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSString+SSK.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSURLSessionDataTask+StatusCode.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSURLSessionDataTask+StatusCode.m (100%) rename SignalUtilitiesKit/{ => Utilities}/NSUserDefaults+OWS.h (100%) rename SignalUtilitiesKit/{ => Utilities}/NSUserDefaults+OWS.m (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSAudioPlayer.h (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSAudioPlayer.m (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSAudioSession.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSFormat.h (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSFormat.m (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSMath.h (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSMediaUtils.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSScrubbingLogFormatter.h (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSScrubbingLogFormatter.m (100%) rename SignalUtilitiesKit/{ => Utilities}/OWSVideoPlayer.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/OrderedDictionary.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/ProtoUtils.h (100%) rename SignalUtilitiesKit/{ => Utilities}/ProtoUtils.m (58%) rename SignalUtilitiesKit/{ => Utilities}/ReverseDispatchQueue.swift (100%) rename SignalUtilitiesKit/{SSKProtoEnvelope+Conversion.swift => Utilities/SNProtoEnvelope+Conversion.swift} (82%) rename SignalUtilitiesKit/{ => Utilities}/SSKAsserts.h (100%) rename SignalUtilitiesKit/{ => Utilities}/ShareViewDelegate.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/String+SSK.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/String+Trimming.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/UIAlertController+OWS.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/UIDevice+featureSupport.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/UIImage+OWS.h (100%) rename SignalUtilitiesKit/{ => Utilities}/UIImage+OWS.m (100%) rename SignalUtilitiesKit/{ => Utilities}/Weak.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/WeakTimer.swift (100%) delete mode 100644 SignalUtilitiesKit/ViewControllerUtils.h delete mode 100644 SignalUtilitiesKit/ViewControllerUtils.m diff --git a/Session/Components/ConversationTitleView.swift b/Session/Components/ConversationTitleView.swift index f6c74d426..2f93f729e 100644 --- a/Session/Components/ConversationTitleView.swift +++ b/Session/Components/ConversationTitleView.swift @@ -50,11 +50,11 @@ final class ConversationTitleView : UIView { updateSubtitleForCurrentStatus() let notificationCenter = NotificationCenter.default notificationCenter.addObserver(self, selector: #selector(handleProfileChangedNotification(_:)), name: NSNotification.Name(rawValue: kNSNotificationName_OtherUsersProfileDidChange), object: nil) - notificationCenter.addObserver(self, selector: #selector(handleCalculatingPoWNotification(_:)), name: .calculatingPoW, object: nil) - notificationCenter.addObserver(self, selector: #selector(handleRoutingNotification(_:)), name: .routing, object: nil) + notificationCenter.addObserver(self, selector: #selector(handleCalculatingMessagePoWNotification(_:)), name: .calculatingMessagePoW, object: nil) + notificationCenter.addObserver(self, selector: #selector(handleEncryptingMessageNotification(_:)), name: .encryptingMessage, object: nil) notificationCenter.addObserver(self, selector: #selector(handleMessageSendingNotification(_:)), name: .messageSending, object: nil) notificationCenter.addObserver(self, selector: #selector(handleMessageSentNotification(_:)), name: .messageSent, object: nil) - notificationCenter.addObserver(self, selector: #selector(handleMessageFailedNotification(_:)), name: .messageFailed, object: nil) + notificationCenter.addObserver(self, selector: #selector(handleMessageSendingFailedNotification(_:)), name: .messageSendingFailed, object: nil) } override init(frame: CGRect) { @@ -112,12 +112,12 @@ final class ConversationTitleView : UIView { updateProfilePicture() } - @objc private func handleCalculatingPoWNotification(_ notification: Notification) { + @objc private func handleCalculatingMessagePoWNotification(_ notification: Notification) { guard let timestamp = notification.object as? NSNumber else { return } setStatusIfNeeded(to: .calculatingPoW, forMessageWithTimestamp: timestamp) } - @objc private func handleRoutingNotification(_ notification: Notification) { + @objc private func handleEncryptingMessageNotification(_ notification: Notification) { guard let timestamp = notification.object as? NSNumber else { return } setStatusIfNeeded(to: .routing, forMessageWithTimestamp: timestamp) } @@ -136,7 +136,7 @@ final class ConversationTitleView : UIView { } } - @objc private func handleMessageFailedNotification(_ notification: Notification) { + @objc private func handleMessageSendingFailedNotification(_ notification: Notification) { guard let timestamp = notification.object as? NSNumber else { return } clearStatusIfNeededForMessageWithTimestamp(timestamp) } @@ -149,14 +149,7 @@ final class ConversationTitleView : UIView { uncheckedTargetInteraction = interaction } guard let targetInteraction = uncheckedTargetInteraction, targetInteraction.interactionType() == .outgoingMessage, - status.rawValue > (currentStatus?.rawValue ?? 0), let hexEncodedPublicKey = targetInteraction.thread.contactIdentifier() else { return } - var masterHexEncodedPublicKey: String! - let storage = OWSPrimaryStorage.shared() - storage.dbReadConnection.read { transaction in - masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: hexEncodedPublicKey, in: transaction) ?? hexEncodedPublicKey - } - let isSlaveDevice = masterHexEncodedPublicKey != hexEncodedPublicKey - guard !isSlaveDevice else { return } + status.rawValue > (currentStatus?.rawValue ?? 0) else { return } currentStatus = status } @@ -184,7 +177,7 @@ final class ConversationTitleView : UIView { dateFormatter.timeStyle = .medium dateFormatter.dateStyle = .medium subtitle.append(NSAttributedString(string: "Muted until " + dateFormatter.string(from: muteEndDate))) - } else if let thread = self.thread as? TSGroupThread, !thread.isRSSFeed { + } else if let thread = self.thread as? TSGroupThread { let storage = OWSPrimaryStorage.shared() var userCount: Int? if thread.groupModel.groupType == .closedGroup { diff --git a/Session/Meta/Signal-Bridging-Header.h b/Session/Meta/Signal-Bridging-Header.h index 30d99c14c..860f774b2 100644 --- a/Session/Meta/Signal-Bridging-Header.h +++ b/Session/Meta/Signal-Bridging-Header.h @@ -16,10 +16,10 @@ #import "ConversationViewCell.h" #import "ConversationViewItem.h" #import "DateUtil.h" -#import "FingerprintViewController.h" + #import "MediaDetailViewController.h" #import "NotificationSettingsViewController.h" -#import "OWSAddToContactViewController.h" + #import "OWSAnyTouchGestureRecognizer.h" #import "OWSAudioPlayer.h" #import "OWSBackup.h" @@ -35,13 +35,12 @@ #import "OWSQuotedMessageView.h" #import "OWSSessionResetJobRecord.h" #import "OWSWindowManager.h" -#import "PinEntryView.h" #import "PrivacySettingsTableViewController.h" #import "RemoteVideoView.h" #import "OWSQRCodeScanningViewController.h" #import "SignalApp.h" #import "UIViewController+Permissions.h" -#import "ViewControllerUtils.h" + #import #import #import @@ -55,52 +54,36 @@ #import #import #import -#import -#import + + #import #import #import #import #import #import -#import #import #import #import #import #import #import -#import -#import #import #import #import #import #import -#import -#import -#import #import #import #import #import -#import -#import #import #import #import #import -#import -#import -#import -#import #import #import -#import #import -#import -#import -#import #import #import #import @@ -113,10 +96,10 @@ #import #import #import -#import + #import #import -#import + #import #import #import diff --git a/Session/Meta/Signal-Prefix.pch b/Session/Meta/Signal-Prefix.pch index 9faa8fd63..bede98c9f 100644 --- a/Session/Meta/Signal-Prefix.pch +++ b/Session/Meta/Signal-Prefix.pch @@ -18,7 +18,6 @@ #import #import #import - #import #import #import #import diff --git a/Session/Signal/AccountManager.swift b/Session/Signal/AccountManager.swift index a3b04c225..60a6ed448 100644 --- a/Session/Signal/AccountManager.swift +++ b/Session/Signal/AccountManager.swift @@ -19,10 +19,6 @@ public class AccountManager: NSObject { return OWSProfileManager.shared() } - private var networkManager: TSNetworkManager { - return SSKEnvironment.shared.networkManager - } - private var preferences: OWSPreferences { return Environment.shared.preferences } @@ -119,28 +115,4 @@ public class AccountManager: NSObject { let anyPromise = tsAccountManager.setIsManualMessageFetchEnabled(true) return Promise(anyPromise).asVoid() } - - // MARK: Turn Server - - func getTurnServerInfo() -> Promise { - return Promise { resolver in - self.networkManager.makeRequest(OWSRequestFactory.turnServerInfoRequest(), - success: { (_: URLSessionDataTask, responseObject: Any?) in - guard responseObject != nil else { - return resolver.reject(OWSErrorMakeUnableToProcessServerResponseError()) - } - - if let responseDictionary = responseObject as? [String: AnyObject] { - if let turnServerInfo = TurnServerInfo(attributes: responseDictionary) { - return resolver.fulfill(turnServerInfo) - } - Logger.error("unexpected server response:\(responseDictionary)") - } - return resolver.reject(OWSErrorMakeUnableToProcessServerResponseError()) - }, - failure: { (_: URLSessionDataTask, error: Error) in - return resolver.reject(error) - }) - } - } } diff --git a/Session/Signal/AddContactShareToExistingContactViewController.swift b/Session/Signal/AddContactShareToExistingContactViewController.swift deleted file mode 100644 index 0cc652d48..000000000 --- a/Session/Signal/AddContactShareToExistingContactViewController.swift +++ /dev/null @@ -1,145 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import UIKit -import ContactsUI - -class AddContactShareToExistingContactViewController: ContactsPicker, ContactsPickerDelegate, CNContactViewControllerDelegate { - - // TODO - there are some hard coded assumptions in this VC that assume we are *pushed* onto a - // navigation controller. That seems fine for now, but if we need to be presented as a modal, - // or need to notify our presenter about our dismisall or other contact actions, a delegate - // would be helpful. It seems like this would require some broad changes to the ContactShareViewHelper, - // so I've left it as is for now, since it happens to work. - // weak var addToExistingContactDelegate: AddContactShareToExistingContactViewControllerDelegate? - - let contactShare: ContactShareViewModel - - required init(contactShare: ContactShareViewModel) { - self.contactShare = contactShare - super.init(allowsMultipleSelection: false, subtitleCellType: .none) - - self.contactsPickerDelegate = self - } - - required public init?(coder aDecoder: NSCoder) { - notImplemented() - } - - @objc required public init(allowsMultipleSelection: Bool, subtitleCellType: SubtitleCellValue) { - notImplemented() - } - - // MARK: - ContactsPickerDelegate - - func contactsPicker(_: ContactsPicker, contactFetchDidFail error: NSError) { - owsFailDebug("with error: \(error)") - - guard let navigationController = self.navigationController else { - owsFailDebug("navigationController was unexpectedly nil") - return - } - - navigationController.popViewController(animated: true) - } - - func contactsPickerDidCancel(_: ContactsPicker) { - Logger.debug("") - guard let navigationController = self.navigationController else { - owsFailDebug("navigationController was unexpectedly nil") - return - } - - navigationController.popViewController(animated: true) - } - - func contactsPicker(_: ContactsPicker, didSelectContact oldContact: Contact) { - Logger.debug("") - - let contactsManager = Environment.shared.contactsManager - guard let oldCNContact = contactsManager?.cnContact(withId: oldContact.cnContactId) else { - owsFailDebug("could not load old CNContact.") - return - } - guard let newCNContact = OWSContacts.systemContact(for: self.contactShare.dbRecord, imageData: self.contactShare.avatarImageData) else { - owsFailDebug("could not load new CNContact.") - return - } - merge(oldCNContact: oldCNContact, newCNContact: newCNContact) - } - - func merge(oldCNContact: CNContact, newCNContact: CNContact) { - Logger.debug("") - - let mergedCNContact: CNContact = Contact.merge(cnContact: oldCNContact, newCNContact: newCNContact) - - // Not actually a "new" contact, but this brings up the edit form rather than the "Read" form - // saving our users a tap in some cases when we already know they want to edit. - let contactViewController: CNContactViewController = CNContactViewController(forNewContact: mergedCNContact) - - // Default title is "New Contact". We could give a more descriptive title, but anything - // seems redundant - the context is sufficiently clear. - contactViewController.title = "" - contactViewController.allowsActions = false - contactViewController.allowsEditing = true - contactViewController.delegate = self - - let modal = OWSNavigationController(rootViewController: contactViewController) - self.present(modal, animated: true) - } - - func contactsPicker(_: ContactsPicker, didSelectMultipleContacts contacts: [Contact]) { - Logger.debug("") - owsFailDebug("only supports single contact select") - - guard let navigationController = self.navigationController else { - owsFailDebug("navigationController was unexpectedly nil") - return - } - - navigationController.popViewController(animated: true) - } - - func contactsPicker(_: ContactsPicker, shouldSelectContact contact: Contact) -> Bool { - return true - } - - // MARK: - CNContactViewControllerDelegate - - public func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) { - Logger.debug("") - - guard let navigationController = self.navigationController else { - owsFailDebug("navigationController was unexpectedly nil") - return - } - - // TODO this is weird - ideally we'd do something like - // self.delegate?.didFinishAddingContact - // and the delegate, which knows about our presentation context could do the right thing. - // - // As it is, we happen to always be *pushing* this view controller onto a navcontroller, so the - // following works in all current cases. - // - // If we ever wanted to do something different, like present this in a modal, we'd have to rethink. - - // We want to pop *this* view *and* the still presented CNContactViewController in a single animation. - // Note this happens for *cancel* and for *done*. Unfortunately, I don't know of a way to detect the difference - // between the two, since both just call this method. - guard let myIndex = navigationController.viewControllers.firstIndex(of: self) else { - owsFailDebug("myIndex was unexpectedly nil") - navigationController.popViewController(animated: true) - navigationController.popViewController(animated: true) - return - } - - let previousViewControllerIndex = navigationController.viewControllers.index(before: myIndex) - let previousViewController = navigationController.viewControllers[previousViewControllerIndex] - - self.dismiss(animated: false) { - navigationController.popToViewController(previousViewController, animated: true) - } - } -} diff --git a/Session/Signal/AddToBlockListViewController.m b/Session/Signal/AddToBlockListViewController.m index 9d67377fb..58b64c436 100644 --- a/Session/Signal/AddToBlockListViewController.m +++ b/Session/Signal/AddToBlockListViewController.m @@ -4,8 +4,8 @@ #import "AddToBlockListViewController.h" #import "BlockListUIUtils.h" -#import "ContactsViewHelper.h" -#import +#import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -51,8 +51,7 @@ NS_ASSUME_NONNULL_BEGIN __weak AddToBlockListViewController *weakSelf = self; [BlockListUIUtils showBlockPhoneNumberActionSheet:phoneNumber fromViewController:self - blockingManager:self.contactsViewHelper.blockingManager - contactsManager:self.contactsViewHelper.contactsManager + blockingManager:SSKEnvironment.shared.blockingManager completionBlock:^(BOOL isBlocked) { if (isBlocked) { [weakSelf.navigationController popViewControllerAnimated:YES]; @@ -65,7 +64,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(signalAccount); ContactsViewHelper *helper = self.contactsViewHelper; - return ![helper isRecipientIdBlocked:signalAccount.recipientId]; + return ![SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]; } - (void)signalAccountWasSelected:(SignalAccount *)signalAccount @@ -73,15 +72,13 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(signalAccount); __weak AddToBlockListViewController *weakSelf = self; - ContactsViewHelper *helper = self.contactsViewHelper; - if ([helper isRecipientIdBlocked:signalAccount.recipientId]) { + if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]) { OWSFailDebug(@"Cannot add already blocked user to block list."); return; } [BlockListUIUtils showBlockSignalAccountActionSheet:signalAccount fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager + blockingManager:SSKEnvironment.shared.blockingManager completionBlock:^(BOOL isBlocked) { if (isBlocked) { [weakSelf.navigationController popViewControllerAnimated:YES]; diff --git a/Session/Signal/AddToGroupViewController.m b/Session/Signal/AddToGroupViewController.m index 1ec474681..c021ce8c3 100644 --- a/Session/Signal/AddToGroupViewController.m +++ b/Session/Signal/AddToGroupViewController.m @@ -4,9 +4,9 @@ #import "AddToGroupViewController.h" #import "BlockListUIUtils.h" -#import "ContactsViewHelper.h" + #import "Session-Swift.h" -#import + #import NS_ASSUME_NONNULL_BEGIN @@ -52,12 +52,10 @@ NS_ASSUME_NONNULL_BEGIN __weak AddToGroupViewController *weakSelf = self; - ContactsViewHelper *helper = self.contactsViewHelper; - if ([helper isRecipientIdBlocked:phoneNumber]) { + if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:phoneNumber]) { [BlockListUIUtils showUnblockPhoneNumberActionSheet:phoneNumber fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager + blockingManager:SSKEnvironment.shared.blockingManager completionBlock:^(BOOL isBlocked) { if (!isBlocked) { [weakSelf addToGroup:phoneNumber]; @@ -66,22 +64,6 @@ NS_ASSUME_NONNULL_BEGIN return; } - BOOL didShowSNAlert = [SafetyNumberConfirmationAlert - presentAlertIfNecessaryWithRecipientId:phoneNumber - confirmationText: - NSLocalizedString(@"SAFETY_NUMBER_CHANGED_CONFIRM_ADD_TO_GROUP_ACTION", - @"button title to confirm adding a recipient to a group when their safety " - @"number has recently changed") - contactsManager:helper.contactsManager - completion:^(BOOL didConfirmIdentity) { - if (didConfirmIdentity) { - [weakSelf addToGroup:phoneNumber]; - } - }]; - if (didShowSNAlert) { - return; - } - [self addToGroup:phoneNumber]; } @@ -97,17 +79,15 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(signalAccount); __weak AddToGroupViewController *weakSelf = self; - ContactsViewHelper *helper = self.contactsViewHelper; if ([self.addToGroupDelegate isRecipientGroupMember:signalAccount.recipientId]) { OWSFailDebug(@"Cannot add user to group member if already a member."); return; } - if ([helper isRecipientIdBlocked:signalAccount.recipientId]) { + if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]) { [BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager + blockingManager:SSKEnvironment.shared.blockingManager completionBlock:^(BOOL isBlocked) { if (!isBlocked) { [weakSelf addToGroup:signalAccount.recipientId]; @@ -116,22 +96,6 @@ NS_ASSUME_NONNULL_BEGIN return; } - BOOL didShowSNAlert = [SafetyNumberConfirmationAlert - presentAlertIfNecessaryWithRecipientId:signalAccount.recipientId - confirmationText: - NSLocalizedString(@"SAFETY_NUMBER_CHANGED_CONFIRM_ADD_TO_GROUP_ACTION", - @"button title to confirm adding a recipient to a group when their safety " - @"number has recently changed") - contactsManager:helper.contactsManager - completion:^(BOOL didConfirmIdentity) { - if (didConfirmIdentity) { - [weakSelf addToGroup:signalAccount.recipientId]; - } - }]; - if (didShowSNAlert) { - return; - } - [self addToGroup:signalAccount.recipientId]; } diff --git a/Session/Signal/AdvancedSettingsTableViewController.h b/Session/Signal/AdvancedSettingsTableViewController.h deleted file mode 100644 index f52659d84..000000000 --- a/Session/Signal/AdvancedSettingsTableViewController.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSTableViewController.h" - -@interface AdvancedSettingsTableViewController : OWSTableViewController - -@end diff --git a/Session/Signal/AdvancedSettingsTableViewController.m b/Session/Signal/AdvancedSettingsTableViewController.m deleted file mode 100644 index cf25c0d8a..000000000 --- a/Session/Signal/AdvancedSettingsTableViewController.m +++ /dev/null @@ -1,312 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "AdvancedSettingsTableViewController.h" -#import "DebugLogger.h" -#import "DomainFrontingCountryViewController.h" -#import "OWSCountryMetadata.h" -#import "Pastelog.h" -#import "Session-Swift.h" -#import "TSAccountManager.h" -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface AdvancedSettingsTableViewController () - -@property (nonatomic) Reachability *reachability; - -@end - -#pragma mark - - -@implementation AdvancedSettingsTableViewController - -- (void)loadView -{ - [super loadView]; - - self.title = NSLocalizedString(@"SETTINGS_ADVANCED_TITLE", @""); - - self.reachability = [Reachability reachabilityForInternetConnection]; - - [self observeNotifications]; - - [self updateTableContents]; -} - -- (void)observeNotifications -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(socketStateDidChange) - name:kNSNotification_OWSWebSocketStateDidChange - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(reachabilityChanged) - name:kReachabilityChangedNotification - object:nil]; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)socketStateDidChange -{ - OWSAssertIsOnMainThread(); - - [self updateTableContents]; -} - -- (void)reachabilityChanged -{ - OWSAssertIsOnMainThread(); - - [self updateTableContents]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - [self updateTableContents]; -} - -#pragma mark - Table Contents - -- (void)updateTableContents -{ - OWSTableContents *contents = [OWSTableContents new]; - - __weak AdvancedSettingsTableViewController *weakSelf = self; - - OWSTableSection *loggingSection = [OWSTableSection new]; - loggingSection.headerTitle = NSLocalizedString(@"LOGGING_SECTION", nil); - [loggingSection addItem:[OWSTableItem switchItemWithText:NSLocalizedString(@"SETTINGS_ADVANCED_DEBUGLOG", @"") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"enable_debug_log") - isOnBlock:^{ - return [OWSPreferences isLoggingEnabled]; - } - isEnabledBlock:^{ - return YES; - } - target:weakSelf - selector:@selector(didToggleEnableLogSwitch:)]]; - - - if ([OWSPreferences isLoggingEnabled]) { - [loggingSection - addItem:[OWSTableItem actionItemWithText:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", @"") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"submit_debug_log") - actionBlock:^{ - OWSLogInfo(@"Submitting debug logs"); - [DDLog flushLog]; - [Pastelog submitLogs]; - }]]; - } - - [contents addSection:loggingSection]; - - OWSTableSection *pushNotificationsSection = [OWSTableSection new]; - pushNotificationsSection.headerTitle - = NSLocalizedString(@"PUSH_REGISTER_TITLE", @"Used in table section header and alert view title contexts"); - [pushNotificationsSection addItem:[OWSTableItem actionItemWithText:NSLocalizedString(@"REREGISTER_FOR_PUSH", nil) - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( - self, @"reregister_push_notifications") - actionBlock:^{ - [weakSelf syncPushTokens]; - }]]; - [contents addSection:pushNotificationsSection]; - - // Censorship circumvention has certain disadvantages so it should only be - // used if necessary. Therefore: - // - // * We disable this setting if the user has a phone number from a censored region - - // censorship circumvention will be auto-activated for this user. - // * We disable this setting if the user is already connected; they're not being - // censored. - // * We continue to show this setting so long as it is set to allow users to disable - // it, for example when they leave a censored region. - OWSTableSection *censorshipSection = [OWSTableSection new]; - censorshipSection.headerTitle = NSLocalizedString(@"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION_HEADER", - @"Table header for the 'censorship circumvention' section."); - BOOL isAnySocketOpen = TSSocketManager.shared.highestSocketState == OWSWebSocketStateOpen; - if (OWSSignalService.sharedInstance.hasCensoredPhoneNumber) { - if (OWSSignalService.sharedInstance.isCensorshipCircumventionManuallyDisabled) { - censorshipSection.footerTitle - = NSLocalizedString(@"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION_FOOTER_MANUALLY_DISABLED", - @"Table footer for the 'censorship circumvention' section shown when censorship circumvention has " - @"been manually disabled."); - } else { - censorshipSection.footerTitle = NSLocalizedString( - @"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION_FOOTER_AUTO_ENABLED", - @"Table footer for the 'censorship circumvention' section shown when censorship circumvention has been " - @"auto-enabled based on local phone number."); - } - } else if (isAnySocketOpen) { - censorshipSection.footerTitle - = NSLocalizedString(@"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION_FOOTER_WEBSOCKET_CONNECTED", - @"Table footer for the 'censorship circumvention' section shown when the app is connected to the " - @"Signal service."); - } else if (!self.reachability.isReachable) { - censorshipSection.footerTitle - = NSLocalizedString(@"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION_FOOTER_NO_CONNECTION", - @"Table footer for the 'censorship circumvention' section shown when the app is not connected to the " - @"internet."); - } else { - censorshipSection.footerTitle = NSLocalizedString(@"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION_FOOTER", - @"Table footer for the 'censorship circumvention' section when censorship circumvention can be manually " - @"enabled."); - } - - // Do enable if : - // - // * ...Censorship circumvention is already manually enabled (to allow users to disable it). - // - // Otherwise, don't enable if: - // - // * ...Censorship circumvention is already enabled based on the local phone number. - // * ...The websocket is connected, since that demonstrates that no censorship is in effect. - // * ...The internet is not reachable, since we don't want to let users to activate - // censorship circumvention unnecessarily, e.g. if they just don't have a valid - // internet connection. - OWSTableSwitchBlock isCensorshipCircumventionOnBlock = ^{ - return OWSSignalService.sharedInstance.isCensorshipCircumventionActive; - }; - Reachability *reachability = self.reachability; - OWSTableSwitchBlock isManualCensorshipCircumventionOnEnabledBlock = ^{ - OWSSignalService *service = OWSSignalService.sharedInstance; - if (service.isCensorshipCircumventionActive) { - return YES; - } else if (service.hasCensoredPhoneNumber && service.isCensorshipCircumventionManuallyDisabled) { - return YES; - } else if (TSSocketManager.shared.highestSocketState == OWSWebSocketStateOpen) { - return NO; - } else { - return reachability.isReachable; - } - }; - - [censorshipSection - addItem:[OWSTableItem switchItemWithText:NSLocalizedString(@"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION", - @"Label for the 'manual censorship circumvention' switch.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"censorship_circumvention") - isOnBlock:isCensorshipCircumventionOnBlock - isEnabledBlock:isManualCensorshipCircumventionOnEnabledBlock - target:weakSelf - selector:@selector(didToggleEnableCensorshipCircumventionSwitch:)]]; - - if (OWSSignalService.sharedInstance.isCensorshipCircumventionManuallyActivated) { - OWSCountryMetadata *manualCensorshipCircumventionCountry = - [weakSelf ensureManualCensorshipCircumventionCountry]; - OWSAssertDebug(manualCensorshipCircumventionCountry); - NSString *text = [NSString - stringWithFormat:NSLocalizedString(@"SETTINGS_ADVANCED_CENSORSHIP_CIRCUMVENTION_COUNTRY_FORMAT", - @"Label for the 'manual censorship circumvention' country. Embeds {{the manual " - @"censorship circumvention country}}."), - manualCensorshipCircumventionCountry.localizedCountryName]; - [censorshipSection addItem:[OWSTableItem disclosureItemWithText:text - actionBlock:^{ - [weakSelf showDomainFrontingCountryView]; - }]]; - } - [contents addSection:censorshipSection]; - - self.contents = contents; -} - -- (void)showDomainFrontingCountryView -{ - DomainFrontingCountryViewController *vc = [DomainFrontingCountryViewController new]; - [self.navigationController pushViewController:vc animated:YES]; -} - -- (OWSCountryMetadata *)ensureManualCensorshipCircumventionCountry -{ - OWSAssertIsOnMainThread(); - - OWSCountryMetadata *countryMetadata = nil; - NSString *countryCode = OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode; - if (countryCode) { - countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; - } - - if (!countryMetadata) { - countryCode = [PhoneNumber defaultCountryCode]; - if (countryCode) { - countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; - } - } - - if (!countryMetadata) { - countryCode = @"US"; - countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; - OWSAssertDebug(countryMetadata); - } - - if (countryMetadata) { - // Ensure the "manual censorship circumvention" country state is in sync. - OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode = countryCode; - } - - return countryMetadata; -} - -#pragma mark - Actions - -- (void)syncPushTokens -{ - OWSSyncPushTokensJob *job = - [[OWSSyncPushTokensJob alloc] initWithAccountManager:AppEnvironment.shared.accountManager - preferences:Environment.shared.preferences]; - job.uploadOnlyIfStale = NO; - [job run] - .then(^{ - [OWSAlerts showAlertWithTitle:NSLocalizedString(@"PUSH_REGISTER_SUCCESS", - @"Title of alert shown when push tokens sync job succeeds.")]; - }) - .catch(^(NSError *error) { - [OWSAlerts showAlertWithTitle:NSLocalizedString(@"REGISTRATION_BODY", - @"Title of alert shown when push tokens sync job fails.")]; - }); -} - -- (void)didToggleEnableLogSwitch:(UISwitch *)sender -{ - if (!sender.isOn) { - OWSLogInfo(@"disabling logging."); - [[DebugLogger sharedLogger] wipeLogs]; - [[DebugLogger sharedLogger] disableFileLogging]; - } else { - [[DebugLogger sharedLogger] enableFileLogging]; - OWSLogInfo(@"enabling logging."); - } - - [OWSPreferences setIsLoggingEnabled:sender.isOn]; - - [self updateTableContents]; -} - -- (void)didToggleEnableCensorshipCircumventionSwitch:(UISwitch *)sender -{ - OWSSignalService *service = OWSSignalService.sharedInstance; - if (sender.isOn) { - service.isCensorshipCircumventionManuallyDisabled = NO; - service.isCensorshipCircumventionManuallyActivated = YES; - } else { - service.isCensorshipCircumventionManuallyDisabled = YES; - service.isCensorshipCircumventionManuallyActivated = NO; - } - - [self updateTableContents]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 3c7474414..1b838dbf9 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -8,31 +8,24 @@ #import "OWSBackup.h" #import "OWSOrphanDataCleaner.h" #import "OWSScreenLockUI.h" -#import "Pastelog.h" #import "Session-Swift.h" #import "SignalApp.h" -#import "SignalsNavigationController.h" -#import "ViewControllerUtils.h" #import #import #import #import -#import #import #import #import #import #import #import -#import -#import #import #import #import #import #import -#import -#import + #import #import #import @@ -40,7 +33,7 @@ #import #import #import -#import + #import #import @@ -118,20 +111,6 @@ static NSTimeInterval launchStartedAt; return SSKEnvironment.shared.disappearingMessagesJob; } -- (TSSocketManager *)socketManager -{ - OWSAssertDebug(SSKEnvironment.shared.socketManager); - - return SSKEnvironment.shared.socketManager; -} - -- (OWSMessageManager *)messageManager -{ - OWSAssertDebug(SSKEnvironment.shared.messageManager); - - return SSKEnvironment.shared.messageManager; -} - - (OWSWindowManager *)windowManager { return Environment.shared.windowManager; @@ -279,18 +258,12 @@ static NSTimeInterval launchStartedAt; selector:@selector(registrationStateDidChange) name:RegistrationStateDidChangeNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(registrationLockDidChange:) - name:NSNotificationName_2FAStateDidChange - object:nil]; // Loki - Observe data nuke request notifications [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleDataNukeRequested:) name:NSNotification.dataNukeRequested object:nil]; OWSLogInfo(@"application: didFinishLaunchingWithOptions completed."); - [OWSAnalytics appLaunchDidBegin]; - return YES; } @@ -394,41 +367,6 @@ static NSTimeInterval launchStartedAt; } } -- (void)showLaunchFailureUI:(NSError *)error -{ - // Disable normal functioning of app. - self.didAppLaunchFail = YES; - - // We perform a subset of the [application:didFinishLaunchingWithOptions:]. - [AppVersion sharedInstance]; - [self startupLogging]; - - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - - // Show the launch screen - self.window.rootViewController = - [[UIStoryboard storyboardWithName:@"Launch Screen" bundle:nil] instantiateInitialViewController]; - - [self.window makeKeyAndVisible]; - - UIAlertController *alert = - [UIAlertController alertControllerWithTitle:NSLocalizedString(@"APP_LAUNCH_FAILURE_ALERT_TITLE", - @"Title for the 'app launch failed' alert.") - message:NSLocalizedString(@"APP_LAUNCH_FAILURE_ALERT_MESSAGE", - @"Message for the 'app launch failed' alert.") - preferredStyle:UIAlertControllerStyleAlert]; - - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil) - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [Pastelog submitLogsWithCompletion:^{ - OWSFail(@"Exiting after sharing debug logs."); - }]; - }]]; - UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController]; - [fromViewController presentAlert:alert]; -} - - (void)startupLogging { OWSLogInfo(@"iOS Version: %@", [UIDevice currentDevice].systemVersion); @@ -498,16 +436,6 @@ static NSTimeInterval launchStartedAt; [[[OWSFailedMessagesJob alloc] initWithPrimaryStorage:self.primaryStorage] run]; [[[OWSFailedAttachmentDownloadsJob alloc] initWithPrimaryStorage:self.primaryStorage] run]; }); - } else { - OWSLogInfo(@"Running post launch block for unregistered user."); - - // Unregistered user should have no unread messages. e.g. if you delete your account. - [AppEnvironment.shared.notificationPresenter clearAllNotifications]; - - UITapGestureRecognizer *gesture = - [[UITapGestureRecognizer alloc] initWithTarget:[Pastelog class] action:@selector(submitLogs)]; - gesture.numberOfTapsRequired = 8; - [self.window addGestureRecognizer:gesture]; } }); // end dispatchOnce for first time we become active @@ -640,8 +568,6 @@ static NSTimeInterval launchStartedAt; [self ensureRootViewController]; - [self.messageManager startObserving]; - [self.udManager setup]; [self preheatDatabaseViews]; @@ -657,8 +583,6 @@ static NSTimeInterval launchStartedAt; if (appVersion.lastAppVersion.length > 0 && ![appVersion.lastAppVersion isEqualToString:appVersion.currentAppVersion]) { [[self.tsAccountManager updateAccountAttributes] retainUntilComplete]; - - [SSKEnvironment.shared.syncManager sendConfigurationSyncMessage]; } } } @@ -734,18 +658,6 @@ static NSTimeInterval launchStartedAt; [UIViewController attemptRotationToDeviceOrientation]; } -#pragma mark - Status Bar Interaction - -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event -{ - [super touchesBegan:touches withEvent:event]; - CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]]; - CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame; - if (CGRectContainsPoint(statusBarFrame, location)) { - [[NSNotificationCenter defaultCenter] postNotificationName:TappedStatusBarNotification object:nil]; - } -} - #pragma mark - Notifications - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken @@ -953,7 +865,6 @@ static NSTimeInterval launchStartedAt; [[LKPushNotificationManager unregisterWithToken:deviceToken isForcedUpdate:YES] retainUntilComplete]; } [ThreadUtil deleteAllContent]; - [SSKEnvironment.shared.messageSenderJobQueue clearAllJobs]; [SSKEnvironment.shared.identityManager clearIdentityKey]; [SNSnodeAPI clearSnodePool]; [self stopPoller]; diff --git a/Session/Signal/AppEnvironment.swift b/Session/Signal/AppEnvironment.swift index 5469779bc..14a57265e 100644 --- a/Session/Signal/AppEnvironment.swift +++ b/Session/Signal/AppEnvironment.swift @@ -34,9 +34,6 @@ import SignalUtilitiesKit // @objc // public var outboundCallInitiator: OutboundCallInitiator - @objc - public var messageFetcherJob: MessageFetcherJob - @objc public var accountManager: AccountManager @@ -81,9 +78,6 @@ import SignalUtilitiesKit private override init() { self.callMessageHandler = WebRTCCallMessageHandler() -// self.callService = CallService() -// self.outboundCallInitiator = OutboundCallInitiator() - self.messageFetcherJob = MessageFetcherJob() self.accountManager = AccountManager() self.notificationPresenter = NotificationPresenter() self.pushRegistrationManager = PushRegistrationManager() diff --git a/Session/Signal/AppNotifications.swift b/Session/Signal/AppNotifications.swift index 29b44b0c0..1b6128be9 100644 --- a/Session/Signal/AppNotifications.swift +++ b/Session/Signal/AppNotifications.swift @@ -120,14 +120,6 @@ protocol NotificationPresenterAdaptee: class { func cancelNotifications(threadId: String) func clearAllNotifications() - - var hasReceivedSyncMessageRecently: Bool { get } -} - -extension NotificationPresenterAdaptee { - var hasReceivedSyncMessageRecently: Bool { - return OWSDeviceManager.shared().hasReceivedSyncMessage(inLastSeconds: 60) - } } @objc(OWSNotificationPresenter) @@ -153,10 +145,6 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { // MARK: - Dependencies - var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - var identityManager: OWSIdentityManager { return OWSIdentityManager.shared() } @@ -209,140 +197,6 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { return adaptee.registerNotificationSettings() } -// func presentIncomingCall(_ call: SignalCall, callerName: String) { -// -// let notificationTitle: String? -// switch previewType { -// case .noNameNoPreview: -// notificationTitle = nil -// case .nameNoPreview, .namePreview: -// notificationTitle = callerName -// } -// let notificationBody = NotificationStrings.incomingCallBody -// -// let remotePhoneNumber = call.remotePhoneNumber -// let thread = TSContactThread.getOrCreateThread(contactId: remotePhoneNumber) -// -// guard let threadId = thread.uniqueId else { -// owsFailDebug("threadId was unexpectedly nil") -// return -// } -// -// let userInfo = [ -// AppNotificationUserInfoKey.threadId: threadId, -// AppNotificationUserInfoKey.localCallId: call.localId.uuidString -// ] -// -// DispatchQueue.main.async { -// self.adaptee.notify(category: .incomingCall, -// title: notificationTitle, -// body: notificationBody, -// userInfo: userInfo, -// sound: .defaultiOSIncomingRingtone, -// replacingIdentifier: call.localId.uuidString) -// } -// } -// -// func presentMissedCall(_ call: SignalCall, callerName: String) { -// let notificationTitle: String? -// switch previewType { -// case .noNameNoPreview: -// notificationTitle = nil -// case .nameNoPreview, .namePreview: -// notificationTitle = callerName -// } -// let notificationBody = NotificationStrings.missedCallBody -// -// let remotePhoneNumber = call.remotePhoneNumber -// let thread = TSContactThread.getOrCreateThread(contactId: remotePhoneNumber) -// -// guard let threadId = thread.uniqueId else { -// owsFailDebug("threadId was unexpectedly nil") -// return -// } -// -// let userInfo = [ -// AppNotificationUserInfoKey.threadId: threadId, -// AppNotificationUserInfoKey.callBackNumber: remotePhoneNumber -// ] -// -// DispatchQueue.main.async { -// let sound = self.requestSound(thread: thread) -// self.adaptee.notify(category: .missedCall, -// title: notificationTitle, -// body: notificationBody, -// userInfo: userInfo, -// sound: sound, -// replacingIdentifier: call.localId.uuidString) -// } -// } -// -// public func presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: SignalCall, callerName: String) { -// let notificationTitle: String? -// switch previewType { -// case .noNameNoPreview: -// notificationTitle = nil -// case .nameNoPreview, .namePreview: -// notificationTitle = callerName -// } -// let notificationBody = NotificationStrings.missedCallBecauseOfIdentityChangeBody -// -// let remotePhoneNumber = call.remotePhoneNumber -// let thread = TSContactThread.getOrCreateThread(contactId: remotePhoneNumber) -// guard let threadId = thread.uniqueId else { -// owsFailDebug("threadId was unexpectedly nil") -// return -// } -// -// let userInfo = [ -// AppNotificationUserInfoKey.threadId: threadId -// ] -// -// DispatchQueue.main.async { -// let sound = self.requestSound(thread: thread) -// self.adaptee.notify(category: .missedCallFromNoLongerVerifiedIdentity, -// title: notificationTitle, -// body: notificationBody, -// userInfo: userInfo, -// sound: sound, -// replacingIdentifier: call.localId.uuidString) -// } -// } -// -// public func presentMissedCallBecauseOfNewIdentity(call: SignalCall, callerName: String) { -// let notificationTitle: String? -// switch previewType { -// case .noNameNoPreview: -// notificationTitle = nil -// case .nameNoPreview, .namePreview: -// notificationTitle = callerName -// } -// let notificationBody = NotificationStrings.missedCallBecauseOfIdentityChangeBody -// -// let remotePhoneNumber = call.remotePhoneNumber -// let thread = TSContactThread.getOrCreateThread(contactId: remotePhoneNumber) -// -// guard let threadId = thread.uniqueId else { -// owsFailDebug("threadId was unexpectedly nil") -// return -// } -// -// let userInfo = [ -// AppNotificationUserInfoKey.threadId: threadId, -// AppNotificationUserInfoKey.callBackNumber: remotePhoneNumber -// ] -// -// DispatchQueue.main.async { -// let sound = self.requestSound(thread: thread) -// self.adaptee.notify(category: .missedCall, -// title: notificationTitle, -// body: notificationBody, -// userInfo: userInfo, -// sound: sound, -// replacingIdentifier: call.localId.uuidString) -// } -// } - public func notifyUser(for incomingMessage: TSIncomingMessage, in thread: TSThread, transaction: YapDatabaseReadTransaction) { guard !thread.isMuted else { @@ -359,7 +213,7 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { // for more details. let messageText = DisplayableText.filterNotificationText(rawMessageText) - let senderName = OWSUserProfile.fetch(uniqueId: incomingMessage.authorId, transaction: transaction)?.profileName ?? contactsManager.displayName(forPhoneIdentifier: incomingMessage.authorId) + let senderName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: incomingMessage.authorId, avoidingWriteTransaction: true)! let notificationTitle: String? switch previewType { @@ -401,12 +255,6 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { // Don't reply from lockscreen if anyone in this conversation is // "no longer verified". var category = AppNotificationCategory.incomingMessage - for recipientId in thread.recipientIdentifiers { - if self.identityManager.verificationState(forRecipientId: recipientId) == .noLongerVerified { - category = AppNotificationCategory.incomingMessageFromNoLongerVerifiedIdentity - break - } - } let userInfo = [ AppNotificationUserInfoKey.threadId: threadId @@ -554,14 +402,6 @@ class NotificationActionHandler { return SignalApp.shared() } - var messageSender: MessageSender { - return SSKEnvironment.shared.messageSender - } - -// var callUIAdapter: CallUIAdapter { -// return AppEnvironment.shared.callService.callUIAdapter -// } - var notificationPresenter: NotificationPresenter { return AppEnvironment.shared.notificationPresenter } @@ -572,41 +412,6 @@ class NotificationActionHandler { // MARK: - -// func answerCall(userInfo: [AnyHashable: Any]) throws -> Promise { -// guard let localCallIdString = userInfo[AppNotificationUserInfoKey.localCallId] as? String else { -// throw NotificationError.failDebug("localCallIdString was unexpectedly nil") -// } -// -// guard let localCallId = UUID(uuidString: localCallIdString) else { -// throw NotificationError.failDebug("unable to build localCallId. localCallIdString: \(localCallIdString)") -// } -// -// callUIAdapter.answerCall(localId: localCallId) -// return Promise.value(()) -// } -// -// func callBack(userInfo: [AnyHashable: Any]) throws -> Promise { -// guard let recipientId = userInfo[AppNotificationUserInfoKey.callBackNumber] as? String else { -// throw NotificationError.failDebug("recipientId was unexpectedly nil") -// } -// -// callUIAdapter.startAndShowOutgoingCall(recipientId: recipientId, hasLocalVideo: false) -// return Promise.value(()) -// } -// -// func declineCall(userInfo: [AnyHashable: Any]) throws -> Promise { -// guard let localCallIdString = userInfo[AppNotificationUserInfoKey.localCallId] as? String else { -// throw NotificationError.failDebug("localCallIdString was unexpectedly nil") -// } -// -// guard let localCallId = UUID(uuidString: localCallIdString) else { -// throw NotificationError.failDebug("unable to build localCallId. localCallIdString: \(localCallIdString)") -// } -// -// callUIAdapter.declineCall(localId: localCallId) -// return Promise.value(()) -// } - func markAsRead(userInfo: [AnyHashable: Any]) throws -> Promise { guard let threadId = userInfo[AppNotificationUserInfoKey.threadId] as? String else { throw NotificationError.failDebug("threadId was unexpectedly nil") @@ -629,15 +434,18 @@ class NotificationActionHandler { } return markAsRead(thread: thread).then { () -> Promise in - let sendPromise = ThreadUtil.sendMessageNonDurably(text: replyText, - thread: thread, - quotedReplyModel: nil, - messageSender: self.messageSender) + // TODO TODO TODO + +// let sendPromise = ThreadUtil.sendMessageNonDurably(text: replyText, +// thread: thread, +// quotedReplyModel: nil, +// messageSender: self.messageSender) - return sendPromise.recover { error in - Logger.warn("Failed to send reply message from notification with error: \(error)") - self.notificationPresenter.notifyForFailedSend(inThread: thread) - } +// return sendPromise.recover { error in +// Logger.warn("Failed to send reply message from notification with error: \(error)") +// self.notificationPresenter.notifyForFailedSend(inThread: thread) +// } + return Promise.value(()) } } @@ -666,25 +474,6 @@ class NotificationActionHandler { } } -extension ThreadUtil { - static var dbReadConnection: YapDatabaseConnection { - return OWSPrimaryStorage.shared().dbReadConnection - } - - class func sendMessageNonDurably(text: String, thread: TSThread, quotedReplyModel: OWSQuotedReplyModel?, messageSender: MessageSender) -> Promise { - return Promise { resolver in - self.dbReadConnection.read { transaction in - _ = self.sendMessageNonDurably(withText: text, - in: thread, - quotedReplyModel: quotedReplyModel, - transaction: transaction, - messageSender: messageSender, - completion: resolver.resolve) - } - } - } -} - enum NotificationError: Error { case assertionError(description: String) } diff --git a/Session/Signal/AvatarTableViewCell.swift b/Session/Signal/AvatarTableViewCell.swift index 955584d82..005cfaca0 100644 --- a/Session/Signal/AvatarTableViewCell.swift +++ b/Session/Signal/AvatarTableViewCell.swift @@ -9,7 +9,7 @@ public class AvatarTableViewCell: UITableViewCell { private let columns: UIStackView private let textRows: UIStackView - private let avatarView: AvatarImageView +// private let avatarView: AvatarImageView private let _textLabel: UILabel override public var textLabel: UILabel? { @@ -27,8 +27,8 @@ public class AvatarTableViewCell: UITableViewCell { @objc public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - self.avatarView = AvatarImageView() - avatarView.autoSetDimensions(to: CGSize(width: CGFloat(kStandardAvatarSize), height: CGFloat(kStandardAvatarSize))) +// self.avatarView = AvatarImageView() +// avatarView.autoSetDimensions(to: CGSize(width: CGFloat(kStandardAvatarSize), height: CGFloat(kStandardAvatarSize))) self._textLabel = UILabel() self._detailTextLabel = UILabel() @@ -36,7 +36,7 @@ public class AvatarTableViewCell: UITableViewCell { self.textRows = UIStackView(arrangedSubviews: [_textLabel, _detailTextLabel]) textRows.axis = .vertical - self.columns = UIStackView(arrangedSubviews: [avatarView, textRows]) + self.columns = UIStackView(arrangedSubviews: [ textRows ]) columns.axis = .horizontal columns.spacing = CGFloat(kContactCellAvatarTextMargin) @@ -54,7 +54,7 @@ public class AvatarTableViewCell: UITableViewCell { @objc public func configure(image: UIImage?, text: String?, detailText: String?) { - self.avatarView.image = image +// self.avatarView.image = image self.textLabel?.text = text self.detailTextLabel?.text = detailText @@ -65,7 +65,7 @@ public class AvatarTableViewCell: UITableViewCell { public override func prepareForReuse() { super.prepareForReuse() - self.avatarView.image = nil +// self.avatarView.image = nil self.textLabel?.text = nil self.detailTextLabel?.text = nil } diff --git a/Session/Signal/AvatarViewHelper.m b/Session/Signal/AvatarViewHelper.m index 6a5e7f712..b5d4b7972 100644 --- a/Session/Signal/AvatarViewHelper.m +++ b/Session/Signal/AvatarViewHelper.m @@ -6,9 +6,9 @@ #import "OWSNavigationController.h" #import "Session-Swift.h" #import -#import + #import -#import + #import #import #import diff --git a/Session/Signal/BlockListViewController.h b/Session/Signal/BlockListViewController.h deleted file mode 100644 index 05fd68422..000000000 --- a/Session/Signal/BlockListViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface BlockListViewController : OWSViewController - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/BlockListViewController.m b/Session/Signal/BlockListViewController.m deleted file mode 100644 index 1f6fc3ed0..000000000 --- a/Session/Signal/BlockListViewController.m +++ /dev/null @@ -1,175 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "BlockListViewController.h" -#import "AddToBlockListViewController.h" -#import "BlockListUIUtils.h" -#import "ContactTableViewCell.h" -#import "ContactsViewHelper.h" -#import "OWSTableViewController.h" -#import "PhoneNumber.h" -#import "Session-Swift.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface BlockListViewController () - -@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; - -@property (nonatomic, readonly) OWSTableViewController *tableViewController; - -@end - -#pragma mark - - -@implementation BlockListViewController - -- (OWSBlockingManager *)blockingManager -{ - return OWSBlockingManager.sharedManager; -} - -- (void)loadView -{ - [super loadView]; - - _contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self]; - - self.title - = NSLocalizedString(@"SETTINGS_BLOCK_LIST_TITLE", @"Label for the block list section of the settings view"); - - _tableViewController = [OWSTableViewController new]; - [self.view addSubview:self.tableViewController.view]; - [self addChildViewController:self.tableViewController]; - [_tableViewController.view autoPinEdgesToSuperviewEdges]; - self.tableViewController.tableView.rowHeight = UITableViewAutomaticDimension; - self.tableViewController.tableView.estimatedRowHeight = 60; - - [self updateTableContents]; -} - -#pragma mark - Table view data source - -- (void)updateTableContents -{ - OWSTableContents *contents = [OWSTableContents new]; - - __weak BlockListViewController *weakSelf = self; - ContactsViewHelper *helper = self.contactsViewHelper; - - // "Add" section - - OWSTableSection *addSection = [OWSTableSection new]; - addSection.footerTitle = NSLocalizedString( - @"BLOCK_USER_BEHAVIOR_EXPLANATION", @"An explanation of the consequences of blocking another user."); - - [addSection - addItem:[OWSTableItem - disclosureItemWithText:NSLocalizedString(@"SETTINGS_BLOCK_LIST_ADD_BUTTON", - @"A label for the 'add phone number' button in the block list table.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"add") - actionBlock:^{ - AddToBlockListViewController *vc = [[AddToBlockListViewController alloc] init]; - [weakSelf.navigationController pushViewController:vc animated:YES]; - }]]; - [contents addSection:addSection]; - - // "Blocklist" section - - NSArray *blockedPhoneNumbers = - [self.blockingManager.blockedPhoneNumbers sortedArrayUsingSelector:@selector(compare:)]; - - if (blockedPhoneNumbers.count > 0) { - OWSTableSection *blockedContactsSection = [OWSTableSection new]; - blockedContactsSection.headerTitle = NSLocalizedString( - @"BLOCK_LIST_BLOCKED_USERS_SECTION", @"Section header for users that have been blocked"); - - for (NSString *phoneNumber in blockedPhoneNumbers) { - [blockedContactsSection addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - ContactTableViewCell *cell = [ContactTableViewCell new]; - [cell configureWithRecipientId:phoneNumber]; - cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME( - BlockListViewController, @"user"); - return cell; - } - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - [BlockListUIUtils - showUnblockPhoneNumberActionSheet:phoneNumber - fromViewController:weakSelf - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager - completionBlock:^(BOOL isBlocked) { - [weakSelf updateTableContents]; - }]; - }]]; - } - [contents addSection:blockedContactsSection]; - } - - NSArray *blockedGroups = self.blockingManager.blockedGroups; - if (blockedGroups.count > 0) { - OWSTableSection *blockedGroupsSection = [OWSTableSection new]; - blockedGroupsSection.headerTitle = NSLocalizedString( - @"BLOCK_LIST_BLOCKED_GROUPS_SECTION", @"Section header for groups that have been blocked"); - - for (TSGroupModel *blockedGroup in blockedGroups) { - UIImage *_Nullable image = blockedGroup.groupImage; - if (!image) { - NSString *conversationColorName = - [TSGroupThread defaultConversationColorNameForGroupId:blockedGroup.groupId]; - image = [OWSGroupAvatarBuilder defaultAvatarForGroupId:blockedGroup.groupId - conversationColorName:conversationColorName - diameter:kStandardAvatarSize]; - } - NSString *groupName - = blockedGroup.groupName.length > 0 ? blockedGroup.groupName : TSGroupThread.defaultGroupName; - - [blockedGroupsSection addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - OWSAvatarTableViewCell *cell = [OWSAvatarTableViewCell new]; - [cell configureWithImage:image - text:groupName - detailText:nil]; - return cell; - } - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - [BlockListUIUtils showUnblockGroupActionSheet:blockedGroup - displayName:groupName - fromViewController:weakSelf - blockingManager:helper.blockingManager - completionBlock:^(BOOL isBlocked) { - [weakSelf updateTableContents]; - }]; - }]]; - } - [contents addSection:blockedGroupsSection]; - } - - self.tableViewController.contents = contents; -} - -#pragma mark - ContactsViewHelperDelegate - -- (void)contactsViewHelperDidUpdateContacts -{ - [self updateTableContents]; -} - -- (BOOL)shouldHideLocalNumber -{ - return YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ColorPickerViewController.swift b/Session/Signal/ColorPickerViewController.swift deleted file mode 100644 index 39e1c0256..000000000 --- a/Session/Signal/ColorPickerViewController.swift +++ /dev/null @@ -1,532 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -class OWSColorPickerAccessoryView: NeverClearView { - override var intrinsicContentSize: CGSize { - return CGSize(width: kSwatchSize, height: kSwatchSize) - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - return self.intrinsicContentSize - } - - let kSwatchSize: CGFloat = 24 - - @objc - required init(color: UIColor) { - super.init(frame: .zero) - - let circleView = CircleView() - circleView.backgroundColor = color - addSubview(circleView) - circleView.autoSetDimensions(to: CGSize(width: kSwatchSize, height: kSwatchSize)) - circleView.autoPinEdgesToSuperviewEdges() - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -@objc (OWSCircleView) -class CircleView: UIView { - override var bounds: CGRect { - didSet { - self.layer.cornerRadius = self.bounds.size.height / 2 - } - } -} - -protocol ColorViewDelegate: class { - func colorViewWasTapped(_ colorView: ColorView) -} - -class ColorView: UIView { - public weak var delegate: ColorViewDelegate? - public let conversationColor: OWSConversationColor - - private let swatchView: CircleView - private let selectedRing: CircleView - public var isSelected: Bool = false { - didSet { - self.selectedRing.isHidden = !isSelected - } - } - - required init(conversationColor: OWSConversationColor) { - self.conversationColor = conversationColor - self.swatchView = CircleView() - self.selectedRing = CircleView() - - super.init(frame: .zero) - self.addSubview(selectedRing) - self.addSubview(swatchView) - - // Selected Ring - let cellHeight: CGFloat = ScaleFromIPhone5(60) - selectedRing.autoSetDimensions(to: CGSize(width: cellHeight, height: cellHeight)) - - selectedRing.layer.borderColor = Theme.secondaryColor.cgColor - selectedRing.layer.borderWidth = 2 - selectedRing.autoPinEdgesToSuperviewEdges() - selectedRing.isHidden = true - - // Color Swatch - swatchView.backgroundColor = conversationColor.primaryColor - - let swatchSize: CGFloat = ScaleFromIPhone5(46) - swatchView.autoSetDimensions(to: CGSize(width: swatchSize, height: swatchSize)) - - swatchView.autoCenterInSuperview() - - // gestures - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap)) - self.addGestureRecognizer(tapGesture) - } - - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - // MARK: Actions - - @objc - func didTap() { - delegate?.colorViewWasTapped(self) - } -} - -@objc -protocol ColorPickerDelegate: class { - func colorPicker(_ colorPicker: ColorPicker, didPickConversationColor conversationColor: OWSConversationColor) -} - -@objc(OWSColorPicker) -class ColorPicker: NSObject, ColorPickerViewDelegate { - - @objc - public weak var delegate: ColorPickerDelegate? - - @objc - let sheetViewController: SheetViewController - - @objc - init(thread: TSThread) { - let colorName = thread.conversationColorName - let currentConversationColor = OWSConversationColor.conversationColorOrDefault(colorName: colorName) - sheetViewController = SheetViewController() - - super.init() - - let colorPickerView = ColorPickerView(thread: thread) - colorPickerView.delegate = self - colorPickerView.select(conversationColor: currentConversationColor) - - sheetViewController.contentView.addSubview(colorPickerView) - colorPickerView.autoPinEdgesToSuperviewEdges() - } - - // MARK: ColorPickerViewDelegate - - func colorPickerView(_ colorPickerView: ColorPickerView, didPickConversationColor conversationColor: OWSConversationColor) { - self.delegate?.colorPicker(self, didPickConversationColor: conversationColor) - } -} - -protocol ColorPickerViewDelegate: class { - func colorPickerView(_ colorPickerView: ColorPickerView, didPickConversationColor conversationColor: OWSConversationColor) -} - -class ColorPickerView: UIView, ColorViewDelegate { - - private let colorViews: [ColorView] - let conversationStyle: ConversationStyle - var outgoingMessageView = OWSMessageBubbleView(forAutoLayout: ()) - var incomingMessageView = OWSMessageBubbleView(forAutoLayout: ()) - weak var delegate: ColorPickerViewDelegate? - - // This is mostly a developer convenience - OWSMessageCell asserts at some point - // that the available method width is greater than 0. - // We ultimately use the width of the picker view which will be larger. - let kMinimumConversationWidth: CGFloat = 300 - override var bounds: CGRect { - didSet { - updateMockConversationView() - } - } - - let mockConversationView: UIView = UIView() - - init(thread: TSThread) { - let allConversationColors = OWSConversationColor.conversationColorNames.map { OWSConversationColor.conversationColorOrDefault(colorName: $0) } - - self.colorViews = allConversationColors.map { ColorView(conversationColor: $0) } - - self.conversationStyle = ConversationStyle(thread: thread) - - super.init(frame: .zero) - - colorViews.forEach { $0.delegate = self } - - let headerView = self.buildHeaderView() - mockConversationView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) - mockConversationView.backgroundColor = Theme.backgroundColor - self.updateMockConversationView() - - let paletteView = self.buildPaletteView(colorViews: colorViews) - - let rowsStackView = UIStackView(arrangedSubviews: [headerView, mockConversationView, paletteView]) - rowsStackView.axis = .vertical - addSubview(rowsStackView) - rowsStackView.autoPinEdgesToSuperviewEdges() - } - - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - // MARK: ColorViewDelegate - - func colorViewWasTapped(_ colorView: ColorView) { - self.select(conversationColor: colorView.conversationColor) - self.delegate?.colorPickerView(self, didPickConversationColor: colorView.conversationColor) - updateMockConversationView() - } - - fileprivate func select(conversationColor selectedConversationColor: OWSConversationColor) { - colorViews.forEach { colorView in - colorView.isSelected = colorView.conversationColor == selectedConversationColor - } - } - - // MARK: View Building - - private func buildHeaderView() -> UIView { - let headerView = UIView() - headerView.layoutMargins = UIEdgeInsets(top: 15, left: 16, bottom: 15, right: 16) - - let titleLabel = UILabel() - titleLabel.text = NSLocalizedString("COLOR_PICKER_SHEET_TITLE", comment: "Modal Sheet title when picking a conversation color.") - titleLabel.textAlignment = .center - titleLabel.font = UIFont.ows_dynamicTypeBody.ows_mediumWeight() - titleLabel.textColor = Theme.primaryColor - - headerView.addSubview(titleLabel) - titleLabel.ows_autoPinToSuperviewMargins() - - let bottomBorderView = UIView() - bottomBorderView.backgroundColor = Theme.hairlineColor - headerView.addSubview(bottomBorderView) - bottomBorderView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top) - bottomBorderView.autoSetDimension(.height, toSize: CGHairlineWidth()) - - return headerView - } - - private func updateMockConversationView() { - /* - conversationStyle.viewWidth = max(bounds.size.width, kMinimumConversationWidth) - mockConversationView.subviews.forEach { $0.removeFromSuperview() } - - // outgoing - outgoingMessageView = OWSMessageBubbleView(forAutoLayout: ()) - let outgoingItem = MockConversationViewItem() - let outgoingText = NSLocalizedString("COLOR_PICKER_DEMO_MESSAGE_1", comment: "The first of two messages demonstrating the chosen conversation color, by rendering this message in an outgoing message bubble.") - outgoingItem.interaction = MockOutgoingMessage(messageBody: outgoingText) - outgoingItem.displayableBodyText = DisplayableText.displayableText(outgoingText) - outgoingItem.interactionType = .outgoingMessage - - outgoingMessageView.viewItem = outgoingItem - outgoingMessageView.cellMediaCache = NSCache() - outgoingMessageView.conversationStyle = conversationStyle - outgoingMessageView.configureViews() - outgoingMessageView.loadContent() - let outgoingCell = UIView() - outgoingCell.addSubview(outgoingMessageView) - outgoingMessageView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .leading) - let outgoingSize = outgoingMessageView.measureSize() - outgoingMessageView.autoSetDimensions(to: outgoingSize) - - // incoming - incomingMessageView = OWSMessageBubbleView(forAutoLayout: ()) - let incomingItem = MockConversationViewItem() - let incomingText = NSLocalizedString("COLOR_PICKER_DEMO_MESSAGE_2", comment: "The second of two messages demonstrating the chosen conversation color, by rendering this message in an incoming message bubble.") - incomingItem.interaction = MockIncomingMessage(messageBody: incomingText) - incomingItem.displayableBodyText = DisplayableText.displayableText(incomingText) - incomingItem.interactionType = .incomingMessage - - incomingMessageView.viewItem = incomingItem - incomingMessageView.cellMediaCache = NSCache() - incomingMessageView.conversationStyle = conversationStyle - incomingMessageView.configureViews() - incomingMessageView.loadContent() - let incomingCell = UIView() - incomingCell.addSubview(incomingMessageView) - incomingMessageView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .trailing) - let incomingSize = incomingMessageView.measureSize() - incomingMessageView.autoSetDimensions(to: incomingSize) - - let messagesStackView = UIStackView(arrangedSubviews: [outgoingCell, incomingCell]) - messagesStackView.axis = .vertical - messagesStackView.spacing = 12 - - mockConversationView.addSubview(messagesStackView) - messagesStackView.autoPinEdgesToSuperviewMargins() - */ - } - - private func buildPaletteView(colorViews: [ColorView]) -> UIView { - let paletteView = UIView() - let paletteMargin = ScaleFromIPhone5(12) - paletteView.layoutMargins = UIEdgeInsets(top: paletteMargin, left: paletteMargin, bottom: 0, right: paletteMargin) - - let kRowLength = 4 - let rows: [UIView] = colorViews.chunked(by: kRowLength).map { colorViewsInRow in - let row = UIStackView(arrangedSubviews: colorViewsInRow) - row.distribution = UIStackView.Distribution.equalSpacing - return row - } - let rowsStackView = UIStackView(arrangedSubviews: rows) - rowsStackView.axis = .vertical - rowsStackView.spacing = ScaleFromIPhone5To7Plus(12, 30) - - paletteView.addSubview(rowsStackView) - rowsStackView.ows_autoPinToSuperviewMargins() - - // no-op gesture to keep taps from dismissing SheetView - paletteView.addGestureRecognizer(UITapGestureRecognizer(target: nil, action: nil)) - return paletteView - } -} - -// MARK: Mock Classes for rendering demo conversation - -/* -@objc -private class MockConversationViewItem: NSObject, ConversationViewItem { - var userCanDeleteGroupMessage: Bool = false - var isRSSFeed: Bool = false - var interaction: TSInteraction = TSMessage() - var interactionType: OWSInteractionType = OWSInteractionType.unknown - var quotedReply: OWSQuotedReplyModel? - var isGroupThread: Bool = false - var hasBodyText: Bool = true - var isQuotedReply: Bool = false - var hasQuotedAttachment: Bool = false - var hasQuotedText: Bool = false - var hasCellHeader: Bool = false - var isExpiringMessage: Bool = false - var shouldShowDate: Bool = false - var shouldShowSenderAvatar: Bool = false - var senderName: NSAttributedString? - var shouldHideFooter: Bool = false - var isFirstInCluster: Bool = true - var isLastInCluster: Bool = true - var unreadIndicator: OWSUnreadIndicator? - var lastAudioMessageView: OWSAudioMessageView? - var audioDurationSeconds: CGFloat = 0 - var audioProgressSeconds: CGFloat = 0 - var messageCellType: OWSMessageCellType = .textOnlyMessage - var displayableBodyText: DisplayableText? - var attachmentStream: TSAttachmentStream? - var attachmentPointer: TSAttachmentPointer? - var mediaSize: CGSize = .zero - var displayableQuotedText: DisplayableText? - var quotedAttachmentMimetype: String? - var quotedRecipientId: String? - var didCellMediaFailToLoad: Bool = false - var contactShare: ContactShareViewModel? - var systemMessageText: String? - var authorConversationColorName: String? - var hasBodyTextActionContent: Bool = false - var hasMediaActionContent: Bool = false - var mediaAlbumItems: [ConversationMediaAlbumItem]? - var hasCachedLayoutState: Bool = false - var linkPreview: OWSLinkPreview? - var linkPreviewAttachment: TSAttachment? - - override init() { - super.init() - } - - func itemId() -> String { - return interaction.uniqueId! - } - - func dequeueCell(for collectionView: UICollectionView, indexPath: IndexPath) -> ConversationViewCell { - owsFailDebug("unexpected invocation") - return ConversationViewCell(forAutoLayout: ()) - } - - func replace(_ interaction: TSInteraction, transaction: YapDatabaseReadTransaction) { - owsFailDebug("unexpected invocation") - return - } - - func clearCachedLayoutState() { - owsFailDebug("unexpected invocation") - return - } - - func copyMediaAction() { - owsFailDebug("unexpected invocation") - return - } - - func copyTextAction() { - owsFailDebug("unexpected invocation") - return - } - - func shareMediaAction() { - owsFailDebug("unexpected invocation") - return - } - - func shareTextAction() { - owsFailDebug("unexpected invocation") - return - } - - func saveMediaAction() { - owsFailDebug("unexpected invocation") - return - } - - func deleteAction() { - owsFailDebug("unexpected invocation") - return - } - - func canCopyMedia() -> Bool { - owsFailDebug("unexpected invocation") - return false - } - - func canSaveMedia() -> Bool { - owsFailDebug("unexpected invocation") - return false - } - - func audioPlaybackState() -> AudioPlaybackState { - owsFailDebug("unexpected invocation") - return AudioPlaybackState.paused - } - - func setAudioPlaybackState(_ state: AudioPlaybackState) { - owsFailDebug("unexpected invocation") - return - } - - func setAudioProgress(_ progress: CGFloat, duration: CGFloat) { - owsFailDebug("unexpected invocation") - return - } - - func cellSize() -> CGSize { - owsFailDebug("unexpected invocation") - return CGSize.zero - } - - func vSpacing(withPreviousLayoutItem previousLayoutItem: ConversationViewLayoutItem) -> CGFloat { - owsFailDebug("unexpected invocation") - return 2 - } - - func firstValidAlbumAttachment() -> TSAttachmentStream? { - owsFailDebug("unexpected invocation") - return nil - } - - func mediaAlbumHasFailedAttachment() -> Bool { - owsFailDebug("unexpected invocation") - return false - } -} - */ - -private class MockIncomingMessage: TSIncomingMessage { - init(messageBody: String) { - super.init(incomingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(), - in: TSThread(), - authorId: "+fake-id", - sourceDeviceId: 1, - messageBody: messageBody, - attachmentIds: [], - expiresInSeconds: 0, - quotedMessage: nil, - contactShare: nil, - linkPreview: nil, - serverTimestamp: nil, - wasReceivedByUD: false) - } - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - required init(dictionary dictionaryValue: [String: Any]!) throws { - fatalError("init(dictionary:) has not been implemented") - } - - override func save(with transaction: YapDatabaseReadWriteTransaction) { - // no - op - owsFailDebug("shouldn't save mock message") - } -} - -private class MockOutgoingMessage: TSOutgoingMessage { - init(messageBody: String) { - super.init(outgoingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(), - in: nil, - messageBody: messageBody, - attachmentIds: [], - expiresInSeconds: 0, - expireStartedAt: 0, - isVoiceMessage: false, - groupMetaMessage: .unspecified, - quotedMessage: nil, - contactShare: nil, - linkPreview: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - required init(dictionary dictionaryValue: [String: Any]!) throws { - fatalError("init(dictionary:) has not been implemented") - } - - override func save(with transaction: YapDatabaseReadWriteTransaction) { - // no - op - owsFailDebug("shouldn't save mock message") - } - - class MockOutgoingMessageRecipientState: TSOutgoingMessageRecipientState { - override var state: OWSOutgoingMessageRecipientState { - return OWSOutgoingMessageRecipientState.sent - } - - override var deliveryTimestamp: NSNumber? { - return NSNumber(value: NSDate.ows_millisecondTimeStamp()) - } - - override var readTimestamp: NSNumber? { - return NSNumber(value: NSDate.ows_millisecondTimeStamp()) - } - } - - override func readRecipientIds() -> [String] { - // makes message appear as read - return ["fake-non-empty-id"] - } - - override func recipientState(forRecipientId recipientId: String) -> TSOutgoingMessageRecipientState? { - return MockOutgoingMessageRecipientState() - } -} diff --git a/Session/Signal/ContactCell.swift b/Session/Signal/ContactCell.swift deleted file mode 100644 index 198b56350..000000000 --- a/Session/Signal/ContactCell.swift +++ /dev/null @@ -1,162 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import UIKit -import Contacts -import SignalUtilitiesKit - -class ContactCell: UITableViewCell { - - public static let kSeparatorHInset: CGFloat = CGFloat(kAvatarDiameter) + 16 + 8 - - static let kAvatarSpacing: CGFloat = 6 - static let kAvatarDiameter: UInt = 40 - - let contactImageView: AvatarImageView - let textStackView: UIStackView - let titleLabel: UILabel - var subtitleLabel: UILabel - - var contact: Contact? - var showsWhenSelected: Bool = false - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - self.contactImageView = AvatarImageView() - self.textStackView = UIStackView() - self.titleLabel = UILabel() - self.titleLabel.font = UIFont.ows_dynamicTypeBody - self.subtitleLabel = UILabel() - self.subtitleLabel.font = UIFont.ows_dynamicTypeSubheadline - - super.init(style: style, reuseIdentifier: reuseIdentifier) - - selectionStyle = UITableViewCell.SelectionStyle.none - - textStackView.axis = .vertical - textStackView.addArrangedSubview(titleLabel) - - contactImageView.autoSetDimensions(to: CGSize(width: CGFloat(ContactCell.kAvatarDiameter), height: CGFloat(ContactCell.kAvatarDiameter))) - - let contentColumns: UIStackView = UIStackView(arrangedSubviews: [contactImageView, textStackView]) - contentColumns.axis = .horizontal - contentColumns.spacing = ContactCell.kAvatarSpacing - contentColumns.alignment = .center - - self.contentView.addSubview(contentColumns) - contentColumns.autoPinEdgesToSuperviewMargins() - - NotificationCenter.default.addObserver(self, selector: #selector(self.didChangePreferredContentSize), name: UIContentSizeCategory.didChangeNotification, object: nil) - } - - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - override func prepareForReuse() { - accessoryType = .none - self.subtitleLabel.removeFromSuperview() - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - if showsWhenSelected { - accessoryType = selected ? .checkmark : .none - } - } - - @objc func didChangePreferredContentSize() { - self.titleLabel.font = UIFont.ows_dynamicTypeBody - self.subtitleLabel.font = UIFont.ows_dynamicTypeSubheadline - } - - func configure(contact: Contact, subtitleType: SubtitleCellValue, showsWhenSelected: Bool, contactsManager: OWSContactsManager) { - - OWSTableItem.configureCell(self) - - self.contact = contact - self.showsWhenSelected = showsWhenSelected - - self.titleLabel.textColor = Theme.primaryColor - self.subtitleLabel.textColor = Theme.secondaryColor - - let cnContact = contactsManager.cnContact(withId: contact.cnContactId) - titleLabel.attributedText = cnContact?.formattedFullName(font: titleLabel.font) - updateSubtitle(subtitleType: subtitleType, contact: contact) - - if let contactImage = contactsManager.avatarImage(forCNContactId: contact.cnContactId) { - contactImageView.image = contactImage - } else { - let contactIdForDeterminingBackgroundColor: String - if let signalId = contact.parsedPhoneNumbers.first?.toE164() { - contactIdForDeterminingBackgroundColor = signalId - } else { - contactIdForDeterminingBackgroundColor = contact.fullName - } - - let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contact.fullName, - colorSeed: contactIdForDeterminingBackgroundColor, - diameter: ContactCell.kAvatarDiameter) - - contactImageView.image = avatarBuilder.build() - } - } - - func updateSubtitle(subtitleType: SubtitleCellValue, contact: Contact) { - switch subtitleType { - case .none: - assert(self.subtitleLabel.superview == nil) - break - case .phoneNumber: - self.textStackView.addArrangedSubview(self.subtitleLabel) - - if let firstPhoneNumber = contact.userTextPhoneNumbers.first { - self.subtitleLabel.text = firstPhoneNumber - } else { - self.subtitleLabel.text = NSLocalizedString("CONTACT_PICKER_NO_PHONE_NUMBERS_AVAILABLE", comment: "table cell subtitle when contact card has no known phone number") - } - case .email: - self.textStackView.addArrangedSubview(self.subtitleLabel) - - if let firstEmail = contact.emails.first { - self.subtitleLabel.text = firstEmail - } else { - self.subtitleLabel.text = NSLocalizedString("CONTACT_PICKER_NO_EMAILS_AVAILABLE", comment: "table cell subtitle when contact card has no email") - } - } - } -} - -fileprivate extension CNContact { - /** - * Bold the sorting portion of the name. e.g. if we sort by family name, bold the family name. - */ - func formattedFullName(font: UIFont) -> NSAttributedString? { - let keyToHighlight = ContactSortOrder == .familyName ? CNContactFamilyNameKey : CNContactGivenNameKey - - let boldDescriptor = font.fontDescriptor.withSymbolicTraits(.traitBold) - let boldAttributes = [ - NSAttributedString.Key.font: UIFont(descriptor: boldDescriptor!, size: 0) - ] - - if let attributedName = CNContactFormatter.attributedString(from: self, style: .fullName, defaultAttributes: nil) { - let highlightedName = attributedName.mutableCopy() as! NSMutableAttributedString - highlightedName.enumerateAttributes(in: NSRange(location: 0, length: highlightedName.length), options: [], using: { (attrs, range, _) in - if let property = attrs[NSAttributedString.Key(rawValue: CNContactPropertyAttribute)] as? String, property == keyToHighlight { - highlightedName.addAttributes(boldAttributes, range: range) - } - }) - return highlightedName - } - - if let emailAddress = self.emailAddresses.first?.value { - return NSAttributedString(string: emailAddress as String, attributes: boldAttributes) - } - - if let phoneNumber = self.phoneNumbers.first?.value.stringValue { - return NSAttributedString(string: phoneNumber, attributes: boldAttributes) - } - - return nil - } -} diff --git a/Session/Signal/ContactShareViewHelper.swift b/Session/Signal/ContactShareViewHelper.swift deleted file mode 100644 index e0dfc6774..000000000 --- a/Session/Signal/ContactShareViewHelper.swift +++ /dev/null @@ -1,215 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit -import ContactsUI -import MessageUI - -@objc -public protocol ContactShareViewHelperDelegate: class { - func didCreateOrEditContact() -} - -@objc -public class ContactShareViewHelper: NSObject, CNContactViewControllerDelegate { - - @objc - weak var delegate: ContactShareViewHelperDelegate? - - let contactsManager: OWSContactsManager - - @objc - public required init(contactsManager: OWSContactsManager) { - AssertIsOnMainThread() - - self.contactsManager = contactsManager - - super.init() - } - - // MARK: Actions - - @objc - public func sendMessage(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - Logger.info("") - - presentThreadAndPeform(action: .compose, contactShare: contactShare, fromViewController: fromViewController) - } - - @objc - public func audioCall(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - Logger.info("") - - presentThreadAndPeform(action: .audioCall, contactShare: contactShare, fromViewController: fromViewController) - } - - @objc - public func videoCall(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - Logger.info("") - - presentThreadAndPeform(action: .videoCall, contactShare: contactShare, fromViewController: fromViewController) - } - - private func presentThreadAndPeform(action: ConversationViewAction, contactShare: ContactShareViewModel, fromViewController: UIViewController) { - // TODO: We're taking the first Signal account id. We might - // want to let the user select if there's more than one. - let phoneNumbers = contactShare.systemContactsWithSignalAccountPhoneNumbers(contactsManager) - guard phoneNumbers.count > 0 else { - owsFailDebug("missing Signal recipient id.") - return - } - guard phoneNumbers.count > 1 else { - let recipientId = phoneNumbers.first! - SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action, animated: true) - return - } - - showPhoneNumberPicker(phoneNumbers: phoneNumbers, fromViewController: fromViewController, completion: { (recipientId) in - SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action, animated: true) - }) - } - - @objc - public func showInviteContact(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - Logger.info("") - - guard MFMessageComposeViewController.canSendText() else { - Logger.info("Device cannot send text") - OWSAlerts.showErrorAlert(message: NSLocalizedString("UNSUPPORTED_FEATURE_ERROR", comment: "")) - return - } - let phoneNumbers = contactShare.e164PhoneNumbers() - guard phoneNumbers.count > 0 else { - owsFailDebug("no phone numbers.") - return - } - - let inviteFlow = InviteFlow(presentingViewController: fromViewController) - inviteFlow.sendSMSTo(phoneNumbers: phoneNumbers) - } - - @objc - func showAddToContacts(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - Logger.info("") - - let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("CONVERSATION_SETTINGS_NEW_CONTACT", - comment: "Label for 'new contact' button in conversation settings view."), - style: .default) { _ in - self.didPressCreateNewContact(contactShare: contactShare, fromViewController: fromViewController) - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("CONVERSATION_SETTINGS_ADD_TO_EXISTING_CONTACT", - comment: "Label for 'new contact' button in conversation settings view."), - style: .default) { _ in - self.didPressAddToExistingContact(contactShare: contactShare, fromViewController: fromViewController) - }) - actionSheet.addAction(OWSAlerts.cancelAction) - - fromViewController.presentAlert(actionSheet) - } - - private func showPhoneNumberPicker(phoneNumbers: [String], fromViewController: UIViewController, completion :@escaping ((String) -> Void)) { - - let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - - for phoneNumber in phoneNumbers { - actionSheet.addAction(UIAlertAction(title: PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber), - style: .default) { _ in - completion(phoneNumber) - }) - } - actionSheet.addAction(OWSAlerts.cancelAction) - - fromViewController.presentAlert(actionSheet) - } - - func didPressCreateNewContact(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - Logger.info("") - - presentNewContactView(contactShare: contactShare, fromViewController: fromViewController) - } - - func didPressAddToExistingContact(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - Logger.info("") - - presentSelectAddToExistingContactView(contactShare: contactShare, fromViewController: fromViewController) - } - - // MARK: - - - private func presentNewContactView(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - guard contactsManager.supportsContactEditing else { - owsFailDebug("Contact editing not supported") - return - } - - guard let systemContact = OWSContacts.systemContact(for: contactShare.dbRecord, imageData: contactShare.avatarImageData) else { - owsFailDebug("Could not derive system contact.") - return - } - - guard contactsManager.isSystemContactsAuthorized else { - ContactsViewHelper.presentMissingContactAccessAlertController(from: fromViewController) - return - } - - let contactViewController = CNContactViewController(forNewContact: systemContact) - contactViewController.delegate = self - contactViewController.allowsActions = false - contactViewController.allowsEditing = true - contactViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: CommonStrings.cancelButton, - style: .plain, - target: self, - action: #selector(didFinishEditingContact)) - - let modal = OWSNavigationController(rootViewController: contactViewController) - fromViewController.present(modal, animated: true) - } - - private func presentSelectAddToExistingContactView(contactShare: ContactShareViewModel, fromViewController: UIViewController) { - guard contactsManager.supportsContactEditing else { - owsFailDebug("Contact editing not supported") - return - } - - guard contactsManager.isSystemContactsAuthorized else { - ContactsViewHelper.presentMissingContactAccessAlertController(from: fromViewController) - return - } - - guard let navigationController = fromViewController.navigationController else { - owsFailDebug("missing navigationController") - return - } - - let viewController = AddContactShareToExistingContactViewController(contactShare: contactShare) - navigationController.pushViewController(viewController, animated: true) - } - - // MARK: - CNContactViewControllerDelegate - - @objc public func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) { - Logger.info("") - - guard let delegate = delegate else { - owsFailDebug("missing delegate") - return - } - - delegate.didCreateOrEditContact() - } - - @objc public func didFinishEditingContact() { - Logger.info("") - - guard let delegate = delegate else { - owsFailDebug("missing delegate") - return - } - - delegate.didCreateOrEditContact() - } -} diff --git a/Session/Signal/ContactViewController.swift b/Session/Signal/ContactViewController.swift deleted file mode 100644 index bc2e23836..000000000 --- a/Session/Signal/ContactViewController.swift +++ /dev/null @@ -1,679 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit -import SignalUtilitiesKit -import Reachability -import ContactsUI -import MessageUI - -class ContactViewController: OWSViewController, ContactShareViewHelperDelegate { - - enum ContactViewMode { - case systemContactWithSignal, - systemContactWithoutSignal, - nonSystemContact, - noPhoneNumber, - unknown - } - - private var hasLoadedView = false - - private var viewMode = ContactViewMode.unknown { - didSet { - AssertIsOnMainThread() - - if oldValue != viewMode && hasLoadedView { - updateContent() - } - } - } - - private let contactsManager: OWSContactsManager - - private var reachability: Reachability? - - private let contactShare: ContactShareViewModel - - private var contactShareViewHelper: ContactShareViewHelper - - private weak var postDismissNavigationController: UINavigationController? - - // MARK: - Initializers - - @available(*, unavailable, message: "use init(call:) constructor instead.") - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - @objc - required init(contactShare: ContactShareViewModel) { - contactsManager = Environment.shared.contactsManager - self.contactShare = contactShare - self.contactShareViewHelper = ContactShareViewHelper(contactsManager: contactsManager) - - super.init(nibName: nil, bundle: nil) - - contactShareViewHelper.delegate = self - - updateMode() - - NotificationCenter.default.addObserver(forName: .OWSContactsManagerSignalAccountsDidChange, object: nil, queue: nil) { [weak self] _ in - guard let strongSelf = self else { return } - strongSelf.updateMode() - } - - reachability = Reachability.forInternetConnection() - - NotificationCenter.default.addObserver(forName: .reachabilityChanged, object: nil, queue: nil) { [weak self] _ in - guard let strongSelf = self else { return } - strongSelf.updateMode() - } - } - - // MARK: - View Lifecycle - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - guard let navigationController = self.navigationController else { - owsFailDebug("navigationController was unexpectedly nil") - return - } - - // self.navigationController is nil in viewWillDisappear when transition via message/call buttons - // so we maintain our own reference to restore the navigation bars. - postDismissNavigationController = navigationController - navigationController.isNavigationBarHidden = true - - contactsManager.requestSystemContactsOnce(completion: { [weak self] _ in - guard let strongSelf = self else { return } - strongSelf.updateMode() - }) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - if self.presentedViewController == nil { - // No need to do this when we're disappearing due to a modal presentation. - // We'll eventually return to to this view and need to hide again. But also, there is a visible - // animation glitch where the navigation bar for this view controller starts to appear while - // the whole nav stack is about to be obscured by the modal we are presenting. - guard let postDismissNavigationController = self.postDismissNavigationController else { - owsFailDebug("postDismissNavigationController was unexpectedly nil") - return - } - - postDismissNavigationController.setNavigationBarHidden(false, animated: animated) - } - } - - override func loadView() { - super.loadView() - - self.view.preservesSuperviewLayoutMargins = false - self.view.backgroundColor = heroBackgroundColor() - - updateContent() - - hasLoadedView = true - } - - private func updateMode() { - AssertIsOnMainThread() - - guard contactShare.e164PhoneNumbers().count > 0 else { - viewMode = .noPhoneNumber - return - } - if systemContactsWithSignalAccountsForContact().count > 0 { - viewMode = .systemContactWithSignal - return - } - if systemContactsForContact().count > 0 { - viewMode = .systemContactWithoutSignal - return - } - - viewMode = .nonSystemContact - } - - private func systemContactsWithSignalAccountsForContact() -> [String] { - AssertIsOnMainThread() - - return contactShare.systemContactsWithSignalAccountPhoneNumbers(contactsManager) - } - - private func systemContactsForContact() -> [String] { - AssertIsOnMainThread() - - return contactShare.systemContactPhoneNumbers(contactsManager) - } - - private func updateContent() { - AssertIsOnMainThread() - - guard let rootView = self.view else { - owsFailDebug("missing root view.") - return - } - - for subview in rootView.subviews { - subview.removeFromSuperview() - } - - let topView = createTopView() - rootView.addSubview(topView) - topView.autoPinEdge(.top, to: .top, of: view) - topView.autoPinWidthToSuperview() - - // This view provides a background "below the fold". - let bottomView = UIView.container() - bottomView.backgroundColor = Theme.backgroundColor - self.view.addSubview(bottomView) - bottomView.layoutMargins = .zero - bottomView.autoPinWidthToSuperview() - bottomView.autoPinEdge(.top, to: .bottom, of: topView) - bottomView.autoPinEdge(toSuperviewEdge: .bottom) - - let scrollView = UIScrollView() - scrollView.preservesSuperviewLayoutMargins = false - self.view.addSubview(scrollView) - scrollView.layoutMargins = .zero - scrollView.autoPinWidthToSuperview() - scrollView.autoPinEdge(.top, to: .bottom, of: topView) - scrollView.autoPinEdge(toSuperviewEdge: .bottom) - - let fieldsView = createFieldsView() - - scrollView.addSubview(fieldsView) - fieldsView.autoPinLeadingToSuperviewMargin() - fieldsView.autoPinTrailingToSuperviewMargin() - fieldsView.autoPinEdge(toSuperviewEdge: .top) - fieldsView.autoPinEdge(toSuperviewEdge: .bottom) - } - - private func heroBackgroundColor() -> UIColor { - return (Theme.isDarkThemeEnabled - ? UIColor(rgbHex: 0x272727) - : UIColor(rgbHex: 0xefeff4)) - } - - private func createTopView() -> UIView { - AssertIsOnMainThread() - - let topView = UIView.container() - topView.backgroundColor = heroBackgroundColor() - topView.preservesSuperviewLayoutMargins = false - - // Back Button - let backButtonSize = CGFloat(50) - let backButton = TappableView(actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressDismiss() - }) - backButton.autoSetDimension(.width, toSize: backButtonSize) - backButton.autoSetDimension(.height, toSize: backButtonSize) - topView.addSubview(backButton) - backButton.autoPinEdge(toSuperviewEdge: .top) - backButton.autoPinLeadingToSuperviewMargin() - - let backIconName = (CurrentAppContext().isRTL ? "system_disclosure_indicator" : "system_disclosure_indicator_rtl") - guard let backIconImage = UIImage(named: backIconName) else { - owsFailDebug("missing icon.") - return topView - } - let backIconView = UIImageView(image: backIconImage.withRenderingMode(.alwaysTemplate)) - backIconView.contentMode = .scaleAspectFit - backIconView.tintColor = Theme.primaryColor.withAlphaComponent(0.6) - backButton.addSubview(backIconView) - backIconView.autoCenterInSuperview() - - let avatarSize: CGFloat = 100 - let avatarView = AvatarImageView() - avatarView.image = contactShare.getAvatarImage(diameter: avatarSize, contactsManager: contactsManager) - topView.addSubview(avatarView) - avatarView.autoPinEdge(toSuperviewEdge: .top, withInset: 20) - avatarView.autoHCenterInSuperview() - avatarView.autoSetDimension(.width, toSize: avatarSize) - avatarView.autoSetDimension(.height, toSize: avatarSize) - - let nameLabel = UILabel() - nameLabel.text = contactShare.displayName - nameLabel.font = UIFont.ows_dynamicTypeTitle1 - nameLabel.textColor = Theme.primaryColor - nameLabel.lineBreakMode = .byTruncatingTail - nameLabel.textAlignment = .center - topView.addSubview(nameLabel) - nameLabel.autoPinEdge(.top, to: .bottom, of: avatarView, withOffset: 10) - nameLabel.autoPinLeadingToSuperviewMargin(withInset: hMargin) - nameLabel.autoPinTrailingToSuperviewMargin(withInset: hMargin) - - var lastView: UIView = nameLabel - - for phoneNumber in systemContactsWithSignalAccountsForContact() { - let phoneNumberLabel = UILabel() - phoneNumberLabel.text = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber) - phoneNumberLabel.font = UIFont.ows_dynamicTypeFootnote - phoneNumberLabel.textColor = Theme.primaryColor - phoneNumberLabel.lineBreakMode = .byTruncatingTail - phoneNumberLabel.textAlignment = .center - topView.addSubview(phoneNumberLabel) - phoneNumberLabel.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 5) - phoneNumberLabel.autoPinLeadingToSuperviewMargin(withInset: hMargin) - phoneNumberLabel.autoPinTrailingToSuperviewMargin(withInset: hMargin) - lastView = phoneNumberLabel - } - - switch viewMode { - case .systemContactWithSignal: - // Show actions buttons for system contacts with a Signal account. - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.distribution = .fillEqually - stackView.addArrangedSubview(createCircleActionButton(text: NSLocalizedString("ACTION_SEND_MESSAGE", - comment: "Label for 'send message' button in contact view."), - imageName: "contact_view_message", - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressSendMessage() - })) - stackView.addArrangedSubview(createCircleActionButton(text: NSLocalizedString("ACTION_AUDIO_CALL", - comment: "Label for 'audio call' button in contact view."), - imageName: "contact_view_audio_call", - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressAudioCall() - })) - stackView.addArrangedSubview(createCircleActionButton(text: NSLocalizedString("ACTION_VIDEO_CALL", - comment: "Label for 'video call' button in contact view."), - imageName: "contact_view_video_call", - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressVideoCall() - })) - topView.addSubview(stackView) - stackView.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 20) - stackView.autoPinLeadingToSuperviewMargin(withInset: hMargin) - stackView.autoPinTrailingToSuperviewMargin(withInset: hMargin) - lastView = stackView - case .systemContactWithoutSignal: - // Show invite button for system contacts without a Signal account. - let inviteButton = createLargePillButton(text: NSLocalizedString("ACTION_INVITE", - comment: "Label for 'invite' button in contact view."), - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressInvite() - }) - topView.addSubview(inviteButton) - inviteButton.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 20) - inviteButton.autoPinLeadingToSuperviewMargin(withInset: 55) - inviteButton.autoPinTrailingToSuperviewMargin(withInset: 55) - lastView = inviteButton - case .nonSystemContact: - // Show no action buttons for non-system contacts. - break - case .noPhoneNumber: - // Show no action buttons for contacts without a phone number. - break - case .unknown: - let activityIndicator = UIActivityIndicatorView(style: .whiteLarge) - topView.addSubview(activityIndicator) - activityIndicator.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 10) - activityIndicator.autoHCenterInSuperview() - lastView = activityIndicator - break - } - - // Always show "add to contacts" button. - let addToContactsButton = createLargePillButton(text: NSLocalizedString("CONVERSATION_VIEW_ADD_TO_CONTACTS_OFFER", - comment: "Message shown in conversation view that offers to add an unknown user to your phone's contacts."), - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressAddToContacts() - }) - topView.addSubview(addToContactsButton) - addToContactsButton.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 20) - addToContactsButton.autoPinLeadingToSuperviewMargin(withInset: 55) - addToContactsButton.autoPinTrailingToSuperviewMargin(withInset: 55) - lastView = addToContactsButton - - lastView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 15) - - return topView - } - - private func createFieldsView() -> UIView { - AssertIsOnMainThread() - - var rows = [UIView]() - - // TODO: Not designed yet. -// if viewMode == .systemContactWithSignal || -// viewMode == .systemContactWithoutSignal { -// addRow(createActionRow(labelText:NSLocalizedString("ACTION_SHARE_CONTACT", -// comment:"Label for 'share contact' button."), -// action:#selector(didPressShareContact))) -// } - - if let organizationName = contactShare.name.organizationName?.ows_stripped() { - if (contactShare.name.hasAnyNamePart() && - organizationName.count > 0) { - rows.append(ContactFieldView.contactFieldView(forOrganizationName: organizationName, - layoutMargins: UIEdgeInsets(top: 5, left: hMargin, bottom: 5, right: hMargin))) - } - } - - for phoneNumber in contactShare.phoneNumbers { - rows.append(ContactFieldView.contactFieldView(forPhoneNumber: phoneNumber, - layoutMargins: UIEdgeInsets(top: 5, left: hMargin, bottom: 5, right: hMargin), - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressPhoneNumber(phoneNumber: phoneNumber) - })) - } - - for email in contactShare.emails { - rows.append(ContactFieldView.contactFieldView(forEmail: email, - layoutMargins: UIEdgeInsets(top: 5, left: hMargin, bottom: 5, right: hMargin), - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressEmail(email: email) - })) - } - - for address in contactShare.addresses { - rows.append(ContactFieldView.contactFieldView(forAddress: address, - layoutMargins: UIEdgeInsets(top: 5, left: hMargin, bottom: 5, right: hMargin), - actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressAddress(address: address) - })) - } - - return ContactFieldView(rows: rows, hMargin: hMargin) - } - - private let hMargin = CGFloat(16) - - private func createActionRow(labelText: String, action: Selector) -> UIView { - let row = UIView() - row.layoutMargins.left = 0 - row.layoutMargins.right = 0 - row.isUserInteractionEnabled = true - row.addGestureRecognizer(UITapGestureRecognizer(target: self, action: action)) - - let label = UILabel() - label.text = labelText - label.font = UIFont.ows_dynamicTypeBody - label.textColor = UIColor.ows_materialBlue - label.lineBreakMode = .byTruncatingTail - row.addSubview(label) - label.autoPinTopToSuperviewMargin() - label.autoPinBottomToSuperviewMargin() - label.autoPinLeadingToSuperviewMargin(withInset: hMargin) - label.autoPinTrailingToSuperviewMargin(withInset: hMargin) - - return row - } - - // TODO: Use real assets. - private func createCircleActionButton(text: String, imageName: String, actionBlock : @escaping () -> Void) -> UIView { - let buttonSize = CGFloat(50) - - let button = TappableView(actionBlock: actionBlock) - button.layoutMargins = .zero - button.autoSetDimension(.width, toSize: buttonSize, relation: .greaterThanOrEqual) - - let circleView = UIView() - circleView.backgroundColor = Theme.backgroundColor - circleView.autoSetDimension(.width, toSize: buttonSize) - circleView.autoSetDimension(.height, toSize: buttonSize) - circleView.layer.cornerRadius = buttonSize * 0.5 - button.addSubview(circleView) - circleView.autoPinEdge(toSuperviewEdge: .top) - circleView.autoHCenterInSuperview() - - guard let image = UIImage(named: imageName) else { - owsFailDebug("missing image.") - return button - } - let imageView = UIImageView(image: image.withRenderingMode(.alwaysTemplate)) - imageView.tintColor = Theme.primaryColor.withAlphaComponent(0.6) - circleView.addSubview(imageView) - imageView.autoCenterInSuperview() - - let label = UILabel() - label.text = text - label.font = UIFont.ows_dynamicTypeCaption2 - label.textColor = Theme.primaryColor - label.lineBreakMode = .byTruncatingTail - label.textAlignment = .center - button.addSubview(label) - label.autoPinEdge(.top, to: .bottom, of: circleView, withOffset: 3) - label.autoPinEdge(toSuperviewEdge: .bottom) - label.autoPinLeadingToSuperviewMargin() - label.autoPinTrailingToSuperviewMargin() - - return button - } - - private func createLargePillButton(text: String, actionBlock : @escaping () -> Void) -> UIView { - let button = TappableView(actionBlock: actionBlock) - button.backgroundColor = Theme.backgroundColor - button.layoutMargins = .zero - button.autoSetDimension(.height, toSize: 45) - button.layer.cornerRadius = 5 - - let label = UILabel() - label.text = text - label.font = UIFont.ows_dynamicTypeBody - label.textColor = UIColor.ows_materialBlue - label.lineBreakMode = .byTruncatingTail - label.textAlignment = .center - button.addSubview(label) - label.autoPinLeadingToSuperviewMargin(withInset: 20) - label.autoPinTrailingToSuperviewMargin(withInset: 20) - label.autoVCenterInSuperview() - label.autoPinEdge(toSuperviewEdge: .top, withInset: 0, relation: .greaterThanOrEqual) - label.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0, relation: .greaterThanOrEqual) - - return button - } - - func didPressShareContact(sender: UIGestureRecognizer) { - Logger.info("") - - guard sender.state == .recognized else { - return - } - // TODO: - } - - func didPressSendMessage() { - Logger.info("") - - self.contactShareViewHelper.sendMessage(contactShare: self.contactShare, fromViewController: self) - } - - func didPressAudioCall() { - Logger.info("") - - self.contactShareViewHelper.audioCall(contactShare: self.contactShare, fromViewController: self) - } - - func didPressVideoCall() { - Logger.info("") - - self.contactShareViewHelper.videoCall(contactShare: self.contactShare, fromViewController: self) - } - - func didPressInvite() { - Logger.info("") - - self.contactShareViewHelper.showInviteContact(contactShare: self.contactShare, fromViewController: self) - } - - func didPressAddToContacts() { - Logger.info("") - - self.contactShareViewHelper.showAddToContacts(contactShare: self.contactShare, fromViewController: self) - } - - func didPressDismiss() { - Logger.info("") - - guard let navigationController = self.navigationController else { - owsFailDebug("navigationController was unexpectedly nil") - return - } - - navigationController.popViewController(animated: true) - } - - func didPressPhoneNumber(phoneNumber: OWSContactPhoneNumber) { - Logger.info("") - - let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - - if let e164 = phoneNumber.tryToConvertToE164() { - if contactShare.systemContactsWithSignalAccountPhoneNumbers(contactsManager).contains(e164) { - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("ACTION_SEND_MESSAGE", - comment: "Label for 'send message' button in contact view."), - style: .default) { _ in - SignalApp.shared().presentConversation(forRecipientId: e164, action: .compose, animated: true) - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("ACTION_AUDIO_CALL", - comment: "Label for 'audio call' button in contact view."), - style: .default) { _ in - SignalApp.shared().presentConversation(forRecipientId: e164, action: .audioCall, animated: true) - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("ACTION_VIDEO_CALL", - comment: "Label for 'video call' button in contact view."), - style: .default) { _ in - SignalApp.shared().presentConversation(forRecipientId: e164, action: .videoCall, animated: true) - }) - } else { - // TODO: We could offer callPhoneNumberWithSystemCall. - } - } - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("EDIT_ITEM_COPY_ACTION", - comment: "Short name for edit menu item to copy contents of media message."), - style: .default) { _ in - UIPasteboard.general.string = phoneNumber.phoneNumber - }) - actionSheet.addAction(OWSAlerts.cancelAction) - presentAlert(actionSheet) - } - - func callPhoneNumberWithSystemCall(phoneNumber: OWSContactPhoneNumber) { - Logger.info("") - - guard let url = NSURL(string: "tel:\(phoneNumber.phoneNumber)") else { - owsFailDebug("could not open phone number.") - return - } - UIApplication.shared.openURL(url as URL) - } - - func didPressEmail(email: OWSContactEmail) { - Logger.info("") - - let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("CONTACT_VIEW_OPEN_EMAIL_IN_EMAIL_APP", - comment: "Label for 'open email in email app' button in contact view."), - style: .default) { [weak self] _ in - self?.openEmailInEmailApp(email: email) - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("EDIT_ITEM_COPY_ACTION", - comment: "Short name for edit menu item to copy contents of media message."), - style: .default) { _ in - UIPasteboard.general.string = email.email - }) - actionSheet.addAction(OWSAlerts.cancelAction) - presentAlert(actionSheet) - } - - func openEmailInEmailApp(email: OWSContactEmail) { - Logger.info("") - - guard let url = NSURL(string: "mailto:\(email.email)") else { - owsFailDebug("could not open email.") - return - } - UIApplication.shared.openURL(url as URL) - } - - func didPressAddress(address: OWSContactAddress) { - Logger.info("") - - let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("CONTACT_VIEW_OPEN_ADDRESS_IN_MAPS_APP", - comment: "Label for 'open address in maps app' button in contact view."), - style: .default) { [weak self] _ in - self?.openAddressInMaps(address: address) - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("EDIT_ITEM_COPY_ACTION", - comment: "Short name for edit menu item to copy contents of media message."), - style: .default) { [weak self] _ in - guard let strongSelf = self else { return } - - UIPasteboard.general.string = strongSelf.formatAddressForQuery(address: address) - }) - actionSheet.addAction(OWSAlerts.cancelAction) - presentAlert(actionSheet) - } - - func openAddressInMaps(address: OWSContactAddress) { - Logger.info("") - - let mapAddress = formatAddressForQuery(address: address) - guard let escapedMapAddress = mapAddress.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { - owsFailDebug("could not open address.") - return - } - // Note that we use "q" (i.e. query) rather than "address" since we can't assume - // this is a well-formed address. - guard let url = URL(string: "http://maps.apple.com/?q=\(escapedMapAddress)") else { - owsFailDebug("could not open address.") - return - } - - UIApplication.shared.openURL(url as URL) - } - - func formatAddressForQuery(address: OWSContactAddress) -> String { - Logger.info("") - - // Open address in Apple Maps app. - var addressParts = [String]() - let addAddressPart: ((String?) -> Void) = { (part) in - guard let part = part else { - return - } - guard part.count > 0 else { - return - } - addressParts.append(part) - } - addAddressPart(address.street) - addAddressPart(address.neighborhood) - addAddressPart(address.city) - addAddressPart(address.region) - addAddressPart(address.postcode) - addAddressPart(address.country) - return addressParts.joined(separator: ", ") - } - - // MARK: - ContactShareViewHelperDelegate - - public func didCreateOrEditContact() { - Logger.info("") - updateContent() - - self.dismiss(animated: true) - } -} diff --git a/Session/Signal/ContactsPicker.swift b/Session/Signal/ContactsPicker.swift deleted file mode 100644 index a2a3b2c98..000000000 --- a/Session/Signal/ContactsPicker.swift +++ /dev/null @@ -1,404 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -// Originally based on EPContacts -// -// Created by Prabaharan Elangovan on 12/10/15. -// Parts Copyright © 2015 Prabaharan Elangovan. All rights reserved - -import UIKit -import Contacts -import SignalUtilitiesKit - -@objc -public protocol ContactsPickerDelegate: class { - func contactsPicker(_: ContactsPicker, contactFetchDidFail error: NSError) - func contactsPickerDidCancel(_: ContactsPicker) - func contactsPicker(_: ContactsPicker, didSelectContact contact: Contact) - func contactsPicker(_: ContactsPicker, didSelectMultipleContacts contacts: [Contact]) - func contactsPicker(_: ContactsPicker, shouldSelectContact contact: Contact) -> Bool -} - -@objc -public enum SubtitleCellValue: Int { - case phoneNumber, email, none -} - -@objc -public class ContactsPicker: OWSViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate { - - var tableView: UITableView! - var searchBar: UISearchBar! - - // MARK: - Properties - - private let contactCellReuseIdentifier = "contactCellReuseIdentifier" - - private var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - - // HACK: Though we don't have an input accessory view, the VC we are presented above (ConversationVC) does. - // If the app is backgrounded and then foregrounded, when OWSWindowManager calls mainWindow.makeKeyAndVisible - // the ConversationVC's inputAccessoryView will appear *above* us unless we'd previously become first responder. - override public var canBecomeFirstResponder: Bool { - Logger.debug("") - return true - } - - override public func becomeFirstResponder() -> Bool { - Logger.debug("") - return super.becomeFirstResponder() - } - - override public func resignFirstResponder() -> Bool { - Logger.debug("") - return super.resignFirstResponder() - } - - private let collation = UILocalizedIndexedCollation.current() - public var collationForTests: UILocalizedIndexedCollation { - get { - return collation - } - } - private let contactStore = CNContactStore() - - // Data Source State - private lazy var sections = [[CNContact]]() - private lazy var filteredSections = [[CNContact]]() - private lazy var selectedContacts = [Contact]() - - // Configuration - @objc - public weak var contactsPickerDelegate: ContactsPickerDelegate? - private let subtitleCellType: SubtitleCellValue - private let allowsMultipleSelection: Bool - private let allowedContactKeys: [CNKeyDescriptor] = ContactsFrameworkContactStoreAdaptee.allowedContactKeys - - // MARK: - Initializers - - @objc - required public init(allowsMultipleSelection: Bool, subtitleCellType: SubtitleCellValue) { - self.allowsMultipleSelection = allowsMultipleSelection - self.subtitleCellType = subtitleCellType - super.init(nibName: nil, bundle: nil) - } - - required public init?(coder aDecoder: NSCoder) { - notImplemented() - } - - // MARK: - Lifecycle Methods - - override public func loadView() { - self.view = UIView() - let tableView = UITableView() - self.tableView = tableView - self.tableView.separatorColor = Theme.cellSeparatorColor - - view.addSubview(tableView) - tableView.autoPinEdge(toSuperviewEdge: .top) - tableView.autoPinEdge(toSuperviewEdge: .bottom) - tableView.autoPinEdge(toSuperviewSafeArea: .leading) - tableView.autoPinEdge(toSuperviewSafeArea: .trailing) - tableView.delegate = self - tableView.dataSource = self - - let searchBar = OWSSearchBar() - self.searchBar = searchBar - searchBar.delegate = self - searchBar.sizeToFit() - - tableView.tableHeaderView = searchBar - } - - override open func viewDidLoad() { - super.viewDidLoad() - - self.view.backgroundColor = Theme.backgroundColor - self.tableView.backgroundColor = Theme.backgroundColor - - searchBar.placeholder = NSLocalizedString("INVITE_FRIENDS_PICKER_SEARCHBAR_PLACEHOLDER", comment: "Search") - - // Auto size cells for dynamic type - tableView.estimatedRowHeight = 60.0 - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 60 - - tableView.allowsMultipleSelection = allowsMultipleSelection - - tableView.separatorInset = UIEdgeInsets(top: 0, left: ContactCell.kSeparatorHInset, bottom: 0, right: 16) - - registerContactCell() - initializeBarButtons() - reloadContacts() - updateSearchResults(searchText: "") - - NotificationCenter.default.addObserver(self, selector: #selector(self.didChangePreferredContentSize), name: UIContentSizeCategory.didChangeNotification, object: nil) - } - - @objc - public func didChangePreferredContentSize() { - self.tableView.reloadData() - } - - private func initializeBarButtons() { - let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(onTouchCancelButton)) - self.navigationItem.leftBarButtonItem = cancelButton - - if allowsMultipleSelection { - let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(onTouchDoneButton)) - self.navigationItem.rightBarButtonItem = doneButton - } - } - - private func registerContactCell() { - tableView.register(ContactCell.self, forCellReuseIdentifier: contactCellReuseIdentifier) - } - - // MARK: - Contact Operations - - private func reloadContacts() { - getContacts( onError: { error in - Logger.error("failed to reload contacts with error:\(error)") - }) - } - - private func getContacts(onError errorHandler: @escaping (_ error: Error) -> Void) { - switch CNContactStore.authorizationStatus(for: CNEntityType.contacts) { - case CNAuthorizationStatus.denied, CNAuthorizationStatus.restricted: - let title = NSLocalizedString("INVITE_FLOW_REQUIRES_CONTACT_ACCESS_TITLE", comment: "Alert title when contacts disabled while trying to invite contacts to signal") - let body = NSLocalizedString("INVITE_FLOW_REQUIRES_CONTACT_ACCESS_BODY", comment: "Alert body when contacts disabled while trying to invite contacts to signal") - - let alert = UIAlertController(title: title, message: body, preferredStyle: .alert) - - let dismissText = CommonStrings.cancelButton - - let cancelAction = UIAlertAction(title: dismissText, style: .cancel, handler: { _ in - let error = NSError(domain: "contactsPickerErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "No Contacts Access"]) - self.contactsPickerDelegate?.contactsPicker(self, contactFetchDidFail: error) - errorHandler(error) - }) - alert.addAction(cancelAction) - - let settingsText = CommonStrings.openSettingsButton - let openSettingsAction = UIAlertAction(title: settingsText, style: .default, handler: { (_) in - UIApplication.shared.openSystemSettings() - }) - alert.addAction(openSettingsAction) - - self.presentAlert(alert) - - case CNAuthorizationStatus.notDetermined: - //This case means the user is prompted for the first time for allowing contacts - contactStore.requestAccess(for: CNEntityType.contacts) { (granted, error) -> Void in - //At this point an alert is provided to the user to provide access to contacts. This will get invoked if a user responds to the alert - if granted { - self.getContacts(onError: errorHandler) - } else { - errorHandler(error!) - } - } - - case CNAuthorizationStatus.authorized: - //Authorization granted by user for this app. - var contacts = [CNContact]() - - do { - let contactFetchRequest = CNContactFetchRequest(keysToFetch: allowedContactKeys) - contactFetchRequest.sortOrder = .userDefault - try contactStore.enumerateContacts(with: contactFetchRequest) { (contact, _) -> Void in - contacts.append(contact) - } - self.sections = collatedContacts(contacts) - } catch let error as NSError { - Logger.error("Failed to fetch contacts with error:\(error)") - } - } - } - - func collatedContacts(_ contacts: [CNContact]) -> [[CNContact]] { - let selector: Selector = #selector(getter: CNContact.nameForCollating) - - var collated = Array(repeating: [CNContact](), count: collation.sectionTitles.count) - for contact in contacts { - let sectionNumber = collation.section(for: contact, collationStringSelector: selector) - collated[sectionNumber].append(contact) - } - return collated - } - - // MARK: - Table View DataSource - - open func numberOfSections(in tableView: UITableView) -> Int { - return self.collation.sectionTitles.count - } - - open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - let dataSource = filteredSections - - guard section < dataSource.count else { - return 0 - } - - return dataSource[section].count - } - - // MARK: - Table View Delegates - - open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: contactCellReuseIdentifier, for: indexPath) as? ContactCell else { - owsFailDebug("cell had unexpected type") - return UITableViewCell() - } - - let dataSource = filteredSections - let cnContact = dataSource[indexPath.section][indexPath.row] - let contact = Contact(systemContact: cnContact) - - cell.configure(contact: contact, subtitleType: subtitleCellType, showsWhenSelected: self.allowsMultipleSelection, contactsManager: self.contactsManager) - let isSelected = selectedContacts.contains(where: { $0.uniqueId == contact.uniqueId }) - cell.isSelected = isSelected - - // Make sure we preserve selection across tableView.reloadData which happens when toggling between - // search controller - if (isSelected) { - self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none) - } else { - self.tableView.deselectRow(at: indexPath, animated: false) - } - - return cell - } - - open func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { - let cell = tableView.cellForRow(at: indexPath) as! ContactCell - let deselectedContact = cell.contact! - - selectedContacts = selectedContacts.filter { - return $0.uniqueId != deselectedContact.uniqueId - } - } - - open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - Logger.verbose("") - - let cell = tableView.cellForRow(at: indexPath) as! ContactCell - let selectedContact = cell.contact! - - guard (contactsPickerDelegate == nil || contactsPickerDelegate!.contactsPicker(self, shouldSelectContact: selectedContact)) else { - self.tableView.deselectRow(at: indexPath, animated: false) - return - } - - selectedContacts.append(selectedContact) - - if !allowsMultipleSelection { - // Single selection code - self.contactsPickerDelegate?.contactsPicker(self, didSelectContact: selectedContact) - } - } - - open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { - return collation.section(forSectionIndexTitle: index) - } - - open func sectionIndexTitles(for tableView: UITableView) -> [String]? { - return collation.sectionIndexTitles - } - - open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - let dataSource = filteredSections - - guard section < dataSource.count else { - return nil - } - - // Don't show empty sections - if dataSource[section].count > 0 { - guard section < collation.sectionTitles.count else { - return nil - } - - return collation.sectionTitles[section] - } else { - return nil - } - } - - // MARK: - Button Actions - - @objc func onTouchCancelButton() { - contactsPickerDelegate?.contactsPickerDidCancel(self) - } - - @objc func onTouchDoneButton() { - contactsPickerDelegate?.contactsPicker(self, didSelectMultipleContacts: selectedContacts) - } - - // MARK: - Search Actions - open func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { - updateSearchResults(searchText: searchText) - } - - open func updateSearchResults(searchText: String) { - let predicate: NSPredicate - if searchText.isEmpty { - filteredSections = sections - } else { - do { - predicate = CNContact.predicateForContacts(matchingName: searchText) - let filteredContacts = try contactStore.unifiedContacts(matching: predicate, keysToFetch: allowedContactKeys) - filteredSections = collatedContacts(filteredContacts) - } catch let error as NSError { - Logger.error("updating search results failed with error: \(error)") - } - } - self.tableView.reloadData() - } -} - -let ContactSortOrder = computeSortOrder() - -func computeSortOrder() -> CNContactSortOrder { - let comparator = CNContact.comparator(forNameSortOrder: .userDefault) - - let contact0 = CNMutableContact() - contact0.givenName = "A" - contact0.familyName = "Z" - - let contact1 = CNMutableContact() - contact1.givenName = "Z" - contact1.familyName = "A" - - let result = comparator(contact0, contact1) - - if result == .orderedAscending { - return .givenName - } else { - return .familyName - } -} - -fileprivate extension CNContact { - /** - * Sorting Key used by collation - */ - @objc var nameForCollating: String { - get { - if self.familyName.isEmpty && self.givenName.isEmpty { - return self.emailAddresses.first?.value as String? ?? "" - } - - let compositeName: String - if ContactSortOrder == .familyName { - compositeName = "\(self.familyName) \(self.givenName)" - } else { - compositeName = "\(self.givenName) \(self.familyName)" - } - return compositeName.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - } - } -} diff --git a/Session/Signal/ConversationConfigurationSyncOperation.swift b/Session/Signal/ConversationConfigurationSyncOperation.swift deleted file mode 100644 index 0a47382b7..000000000 --- a/Session/Signal/ConversationConfigurationSyncOperation.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -class ConversationConfigurationSyncOperation: OWSOperation { - - enum ColorSyncOperationError: Error { - case assertionError(description: String) - } - - private var dbConnection: YapDatabaseConnection { - return OWSPrimaryStorage.shared().dbReadConnection - } - - private var messageSenderJobQueue: MessageSenderJobQueue { - return SSKEnvironment.shared.messageSenderJobQueue - } - - private var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - - private var syncManager: OWSSyncManagerProtocol { - return SSKEnvironment.shared.syncManager - } - - private let thread: TSThread - - @objc - public init(thread: TSThread) { - self.thread = thread - super.init() - } - - override public func run() { - if let contactThread = thread as? TSContactThread { - sync(contactThread: contactThread) - } else if let groupThread = thread as? TSGroupThread { - sync(groupThread: groupThread) - } else { - self.reportAssertionError(description: "unknown thread type") - } - } - - private func reportAssertionError(description: String) { - let error = ColorSyncOperationError.assertionError(description: description) - self.reportError(error) - } - - private func sync(contactThread: TSContactThread) { - guard let signalAccount: SignalAccount = self.contactsManager.fetchSignalAccount(forRecipientId: contactThread.contactIdentifier()) else { - reportAssertionError(description: "unable to find signalAccount") - return - } - - syncManager.syncContacts(for: [signalAccount]).retainUntilComplete() - } - - private func sync(groupThread: TSGroupThread) { - // TODO sync only the affected group - // The current implementation works, but seems wasteful. - // Does desktop handle single group sync correctly? - // What does Android do? - let syncMessage: OWSSyncGroupsMessage = OWSSyncGroupsMessage(groupThread: groupThread) - - var dataSource: DataSource? - self.dbConnection.read { transaction in - guard let messageData: Data = syncMessage.buildPlainTextAttachmentData(with: transaction) else { - owsFailDebug("could not serialize sync groups data") - return - } - dataSource = DataSourceValue.dataSource(withSyncMessageData: messageData) - } - - guard let attachmentDataSource = dataSource else { - self.reportAssertionError(description: "unable to build attachment data source") - return - } - - self.sendConfiguration(attachmentDataSource: attachmentDataSource, syncMessage: syncMessage) - } - - private func sendConfiguration(attachmentDataSource: DataSource, syncMessage: OWSOutgoingSyncMessage) { - self.messageSenderJobQueue.add(mediaMessage: syncMessage, - dataSource: attachmentDataSource, - contentType: OWSMimeTypeApplicationOctetStream, - sourceFilename: nil, - caption: nil, - albumMessageId: nil, - isTemporaryAttachment: true) - self.reportSuccess() - } - -} diff --git a/Session/Signal/ConversationView/Cells/ConversationViewCell.h b/Session/Signal/ConversationView/Cells/ConversationViewCell.h index d8617b62f..8d7c7fd17 100644 --- a/Session/Signal/ConversationView/Cells/ConversationViewCell.h +++ b/Session/Signal/ConversationView/Cells/ConversationViewCell.h @@ -35,23 +35,9 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - System Cell -- (void)tappedNonBlockingIdentityChangeForRecipientId:(nullable NSString *)signalId; -- (void)tappedInvalidIdentityKeyErrorMessage:(TSInvalidIdentityKeyErrorMessage *)errorMessage; - (void)tappedCorruptedMessage:(TSErrorMessage *)message; - (void)resendGroupUpdateForErrorMessage:(TSErrorMessage *)message; -- (void)showFingerprintWithRecipientId:(NSString *)recipientId; - (void)showConversationSettings; -- (void)handleCallTap:(TSCall *)call; - -#pragma mark - Offers - -- (void)tappedUnknownContactBlockOfferMessage:(OWSContactOffersInteraction *)interaction; -- (void)tappedAddToContactsOfferMessage:(OWSContactOffersInteraction *)interaction; -- (void)tappedAddToProfileWhitelistOfferMessage:(OWSContactOffersInteraction *)interaction; - -#pragma mark - Formatting - -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId; #pragma mark - Caching @@ -61,10 +47,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)didTapFailedOutgoingMessage:(TSOutgoingMessage *)message; -#pragma mark - Contacts - -- (OWSContactsManager *)contactsManager; - @end #pragma mark - diff --git a/Session/Signal/ConversationView/Cells/OWSContactOffersCell.h b/Session/Signal/ConversationView/Cells/OWSContactOffersCell.h deleted file mode 100644 index a06ca53e0..000000000 --- a/Session/Signal/ConversationView/Cells/OWSContactOffersCell.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "ConversationViewCell.h" - -NS_ASSUME_NONNULL_BEGIN - -@class OWSContactOffersInteraction; - -#pragma mark - - -@interface OWSContactOffersCell : ConversationViewCell - -+ (NSString *)cellReuseIdentifier; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/Cells/OWSContactOffersCell.m b/Session/Signal/ConversationView/Cells/OWSContactOffersCell.m deleted file mode 100644 index edb01c26f..000000000 --- a/Session/Signal/ConversationView/Cells/OWSContactOffersCell.m +++ /dev/null @@ -1,263 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSContactOffersCell.h" -#import "ConversationViewItem.h" -#import "Session-Swift.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSContactOffersCell () - -@property (nonatomic) UILabel *titleLabel; -@property (nonatomic) UIButton *addToContactsButton; -@property (nonatomic) UIButton *addToProfileWhitelistButton; -@property (nonatomic) UIButton *blockButton; -@property (nonatomic) NSArray *layoutConstraints; -@property (nonatomic) UIStackView *stackView; -@property (nonatomic) UIStackView *buttonStackView; - -@end - -#pragma mark - - -@implementation OWSContactOffersCell - -// `[UIView init]` invokes `[self initWithFrame:...]`. -- (instancetype)initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) { - [self commontInit]; - } - - return self; -} - -- (void)commontInit -{ - OWSAssertDebug(!self.titleLabel); - - self.layoutMargins = UIEdgeInsetsZero; - self.contentView.layoutMargins = UIEdgeInsetsZero; - self.layoutConstraints = @[]; - - self.titleLabel = [UILabel new]; - self.titleLabel.text = NSLocalizedString(@"CONVERSATION_VIEW_CONTACTS_OFFER_TITLE", - @"Title for the group of buttons show for unknown contacts offering to add them to contacts, etc."); - self.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail; - self.titleLabel.textAlignment = NSTextAlignmentCenter; - - self.addToContactsButton = [self - createButtonWithTitle: - NSLocalizedString(@"CONVERSATION_VIEW_ADD_TO_CONTACTS_OFFER", - @"Message shown in conversation view that offers to add an unknown user to your phone's contacts.") - selector:@selector(addToContacts)]; - self.addToProfileWhitelistButton = [self - createButtonWithTitle:NSLocalizedString(@"CONVERSATION_VIEW_ADD_USER_TO_PROFILE_WHITELIST_OFFER", - @"Message shown in conversation view that offers to share your profile with a user.") - selector:@selector(addToProfileWhitelist)]; - self.blockButton = - [self createButtonWithTitle:NSLocalizedString(@"CONVERSATION_VIEW_UNKNOWN_CONTACT_BLOCK_OFFER", - @"Message shown in conversation view that offers to block an unknown user.") - selector:@selector(block)]; - - UIStackView *buttonStackView = [[UIStackView alloc] initWithArrangedSubviews:self.buttons]; - buttonStackView.axis = UILayoutConstraintAxisVertical; - buttonStackView.spacing = self.vSpacing; - self.buttonStackView = buttonStackView; - - self.stackView = [[UIStackView alloc] initWithArrangedSubviews:@[ - self.titleLabel, - buttonStackView, - ]]; - self.stackView.axis = UILayoutConstraintAxisVertical; - self.stackView.spacing = self.vSpacing; - self.stackView.alignment = UIStackViewAlignmentCenter; - [self.contentView addSubview:self.stackView]; -} - -- (void)configureFonts -{ - self.titleLabel.font = UIFont.ows_dynamicTypeSubheadlineFont; - - UIFont *buttonFont = UIFont.ows_dynamicTypeSubheadlineFont.ows_mediumWeight; - self.addToContactsButton.titleLabel.font = buttonFont; - self.addToProfileWhitelistButton.titleLabel.font = buttonFont; - self.blockButton.titleLabel.font = buttonFont; -} - -- (UIButton *)createButtonWithTitle:(NSString *)title selector:(SEL)selector -{ - UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; - [button setTitle:title forState:UIControlStateNormal]; - button.titleLabel.textAlignment = NSTextAlignmentCenter; - button.layer.cornerRadius = 4.f; - [button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside]; - button.contentEdgeInsets = UIEdgeInsetsMake(0, 10.f, 0, 10.f); - return button; -} - -+ (NSString *)cellReuseIdentifier -{ - return NSStringFromClass([self class]); -} - -- (void)loadForDisplay -{ - OWSAssertDebug(self.conversationStyle); - OWSAssertDebug(self.conversationStyle.viewWidth > 0); - OWSAssertDebug(self.viewItem); - OWSAssertDebug([self.viewItem.interaction isKindOfClass:[OWSContactOffersInteraction class]]); - - self.backgroundColor = [Theme backgroundColor]; - - [self configureFonts]; - - self.titleLabel.textColor = Theme.secondaryColor; - for (UIButton *button in self.buttons) { - [button setTitleColor:[UIColor ows_signalBlueColor] forState:UIControlStateNormal]; - [button setBackgroundColor:Theme.conversationButtonBackgroundColor]; - } - - OWSContactOffersInteraction *interaction = (OWSContactOffersInteraction *)self.viewItem.interaction; - - OWSAssertDebug( - interaction.hasBlockOffer || interaction.hasAddToContactsOffer || interaction.hasAddToProfileWhitelistOffer); - - self.addToContactsButton.hidden = !interaction.hasAddToContactsOffer; - self.addToProfileWhitelistButton.hidden = !interaction.hasAddToProfileWhitelistOffer; - self.blockButton.hidden = !interaction.hasBlockOffer; - - [NSLayoutConstraint deactivateConstraints:self.layoutConstraints]; - self.layoutConstraints = @[ - [self.addToContactsButton autoSetDimension:ALDimensionHeight toSize:self.buttonHeight], - [self.addToProfileWhitelistButton autoSetDimension:ALDimensionHeight toSize:self.buttonHeight], - [self.blockButton autoSetDimension:ALDimensionHeight toSize:self.buttonHeight], - - [self.stackView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.topVMargin], - [self.stackView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.bottomVMargin], - [self.stackView autoPinEdgeToSuperviewEdge:ALEdgeLeading - withInset:self.conversationStyle.fullWidthGutterLeading], - [self.stackView autoPinEdgeToSuperviewEdge:ALEdgeTrailing - withInset:self.conversationStyle.fullWidthGutterTrailing], - ]; - - // This hack fixes a bug that I don't understand. - // - // On an iPhone 5C running iOS 10.3.3, - // - // * Alice is a contact for which we should show some but not all contact offer buttons. - // * Delete thread with Alice. - // * Send yourself a message from Alice. - // * Open conversation with Alice. - // - // Expected: Some (but not all) offer buttons are displayed. - // Observed: All offer buttons are displayed, in a cramped layout. - for (UIButton *button in self.buttons) { - [button removeFromSuperview]; - } - for (UIButton *button in self.buttons) { - if (!button.hidden) { - [self.buttonStackView addArrangedSubview:button]; - } - } -} - -- (NSArray *)buttons -{ - return @[ - self.addToContactsButton, - self.addToProfileWhitelistButton, - self.blockButton, - ]; -} - -- (CGFloat)topVMargin -{ - return 0.f; -} - -- (CGFloat)bottomVMargin -{ - return 0.f; -} - -- (CGFloat)vSpacing -{ - return 8.f; -} - -- (CGFloat)buttonHeight -{ - return (24.f + self.addToContactsButton.titleLabel.font.lineHeight); -} - -- (CGSize)cellSize -{ - OWSAssertDebug(self.conversationStyle); - OWSAssertDebug(self.conversationStyle.viewWidth > 0); - OWSAssertDebug(self.viewItem); - OWSAssertDebug([self.viewItem.interaction isKindOfClass:[OWSContactOffersInteraction class]]); - - [self configureFonts]; - - OWSContactOffersInteraction *interaction = (OWSContactOffersInteraction *)self.viewItem.interaction; - - CGSize result = CGSizeMake(self.conversationStyle.viewWidth, 0); - result.height += self.topVMargin; - result.height += self.bottomVMargin; - - result.height += ceil([self.titleLabel sizeThatFits:CGSizeZero].height); - - int buttonCount = ((interaction.hasBlockOffer ? 1 : 0) + (interaction.hasAddToContactsOffer ? 1 : 0) - + (interaction.hasAddToProfileWhitelistOffer ? 1 : 0)); - result.height += buttonCount * (self.vSpacing + self.buttonHeight); - - return result; -} - -#pragma mark - Events - -- (nullable OWSContactOffersInteraction *)interaction -{ - OWSAssertDebug(self.viewItem); - OWSAssertDebug(self.viewItem.interaction); - if (![self.viewItem.interaction isKindOfClass:[OWSContactOffersInteraction class]]) { - OWSFailDebug(@"expected OWSContactOffersInteraction but found: %@", self.viewItem.interaction); - return nil; - } - return (OWSContactOffersInteraction *)self.viewItem.interaction; -} - -- (void)addToContacts -{ - OWSAssertDebug(self.delegate); - OWSAssertDebug(self.interaction); - - [self.delegate tappedAddToContactsOfferMessage:self.interaction]; -} - -- (void)addToProfileWhitelist -{ - OWSAssertDebug(self.delegate); - OWSAssertDebug(self.interaction); - - [self.delegate tappedAddToProfileWhitelistOfferMessage:self.interaction]; -} - -- (void)block -{ - OWSAssertDebug(self.delegate); - OWSAssertDebug(self.interaction); - - [self.delegate tappedUnknownContactBlockOfferMessage:self.interaction]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.h b/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.h deleted file mode 100644 index 4997ef985..000000000 --- a/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class ContactShareViewModel; - -@protocol OWSContactShareButtonsViewDelegate - -- (void)didTapSendMessageToContactShare:(ContactShareViewModel *)contactShare; -- (void)didTapSendInviteToContactShare:(ContactShareViewModel *)contactShare; -- (void)didTapShowAddToContactUIForContactShare:(ContactShareViewModel *)contactShare; - -@end - -#pragma mark - - -@interface OWSContactShareButtonsView : UIView - -- (instancetype)initWithContactShare:(ContactShareViewModel *)contactShare - delegate:(id)delegate; - -+ (CGFloat)bubbleHeight; - -// Returns YES IFF the tap was handled. -- (BOOL)handleTapGesture:(UITapGestureRecognizer *)sender; - -+ (BOOL)hasAnyButton:(ContactShareViewModel *)contactShare; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.m b/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.m deleted file mode 100644 index 782b81925..000000000 --- a/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.m +++ /dev/null @@ -1,169 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSContactShareButtonsView.h" -#import "Session-Swift.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSContactShareButtonsView () - -@property (nonatomic, readonly) ContactShareViewModel *contactShare; -@property (nonatomic, weak) id delegate; - -@property (nonatomic, readonly) OWSContactsManager *contactsManager; - -@property (nonatomic, nullable) UIView *buttonView; - -@end - -#pragma mark - - -@implementation OWSContactShareButtonsView - -- (instancetype)initWithContactShare:(ContactShareViewModel *)contactShare - delegate:(id)delegate -{ - self = [super init]; - - if (self) { - _delegate = delegate; - _contactShare = contactShare; - _contactsManager = Environment.shared.contactsManager; - - [self createContents]; - } - - return self; -} - -#pragma mark - - -+ (BOOL)hasSendTextButton:(ContactShareViewModel *)contactShare contactsManager:(OWSContactsManager *)contactsManager -{ - OWSAssertDebug(contactShare); - OWSAssertDebug(contactsManager); - - return [contactShare systemContactsWithSignalAccountPhoneNumbers:contactsManager].count > 0; -} - -+ (BOOL)hasInviteButton:(ContactShareViewModel *)contactShare contactsManager:(OWSContactsManager *)contactsManager -{ - OWSAssertDebug(contactShare); - OWSAssertDebug(contactsManager); - - return [contactShare systemContactPhoneNumbers:contactsManager].count > 0; -} - -+ (BOOL)hasAddToContactsButton:(ContactShareViewModel *)contactShare -{ - OWSAssertDebug(contactShare); - - return [contactShare e164PhoneNumbers].count > 0; -} - -+ (BOOL)hasAnyButton:(ContactShareViewModel *)contactShare -{ - OWSAssertDebug(contactShare); - - OWSContactsManager *contactsManager = Environment.shared.contactsManager; - - return [self hasAnyButton:contactShare contactsManager:contactsManager]; -} - -+ (BOOL)hasAnyButton:(ContactShareViewModel *)contactShare contactsManager:(OWSContactsManager *)contactsManager -{ - OWSAssertDebug(contactShare); - - return ([self hasSendTextButton:contactShare contactsManager:contactsManager] || - [self hasInviteButton:contactShare contactsManager:contactsManager] || - [self hasAddToContactsButton:contactShare]); -} - -+ (CGFloat)bubbleHeight -{ - return self.buttonHeight; -} - -+ (CGFloat)buttonHeight -{ - return MAX(44.f, self.buttonFont.lineHeight + self.buttonVMargin * 2); -} - -+ (UIFont *)buttonFont -{ - return [UIFont ows_dynamicTypeBodyFont].ows_mediumWeight; -} - -+ (CGFloat)buttonVMargin -{ - return 5; -} - -- (void)createContents -{ - OWSAssertDebug([OWSContactShareButtonsView hasAnyButton:self.contactShare contactsManager:self.contactsManager]); - - self.layoutMargins = UIEdgeInsetsZero; - self.backgroundColor = Theme.conversationButtonBackgroundColor; - - UILabel *label = [UILabel new]; - self.buttonView = label; - if ([OWSContactShareButtonsView hasSendTextButton:self.contactShare contactsManager:self.contactsManager]) { - label.text - = NSLocalizedString(@"ACTION_SEND_MESSAGE", @"Label for button that lets you send a message to a contact."); - } else if ([OWSContactShareButtonsView hasInviteButton:self.contactShare contactsManager:self.contactsManager]) { - label.text = NSLocalizedString(@"ACTION_INVITE", @"Label for 'invite' button in contact view."); - } else if ([OWSContactShareButtonsView hasAddToContactsButton:self.contactShare]) { - label.text = NSLocalizedString(@"CONVERSATION_VIEW_ADD_TO_CONTACTS_OFFER", - @"Message shown in conversation view that offers to add an unknown user to your phone's contacts."); - } else { - OWSFailDebug(@"unexpected button state."); - } - label.font = OWSContactShareButtonsView.buttonFont; - label.textColor = (Theme.isDarkThemeEnabled ? UIColor.ows_whiteColor : UIColor.ows_materialBlueColor); - label.textAlignment = NSTextAlignmentCenter; - [self addSubview:label]; - [label ows_autoPinToSuperviewEdges]; - [label autoSetDimension:ALDimensionHeight toSize:OWSContactShareButtonsView.buttonHeight]; - - self.userInteractionEnabled = YES; - UITapGestureRecognizer *tap = - [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; - [self addGestureRecognizer:tap]; -} - -- (BOOL)handleTapGesture:(UITapGestureRecognizer *)sender -{ - if (!self.buttonView) { - return NO; - } - CGPoint location = [sender locationInView:self.buttonView]; - if (!CGRectContainsPoint(self.buttonView.bounds, location)) { - return NO; - } - - if ([OWSContactShareButtonsView hasSendTextButton:self.contactShare contactsManager:self.contactsManager]) { - [self.delegate didTapSendMessageToContactShare:self.contactShare]; - } else if ([OWSContactShareButtonsView hasInviteButton:self.contactShare contactsManager:self.contactsManager]) { - [self.delegate didTapSendInviteToContactShare:self.contactShare]; - } else if ([OWSContactShareButtonsView hasAddToContactsButton:self.contactShare]) { - [self.delegate didTapShowAddToContactUIForContactShare:self.contactShare]; - } else { - OWSFailDebug(@"unexpected button tap."); - } - - return YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/Cells/OWSContactShareView.h b/Session/Signal/ConversationView/Cells/OWSContactShareView.h deleted file mode 100644 index b8cab42bc..000000000 --- a/Session/Signal/ConversationView/Cells/OWSContactShareView.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class ContactShareViewModel; -@class ConversationStyle; - -@interface OWSContactShareView : UIView - -- (instancetype)initWithContactShare:(ContactShareViewModel *)contactShare - isIncoming:(BOOL)isIncoming - conversationStyle:(ConversationStyle *)conversationStyle; - -- (void)createContents; - -+ (CGFloat)bubbleHeight; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/Cells/OWSContactShareView.m b/Session/Signal/ConversationView/Cells/OWSContactShareView.m deleted file mode 100644 index fad2ee026..000000000 --- a/Session/Signal/ConversationView/Cells/OWSContactShareView.m +++ /dev/null @@ -1,165 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSContactShareView.h" -#import "OWSContactAvatarBuilder.h" -#import "Session-Swift.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSContactShareView () - -@property (nonatomic, readonly) ContactShareViewModel *contactShare; - -@property (nonatomic, readonly) BOOL isIncoming; -@property (nonatomic, readonly) ConversationStyle *conversationStyle; -@property (nonatomic, readonly) OWSContactsManager *contactsManager; - -@end - -#pragma mark - - -@implementation OWSContactShareView - -- (instancetype)initWithContactShare:(ContactShareViewModel *)contactShare - isIncoming:(BOOL)isIncoming - conversationStyle:(ConversationStyle *)conversationStyle -{ - self = [super init]; - - if (self) { - _contactShare = contactShare; - _isIncoming = isIncoming; - _conversationStyle = conversationStyle; - _contactsManager = Environment.shared.contactsManager; - } - - return self; -} - -#pragma mark - - -- (CGFloat)hMargin -{ - return 12.f; -} - -+ (CGFloat)vMargin -{ - return 0.f; -} - -- (CGFloat)iconHSpacing -{ - return 8.f; -} - -+ (CGFloat)bubbleHeight -{ - return self.contentHeight; -} - -+ (CGFloat)contentHeight -{ - CGFloat labelsHeight = (self.nameFont.lineHeight + self.labelsVSpacing + self.subtitleFont.lineHeight); - CGFloat contentHeight = MAX(self.iconSize, labelsHeight); - contentHeight += OWSContactShareView.vMargin * 2; - return contentHeight; -} - -+ (CGFloat)iconSize -{ - return kStandardAvatarSize; -} - -- (CGFloat)iconSize -{ - return [OWSContactShareView iconSize]; -} - -+ (UIFont *)nameFont -{ - return [UIFont ows_dynamicTypeBodyFont]; -} - -+ (UIFont *)subtitleFont -{ - return [UIFont ows_dynamicTypeCaption1Font]; -} - -+ (CGFloat)labelsVSpacing -{ - return 2; -} - -- (void)createContents -{ - self.layoutMargins = UIEdgeInsetsZero; - - UIColor *textColor = [self.conversationStyle bubbleTextColorWithIsIncoming:self.isIncoming]; - - AvatarImageView *avatarView = [AvatarImageView new]; - avatarView.image = - [self.contactShare getAvatarImageWithDiameter:self.iconSize contactsManager:self.contactsManager]; - - [avatarView autoSetDimension:ALDimensionWidth toSize:self.iconSize]; - [avatarView autoSetDimension:ALDimensionHeight toSize:self.iconSize]; - [avatarView setCompressionResistanceHigh]; - [avatarView setContentHuggingHigh]; - - UILabel *topLabel = [UILabel new]; - topLabel.text = self.contactShare.displayName; - topLabel.textColor = textColor; - topLabel.lineBreakMode = NSLineBreakByTruncatingTail; - topLabel.font = OWSContactShareView.nameFont; - - UIStackView *labelsView = [UIStackView new]; - labelsView.axis = UILayoutConstraintAxisVertical; - labelsView.spacing = OWSContactShareView.labelsVSpacing; - [labelsView addArrangedSubview:topLabel]; - - NSString *_Nullable firstPhoneNumber = - [self.contactShare systemContactsWithSignalAccountPhoneNumbers:self.contactsManager].firstObject; - if (firstPhoneNumber.length > 0) { - UILabel *bottomLabel = [UILabel new]; - bottomLabel.text = [PhoneNumber bestEffortLocalizedPhoneNumberWithE164:firstPhoneNumber]; - bottomLabel.textColor = [self.conversationStyle bubbleSecondaryTextColorWithIsIncoming:self.isIncoming]; - bottomLabel.lineBreakMode = NSLineBreakByTruncatingTail; - bottomLabel.font = OWSContactShareView.subtitleFont; - [labelsView addArrangedSubview:bottomLabel]; - } - - UIImage *disclosureImage = - [UIImage imageNamed:(CurrentAppContext().isRTL ? @"small_chevron_left" : @"small_chevron_right")]; - OWSAssertDebug(disclosureImage); - UIImageView *disclosureImageView = [UIImageView new]; - disclosureImageView.image = [disclosureImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; - disclosureImageView.tintColor = textColor; - [disclosureImageView setCompressionResistanceHigh]; - [disclosureImageView setContentHuggingHigh]; - - UIStackView *hStackView = [UIStackView new]; - hStackView.axis = UILayoutConstraintAxisHorizontal; - hStackView.spacing = self.iconHSpacing; - hStackView.alignment = UIStackViewAlignmentCenter; - hStackView.layoutMarginsRelativeArrangement = YES; - hStackView.layoutMargins - = UIEdgeInsetsMake(OWSContactShareView.vMargin, self.hMargin, OWSContactShareView.vMargin, self.hMargin); - [hStackView addArrangedSubview:avatarView]; - [hStackView addArrangedSubview:labelsView]; - [hStackView addArrangedSubview:disclosureImageView]; - [self addSubview:hStackView]; - [hStackView ows_autoPinToSuperviewEdges]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m index b6b695c43..5782c329d 100644 --- a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m +++ b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m @@ -7,7 +7,7 @@ #import "Session-Swift.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" -#import "ViewControllerUtils.h" + #import #import #import @@ -91,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN - (CGFloat)iconHeight { - return kStandardAvatarSize; + return 48.0f; } - (void)createContentsWithConversationStyle:(ConversationStyle *)conversationStyle diff --git a/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.h b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.h index ba63b6774..4db47bec3 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.h +++ b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.h @@ -49,15 +49,6 @@ typedef NS_ENUM(NSUInteger, OWSMessageGestureLocation) { - (void)didTapConversationItem:(id)viewItem linkPreview:(OWSLinkPreview *)linkPreview; -- (void)didTapContactShareViewItem:(id)viewItem; - -- (void)didTapSendMessageToContactShare:(ContactShareViewModel *)contactShare - NS_SWIFT_NAME(didTapSendMessage(toContactShare:)); -- (void)didTapSendInviteToContactShare:(ContactShareViewModel *)contactShare - NS_SWIFT_NAME(didTapSendInvite(toContactShare:)); -- (void)didTapShowAddToContactUIForContactShare:(ContactShareViewModel *)contactShare - NS_SWIFT_NAME(didTapShowAddToContactUI(forContactShare:)); - @property (nonatomic, readonly, nullable) NSString *lastSearchedText; @end diff --git a/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m index 9ec3201a5..8c736cee4 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m @@ -7,8 +7,6 @@ #import "ConversationViewItem.h" #import "OWSBubbleShapeView.h" #import "OWSBubbleView.h" -#import "OWSContactShareButtonsView.h" -#import "OWSContactShareView.h" #import "OWSGenericAttachmentView.h" #import "OWSLabel.h" #import "OWSMessageFooterView.h" @@ -20,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface OWSMessageBubbleView () +@interface OWSMessageBubbleView () @property (nonatomic) OWSBubbleView *bubbleView; @@ -48,8 +46,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) OWSMessageFooterView *footerView; -@property (nonatomic, nullable) OWSContactShareButtonsView *contactShareButtonsView; - @end #pragma mark - @@ -267,9 +263,6 @@ NS_ASSUME_NONNULL_BEGIN case OWSMessageCellType_GenericAttachment: bodyMediaView = [self loadViewForGenericAttachment]; break; - case OWSMessageCellType_ContactShare: - bodyMediaView = [self loadViewForContactShare]; - break; case OWSMessageCellType_MediaMessage: bodyMediaView = [self loadViewForMediaAlbum]; break; @@ -300,24 +293,6 @@ NS_ASSUME_NONNULL_BEGIN if (self.hasBodyMediaWithThumbnail) { [self.stackView addArrangedSubview:bodyMediaView]; - } else { - OWSAssertDebug(self.cellType == OWSMessageCellType_ContactShare); - - if (self.contactShareHasSpacerTop) { - UIView *spacerView = [UIView containerView]; - [spacerView autoSetDimension:ALDimensionHeight toSize:self.contactShareVSpacing]; - [spacerView setCompressionResistanceHigh]; - [self.stackView addArrangedSubview:spacerView]; - } - - [self.stackView addArrangedSubview:bodyMediaView]; - - if (self.contactShareHasSpacerBottom) { - UIView *spacerView = [UIView containerView]; - [spacerView autoSetDimension:ALDimensionHeight toSize:self.contactShareVSpacing]; - [spacerView setCompressionResistanceHigh]; - [self.stackView addArrangedSubview:spacerView]; - } } } else { [textViews addObject:bodyMediaView]; @@ -414,86 +389,11 @@ NS_ASSUME_NONNULL_BEGIN addObject:[bodyMediaView autoSetDimension:ALDimensionHeight toSize:bodyMediaSize.CGSizeValue.height]]; } - [self insertContactShareButtonsIfNecessary]; - [self updateBubbleColor]; [self configureBubbleRounding]; } -- (void)insertContactShareButtonsIfNecessary -{ - if (self.cellType != OWSMessageCellType_ContactShare) { - return; - } - - if (![OWSContactShareButtonsView hasAnyButton:self.viewItem.contactShare]) { - return; - } - - OWSAssertDebug(self.viewItem.contactShare); - - OWSContactShareButtonsView *buttonsView = - [[OWSContactShareButtonsView alloc] initWithContactShare:self.viewItem.contactShare delegate:self]; - - NSValue *_Nullable actionButtonsSize = [self actionButtonsSize]; - OWSAssertDebug(actionButtonsSize); - [self.viewConstraints addObjectsFromArray:@[ - [buttonsView autoSetDimension:ALDimensionHeight toSize:actionButtonsSize.CGSizeValue.height], - ]]; - - // The "contact share" view casts a shadow "downward" onto adjacent views, - // so we use a "proxy" view to take its place within the v-stack - // view and then insert the "contact share" view above its proxy so that - // it floats above the other content of the bubble view. - - UIView *proxyView = [UIView new]; - [self.stackView addArrangedSubview:proxyView]; - - OWSBubbleShapeView *shadowView = [[OWSBubbleShapeView alloc] initShadow]; - OWSBubbleShapeView *clipView = [[OWSBubbleShapeView alloc] initClip]; - - [self addSubview:shadowView]; - [self addSubview:clipView]; - - [self.viewConstraints addObjectsFromArray:[shadowView autoPinToEdgesOfView:proxyView]]; - [self.viewConstraints addObjectsFromArray:[clipView autoPinToEdgesOfView:proxyView]]; - - [clipView addSubview:buttonsView]; - [self.viewConstraints addObjectsFromArray:[buttonsView ows_autoPinToSuperviewEdges]]; - - [self.bubbleView addPartnerView:shadowView]; - [self.bubbleView addPartnerView:clipView]; - - // Prevent the layer from animating changes. - [CATransaction begin]; - [CATransaction setDisableActions:YES]; - - OWSAssertDebug(buttonsView.backgroundColor); - shadowView.fillColor = buttonsView.backgroundColor; - shadowView.layer.shadowColor = Theme.boldColor.CGColor; - shadowView.layer.shadowOpacity = 0.12f; - shadowView.layer.shadowOffset = CGSizeZero; - shadowView.layer.shadowRadius = 1.f; - - [CATransaction commit]; -} - -- (BOOL)contactShareHasSpacerTop -{ - return (self.cellType == OWSMessageCellType_ContactShare && (self.isQuotedReply || !self.shouldShowSenderName)); -} - -- (BOOL)contactShareHasSpacerBottom -{ - return (self.cellType == OWSMessageCellType_ContactShare && !self.hasBottomFooter); -} - -- (CGFloat)contactShareVSpacing -{ - return 12.f; -} - - (CGFloat)senderNameBottomSpacing { return 0.f; @@ -557,7 +457,6 @@ NS_ASSUME_NONNULL_BEGIN case OWSMessageCellType_TextOnlyMessage: case OWSMessageCellType_Audio: case OWSMessageCellType_GenericAttachment: - case OWSMessageCellType_ContactShare: case OWSMessageCellType_OversizeTextDownloading: return NO; case OWSMessageCellType_MediaMessage: @@ -572,7 +471,6 @@ NS_ASSUME_NONNULL_BEGIN return NO; case OWSMessageCellType_Audio: case OWSMessageCellType_GenericAttachment: - case OWSMessageCellType_ContactShare: case OWSMessageCellType_MediaMessage: case OWSMessageCellType_OversizeTextDownloading: return YES; @@ -581,8 +479,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)hasFullWidthMediaView { - return (self.hasBodyMediaWithThumbnail || self.cellType == OWSMessageCellType_ContactShare - || self.cellType == OWSMessageCellType_MediaMessage); + return (self.hasBodyMediaWithThumbnail || self.cellType == OWSMessageCellType_MediaMessage); } - (BOOL)canFooterOverlayMedia @@ -876,26 +773,6 @@ NS_ASSUME_NONNULL_BEGIN return attachmentView; } -- (UIView *)loadViewForContactShare -{ - OWSAssertDebug(self.viewItem.contactShare); - - OWSContactShareView *contactShareView = [[OWSContactShareView alloc] initWithContactShare:self.viewItem.contactShare - isIncoming:self.isIncoming - conversationStyle:self.conversationStyle]; - [contactShareView createContents]; - // TODO: Should we change appearance if contact avatar is uploading? - - self.loadCellContentBlock = ^{ - // Do nothing. - }; - self.unloadCellContentBlock = ^{ - // Do nothing. - }; - - return contactShareView; -} - - (UIView *)loadViewForOversizeTextDownload { // We can use an empty view. The progress views will display download @@ -1079,11 +956,6 @@ NS_ASSUME_NONNULL_BEGIN result = [attachmentView measureSizeWithMaxMessageWidth:maxMessageWidth]; break; } - case OWSMessageCellType_ContactShare: - OWSAssertDebug(self.viewItem.contactShare); - - result = CGSizeMake(maxMessageWidth, [OWSContactShareView bubbleHeight]); - break; case OWSMessageCellType_MediaMessage: result = [OWSMediaAlbumCellView layoutSizeForMaxMessageWidth:maxMessageWidth items:self.viewItem.mediaAlbumItems]; @@ -1186,23 +1058,6 @@ NS_ASSUME_NONNULL_BEGIN return [NSValue valueWithCGSize:result]; } -- (nullable NSValue *)actionButtonsSize -{ - OWSAssertDebug(self.conversationStyle); - OWSAssertDebug(self.conversationStyle.maxMessageWidth > 0); - - if (self.cellType == OWSMessageCellType_ContactShare) { - OWSAssertDebug(self.viewItem.contactShare); - - if ([OWSContactShareButtonsView hasAnyButton:self.viewItem.contactShare]) { - CGSize buttonsSize = CGSizeCeil( - CGSizeMake(self.conversationStyle.maxMessageWidth, [OWSContactShareButtonsView bubbleHeight])); - return [NSValue valueWithCGSize:buttonsSize]; - } - } - return nil; -} - - (CGSize)measureSize { OWSAssertDebug(self.conversationStyle); @@ -1239,13 +1094,6 @@ NS_ASSUME_NONNULL_BEGIN [textViewSizes addObject:bodyMediaSize]; bodyMediaSize = nil; } - - if (self.contactShareHasSpacerTop) { - cellSize.height += self.contactShareVSpacing; - } - if (self.contactShareHasSpacerBottom) { - cellSize.height += self.contactShareVSpacing; - } } if (bodyMediaSize || quotedMessageSize) { @@ -1296,12 +1144,6 @@ NS_ASSUME_NONNULL_BEGIN cellSize.height += self.tapForMoreHeight + self.textViewVSpacing; } - NSValue *_Nullable actionButtonsSize = [self actionButtonsSize]; - if (actionButtonsSize) { - cellSize.width = MAX(cellSize.width, actionButtonsSize.CGSizeValue.width); - cellSize.height += actionButtonsSize.CGSizeValue.height; - } - cellSize = CGSizeCeil(cellSize); OWSAssertDebug(cellSize.width <= self.conversationStyle.maxMessageWidth); @@ -1395,9 +1237,6 @@ NS_ASSUME_NONNULL_BEGIN } } - [self.contactShareButtonsView removeFromSuperview]; - self.contactShareButtonsView = nil; - [self.linkPreviewView removeFromSuperview]; self.linkPreviewView.state = nil; } @@ -1430,12 +1269,6 @@ NS_ASSUME_NONNULL_BEGIN } } - if (self.contactShareButtonsView) { - if ([self.contactShareButtonsView handleTapGesture:sender]) { - return; - } - } - CGPoint locationInMessageBubble = [sender locationInView:self]; switch ([self gestureLocationForLocation:locationInMessageBubble]) { case OWSMessageGestureLocation_Default: @@ -1488,9 +1321,6 @@ NS_ASSUME_NONNULL_BEGIN [AttachmentSharing showShareUIForAttachment:self.viewItem.attachmentStream]; } break; - case OWSMessageCellType_ContactShare: - [self.delegate didTapContactShareViewItem:self.viewItem]; - break; case OWSMessageCellType_MediaMessage: { OWSAssertDebug(self.bodyMediaView); OWSAssertDebug(self.viewItem.mediaAlbumItems.count > 0); @@ -1603,32 +1433,6 @@ NS_ASSUME_NONNULL_BEGIN OWSFailDebug(@"Sent quoted replies should not be cancellable."); } -#pragma mark - OWSContactShareButtonsViewDelegate - -- (void)didTapSendMessageToContactShare:(ContactShareViewModel *)contactShare -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - - [self.delegate didTapSendMessageToContactShare:contactShare]; -} - -- (void)didTapSendInviteToContactShare:(ContactShareViewModel *)contactShare -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - - [self.delegate didTapSendInviteToContactShare:contactShare]; -} - -- (void)didTapShowAddToContactUIForContactShare:(ContactShareViewModel *)contactShare -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - - [self.delegate didTapShowAddToContactUIForContactShare:contactShare]; -} - @end NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/Cells/OWSMessageCell.m b/Session/Signal/ConversationView/Cells/OWSMessageCell.m index 443f4614e..6190bb0be 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageCell.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageCell.m @@ -3,7 +3,6 @@ // #import "OWSMessageCell.h" -#import "OWSContactAvatarBuilder.h" #import "OWSMessageBubbleView.h" #import "OWSMessageHeaderView.h" #import "Session-Swift.h" @@ -286,7 +285,7 @@ NS_ASSUME_NONNULL_BEGIN [self.avatarView update]; // Loki: Show the moderator icon if needed - if (self.viewItem.isGroupThread && !self.viewItem.isRSSFeed) { // FIXME: This logic also shouldn't apply to closed groups + if (self.viewItem.isGroupThread) { // FIXME: This logic also shouldn't apply to closed groups __block SNOpenGroup *publicChat; [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { publicChat = [LKDatabaseUtilities getPublicChatForThreadID:self.viewItem.interaction.uniqueThreadId transaction: transaction]; diff --git a/Session/Signal/ConversationView/Cells/OWSMessageFooterView.m b/Session/Signal/ConversationView/Cells/OWSMessageFooterView.m index c0f6fdf17..72ac15eb3 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageFooterView.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageFooterView.m @@ -122,7 +122,8 @@ NS_ASSUME_NONNULL_BEGIN [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { TSContactThread *thread = [outgoingMessage.thread as:TSContactThread.class]; if (thread != nil) { - isNoteToSelf = [LKDatabaseUtilities isUserLinkedDevice:thread.contactIdentifier in:transaction]; + NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; + isNoteToSelf = ([thread.contactIdentifier isEqual:userPublicKey]); } }]; diff --git a/Session/Signal/ConversationView/Cells/OWSMessageTimerView.m b/Session/Signal/ConversationView/Cells/OWSMessageTimerView.m index 67921dc3a..1b4bd621d 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageTimerView.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageTimerView.m @@ -9,7 +9,7 @@ #import "UIView+OWS.h" #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m index 475a78faf..199d35df7 100644 --- a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m @@ -8,7 +8,7 @@ #import "OWSBubbleView.h" #import "Session-Swift.h" #import -#import + #import #import #import @@ -550,8 +550,7 @@ const CGFloat kRemotelySourcedContentRowSpacing = 4; quotedAuthorText = NSLocalizedString(@"You", @""); } } else { - OWSContactsManager *contactsManager = Environment.shared.contactsManager; - __block NSString *quotedAuthor = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.quotedMessage.authorId] ?: [contactsManager contactOrProfileNameForPhoneIdentifier:self.quotedMessage.authorId]; + __block NSString *quotedAuthor = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.quotedMessage.authorId]; if (quotedAuthor == self.quotedMessage.authorId) { [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { diff --git a/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m index 683c00b61..d3c18cf51 100644 --- a/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m +++ b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m @@ -9,9 +9,8 @@ #import "UIColor+OWS.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" +#import #import -#import -#import #import #import #import @@ -290,17 +289,6 @@ typedef void (^SystemMessageActionBlock)(void); : [UIImage imageNamed:@"system_message_disappearing_messages_disabled"]); break; } - case TSInfoMessageVerificationStateChange: - OWSAssertDebug([interaction isKindOfClass:[OWSVerificationStateChangeMessage class]]); - if ([interaction isKindOfClass:[OWSVerificationStateChangeMessage class]]) { - OWSVerificationStateChangeMessage *message = (OWSVerificationStateChangeMessage *)interaction; - BOOL isVerified = message.verificationState == OWSVerificationStateVerified; - if (!isVerified) { - return nil; - } - } - result = [UIImage imageNamed:@"system_message_verified"]; - break; } } else if ([interaction isKindOfClass:[TSCall class]]) { result = [UIImage imageNamed:@"system_message_call"]; @@ -398,8 +386,6 @@ typedef void (^SystemMessageActionBlock)(void); return [self actionForErrorMessage:(TSErrorMessage *)interaction]; } else if ([interaction isKindOfClass:[TSInfoMessage class]]) { return [self actionForInfoMessage:(TSInfoMessage *)interaction]; - } else if ([interaction isKindOfClass:[TSCall class]]) { - return [self actionForCall:(TSCall *)interaction]; } else { OWSFailDebug(@"Tap for system messages of unknown type: %@", [interaction class]); return nil; @@ -414,21 +400,6 @@ typedef void (^SystemMessageActionBlock)(void); switch (message.errorType) { case TSErrorMessageInvalidKeyException: return nil; - case TSErrorMessageNonBlockingIdentityChange: - return [SystemMessageAction - actionWithTitle:NSLocalizedString(@"SYSTEM_MESSAGE_ACTION_VERIFY_SAFETY_NUMBER", - @"Label for button to verify a user's safety number.") - block:^{ - [weakSelf.delegate tappedNonBlockingIdentityChangeForRecipientId:message.recipientId]; - }]; - case TSErrorMessageWrongTrustedIdentityKey: - return [SystemMessageAction - actionWithTitle:NSLocalizedString(@"SYSTEM_MESSAGE_ACTION_VERIFY_SAFETY_NUMBER", - @"Label for button to verify a user's safety number.") - block:^{ - [weakSelf.delegate - tappedInvalidIdentityKeyErrorMessage:(TSInvalidIdentityKeyErrorMessage *)message]; - }]; case TSErrorMessageMissingKeyId: case TSErrorMessageNoSession: case TSErrorMessageInvalidMessage: @@ -486,48 +457,12 @@ typedef void (^SystemMessageActionBlock)(void); block:^{ [weakSelf.delegate showConversationSettings]; }]; - case TSInfoMessageVerificationStateChange: - return [SystemMessageAction - actionWithTitle:NSLocalizedString(@"SHOW_SAFETY_NUMBER_ACTION", @"Action sheet item") - block:^{ - [weakSelf.delegate - showFingerprintWithRecipientId:((OWSVerificationStateChangeMessage *)message) - .recipientId]; - }]; } OWSLogInfo(@"Unhandled tap for info message: %@", message); return nil; } -- (nullable SystemMessageAction *)actionForCall:(TSCall *)call -{ - OWSAssertDebug(call); - - __weak OWSSystemMessageCell *weakSelf = self; - switch (call.callType) { - case RPRecentCallTypeIncoming: - case RPRecentCallTypeIncomingMissed: - case RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity: - case RPRecentCallTypeIncomingDeclined: - return - [SystemMessageAction actionWithTitle:NSLocalizedString(@"CALLBACK_BUTTON_TITLE", @"notification action") - block:^{ - [weakSelf.delegate handleCallTap:call]; - }]; - case RPRecentCallTypeOutgoing: - case RPRecentCallTypeOutgoingMissed: - return [SystemMessageAction actionWithTitle:NSLocalizedString(@"CALL_AGAIN_BUTTON_TITLE", - @"Label for button that lets users call a contact again.") - block:^{ - [weakSelf.delegate handleCallTap:call]; - }]; - case RPRecentCallTypeOutgoingIncomplete: - case RPRecentCallTypeIncomingIncomplete: - return nil; - } -} - #pragma mark - Events - (void)handleLongPressGesture:(UILongPressGestureRecognizer *)longPress diff --git a/Session/Signal/ConversationView/Cells/TypingIndicatorCell.swift b/Session/Signal/ConversationView/Cells/TypingIndicatorCell.swift index 1de1235c6..064a05ec6 100644 --- a/Session/Signal/ConversationView/Cells/TypingIndicatorCell.swift +++ b/Session/Signal/ConversationView/Cells/TypingIndicatorCell.swift @@ -19,7 +19,7 @@ public class TypingIndicatorCell: ConversationViewCell { private let kAvatarSize: CGFloat = 36 private let kAvatarHSpacing: CGFloat = 8 - private let avatarView = AvatarImageView() +// private let avatarView = AvatarImageView() private let bubbleView = OWSBubbleView() private let typingIndicatorView = TypingIndicatorView() private var viewConstraints = [NSLayoutConstraint]() @@ -39,8 +39,8 @@ public class TypingIndicatorCell: ConversationViewCell { bubbleView.addSubview(typingIndicatorView) contentView.addSubview(bubbleView) - avatarView.autoSetDimension(.width, toSize: kAvatarSize) - avatarView.autoSetDimension(.height, toSize: kAvatarSize) +// avatarView.autoSetDimension(.width, toSize: kAvatarSize) +// avatarView.autoSetDimension(.height, toSize: kAvatarSize) } @objc @@ -65,16 +65,16 @@ public class TypingIndicatorCell: ConversationViewCell { typingIndicatorView.autoPinBottomToSuperviewMargin(withInset: conversationStyle.textInsetBottom) ]) - if let avatarView = configureAvatarView() { - contentView.addSubview(avatarView) - viewConstraints.append(contentsOf: [ - bubbleView.autoPinLeading(toTrailingEdgeOf: avatarView, offset: kAvatarHSpacing), - bubbleView.autoAlignAxis(.horizontal, toSameAxisOf: avatarView) - ]) - - } else { - avatarView.removeFromSuperview() - } +// if let avatarView = configureAvatarView() { +// contentView.addSubview(avatarView) +// viewConstraints.append(contentsOf: [ +// bubbleView.autoPinLeading(toTrailingEdgeOf: avatarView, offset: kAvatarHSpacing), +// bubbleView.autoAlignAxis(.horizontal, toSameAxisOf: avatarView) +// ]) +// +// } else { +// avatarView.removeFromSuperview() +// } } private func configureAvatarView() -> UIView? { @@ -93,15 +93,16 @@ public class TypingIndicatorCell: ConversationViewCell { owsFailDebug("Missing authorConversationColorName") return nil } - guard let authorAvatarImage = - OWSContactAvatarBuilder(signalId: typingIndicators.recipientId, - colorName: ConversationColorName(rawValue: colorName), - diameter: UInt(kAvatarSize)).build() else { - owsFailDebug("Could build avatar image") - return nil - } - avatarView.image = authorAvatarImage - return avatarView +// guard let authorAvatarImage = +// OWSContactAvatarBuilder(signalId: typingIndicators.recipientId, +// colorName: ConversationColorName(rawValue: colorName), +// diameter: UInt(kAvatarSize)).build() else { +// owsFailDebug("Could build avatar image") +// return nil +// } +// avatarView.image = authorAvatarImage +// return avatarView + return UIView() } private func shouldShowAvatar() -> Bool { @@ -140,8 +141,8 @@ public class TypingIndicatorCell: ConversationViewCell { NSLayoutConstraint.deactivate(viewConstraints) viewConstraints = [NSLayoutConstraint]() - avatarView.image = nil - avatarView.removeFromSuperview() +// avatarView.image = nil +// avatarView.removeFromSuperview() typingIndicatorView.stopAnimation() } diff --git a/Session/Signal/ConversationView/ConversationHeaderView.swift b/Session/Signal/ConversationView/ConversationHeaderView.swift deleted file mode 100644 index 680060ac6..000000000 --- a/Session/Signal/ConversationView/ConversationHeaderView.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -public protocol ConversationHeaderViewDelegate { - func didTapConversationHeaderView(_ conversationHeaderView: ConversationHeaderView) -} - -@objc -public class ConversationHeaderView: UIStackView { - - @objc - public weak var delegate: ConversationHeaderViewDelegate? - - @objc - public var attributedTitle: NSAttributedString? { - get { - return self.titleLabel.attributedText - } - set { - self.titleLabel.attributedText = newValue - } - } - - @objc - public var attributedSubtitle: NSAttributedString? { - get { - return self.subtitleLabel.attributedText - } - set { - self.subtitleLabel.attributedText = newValue - self.subtitleLabel.isHidden = newValue == nil - } - } - - public var avatarImage: UIImage? { - get { - return self.avatarView.image - } - set { - self.avatarView.image = newValue - } - } - - @objc - public let titlePrimaryFont: UIFont = UIFont.ows_boldFont(withSize: 17) - @objc - public let titleSecondaryFont: UIFont = UIFont.ows_regularFont(withSize: 9) - @objc - public let subtitleFont: UIFont = UIFont.ows_regularFont(withSize: 12) - - private let titleLabel: UILabel - private let subtitleLabel: UILabel - private let avatarView: ConversationAvatarImageView - - @objc - public required init(thread: TSThread, contactsManager: OWSContactsManager) { - - let avatarView = ConversationAvatarImageView(thread: thread, diameter: 36, contactsManager: contactsManager) - self.avatarView = avatarView - - titleLabel = UILabel() - titleLabel.textColor = Theme.navbarTitleColor - titleLabel.lineBreakMode = .byTruncatingTail - titleLabel.font = titlePrimaryFont - titleLabel.setContentHuggingHigh() - - subtitleLabel = UILabel() - subtitleLabel.textColor = Theme.navbarTitleColor - subtitleLabel.lineBreakMode = .byTruncatingTail - subtitleLabel.font = subtitleFont - subtitleLabel.setContentHuggingHigh() - - let textRows = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel]) - textRows.axis = .vertical - textRows.alignment = .leading - textRows.distribution = .fillProportionally - textRows.spacing = 0 - - textRows.layoutMargins = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8) - textRows.isLayoutMarginsRelativeArrangement = true - - // low content hugging so that the text rows push container to the right bar button item(s) - textRows.setContentHuggingLow() - - super.init(frame: .zero) - - self.layoutMargins = UIEdgeInsets(top: 4, left: 2, bottom: 4, right: 2) - self.isLayoutMarginsRelativeArrangement = true - - self.axis = .horizontal - self.alignment = .center - self.spacing = 0 - self.addArrangedSubview(avatarView) - self.addArrangedSubview(textRows) - - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapView)) - self.addGestureRecognizer(tapGesture) - } - - required public init(coder: NSCoder) { - notImplemented() - } - - required public override init(frame: CGRect) { - notImplemented() - } - - public override var intrinsicContentSize: CGSize { - // Grow to fill as much of the navbar as possible. - return UIView.layoutFittingExpandedSize - } - - @objc - public func updateAvatar() { - self.avatarView.updateImage() - } - - // MARK: Delegate Methods - - @objc func didTapView(tapGesture: UITapGestureRecognizer) { - guard tapGesture.state == .recognized else { - return - } - - self.delegate?.didTapConversationHeaderView(self) - } -} diff --git a/Session/Signal/ConversationView/ConversationInputToolbar.m b/Session/Signal/ConversationView/ConversationInputToolbar.m index 8680e4947..48e28baf3 100644 --- a/Session/Signal/ConversationView/ConversationInputToolbar.m +++ b/Session/Signal/ConversationView/ConversationInputToolbar.m @@ -5,17 +5,14 @@ #import "ConversationInputToolbar.h" #import "ConversationInputTextView.h" #import "Environment.h" -#import "OWSContactsManager.h" #import "OWSMath.h" #import "Session-Swift.h" #import "UIColor+OWS.h" #import "UIFont+OWS.h" -#import "ViewControllerUtils.h" #import #import #import #import -#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index c9081489b..d58e70587 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -5,8 +5,6 @@ #import "ConversationViewController.h" #import "AppDelegate.h" #import -#import "BlockListViewController.h" -#import "ContactsViewHelper.h" #import "ConversationCollectionView.h" #import "ConversationInputTextView.h" #import "ConversationInputToolbar.h" @@ -16,10 +14,9 @@ #import "ConversationViewLayout.h" #import "ConversationViewModel.h" #import "DateUtil.h" -#import "FingerprintViewController.h" #import #import "OWSAudioPlayer.h" -#import "OWSContactOffersCell.h" + #import "OWSConversationSettingsViewController.h" #import "OWSConversationSettingsViewDelegate.h" #import "OWSDisappearingMessagesJob.h" @@ -40,7 +37,6 @@ #import #import "UIFont+OWS.h" #import "UIViewController+Permissions.h" -#import "ViewControllerUtils.h" #import #import #import @@ -50,38 +46,27 @@ #import #import #import -#import #import #import #import #import #import -#import #import #import -#import -#import #import #import -#import -#import -#import #import #import #import #import -#import -#import #import #import #import #import -#import #import #import #import #import -#import #import #import #import @@ -109,13 +94,8 @@ typedef enum : NSUInteger { #pragma mark - @interface ConversationViewController () )typingIndicators { return SSKEnvironment.shared.typingIndicators; @@ -428,11 +374,11 @@ typedef enum : NSUInteger { object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleCalculatingPoWNotification:) - name:NSNotification.calculatingPoW + name:NSNotification.calculatingMessagePoW object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRoutingNotification:) - name:NSNotification.routing + name:NSNotification.encryptingMessage object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageSendingNotification:) @@ -444,12 +390,7 @@ typedef enum : NSUInteger { object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageFailedNotification:) - name:NSNotification.messageFailed - object:nil]; - // Device linking - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleUnexpectedDeviceLinkRequestReceivedNotification) - name:NSNotification.unexpectedDeviceLinkRequestReceived + name:NSNotification.messageSendingFailed object:nil]; } @@ -566,7 +507,7 @@ typedef enum : NSUInteger { _conversationStyle = [[ConversationStyle alloc] initWithThread:thread]; _conversationViewModel = - [[ConversationViewModel alloc] initWithThread:thread focusMessageIdOnOpen:focusMessageId isRSSFeed:self.isRSSFeed delegate:self]; + [[ConversationViewModel alloc] initWithThread:thread focusMessageIdOnOpen:focusMessageId delegate:self]; _searchController = [[ConversationSearchController alloc] initWithThread:thread]; _searchController.delegate = self; @@ -616,14 +557,7 @@ typedef enum : NSUInteger { } TSGroupThread *groupThread = (TSGroupThread *)self.thread; - return !groupThread.isLocalUserInGroup; -} - -- (BOOL)isRSSFeed -{ - if (![_thread isKindOfClass:[TSGroupThread class]]) { return NO; } - TSGroupThread *thread = (TSGroupThread *)self.thread; - return thread.isRSSFeed; + return !groupThread.isCurrentUserInGroup; } - (void)hideInputIfNeeded @@ -640,11 +574,6 @@ typedef enum : NSUInteger { } else { self.inputToolbar.hidden = NO; } - - // Loki: In RSS feeds, don't hide the input bar entirely; just hide the text field inside. - if (self.isRSSFeed) { - [self.inputToolbar hideInputMethod]; - } } - (void)viewDidLoad @@ -678,7 +607,7 @@ typedef enum : NSUInteger { if (self.thread.isGroupThread) { TSGroupThread *thread = (TSGroupThread *)self.thread; - if (!thread.isPublicChat) { return; } + if (!thread.isOpenGroup) { return; } __block SNOpenGroup *publicChat; [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { publicChat = [LKDatabaseUtilities getPublicChatForThreadID:thread.uniqueId transaction:transaction]; @@ -795,8 +724,6 @@ typedef enum : NSUInteger { forCellWithReuseIdentifier:[OWSSystemMessageCell cellReuseIdentifier]]; [self.collectionView registerClass:[OWSTypingIndicatorCell class] forCellWithReuseIdentifier:[OWSTypingIndicatorCell cellReuseIdentifier]]; - [self.collectionView registerClass:[OWSContactOffersCell class] - forCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]]; [self.collectionView registerClass:[OWSMessageCell class] forCellWithReuseIdentifier:[OWSMessageCell cellReuseIdentifier]]; } @@ -866,10 +793,6 @@ typedef enum : NSUInteger { self.isViewVisible = YES; - // We should have already requested contact access at this point, so this should be a no-op - // unless it ever becomes possible to load this VC without going via the HomeViewController. - [self.contactsManager requestSystemContactsOnce]; - [self updateDisappearingMessagesConfiguration]; [self updateBarButtonItems]; @@ -1001,48 +924,35 @@ typedef enum : NSUInteger { [self ensureBannerState]; } -// Returns a collection of the group members who are "no longer verified". -- (NSArray *)noLongerVerifiedRecipientIds -{ - NSMutableArray *result = [NSMutableArray new]; - for (NSString *recipientId in self.thread.recipientIdentifiers) { - if ([[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId] - == OWSVerificationStateNoLongerVerified) { - [result addObject:recipientId]; - } - } - return [result copy]; -} - - (void)updateSessionRestoreBanner { - BOOL isContactThread = [self.thread isKindOfClass:[TSContactThread class]]; - BOOL shouldDetachBanner = !isContactThread; - if (isContactThread) { - TSContactThread *thread = (TSContactThread *)self.thread; - if (thread.sessionRestoreDevices.count > 0) { - if (self.restoreSessionBannerView == nil) { - LKSessionRestorationView *bannerView = [[LKSessionRestorationView alloc] initWithThread:thread]; - [self.view addSubview:bannerView]; - [bannerView autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:LKValues.mediumSpacing]; - [bannerView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:LKValues.largeSpacing]; - [bannerView autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:LKValues.mediumSpacing]; - [self.view layoutSubviews]; - self.restoreSessionBannerView = bannerView; - [bannerView setOnRestore:^{ - [self restoreSession]; - }]; - [bannerView setOnDismiss:^{ - [thread removeAllSessionRestoreDevicesWithTransaction:nil]; - }]; - } - } else { - shouldDetachBanner = true; - } - } - if (shouldDetachBanner && self.restoreSessionBannerView != nil) { - [self.restoreSessionBannerView removeFromSuperview]; - self.restoreSessionBannerView = nil; - } +// BOOL isContactThread = [self.thread isKindOfClass:[TSContactThread class]]; +// BOOL shouldDetachBanner = !isContactThread; +// if (isContactThread) { +// TSContactThread *thread = (TSContactThread *)self.thread; +// if (thread.sessionRestoreDevices.count > 0) { +// if (self.restoreSessionBannerView == nil) { +// LKSessionRestorationView *bannerView = [[LKSessionRestorationView alloc] initWithThread:thread]; +// [self.view addSubview:bannerView]; +// [bannerView autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:LKValues.mediumSpacing]; +// [bannerView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:LKValues.largeSpacing]; +// [bannerView autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:LKValues.mediumSpacing]; +// [self.view layoutSubviews]; +// self.restoreSessionBannerView = bannerView; +// [bannerView setOnRestore:^{ +// [self restoreSession]; +// }]; +// [bannerView setOnDismiss:^{ +// [thread removeAllSessionRestoreDevicesWithTransaction:nil]; +// }]; +// } +// } else { +// shouldDetachBanner = true; +// } +// } +// if (shouldDetachBanner && self.restoreSessionBannerView != nil) { +// [self.restoreSessionBannerView removeFromSuperview]; +// self.restoreSessionBannerView = nil; +// } } - (void)ensureBannerState @@ -1056,32 +966,6 @@ typedef enum : NSUInteger { return; } - NSArray *noLongerVerifiedRecipientIds = [self noLongerVerifiedRecipientIds]; - - if (noLongerVerifiedRecipientIds.count > 0) { - NSString *message; - if (noLongerVerifiedRecipientIds.count > 1) { - message = NSLocalizedString(@"MESSAGES_VIEW_N_MEMBERS_NO_LONGER_VERIFIED", - @"Indicates that more than one member of this group conversation is no longer verified."); - } else { - NSString *recipientId = [noLongerVerifiedRecipientIds firstObject]; - NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:recipientId]; - NSString *format - = (self.isGroupConversation ? NSLocalizedString(@"MESSAGES_VIEW_1_MEMBER_NO_LONGER_VERIFIED_FORMAT", - @"Indicates that one member of this group conversation is no longer " - @"verified. Embeds {{user's name or phone number}}.") - : NSLocalizedString(@"MESSAGES_VIEW_CONTACT_NO_LONGER_VERIFIED_FORMAT", - @"Indicates that this 1:1 conversation is no longer verified. Embeds " - @"{{user's name or phone number}}.")); - message = [NSString stringWithFormat:format, displayName]; - } - - [self createBannerWithTitle:message - bannerColor:[UIColor ows_destructiveRedColor] - tapSelector:@selector(noLongerVerifiedBannerViewWasTapped:)]; - return; - } - NSString *blockStateMessage = nil; if ([self isBlockedConversation]) { if (self.isGroupConversation) { @@ -1093,20 +977,6 @@ typedef enum : NSUInteger { blockStateMessage = NSLocalizedString( @"MESSAGES_VIEW_CONTACT_BLOCKED", @"Indicates that this 1:1 conversation has been blocked."); } - } else if (self.isGroupConversation) { - /* - int blockedGroupMemberCount = [self blockedGroupMemberCount]; - if (blockedGroupMemberCount == 1) { - blockStateMessage = NSLocalizedString(@"MESSAGES_VIEW_GROUP_1_MEMBER_BLOCKED", - @"Indicates that a single member of this group has been blocked."); - } else if (blockedGroupMemberCount > 1) { - blockStateMessage = - [NSString stringWithFormat:NSLocalizedString(@"MESSAGES_VIEW_GROUP_N_MEMBERS_BLOCKED_FORMAT", - @"Indicates that some members of this group has been blocked. Embeds " - @"{{the number of blocked users in this group}}."), - [OWSFormat formatInt:blockedGroupMemberCount]]; - } - */ } if (blockStateMessage) { @@ -1115,17 +985,6 @@ typedef enum : NSUInteger { tapSelector:@selector(blockBannerViewWasTapped:)]; return; } - - /* - if ([ThreadUtil shouldShowGroupProfileBannerInThread:self.thread blockingManager:self.blockingManager]) { - [self createBannerWithTitle: - NSLocalizedString(@"MESSAGES_VIEW_GROUP_PROFILE_WHITELIST_BANNER", - @"Text for banner in group conversation view that offers to share your profile with this group.") - bannerColor:[UIColor ows_reminderDarkYellowColor] - tapSelector:@selector(groupProfileWhitelistBannerWasTapped:)]; - return; - } - */ } - (void)createBannerWithTitle:(NSString *)title bannerColor:(UIColor *)bannerColor tapSelector:(SEL)tapSelector @@ -1198,105 +1057,20 @@ typedef enum : NSUInteger { if ([self isBlockedConversation]) { // If this a blocked conversation, offer to unblock. [self showUnblockConversationUI:nil]; - } else if (self.isGroupConversation) { - // If this a group conversation with at least one blocked member, - // Show the block list view. - int blockedGroupMemberCount = [self blockedGroupMemberCount]; - if (blockedGroupMemberCount > 0) { - BlockListViewController *vc = [[BlockListViewController alloc] init]; - [self.navigationController pushViewController:vc animated:YES]; - } } } -- (void)groupProfileWhitelistBannerWasTapped:(UIGestureRecognizer *)sender -{ - if (sender.state != UIGestureRecognizerStateRecognized) { - return; - } - - [self presentAddThreadToProfileWhitelistWithSuccess:^{ - [self ensureBannerState]; - }]; -} - - (void)restoreSession { - if (![self.thread isKindOfClass:TSContactThread.class]) { return; } - TSContactThread *thread = (TSContactThread *)self.thread; - __weak ConversationViewController *weakSelf = self; - dispatch_async(dispatch_get_main_queue(), ^{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [thread addSessionRestoreDevice:thread.contactIdentifier transaction:transaction]; - [LKSessionManagementProtocol startSessionResetInThread:thread transaction:transaction]; - }]; - [weakSelf updateSessionRestoreBanner]; - }); -} - -- (void)noLongerVerifiedBannerViewWasTapped:(UIGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized) { - NSArray *noLongerVerifiedRecipientIds = [self noLongerVerifiedRecipientIds]; - if (noLongerVerifiedRecipientIds.count < 1) { - return; - } - BOOL hasMultiple = noLongerVerifiedRecipientIds.count > 1; - - UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil - message:nil - preferredStyle:UIAlertControllerStyleActionSheet]; - - __weak ConversationViewController *weakSelf = self; - UIAlertAction *verifyAction = [UIAlertAction - actionWithTitle:(hasMultiple ? NSLocalizedString(@"VERIFY_PRIVACY_MULTIPLE", - @"Label for button or row which allows users to verify the safety " - @"numbers of multiple users.") - : NSLocalizedString(@"VERIFY_PRIVACY", - @"Label for button or row which allows users to verify the safety " - @"number of another user.")) - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [weakSelf showNoLongerVerifiedUI]; - }]; - [actionSheet addAction:verifyAction]; - - UIAlertAction *dismissAction = - [UIAlertAction actionWithTitle:CommonStrings.dismissButton - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss") - style:UIAlertActionStyleCancel - handler:^(UIAlertAction *action) { - [weakSelf resetVerificationStateToDefault]; - }]; - [actionSheet addAction:dismissAction]; - - [self dismissKeyBoard]; - [self presentAlert:actionSheet]; - } -} - -- (void)resetVerificationStateToDefault -{ - OWSAssertIsOnMainThread(); - - NSArray *noLongerVerifiedRecipientIds = [self noLongerVerifiedRecipientIds]; - for (NSString *recipientId in noLongerVerifiedRecipientIds) { - OWSAssertDebug(recipientId.length > 0); - - OWSRecipientIdentity *_Nullable recipientIdentity = - [[OWSIdentityManager sharedManager] recipientIdentityForRecipientId:recipientId]; - OWSAssertDebug(recipientIdentity); - - NSData *identityKey = recipientIdentity.identityKey; - OWSAssertDebug(identityKey.length > 0); - if (identityKey.length < 1) { - continue; - } - - [OWSIdentityManager.sharedManager setVerificationState:OWSVerificationStateDefault - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:YES]; - } +// if (![self.thread isKindOfClass:TSContactThread.class]) { return; } +// TSContactThread *thread = (TSContactThread *)self.thread; +// __weak ConversationViewController *weakSelf = self; +// dispatch_async(dispatch_get_main_queue(), ^{ +// [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { +// [thread addSessionRestoreDevice:thread.contactIdentifier transaction:transaction]; +// [LKSessionManagementProtocol startSessionResetInThread:thread transaction:transaction]; +// }]; +// [weakSelf updateSessionRestoreBanner]; +// }); } - (void)showUnblockConversationUI:(nullable BlockActionCompletionBlock)completionBlock @@ -1308,7 +1082,6 @@ typedef enum : NSUInteger { [BlockListUIUtils showUnblockThreadActionSheet:self.thread fromViewController:self blockingManager:self.blockingManager - contactsManager:self.contactsManager completionBlock:completionBlock]; [UIView setAnimationsEnabled:YES]; @@ -1370,7 +1143,6 @@ typedef enum : NSUInteger { // recover status bar when returning from PhotoPicker, which is dark (uses light status bar) [self setNeedsStatusBarAppearanceUpdate]; - [ProfileFetcherJob runWithThread:self.thread]; [self markVisibleMessagesAsRead]; [self startReadTimer]; [self autoLoadMoreIfNecessary]; @@ -1422,12 +1194,6 @@ typedef enum : NSUInteger { case ConversationViewActionCompose: [self popKeyBoard]; break; - case ConversationViewActionAudioCall: - [self startAudioCall]; - break; - case ConversationViewActionVideoCall: - [self startVideoCall]; - break; } // Clear the "on open" state after the view has been presented. @@ -1567,52 +1333,6 @@ typedef enum : NSUInteger { const CGFloat kBarButtonSize = 44; NSMutableArray *barButtons = [NSMutableArray new]; - if ([self canCall]) { - // We use UIButtons with [UIBarButtonItem initWithCustomView:...] instead of - // UIBarButtonItem in order to ensure that these buttons are spaced tightly. - // The contents of the navigation bar are cramped in this view. - UIButton *callButton = [UIButton buttonWithType:UIButtonTypeCustom]; - UIImage *image = [[UIImage imageNamed:@"button_phone_white"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; - [callButton setImage:image forState:UIControlStateNormal]; - - if (OWSWindowManager.sharedManager.hasCall) { - callButton.enabled = NO; - callButton.userInteractionEnabled = NO; - callButton.tintColor = [Theme.navbarIconColor colorWithAlphaComponent:0.7]; - } else { - callButton.enabled = YES; - callButton.userInteractionEnabled = YES; - callButton.tintColor = Theme.navbarIconColor; - } - - UIEdgeInsets imageEdgeInsets = UIEdgeInsetsZero; - - // We normally would want to use left and right insets that ensure the button - // is square and the icon is centered. However UINavigationBar doesn't offer us - // control over the margins and spacing of its content, and the buttons end up - // too far apart and too far from the edge of the screen. So we use a smaller - // right inset tighten up the layout. - BOOL hasCompactHeader = self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact; - if (!hasCompactHeader) { - imageEdgeInsets.left = round((kBarButtonSize - image.size.width) * 0.5f); - imageEdgeInsets.right = round((kBarButtonSize - (image.size.width + imageEdgeInsets.left)) * 0.5f); - imageEdgeInsets.top = round((kBarButtonSize - image.size.height) * 0.5f); - imageEdgeInsets.bottom = round(kBarButtonSize - (image.size.height + imageEdgeInsets.top)); - } - callButton.imageEdgeInsets = imageEdgeInsets; - callButton.accessibilityLabel = NSLocalizedString(@"CALL_LABEL", "Accessibility label for placing call button"); - [callButton addTarget:self action:@selector(startAudioCall) forControlEvents:UIControlEventTouchUpInside]; - callButton.frame = CGRectMake(0, - 0, - round(image.size.width + imageEdgeInsets.left + imageEdgeInsets.right), - round(image.size.height + imageEdgeInsets.top + imageEdgeInsets.bottom)); - // Loki: Original code - // ======== -// [barButtons -// addObject:[[UIBarButtonItem alloc] initWithCustomView:callButton -// accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"call")]]; - // ======== - } if (self.disappearingMessagesConfiguration.isEnabled) { DisappearingTimerConfigurationView *timerView = [[DisappearingTimerConfigurationView alloc] @@ -1638,102 +1358,6 @@ typedef enum : NSUInteger { self.navigationItem.rightBarButtonItems = [barButtons copy]; } -#pragma mark - Identity - -/** - * Shows confirmation dialog if at least one of the recipient id's is not confirmed. - * - * returns YES if an alert was shown - * NO if there were no unconfirmed identities - */ -- (BOOL)showSafetyNumberConfirmationIfNecessaryWithConfirmationText:(NSString *)confirmationText - completion:(void (^)(BOOL didConfirmIdentity))completionHandler -{ - return [SafetyNumberConfirmationAlert presentAlertIfNecessaryWithRecipientIds:self.thread.recipientIdentifiers - confirmationText:confirmationText - contactsManager:self.contactsManager - completion:^(BOOL didShowAlert) { - // Pre iOS-11, the keyboard and inputAccessoryView will obscure the alert if the keyboard is up when the - // alert is presented, so after hiding it, we regain first responder here. - if (@available(iOS 11.0, *)) { - // do nothing - } else { - [self becomeFirstResponder]; - } - completionHandler(didShowAlert); - } - beforePresentationHandler:^(void) { - if (@available(iOS 11.0, *)) { - // do nothing - } else { - // Pre iOS-11, the keyboard and inputAccessoryView will obscure the alert if the keyboard is up when the - // alert is presented. - [self dismissKeyBoard]; - [self resignFirstResponder]; - } - }]; -} - -- (void)showFingerprintWithRecipientId:(NSString *)recipientId -{ - // Ensure keyboard isn't hiding the "safety numbers changed" interaction when we - // return from FingerprintViewController. - [self dismissKeyBoard]; - - [FingerprintViewController presentFromViewController:self recipientId:recipientId]; -} - -#pragma mark - Calls - -- (void)startAudioCall -{ - [self callWithVideo:NO]; -} - -- (void)startVideoCall -{ - [self callWithVideo:YES]; -} - -- (void)callWithVideo:(BOOL)isVideo -{ - OWSAssertDebug([self.thread isKindOfClass:[TSContactThread class]]); - - if (![self canCall]) { - OWSLogWarn(@"Tried to initiate a call but thread is not callable."); - return; - } - - __weak ConversationViewController *weakSelf = self; - if ([self isBlockedConversation]) { - [self showUnblockConversationUI:^(BOOL isBlocked) { - if (!isBlocked) { - [weakSelf callWithVideo:isVideo]; - } - }]; - return; - } - - BOOL didShowSNAlert = - [self showSafetyNumberConfirmationIfNecessaryWithConfirmationText:[CallStrings confirmAndCallButtonTitle] - completion:^(BOOL didConfirmIdentity) { - if (didConfirmIdentity) { - [weakSelf callWithVideo:isVideo]; - } - }]; - if (didShowSNAlert) { - return; - } - -// [self.outboundCallInitiator initiateCallWithRecipientId:self.thread.contactIdentifier isVideo:isVideo]; -} - -- (BOOL)canCall -{ - return !(self.isGroupConversation || - [((TSContactThread *)self.thread).contactIdentifier isEqualToString:self.tsAccountManager.localNumber]); -} - #pragma mark - Dynamic Text /** @@ -1752,18 +1376,6 @@ typedef enum : NSUInteger { #pragma mark - Actions -- (void)showNoLongerVerifiedUI -{ - NSArray *noLongerVerifiedRecipientIds = [self noLongerVerifiedRecipientIds]; - if (noLongerVerifiedRecipientIds.count > 1) { - [self showConversationSettingsAndShowVerification:YES]; - } else if (noLongerVerifiedRecipientIds.count == 1) { - // Pick one in an arbitrary but deterministic manner. - NSString *recipientId = noLongerVerifiedRecipientIds.lastObject; - [self showFingerprintWithRecipientId:recipientId]; - } -} - - (void)showConversationSettings { [self showConversationSettingsAndShowVerification:NO]; @@ -1878,42 +1490,24 @@ typedef enum : NSUInteger { }]; [actionSheet addAction:deleteMessageAction]; - UIAlertAction *resendMessageAction = [UIAlertAction - actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_again") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; - }]; + // TODO TODO TODO + +// UIAlertAction *resendMessageAction = [UIAlertAction +// actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") +// accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_again") +// style:UIAlertActionStyleDefault +// handler:^(UIAlertAction *action) { +// [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { +// [self.messageSenderJobQueue addMessage:message transaction:transaction]; +// }]; +// }]; - [actionSheet addAction:resendMessageAction]; +// [actionSheet addAction:resendMessageAction]; [self dismissKeyBoard]; [self presentAlert:actionSheet]; } -- (void)tappedNonBlockingIdentityChangeForRecipientId:(nullable NSString *)signalIdParam -{ - if (signalIdParam == nil) { - if (self.thread.isGroupThread) { - // Before 2.13 we didn't track the recipient id in the identity change error. - OWSLogWarn(@"Ignoring tap on legacy nonblocking identity change since it has no signal id"); - return; - - } else { - OWSLogInfo(@"Assuming tap on legacy nonblocking identity change corresponds to current contact thread: %@", - self.thread.contactIdentifier); - signalIdParam = self.thread.contactIdentifier; - } - } - - NSString *signalId = signalIdParam; - - [self showFingerprintWithRecipientId:signalId]; -} - - (void)tappedCorruptedMessage:(TSErrorMessage *)message { NSString *alertMessage = [NSString @@ -1946,85 +1540,6 @@ typedef enum : NSUInteger { [self presentAlert:alert]; } -- (void)tappedInvalidIdentityKeyErrorMessage:(TSInvalidIdentityKeyErrorMessage *)errorMessage -{ - NSString *keyOwner = [self.contactsManager displayNameForPhoneIdentifier:errorMessage.theirSignalId]; - NSString *titleFormat = NSLocalizedString(@"SAFETY_NUMBERS_ACTIONSHEET_TITLE", @"Action sheet heading"); - NSString *titleText = [NSString stringWithFormat:titleFormat, keyOwner]; - - UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:titleText - message:nil - preferredStyle:UIAlertControllerStyleActionSheet]; - - [actionSheet addAction:[OWSAlerts cancelAction]]; - - UIAlertAction *showSafteyNumberAction = - [UIAlertAction actionWithTitle:NSLocalizedString(@"SHOW_SAFETY_NUMBER_ACTION", @"Action sheet item") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"show_safety_number") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - OWSLogInfo(@"Remote Key Changed actions: Show fingerprint display"); - [self showFingerprintWithRecipientId:errorMessage.theirSignalId]; - }]; - [actionSheet addAction:showSafteyNumberAction]; - - UIAlertAction *acceptSafetyNumberAction = - [UIAlertAction actionWithTitle:NSLocalizedString(@"ACCEPT_NEW_IDENTITY_ACTION", @"Action sheet item") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"accept_safety_number") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - OWSLogInfo(@"Remote Key Changed actions: Accepted new identity key"); - - // DEPRECATED: we're no longer creating these incoming SN error's per message, - // but there will be some legacy ones in the wild, behind which await - // as-of-yet-undecrypted messages -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - if ([errorMessage isKindOfClass:[TSInvalidIdentityKeyReceivingErrorMessage class]]) { - // Deliberately crash if the user fails to explicitly accept the new identity - // key. In practice we haven't been creating these messages in over a year. - [errorMessage throws_acceptNewIdentityKey]; -#pragma clang diagnostic pop - - } - }]; - [actionSheet addAction:acceptSafetyNumberAction]; - - [self dismissKeyBoard]; - [self presentAlert:actionSheet]; -} - -- (void)handleCallTap:(TSCall *)call -{ - OWSAssertDebug(call); - - if (![self.thread isKindOfClass:[TSContactThread class]]) { - OWSFailDebug(@"unexpected thread: %@", self.thread); - return; - } - - TSContactThread *contactThread = (TSContactThread *)self.thread; - NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:contactThread.contactIdentifier]; - - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:[CallStrings callBackAlertTitle] - message:[NSString stringWithFormat:[CallStrings callBackAlertMessageFormat], displayName] - preferredStyle:UIAlertControllerStyleAlert]; - - __weak ConversationViewController *weakSelf = self; - UIAlertAction *callAction = [UIAlertAction actionWithTitle:[CallStrings callBackAlertCallButton] - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"call_back") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [weakSelf startAudioCall]; - }]; - [alert addAction:callAction]; - [alert addAction:[OWSAlerts cancelAction]]; - - [self dismissKeyBoard]; - [self presentAlert:alert]; -} - #pragma mark - MessageActionsDelegate - (void)messageActionsShowDetailsForItem:(id)conversationViewItem @@ -2276,104 +1791,6 @@ typedef enum : NSUInteger { [[OWSWindowManager sharedManager] showMenuActionsWindow:menuActionsViewController]; } -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(recipientId.length > 0); - - return [self.contactsManager attributedContactOrProfileNameForPhoneIdentifier:recipientId]; -} - -- (void)tappedUnknownContactBlockOfferMessage:(OWSContactOffersInteraction *)interaction -{ - if (![self.thread isKindOfClass:[TSContactThread class]]) { - OWSFailDebug(@"unexpected thread: %@", self.thread); - return; - } - TSContactThread *contactThread = (TSContactThread *)self.thread; - - NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:interaction.recipientId]; - NSString *title = - [NSString stringWithFormat:NSLocalizedString(@"BLOCK_OFFER_ACTIONSHEET_TITLE_FORMAT", - @"Title format for action sheet that offers to block an unknown user." - @"Embeds {{the unknown user's name or phone number}}."), - [BlockListUIUtils formatDisplayNameForAlertTitle:displayName]]; - - UIAlertController *actionSheet = - [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet]; - - [actionSheet addAction:[OWSAlerts cancelAction]]; - - UIAlertAction *blockAction = - [UIAlertAction actionWithTitle:NSLocalizedString(@"BLOCK_OFFER_ACTIONSHEET_BLOCK_ACTION", - @"Action sheet that will block an unknown user.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"block_user") - style:UIAlertActionStyleDestructive - handler:^(UIAlertAction *action) { - OWSLogInfo(@"Blocking an unknown user."); - [self.blockingManager addBlockedPhoneNumber:interaction.recipientId]; - // Delete the offers. - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - contactThread.hasDismissedOffers = YES; - [contactThread saveWithTransaction:transaction]; - [interaction removeWithTransaction:transaction]; - }]; - }]; - [actionSheet addAction:blockAction]; - - [self dismissKeyBoard]; - [self presentAlert:actionSheet]; -} - -- (void)tappedAddToContactsOfferMessage:(OWSContactOffersInteraction *)interaction -{ - if (!self.contactsManager.supportsContactEditing) { - OWSFailDebug(@"Contact editing not supported"); - return; - } - if (![self.thread isKindOfClass:[TSContactThread class]]) { - OWSFailDebug(@"unexpected thread: %@", [self.thread class]); - return; - } - TSContactThread *contactThread = (TSContactThread *)self.thread; - [self.contactsViewHelper presentContactViewControllerForRecipientId:contactThread.contactIdentifier - fromViewController:self - editImmediately:YES]; - - // Delete the offers. - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - contactThread.hasDismissedOffers = YES; - [contactThread saveWithTransaction:transaction]; - [interaction removeWithTransaction:transaction]; - }]; -} - -- (void)tappedAddToProfileWhitelistOfferMessage:(OWSContactOffersInteraction *)interaction -{ - // This is accessed via the contact offer. Group whitelisting happens via a different interaction. - if (![self.thread isKindOfClass:[TSContactThread class]]) { - OWSFailDebug(@"unexpected thread: %@", [self.thread class]); - return; - } - TSContactThread *contactThread = (TSContactThread *)self.thread; - - [self presentAddThreadToProfileWhitelistWithSuccess:^() { - // Delete the offers. - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - contactThread.hasDismissedOffers = YES; - [contactThread saveWithTransaction:transaction]; - [interaction removeWithTransaction:transaction]; - }]; - }]; -} - -- (void)presentAddThreadToProfileWhitelistWithSuccess:(void (^)(void))successHandler -{ - [[OWSProfileManager sharedManager] presentAddThreadToProfileWhitelist:self.thread - fromViewController:self - success:successHandler]; -} - #pragma mark - OWSMessageBubbleViewDelegate - (void)didTapImageViewItem:(id)viewItem @@ -2471,41 +1888,6 @@ typedef enum : NSUInteger { [self.navigationController pushViewController:viewController animated:YES]; } -- (void)didTapContactShareViewItem:(id)conversationItem -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(conversationItem); - OWSAssertDebug(conversationItem.contactShare); - OWSAssertDebug([conversationItem.interaction isKindOfClass:[TSMessage class]]); - - ContactViewController *view = [[ContactViewController alloc] initWithContactShare:conversationItem.contactShare]; - [self.navigationController pushViewController:view animated:YES]; -} - -- (void)didTapSendMessageToContactShare:(ContactShareViewModel *)contactShare -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - - [self.contactShareViewHelper sendMessageWithContactShare:contactShare fromViewController:self]; -} - -- (void)didTapSendInviteToContactShare:(ContactShareViewModel *)contactShare -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - - [self.contactShareViewHelper showInviteContactWithContactShare:contactShare fromViewController:self]; -} - -- (void)didTapShowAddToContactUIForContactShare:(ContactShareViewModel *)contactShare -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - - [self.contactShareViewHelper showAddToContactsWithContactShare:contactShare fromViewController:self]; -} - - (void)didTapFailedIncomingAttachment:(id)viewItem { OWSAssertIsOnMainThread(); @@ -2753,22 +2135,6 @@ typedef enum : NSUInteger { self.scrollDownButton.hidden = !shouldShowScrollDownButton; } -#pragma mark - Attachment Picking: Contacts - -- (void)chooseContactForSending -{ - ContactsPicker *contactsPicker = - [[ContactsPicker alloc] initWithAllowsMultipleSelection:NO subtitleCellType:SubtitleCellValueNone]; - contactsPicker.contactsPickerDelegate = self; - contactsPicker.title - = NSLocalizedString(@"CONTACT_PICKER_TITLE", @"navbar title for contact picker when sharing a contact"); - - OWSNavigationController *navigationController = - [[OWSNavigationController alloc] initWithRootViewController:contactsPicker]; - [self dismissKeyBoard]; - [self presentViewController:navigationController animated:YES completion:nil]; -} - #pragma mark - Attachment Picking: Documents - (void)showAttachmentDocumentPickerMenu @@ -2815,7 +2181,7 @@ typedef enum : NSUInteger { - (void)showGifPicker { GifPickerViewController *view = - [[GifPickerViewController alloc] initWithThread:self.thread messageSender:self.messageSender]; + [[GifPickerViewController alloc] initWithThread:self.thread]; view.delegate = self; OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:view]; @@ -2831,7 +2197,6 @@ typedef enum : NSUInteger { [self showApprovalDialogForAttachment:attachment]; - [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } @@ -3210,34 +2575,6 @@ typedef enum : NSUInteger { } } -- (void)sendContactShare:(ContactShareViewModel *)contactShare -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(contactShare); - - OWSLogVerbose(@"Sending contact share."); - - BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - - [self.editingDatabaseConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - // TODO - in line with QuotedReply and other message attachments, saving should happen as part of sending - // preparation rather than duplicated here and in the SAE - if (contactShare.avatarImage) { - [contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction]; - } - } - completionBlock:^{ - TSOutgoingMessage *message = - [ThreadUtil enqueueMessageWithContactShare:contactShare.dbRecord inThread:self.thread]; - [self messageWasSent:message]; - - if (didAddToProfileWhitelist) { - [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; - } - }]; -} - - (void)showApprovalDialogAfterProcessingVideoURL:(NSURL *)movieURL filename:(nullable NSString *)filename { OWSAssertIsOnMainThread(); @@ -3486,19 +2823,6 @@ typedef enum : NSUInteger { return; } - BOOL didShowSNAlert = - [self showSafetyNumberConfirmationIfNecessaryWithConfirmationText: - NSLocalizedString(@"CONFIRMATION_TITLE", @"Generic button text to proceed with an action") - completion:^(BOOL didConfirmIdentity) { - if (didConfirmIdentity) { - [weakSelf attachmentButtonPressed]; - } - }]; - if (didShowSNAlert) { - return; - } - - UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; @@ -3682,7 +3006,7 @@ typedef enum : NSUInteger { groupThread = [TSGroupThread getOrCreateThreadWithGroupModel:newGroupModel transaction:transaction]; NSString *updateGroupInfo = - [groupThread.groupModel getInfoStringAboutUpdateTo:newGroupModel contactsManager:self.contactsManager]; + [groupThread.groupModel getInfoStringAboutUpdateTo:newGroupModel]; groupThread.groupModel = newGroupModel; [groupThread saveWithTransaction:transaction]; @@ -3702,32 +3026,38 @@ typedef enum : NSUInteger { // DURABLE CLEANUP - currently one caller uses the completion handler to delete the tappable error message // which causes this code to be called. Once we're more aggressive about durable sending retry, // we could get rid of this "retryable tappable error message". - [self.messageSender sendTemporaryAttachment:dataSource - contentType:OWSMimeTypeImagePng - inMessage:message - success:^{ - OWSLogDebug(@"Successfully sent group update with avatar"); - if (successCompletion) { - successCompletion(); - } - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send group avatar update with error: %@", error); - }]; + + // TODO TODO TODO + +// [self.messageSender sendTemporaryAttachment:dataSource +// contentType:OWSMimeTypeImagePng +// inMessage:message +// success:^{ +// OWSLogDebug(@"Successfully sent group update with avatar"); +// if (successCompletion) { +// successCompletion(); +// } +// } +// failure:^(NSError *error) { +// OWSLogError(@"Failed to send group avatar update with error: %@", error); +// }]; } else { // DURABLE CLEANUP - currently one caller uses the completion handler to delete the tappable error message // which causes this code to be called. Once we're more aggressive about durable sending retry, // we could get rid of this "retryable tappable error message". - [self.messageSender sendMessage:message - success:^{ - OWSLogDebug(@"Successfully sent group update"); - if (successCompletion) { - successCompletion(); - } - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send group update with error: %@", error); - }]; + + // TODO TODO TODO + +// [self.messageSender sendMessage:message +// success:^{ +// OWSLogDebug(@"Successfully sent group update"); +// if (successCompletion) { +// successCompletion(); +// } +// } +// failure:^(NSError *error) { +// OWSLogError(@"Failed to send group update with error: %@", error); +// }]; } self.thread = groupThread; @@ -3775,13 +3105,6 @@ typedef enum : NSUInteger { return @[]; } -#pragma mark - ConversationHeaderViewDelegate - -- (void)didTapConversationHeaderView:(ConversationHeaderView *)conversationHeaderView -{ - [self showConversationSettings]; -} - #ifdef USE_DEBUG_UI - (void)navigationTitleLongPressed:(UIGestureRecognizer *)gestureRecognizer { @@ -3909,18 +3232,6 @@ typedef enum : NSUInteger { return; } - BOOL didShowSNAlert = [self - showSafetyNumberConfirmationIfNecessaryWithConfirmationText:[SafetyNumberStrings confirmSendButton] - completion:^(BOOL didConfirmIdentity) { - if (didConfirmIdentity) { - [weakSelf tryToSendAttachments:attachments - messageText:messageText]; - } - }]; - if (didShowSNAlert) { - return; - } - for (SignalAttachment *attachment in attachments) { if ([attachment hasError]) { OWSLogWarn(@"Invalid attachment: %@.", attachment ? [attachment errorName] : @"Missing data"); @@ -3929,24 +3240,21 @@ typedef enum : NSUInteger { } } - BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - __block TSOutgoingMessage *message; - [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - message = [ThreadUtil enqueueMessageWithText:messageText - mediaAttachments:attachments - inThread:self.thread - quotedReplyModel:self.inputToolbar.quotedReply - linkPreviewDraft:nil - transaction:transaction]; - }]; + + // TODO TODO TODO + +// [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { +// message = [ThreadUtil enqueueMessageWithText:messageText +// mediaAttachments:attachments +// inThread:self.thread +// quotedReplyModel:self.inputToolbar.quotedReply +// linkPreviewDraft:nil +// transaction:transaction]; +// }]; [self messageWasSent:message]; - if (didAddToProfileWhitelist) { - [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; - } - if ([self.thread isKindOfClass:TSContactThread.class]) { [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [LKSessionManagementProtocol sendSessionRequestIfNeededToPublicKey:self.thread.contactIdentifier transaction:transaction]; @@ -4512,18 +3820,6 @@ typedef enum : NSUInteger { return; } - BOOL didShowSNAlert = - [self showSafetyNumberConfirmationIfNecessaryWithConfirmationText:[SafetyNumberStrings confirmSendButton] - completion:^(BOOL didConfirmIdentity) { - if (didConfirmIdentity) { - [weakSelf tryToSendTextMessage:text - updateKeyboardState:NO]; - } - }]; - if (didShowSNAlert) { - return; - } - text = [text ows_stripped]; if (text.length < 1) { @@ -4534,16 +3830,19 @@ typedef enum : NSUInteger { // // We convert large text messages to attachments // which are presented as normal text messages. - BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; + + // TODO TODO TODO + +// BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; __block TSOutgoingMessage *message; - [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - message = [ThreadUtil enqueueMessageWithText:text - inThread:self.thread - quotedReplyModel:self.inputToolbar.quotedReply - linkPreviewDraft:self.inputToolbar.linkPreviewDraft - transaction:transaction]; - }]; - [self.conversationViewModel appendUnsavedOutgoingTextMessage:message]; +// [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { +// message = [ThreadUtil enqueueMessageWithText:text +// inThread:self.thread +// quotedReplyModel:self.inputToolbar.quotedReply +// linkPreviewDraft:self.inputToolbar.linkPreviewDraft +// transaction:transaction]; +// }]; +// [self.conversationViewModel appendUnsavedOutgoingTextMessage:message]; [self messageWasSent:message]; @@ -4572,10 +3871,6 @@ typedef enum : NSUInteger { [self.thread setDraft:@"" transaction:transaction]; }]; - if (didAddToProfileWhitelist) { - [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; - } - if ([self.thread isKindOfClass:TSContactThread.class]) { [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [LKSessionManagementProtocol sendSessionRequestIfNeededToPublicKey:self.thread.contactIdentifier transaction:transaction]; @@ -4891,104 +4186,6 @@ typedef enum : NSUInteger { return maxContentOffsetY; } -#pragma mark - ContactsPickerDelegate - -- (void)contactsPickerDidCancel:(ContactsPicker *)contactsPicker -{ - OWSLogDebug(@""); - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (void)contactsPicker:(ContactsPicker *)contactsPicker contactFetchDidFail:(NSError *)error -{ - OWSLogDebug(@"with error %@", error); - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (void)contactsPicker:(ContactsPicker *)contactsPicker didSelectContact:(Contact *)contact -{ - OWSAssertDebug(contact); - - CNContact *_Nullable cnContact = [self.contactsManager cnContactWithId:contact.cnContactId]; - if (!cnContact) { - OWSFailDebug(@"Could not load system contact."); - return; - } - - OWSLogDebug(@"with contact: %@", contact); - - OWSContact *_Nullable contactShareRecord = [OWSContacts contactForSystemContact:cnContact]; - if (!contactShareRecord) { - OWSFailDebug(@"Could not convert system contact."); - return; - } - - BOOL isProfileAvatar = NO; - NSData *_Nullable avatarImageData = [self.contactsManager avatarDataForCNContactId:cnContact.identifier]; - for (NSString *recipientId in contact.textSecureIdentifiers) { - if (avatarImageData) { - break; - } - avatarImageData = [self.contactsManager profileImageDataForPhoneIdentifier:recipientId]; - if (avatarImageData) { - isProfileAvatar = YES; - } - } - contactShareRecord.isProfileAvatar = isProfileAvatar; - - ContactShareViewModel *contactShare = - [[ContactShareViewModel alloc] initWithContactShareRecord:contactShareRecord avatarImageData:avatarImageData]; - - // TODO: We should probably show this in the same navigation view controller. - ContactShareApprovalViewController *approveContactShare = - [[ContactShareApprovalViewController alloc] initWithContactShare:contactShare - contactsManager:self.contactsManager - delegate:self]; - OWSAssertDebug(contactsPicker.navigationController); - [contactsPicker.navigationController pushViewController:approveContactShare animated:YES]; -} - -- (void)contactsPicker:(ContactsPicker *)contactsPicker didSelectMultipleContacts:(NSArray *)contacts -{ - OWSFailDebug(@"with contacts: %@", contacts); - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (BOOL)contactsPicker:(ContactsPicker *)contactsPicker shouldSelectContact:(Contact *)contact -{ - // Any reason to preclude contacts? - return YES; -} - -#pragma mark - ContactShareApprovalViewControllerDelegate - -- (void)approveContactShare:(ContactShareApprovalViewController *)approveContactShare - didApproveContactShare:(ContactShareViewModel *)contactShare -{ - OWSLogInfo(@""); - - [self dismissViewControllerAnimated:YES - completion:^{ - [self sendContactShare:contactShare]; - }]; -} - -- (void)approveContactShare:(ContactShareApprovalViewController *)approveContactShare - didCancelContactShare:(ContactShareViewModel *)contactShare -{ - OWSLogInfo(@""); - - [self dismissViewControllerAnimated:YES completion:nil]; -} - -#pragma mark - ContactShareViewHelperDelegate - -- (void)didCreateOrEditContact -{ - OWSLogInfo(@""); - [self dismissViewControllerAnimated:YES completion:nil]; -} - #pragma mark - Toast - (void)presentMissingQuotedReplyToast @@ -5424,12 +4621,6 @@ typedef enum : NSUInteger { if (targetInteraction == nil || targetInteraction.interactionType != OWSInteractionType_OutgoingMessage) { return; } NSString *hexEncodedPublicKey = targetInteraction.thread.contactIdentifier; if (hexEncodedPublicKey == nil) { return; } - __block NSString *masterHexEncodedPublicKey; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - masterHexEncodedPublicKey = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:hexEncodedPublicKey in:transaction] ?: hexEncodedPublicKey; - }]; - BOOL isSlaveDevice = ![masterHexEncodedPublicKey isEqual:hexEncodedPublicKey]; - if (isSlaveDevice) { return; } if (progress <= self.progressIndicatorView.progress) { return; } self.progressIndicatorView.alpha = 1; [self.progressIndicatorView setProgress:progress animated:YES]; @@ -5454,16 +4645,6 @@ typedef enum : NSUInteger { }); } -- (void)handleUnexpectedDeviceLinkRequestReceivedNotification -{ - if (!LKDeviceLinkingUtilities.shouldShowUnexpectedDeviceLinkRequestReceivedAlert) { return; } - dispatch_async(dispatch_get_main_queue(), ^{ - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Device Link Request Received" message:@"Open the device link screen by going to \"Settings\" > \"Devices\" > \"Link a Device\" to link your devices." preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; - [self presentViewController:alert animated:YES completion:nil]; - }); -} - @end NS_ASSUME_NONNULL_END diff --git a/Session/Signal/ConversationView/ConversationViewItem.h b/Session/Signal/ConversationView/ConversationViewItem.h index 984210640..3464d077d 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.h +++ b/Session/Signal/ConversationView/ConversationViewItem.h @@ -12,7 +12,6 @@ typedef NS_ENUM(NSInteger, OWSMessageCellType) { OWSMessageCellType_TextOnlyMessage, OWSMessageCellType_Audio, OWSMessageCellType_GenericAttachment, - OWSMessageCellType_ContactShare, OWSMessageCellType_MediaMessage, OWSMessageCellType_OversizeTextDownloading, }; @@ -67,7 +66,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType); @property (nonatomic, readonly, nullable) OWSQuotedReplyModel *quotedReply; @property (nonatomic, readonly) BOOL isGroupThread; -@property (nonatomic, readonly) BOOL isRSSFeed; @property (nonatomic, readonly) BOOL userCanDeleteGroupMessage; @property (nonatomic, readonly) BOOL hasBodyText; @@ -163,7 +161,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType); - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithInteraction:(TSInteraction *)interaction isGroupThread:(BOOL)isGroupThread - isRSSFeed:(BOOL)isRSSFeed transaction:(YapDatabaseReadTransaction *)transaction conversationStyle:(ConversationStyle *)conversationStyle; diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index c3fa1eaca..593cf28a7 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -4,7 +4,7 @@ #import #import "ConversationViewItem.h" -#import "OWSContactOffersCell.h" + #import "OWSMessageCell.h" #import "OWSMessageHeaderView.h" #import "OWSSystemMessageCell.h" @@ -13,7 +13,7 @@ #import #import #import -#import + #import #import #import @@ -31,8 +31,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) return @"OWSMessageCellType_GenericAttachment"; case OWSMessageCellType_Unknown: return @"OWSMessageCellType_Unknown"; - case OWSMessageCellType_ContactShare: - return @"OWSMessageCellType_ContactShare"; case OWSMessageCellType_MediaMessage: return @"OWSMessageCellType_MediaMessage"; case OWSMessageCellType_OversizeTextDownloading: @@ -119,7 +117,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) @synthesize interaction = _interaction; @synthesize isFirstInCluster = _isFirstInCluster; @synthesize isGroupThread = _isGroupThread; -@synthesize isRSSFeed = _isRSSFeed; @synthesize isLastInCluster = _isLastInCluster; @synthesize lastAudioMessageView = _lastAudioMessageView; @synthesize senderName = _senderName; @@ -127,7 +124,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) - (instancetype)initWithInteraction:(TSInteraction *)interaction isGroupThread:(BOOL)isGroupThread - isRSSFeed:(BOOL)isRSSFeed transaction:(YapDatabaseReadTransaction *)transaction conversationStyle:(ConversationStyle *)conversationStyle { @@ -143,11 +139,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) _interaction = interaction; _isGroupThread = isGroupThread; - _isRSSFeed = isRSSFeed; _conversationStyle = conversationStyle; - [self updateAuthorConversationColorNameWithTransaction:transaction]; - [self ensureViewState:transaction]; return self; @@ -173,37 +166,11 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) self.linkPreview = nil; self.linkPreviewAttachment = nil; - [self updateAuthorConversationColorNameWithTransaction:transaction]; - [self clearCachedLayoutState]; [self ensureViewState:transaction]; } -- (void)updateAuthorConversationColorNameWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - switch (self.interaction.interactionType) { - case OWSInteractionType_TypingIndicator: { - OWSTypingIndicatorInteraction *typingIndicator = (OWSTypingIndicatorInteraction *)self.interaction; - _authorConversationColorName = - [TSContactThread conversationColorNameForRecipientId:typingIndicator.recipientId - transaction:transaction]; - break; - } - case OWSInteractionType_IncomingMessage: { - TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.interaction; - _authorConversationColorName = - [TSContactThread conversationColorNameForRecipientId:incomingMessage.authorId transaction:transaction]; - break; - } - default: - _authorConversationColorName = nil; - break; - } -} - - (OWSPrimaryStorage *)primaryStorage { return SSKEnvironment.shared.primaryStorage; @@ -385,9 +352,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) case OWSInteractionType_Call: measurementCell = [OWSSystemMessageCell new]; break; - case OWSInteractionType_Offer: - measurementCell = [OWSContactOffersCell new]; - break; case OWSInteractionType_TypingIndicator: measurementCell = [OWSTypingIndicatorCell new]; break; @@ -445,10 +409,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) case OWSInteractionType_Call: return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSSystemMessageCell cellReuseIdentifier] forIndexPath:indexPath]; - case OWSInteractionType_Offer: - return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier] - forIndexPath:indexPath]; - case OWSInteractionType_TypingIndicator: return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSTypingIndicatorCell cellReuseIdentifier] forIndexPath:indexPath]; @@ -609,12 +569,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) self.hasViewState = YES; TSMessage *message = (TSMessage *)self.interaction; - if (message.contactShare) { - self.contactShare = - [[ContactShareViewModel alloc] initWithContactShareRecord:message.contactShare transaction:transaction]; - self.messageCellType = OWSMessageCellType_ContactShare; - return; - } // Check for quoted replies _before_ media album handling, // since that logic may exit early. @@ -804,35 +758,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) } case OWSInteractionType_Info: { TSInfoMessage *infoMessage = (TSInfoMessage *)self.interaction; - if ([infoMessage isKindOfClass:[OWSVerificationStateChangeMessage class]]) { - OWSVerificationStateChangeMessage *verificationMessage - = (OWSVerificationStateChangeMessage *)infoMessage; - BOOL isVerified = verificationMessage.verificationState == OWSVerificationStateVerified; - NSString *displayName = - [Environment.shared.contactsManager displayNameForPhoneIdentifier:verificationMessage.recipientId]; - NSString *titleFormat = (isVerified - ? (verificationMessage.isLocalChange - ? NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_VERIFIED_LOCAL", - @"Format for info message indicating that the verification state was verified " - @"on " - @"this device. Embeds {{user's name or phone number}}.") - : NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_VERIFIED_OTHER_DEVICE", - @"Format for info message indicating that the verification state was verified " - @"on " - @"another device. Embeds {{user's name or phone number}}.")) - : (verificationMessage.isLocalChange - ? NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_NOT_VERIFIED_LOCAL", - @"Format for info message indicating that the verification state was " - @"unverified on " - @"this device. Embeds {{user's name or phone number}}.") - : NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_NOT_VERIFIED_OTHER_DEVICE", - @"Format for info message indicating that the verification state was " - @"unverified on " - @"another device. Embeds {{user's name or phone number}}."))); - return [NSString stringWithFormat:titleFormat, displayName]; - } else { - return [infoMessage previewTextWithTransaction:transaction]; - } + return [infoMessage previewTextWithTransaction:transaction]; } case OWSInteractionType_Call: { TSCall *call = (TSCall *)self.interaction; @@ -921,11 +847,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) OWSFailDebug(@"No text to copy"); break; } - case OWSMessageCellType_ContactShare: { - // TODO: Implement copy contact. - OWSFailDebug(@"Not implemented yet"); - break; - } case OWSMessageCellType_OversizeTextDownloading: OWSFailDebug(@"Can't copy not-yet-downloaded attachment"); return; @@ -942,10 +863,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) switch (self.messageCellType) { case OWSMessageCellType_Unknown: case OWSMessageCellType_TextOnlyMessage: - case OWSMessageCellType_ContactShare: { - OWSFailDebug(@"No media to copy"); - break; - } case OWSMessageCellType_Audio: case OWSMessageCellType_GenericAttachment: { [self copyAttachmentToPasteboard:self.attachmentStream]; @@ -996,9 +913,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) switch (self.messageCellType) { case OWSMessageCellType_Unknown: case OWSMessageCellType_TextOnlyMessage: - case OWSMessageCellType_ContactShare: - OWSFailDebug(@"No media to share."); - break; case OWSMessageCellType_Audio: case OWSMessageCellType_GenericAttachment: [AttachmentSharing showShareUIForAttachment:self.attachmentStream]; @@ -1035,8 +949,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) switch (self.messageCellType) { case OWSMessageCellType_Unknown: case OWSMessageCellType_TextOnlyMessage: - case OWSMessageCellType_ContactShare: - return NO; case OWSMessageCellType_Audio: return NO; case OWSMessageCellType_GenericAttachment: @@ -1064,8 +976,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) switch (self.messageCellType) { case OWSMessageCellType_Unknown: case OWSMessageCellType_TextOnlyMessage: - case OWSMessageCellType_ContactShare: - return NO; case OWSMessageCellType_Audio: return NO; case OWSMessageCellType_GenericAttachment: @@ -1104,9 +1014,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) switch (self.messageCellType) { case OWSMessageCellType_Unknown: case OWSMessageCellType_TextOnlyMessage: - case OWSMessageCellType_ContactShare: - OWSFailDebug(@"Cannot save text data."); - break; case OWSMessageCellType_Audio: OWSFailDebug(@"Cannot save media data."); break; @@ -1177,7 +1084,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) if (self.isGroupThread) { // Skip if the thread is an RSS feed TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread; - if (groupThread.isRSSFeed) return; // Only allow deletion on incoming and outgoing messages OWSInteractionType interationType = self.interaction.interactionType; @@ -1217,8 +1123,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) switch (self.messageCellType) { case OWSMessageCellType_Unknown: case OWSMessageCellType_TextOnlyMessage: - case OWSMessageCellType_ContactShare: - return NO; case OWSMessageCellType_Audio: case OWSMessageCellType_GenericAttachment: return self.attachmentStream != nil; @@ -1252,7 +1156,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) // Ensure the thread is a public chat and not an RSS feed TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread; - if (groupThread.isRSSFeed) return false; // Only allow deletion on incoming and outgoing messages OWSInteractionType interationType = self.interaction.interactionType; diff --git a/Session/Signal/ConversationView/ConversationViewModel.h b/Session/Signal/ConversationView/ConversationViewModel.h index daa28db23..84ef4a6db 100644 --- a/Session/Signal/ConversationView/ConversationViewModel.h +++ b/Session/Signal/ConversationView/ConversationViewModel.h @@ -98,12 +98,10 @@ typedef NS_ENUM(NSUInteger, ConversationUpdateItemType) { @property (nonatomic, readonly) ConversationViewState *viewState; @property (nonatomic, nullable) NSString *focusMessageIdOnOpen; @property (nonatomic, readonly, nullable) ThreadDynamicInteractions *dynamicInteractions; -@property (nonatomic, readonly) BOOL isRSSFeed; - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithThread:(TSThread *)thread focusMessageIdOnOpen:(nullable NSString *)focusMessageIdOnOpen - isRSSFeed:(BOOL)isRSSFeed delegate:(id)delegate NS_DESIGNATED_INITIALIZER; - (void)ensureDynamicInteractionsAndUpdateIfNecessary:(BOOL)updateIfNecessary; diff --git a/Session/Signal/ConversationView/ConversationViewModel.m b/Session/Signal/ConversationView/ConversationViewModel.m index aa287a615..12a2c5cae 100644 --- a/Session/Signal/ConversationView/ConversationViewModel.m +++ b/Session/Signal/ConversationView/ConversationViewModel.m @@ -10,10 +10,10 @@ #import "Session-Swift.h" #import #import -#import + #import #import -#import + #import #import #import @@ -226,7 +226,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; - (instancetype)initWithThread:(TSThread *)thread focusMessageIdOnOpen:(nullable NSString *)focusMessageIdOnOpen - isRSSFeed:(BOOL)isRSSFeed delegate:(id)delegate { self = [super init]; @@ -242,7 +241,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; _persistedViewItems = @[]; _unsavedOutgoingMessages = @[]; self.focusMessageIdOnOpen = focusMessageIdOnOpen; - _isRSSFeed = isRSSFeed; _viewState = [[ConversationViewState alloc] initWithViewItems:@[]]; [self configure]; @@ -269,11 +267,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; return self.primaryStorage.dbReadWriteConnection; } -- (OWSContactsManager *)contactsManager -{ - return (OWSContactsManager *)SSKEnvironment.shared.contactsManager; -} - - (OWSBlockingManager *)blockingManager { return OWSBlockingManager.sharedManager; @@ -304,10 +297,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; selector:@selector(applicationDidEnterBackground:) name:OWSApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(signalAccountsDidChange:) - name:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(typingIndicatorStateDidChange:) name:[OWSTypingIndicatorsImpl typingIndicatorStateDidChange] @@ -530,7 +519,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; ThreadDynamicInteractions *dynamicInteractions = [ThreadUtil ensureDynamicInteractionsForThread:self.thread - contactsManager:self.contactsManager blockingManager:self.blockingManager dbConnection:self.editingDatabaseConnection hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator @@ -1023,24 +1011,10 @@ static const int kYapDatabaseRangeMaxLength = 25000; return; } - // Many OWSProfileManager methods aren't safe to call from inside a database - // transaction, so do this work now. - // - // TODO: It'd be nice if these methods took a transaction. - BOOL hasLocalProfile = [self.profileManager hasLocalProfile]; - BOOL isThreadInProfileWhitelist = [self.profileManager isThreadInProfileWhitelist:self.thread]; - BOOL hasUnwhitelistedMember = NO; - for (NSString *recipientId in self.thread.recipientIdentifiers) { - if (![self.profileManager isUserInProfileWhitelist:recipientId]) { - hasUnwhitelistedMember = YES; - break; - } - } - ConversationProfileState *conversationProfileState = [ConversationProfileState new]; - conversationProfileState.hasLocalProfile = hasLocalProfile; - conversationProfileState.isThreadInProfileWhitelist = isThreadInProfileWhitelist; - conversationProfileState.hasUnwhitelistedMember = hasUnwhitelistedMember; + conversationProfileState.hasLocalProfile = YES; + conversationProfileState.isThreadInProfileWhitelist = YES; + conversationProfileState.hasUnwhitelistedMember = NO; self.conversationProfileState = conversationProfileState; } @@ -1136,15 +1110,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; // Don't create profile whitelist offers for users which are not already blocked. shouldHaveAddToProfileWhitelistOffer = NO; } - - if ([self.contactsManager hasSignalAccountForRecipientId:recipientId]) { - // Only create "add to contacts" offers for non-contacts. - shouldHaveAddToContactsOffer = NO; - // Only create block offers for non-contacts. - shouldHaveBlockOffer = NO; - // Don't create profile whitelist offers for non-contacts. - shouldHaveAddToProfileWhitelistOffer = NO; - } } if (hasTooManyOutgoingMessagesToBlock) { @@ -1214,7 +1179,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; NSArray *loadedUniqueIds = [self.messageMapping loadedUniqueIds]; BOOL isGroupThread = self.thread.isGroupThread; - BOOL isRSSFeed = self.isRSSFeed; ConversationStyle *conversationStyle = self.delegate.conversationStyle; [self ensureConversationProfileState]; @@ -1228,7 +1192,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; if (!viewItem) { viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:interaction isGroupThread:isGroupThread - isRSSFeed:isRSSFeed transaction:transaction conversationStyle:conversationStyle]; } @@ -1236,7 +1199,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; viewItemCache[interaction.uniqueId] = viewItem; [viewItems addObject:viewItem]; TSMessage *message = (TSMessage *)viewItem.interaction; - if (message.hasAttachmentsInNSE) { + if (message.hasUnfetchedAttachmentsFromPN) { [SSKEnvironment.shared.attachmentDownloads downloadAttachmentsForMessage:message transaction:transaction success:^(NSArray *attachmentStreams) { @@ -1534,8 +1497,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; } if (shouldShowSenderName) { - senderName = [self.contactsManager attributedContactOrProfileNameForPhoneIdentifier:incomingSenderId primaryAttributes:[OWSMessageBubbleView senderNamePrimaryAttributes] - secondaryAttributes:[OWSMessageBubbleView senderNameSecondaryAttributes]]; + senderName = [[NSAttributedString alloc] initWithString:[SSKEnvironment.shared.profileManager profileNameForRecipientWithID:incomingSenderId avoidingWriteTransaction:YES]]; if ([self.thread isKindOfClass:[TSGroupThread class]]) { TSGroupThread *groupThread = (TSGroupThread *)self.thread; @@ -1558,9 +1520,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; // the next message has the same sender avatar and // no "date break" separates us. shouldShowSenderAvatar = YES; - if (viewItem.isRSSFeed) { - shouldShowSenderAvatar = NO; - } else if (previousViewItem && previousViewItem.interaction.interactionType == interactionType) { + if (previousViewItem && previousViewItem.interaction.interactionType == interactionType) { shouldShowSenderAvatar = (![NSObject isNullableObject:previousIncomingSenderId equalTo:incomingSenderId]); } } diff --git a/Session/Signal/DomainFrontingCountryViewController.h b/Session/Signal/DomainFrontingCountryViewController.h deleted file mode 100644 index 77899f26b..000000000 --- a/Session/Signal/DomainFrontingCountryViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface DomainFrontingCountryViewController : OWSViewController - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/DomainFrontingCountryViewController.m b/Session/Signal/DomainFrontingCountryViewController.m deleted file mode 100644 index 5497842f7..000000000 --- a/Session/Signal/DomainFrontingCountryViewController.m +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "DomainFrontingCountryViewController.h" -#import "OWSCountryMetadata.h" -#import "OWSTableViewController.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - - -@interface DomainFrontingCountryViewController () - -@property (nonatomic, readonly) OWSTableViewController *tableViewController; - -@end - -#pragma mark - - -@implementation DomainFrontingCountryViewController - -- (void)loadView -{ - [super loadView]; - - self.title = NSLocalizedString( - @"CENSORSHIP_CIRCUMVENTION_COUNTRY_VIEW_TITLE", @"Title for the 'censorship circumvention country' view."); - - self.view.backgroundColor = Theme.backgroundColor; - - [self createViews]; -} - -- (void)createViews -{ - _tableViewController = [OWSTableViewController new]; - [self.view addSubview:self.tableViewController.view]; - [self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeLeading]; - [self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing]; - [_tableViewController.view autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:0.0f]; - [_tableViewController.view autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.view withOffset:0.0f]; - - [self updateTableContents]; -} - -#pragma mark - Table Contents - -- (void)updateTableContents -{ - OWSTableContents *contents = [OWSTableContents new]; - - NSString *currentCountryCode = OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode; - - __weak DomainFrontingCountryViewController *weakSelf = self; - - OWSTableSection *section = [OWSTableSection new]; - section.headerTitle = NSLocalizedString( - @"DOMAIN_FRONTING_COUNTRY_VIEW_SECTION_HEADER", @"Section title for the 'domain fronting country' view."); - for (OWSCountryMetadata *countryMetadata in [OWSCountryMetadata allCountryMetadatas]) { - [section addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - UITableViewCell *cell = [OWSTableItem newCell]; - [OWSTableItem configureCell:cell]; - cell.textLabel.text = countryMetadata.localizedCountryName; - - if ([countryMetadata.countryCode isEqualToString:currentCountryCode]) { - cell.accessoryType = UITableViewCellAccessoryCheckmark; - } - - return cell; - } - actionBlock:^{ - [weakSelf selectCountry:countryMetadata]; - }]]; - } - [contents addSection:section]; - - self.tableViewController.contents = contents; -} - -- (void)selectCountry:(OWSCountryMetadata *)countryMetadata -{ - OWSAssertDebug(countryMetadata); - - OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode = countryMetadata.countryCode; - - [self.navigationController popViewControllerAnimated:YES]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/FingerprintViewController.h b/Session/Signal/FingerprintViewController.h deleted file mode 100644 index b99859937..000000000 --- a/Session/Signal/FingerprintViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FingerprintViewController : OWSViewController - -+ (void)presentFromViewController:(UIViewController *)viewController recipientId:(NSString *)recipientId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/FingerprintViewController.m b/Session/Signal/FingerprintViewController.m deleted file mode 100644 index 8c185f364..000000000 --- a/Session/Signal/FingerprintViewController.m +++ /dev/null @@ -1,558 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "FingerprintViewController.h" -#import "FingerprintViewScanController.h" -#import "OWSBezierPathView.h" -#import "Session-Swift.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^CustomLayoutBlock)(void); - -@interface CustomLayoutView : UIView - -@property (nonatomic) CustomLayoutBlock layoutBlock; - -@end - -#pragma mark - - -@implementation CustomLayoutView - -- (instancetype)init -{ - if (self = [super init]) { - self.translatesAutoresizingMaskIntoConstraints = NO; - } - return self; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) { - self.translatesAutoresizingMaskIntoConstraints = NO; - } - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder -{ - if (self = [super initWithCoder:aDecoder]) { - self.translatesAutoresizingMaskIntoConstraints = NO; - } - return self; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - self.layoutBlock(); -} - -@end - -#pragma mark - - -@interface FingerprintViewController () - -@property (nonatomic) NSString *recipientId; -@property (nonatomic) NSData *identityKey; -@property (nonatomic) TSAccountManager *accountManager; -@property (nonatomic) OWSFingerprint *fingerprint; -@property (nonatomic) NSString *contactName; - -@property (nonatomic) UIBarButtonItem *shareButton; - -@property (nonatomic) UILabel *verificationStateLabel; -@property (nonatomic) UILabel *verifyUnverifyButtonLabel; - -@end - -#pragma mark - - -@implementation FingerprintViewController - -+ (void)presentFromViewController:(UIViewController *)viewController recipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - OWSRecipientIdentity *_Nullable recipientIdentity = - [[OWSIdentityManager sharedManager] recipientIdentityForRecipientId:recipientId]; - if (!recipientIdentity) { - [OWSAlerts showAlertWithTitle:NSLocalizedString(@"CANT_VERIFY_IDENTITY_ALERT_TITLE", - @"Title for alert explaining that a user cannot be verified.") - message:NSLocalizedString(@"CANT_VERIFY_IDENTITY_ALERT_MESSAGE", - @"Message for alert explaining that a user cannot be verified.")]; - return; - } - - FingerprintViewController *fingerprintViewController = [FingerprintViewController new]; - [fingerprintViewController configureWithRecipientId:recipientId]; - OWSNavigationController *navigationController = - [[OWSNavigationController alloc] initWithRootViewController:fingerprintViewController]; - [viewController presentViewController:navigationController animated:YES completion:nil]; -} - -- (instancetype)init -{ - self = [super init]; - - if (!self) { - return self; - } - - _accountManager = [TSAccountManager sharedInstance]; - - [self observeNotifications]; - - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)observeNotifications -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(identityStateDidChange:) - name:kNSNotificationName_IdentityStateDidChange - object:nil]; -} - -- (void)configureWithRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - self.recipientId = recipientId; - - OWSContactsManager *contactsManager = Environment.shared.contactsManager; - self.contactName = [contactsManager displayNameForPhoneIdentifier:recipientId]; - - OWSRecipientIdentity *_Nullable recipientIdentity = - [[OWSIdentityManager sharedManager] recipientIdentityForRecipientId:recipientId]; - OWSAssertDebug(recipientIdentity); - // By capturing the identity key when we enter these views, we prevent the edge case - // where the user verifies a key that we learned about while this view was open. - self.identityKey = recipientIdentity.identityKey; - - OWSFingerprintBuilder *builder = - [[OWSFingerprintBuilder alloc] initWithAccountManager:self.accountManager contactsManager:contactsManager]; - self.fingerprint = - [builder fingerprintWithTheirSignalId:recipientId theirIdentityKey:recipientIdentity.identityKey]; -} - -- (void)loadView -{ - [super loadView]; - - self.title = NSLocalizedString(@"PRIVACY_VERIFICATION_TITLE", @"Navbar title"); - - self.navigationItem.leftBarButtonItem = - [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop - target:self - action:@selector(closeButton) - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"stop")]; - self.shareButton = - [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction - target:self - action:@selector(didTapShareButton) - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"share")]; - self.navigationItem.rightBarButtonItem = self.shareButton; - - [self createViews]; -} - -- (void)createViews -{ - self.view.backgroundColor = Theme.backgroundColor; - - // Verify/Unverify Button - UIView *verifyUnverifyButton = [UIView new]; - [verifyUnverifyButton - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(verifyUnverifyButtonTapped:)]]; - [self.view addSubview:verifyUnverifyButton]; - [verifyUnverifyButton autoPinWidthToSuperview]; - [verifyUnverifyButton autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.view withOffset:0.0f]; - SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, verifyUnverifyButton); - - UIView *verifyUnverifyPillbox = [UIView new]; - verifyUnverifyPillbox.backgroundColor = [UIColor ows_materialBlueColor]; - verifyUnverifyPillbox.layer.cornerRadius = 3.f; - verifyUnverifyPillbox.clipsToBounds = YES; - [verifyUnverifyButton addSubview:verifyUnverifyPillbox]; - [verifyUnverifyPillbox autoHCenterInSuperview]; - [verifyUnverifyPillbox autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:ScaleFromIPhone5To7Plus(10.f, 15.f)]; - [verifyUnverifyPillbox autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:ScaleFromIPhone5To7Plus(10.f, 20.f)]; - - UILabel *verifyUnverifyButtonLabel = [UILabel new]; - self.verifyUnverifyButtonLabel = verifyUnverifyButtonLabel; - verifyUnverifyButtonLabel.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(14.f, 20.f)]; - verifyUnverifyButtonLabel.textColor = [UIColor whiteColor]; - verifyUnverifyButtonLabel.textAlignment = NSTextAlignmentCenter; - [verifyUnverifyPillbox addSubview:verifyUnverifyButtonLabel]; - [verifyUnverifyButtonLabel autoPinWidthToSuperviewWithMargin:ScaleFromIPhone5To7Plus(50.f, 50.f)]; - [verifyUnverifyButtonLabel autoPinHeightToSuperviewWithMargin:ScaleFromIPhone5To7Plus(8.f, 8.f)]; - - // Learn More - UIView *learnMoreButton = [UIView new]; - [learnMoreButton - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(learnMoreButtonTapped:)]]; - [self.view addSubview:learnMoreButton]; - [learnMoreButton autoPinWidthToSuperview]; - [learnMoreButton autoPinEdge:ALEdgeBottom toEdge:ALEdgeTop ofView:verifyUnverifyButton withOffset:0]; - SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, learnMoreButton); - - UILabel *learnMoreLabel = [UILabel new]; - learnMoreLabel.attributedText = [[NSAttributedString alloc] - initWithString:NSLocalizedString(@"PRIVACY_SAFETY_NUMBERS_LEARN_MORE", - @"Label for a link to more information about safety numbers and verification.") - attributes:@{ - NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid), - }]; - learnMoreLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(13.f, 16.f)]; - learnMoreLabel.textColor = [UIColor ows_materialBlueColor]; - learnMoreLabel.textAlignment = NSTextAlignmentCenter; - [learnMoreButton addSubview:learnMoreLabel]; - [learnMoreLabel autoPinWidthToSuperviewWithMargin:16.f]; - [learnMoreLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:ScaleFromIPhone5To7Plus(5.f, 10.f)]; - [learnMoreLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:ScaleFromIPhone5To7Plus(5.f, 10.f)]; - - // Instructions - NSString *instructionsFormat = NSLocalizedString(@"PRIVACY_VERIFICATION_INSTRUCTIONS", - @"Paragraph(s) shown alongside the safety number when verifying privacy with {{contact name}}"); - UILabel *instructionsLabel = [UILabel new]; - instructionsLabel.text = [NSString stringWithFormat:instructionsFormat, self.contactName]; - instructionsLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(11.f, 14.f)]; - instructionsLabel.textColor = Theme.secondaryColor; - instructionsLabel.textAlignment = NSTextAlignmentCenter; - instructionsLabel.numberOfLines = 0; - instructionsLabel.lineBreakMode = NSLineBreakByWordWrapping; - [self.view addSubview:instructionsLabel]; - [instructionsLabel autoPinWidthToSuperviewWithMargin:16.f]; - [instructionsLabel autoPinEdge:ALEdgeBottom toEdge:ALEdgeTop ofView:learnMoreButton withOffset:0]; - - // Fingerprint Label - UILabel *fingerprintLabel = [UILabel new]; - fingerprintLabel.text = self.fingerprint.displayableText; - fingerprintLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:ScaleFromIPhone5To7Plus(20.f, 23.f)]; - fingerprintLabel.textColor = Theme.secondaryColor; - fingerprintLabel.numberOfLines = 3; - fingerprintLabel.lineBreakMode = NSLineBreakByTruncatingTail; - fingerprintLabel.adjustsFontSizeToFitWidth = YES; - [fingerprintLabel - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(fingerprintLabelTapped:)]]; - fingerprintLabel.userInteractionEnabled = YES; - [self.view addSubview:fingerprintLabel]; - [fingerprintLabel autoPinWidthToSuperviewWithMargin:ScaleFromIPhone5To7Plus(50.f, 60.f)]; - [fingerprintLabel autoPinEdge:ALEdgeBottom - toEdge:ALEdgeTop - ofView:instructionsLabel - withOffset:-ScaleFromIPhone5To7Plus(8.f, 15.f)]; - SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, fingerprintLabel); - - // Fingerprint Image - CustomLayoutView *fingerprintView = [CustomLayoutView new]; - [self.view addSubview:fingerprintView]; - [fingerprintView autoPinWidthToSuperview]; - [fingerprintView autoPinEdge:ALEdgeBottom - toEdge:ALEdgeTop - ofView:fingerprintLabel - withOffset:-ScaleFromIPhone5To7Plus(10.f, 15.f)]; - [fingerprintView - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(fingerprintViewTapped:)]]; - fingerprintView.userInteractionEnabled = YES; - SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, fingerprintView); - - OWSBezierPathView *fingerprintCircle = [OWSBezierPathView new]; - [fingerprintCircle setConfigureShapeLayerBlock:^(CAShapeLayer *layer, CGRect bounds) { - layer.fillColor = Theme.offBackgroundColor.CGColor; - CGFloat size = MIN(bounds.size.width, bounds.size.height); - CGRect circle = CGRectMake((bounds.size.width - size) * 0.5f, (bounds.size.height - size) * 0.5f, size, size); - layer.path = [UIBezierPath bezierPathWithOvalInRect:circle].CGPath; - }]; - [fingerprintView addSubview:fingerprintCircle]; - [fingerprintCircle ows_autoPinToSuperviewEdges]; - - UIImageView *fingerprintImageView = [UIImageView new]; - fingerprintImageView.image = self.fingerprint.image; - // Don't antialias QR Codes. - fingerprintImageView.layer.magnificationFilter = kCAFilterNearest; - fingerprintImageView.layer.minificationFilter = kCAFilterNearest; - [fingerprintView addSubview:fingerprintImageView]; - - UILabel *scanLabel = [UILabel new]; - scanLabel.text = NSLocalizedString(@"PRIVACY_TAP_TO_SCAN", @"Button that shows the 'scan with camera' view."); - scanLabel.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(14.f, 16.f)]; - scanLabel.textColor = Theme.secondaryColor; - [scanLabel sizeToFit]; - [fingerprintView addSubview:scanLabel]; - - fingerprintView.layoutBlock = ^{ - CGFloat size = round(MIN(fingerprintView.width, fingerprintView.height) * 0.675f); - fingerprintImageView.frame = CGRectMake( - round((fingerprintView.width - size) * 0.5f), round((fingerprintView.height - size) * 0.5f), size, size); - CGFloat scanY = round(fingerprintImageView.bottom - + ((fingerprintView.height - fingerprintImageView.bottom) - scanLabel.height) * 0.33f); - scanLabel.frame = CGRectMake( - round((fingerprintView.width - scanLabel.width) * 0.5f), scanY, scanLabel.width, scanLabel.height); - }; - - // Verification State - UILabel *verificationStateLabel = [UILabel new]; - self.verificationStateLabel = verificationStateLabel; - verificationStateLabel.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(16.f, 20.f)]; - verificationStateLabel.textColor = Theme.secondaryColor; - verificationStateLabel.textAlignment = NSTextAlignmentCenter; - verificationStateLabel.numberOfLines = 0; - verificationStateLabel.lineBreakMode = NSLineBreakByWordWrapping; - [self.view addSubview:verificationStateLabel]; - [verificationStateLabel autoPinWidthToSuperviewWithMargin:16.f]; - // Bind height of label to height of two lines of text. - // This should always be sufficient, and will prevent the view's - // layout from changing if the user is marked as verified or not - // verified. - [verificationStateLabel autoSetDimension:ALDimensionHeight - toSize:round(verificationStateLabel.font.lineHeight * 2.25f)]; - [verificationStateLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:ScaleFromIPhone5To7Plus(15.f, 20.f)]; - [verificationStateLabel autoPinEdge:ALEdgeBottom - toEdge:ALEdgeTop - ofView:fingerprintView - withOffset:-ScaleFromIPhone5To7Plus(10.f, 15.f)]; - - [self updateVerificationStateLabel]; -} - -- (void)updateVerificationStateLabel -{ - OWSAssertDebug(self.recipientId.length > 0); - - BOOL isVerified = [[OWSIdentityManager sharedManager] verificationStateForRecipientId:self.recipientId] - == OWSVerificationStateVerified; - - if (isVerified) { - NSMutableAttributedString *labelText = [NSMutableAttributedString new]; - - if (isVerified) { - // Show a "checkmark" if this user is verified. - [labelText - appendAttributedString:[[NSAttributedString alloc] - initWithString:LocalizationNotNeeded(@"\uf00c ") - attributes:@{ - NSFontAttributeName : [UIFont - ows_fontAwesomeFont:self.verificationStateLabel.font.pointSize], - }]]; - } - - [labelText - appendAttributedString: - [[NSAttributedString alloc] - initWithString:[NSString stringWithFormat:NSLocalizedString(@"PRIVACY_IDENTITY_IS_VERIFIED_FORMAT", - @"Label indicating that the user is verified. Embeds " - @"{{the user's name or phone number}}."), - self.contactName]]]; - self.verificationStateLabel.attributedText = labelText; - - self.verifyUnverifyButtonLabel.text = NSLocalizedString( - @"PRIVACY_UNVERIFY_BUTTON", @"Button that lets user mark another user's identity as unverified."); - } else { - self.verificationStateLabel.text = [NSString - stringWithFormat:NSLocalizedString(@"PRIVACY_IDENTITY_IS_NOT_VERIFIED_FORMAT", - @"Label indicating that the user is not verified. Embeds {{the user's name or phone " - @"number}}."), - self.contactName]; - - NSMutableAttributedString *buttonText = [NSMutableAttributedString new]; - // Show a "checkmark" if this user is not verified. - [buttonText - appendAttributedString:[[NSAttributedString alloc] - initWithString:LocalizationNotNeeded(@"\uf00c ") - attributes:@{ - NSFontAttributeName : [UIFont - ows_fontAwesomeFont:self.verifyUnverifyButtonLabel.font.pointSize], - }]]; - [buttonText appendAttributedString: - [[NSAttributedString alloc] - initWithString:NSLocalizedString(@"PRIVACY_VERIFY_BUTTON", - @"Button that lets user mark another user's identity as verified.")]]; - self.verifyUnverifyButtonLabel.attributedText = buttonText; - } - - [self.view setNeedsLayout]; -} - -#pragma mark - - -- (void)showSharingActivityWithCompletion:(nullable void (^)(void))completionHandler -{ - OWSLogDebug(@"Sharing safety numbers"); - - OWSCompareSafetyNumbersActivity *compareActivity = [[OWSCompareSafetyNumbersActivity alloc] initWithDelegate:self]; - - NSString *shareFormat = NSLocalizedString( - @"SAFETY_NUMBER_SHARE_FORMAT", @"Snippet to share {{safety number}} with a friend. sent e.g. via SMS"); - NSString *shareString = [NSString stringWithFormat:shareFormat, self.fingerprint.displayableText]; - - UIActivityViewController *activityController = - [[UIActivityViewController alloc] initWithActivityItems:@[ shareString ] - applicationActivities:@[ compareActivity ]]; - - activityController.completionWithItemsHandler = ^void(UIActivityType __nullable activityType, - BOOL completed, - NSArray *__nullable returnedItems, - NSError *__nullable activityError) { - if (completionHandler) { - completionHandler(); - } - }; - - // This value was extracted by inspecting `activityType` in the activityController.completionHandler - NSString *const iCloudActivityType = @"com.apple.CloudDocsUI.AddToiCloudDrive"; - activityController.excludedActivityTypes = @[ - UIActivityTypePostToFacebook, - UIActivityTypePostToWeibo, - UIActivityTypeAirDrop, - UIActivityTypePostToTwitter, - iCloudActivityType // This isn't being excluded. RADAR https://openradar.appspot.com/27493621 - ]; - - [self presentViewController:activityController animated:YES completion:nil]; -} - -#pragma mark - OWSCompareSafetyNumbersActivityDelegate - -- (void)compareSafetyNumbersActivitySucceededWithActivity:(OWSCompareSafetyNumbersActivity *)activity -{ - [self showVerificationSucceeded]; -} - -- (void)compareSafetyNumbersActivity:(OWSCompareSafetyNumbersActivity *)activity failedWithError:(NSError *)error -{ - [self showVerificationFailedWithError:error]; -} - -- (void)showVerificationSucceeded -{ - [FingerprintViewScanController showVerificationSucceeded:self - identityKey:self.identityKey - recipientId:self.recipientId - contactName:self.contactName - tag:self.logTag]; -} - -- (void)showVerificationFailedWithError:(NSError *)error -{ - - [FingerprintViewScanController showVerificationFailedWithError:error - viewController:self - retryBlock:nil - cancelBlock:^{ - // Do nothing. - } - tag:self.logTag]; -} - -#pragma mark - Action - -- (void)closeButton -{ - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (void)didTapShareButton -{ - [self showSharingActivityWithCompletion:nil]; -} - -- (void)showScanner -{ - FingerprintViewScanController *scanView = [FingerprintViewScanController new]; - [scanView configureWithRecipientId:self.recipientId]; - [self.navigationController pushViewController:scanView animated:YES]; -} - -- (void)learnMoreButtonTapped:(UIGestureRecognizer *)gestureRecognizer -{ - if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { - NSString *learnMoreURL = @"https://support.signal.org/hc/en-us/articles/" - @"213134107"; - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:learnMoreURL]]; - } -} - -- (void)fingerprintLabelTapped:(UIGestureRecognizer *)gestureRecognizer -{ - if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { - [self showSharingActivityWithCompletion:nil]; - } -} - -- (void)fingerprintViewTapped:(UIGestureRecognizer *)gestureRecognizer -{ - if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { - [self showScanner]; - } -} - -- (void)verifyUnverifyButtonTapped:(UIGestureRecognizer *)gestureRecognizer -{ - if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - BOOL isVerified = [[OWSIdentityManager sharedManager] verificationStateForRecipientId:self.recipientId - transaction:transaction] - == OWSVerificationStateVerified; - - OWSVerificationState newVerificationState - = (isVerified ? OWSVerificationStateDefault : OWSVerificationStateVerified); - [[OWSIdentityManager sharedManager] setVerificationState:newVerificationState - identityKey:self.identityKey - recipientId:self.recipientId - isUserInitiatedChange:YES - transaction:transaction]; - }]; - - [self dismissViewControllerAnimated:YES completion:nil]; - } -} - -#pragma mark - Notifications - -- (void)identityStateDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [self updateVerificationStateLabel]; -} - -#pragma mark - Orientation - -- (UIInterfaceOrientationMask)supportedInterfaceOrientations -{ - return UIInterfaceOrientationMaskPortrait; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/FingerprintViewScanController.h b/Session/Signal/FingerprintViewScanController.h deleted file mode 100644 index 8c54f0ebf..000000000 --- a/Session/Signal/FingerprintViewScanController.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FingerprintViewScanController : OWSViewController - -- (void)configureWithRecipientId:(NSString *)recipientId NS_SWIFT_NAME(configure(recipientId:)); - -+ (void)showVerificationSucceeded:(UIViewController *)viewController - identityKey:(NSData *)identityKey - recipientId:(NSString *)recipientId - contactName:(NSString *)contactName - tag:(NSString *)tag; - -+ (void)showVerificationFailedWithError:(NSError *)error - viewController:(UIViewController *)viewController - retryBlock:(void (^_Nullable)(void))retryBlock - cancelBlock:(void (^_Nonnull)(void))cancelBlock - tag:(NSString *)tag; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/FingerprintViewScanController.m b/Session/Signal/FingerprintViewScanController.m deleted file mode 100644 index 743ab3210..000000000 --- a/Session/Signal/FingerprintViewScanController.m +++ /dev/null @@ -1,258 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "FingerprintViewScanController.h" -#import "OWSQRCodeScanningViewController.h" -#import "Session-Swift.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import "UIViewController+Permissions.h" -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FingerprintViewScanController () - -@property (nonatomic) TSAccountManager *accountManager; -@property (nonatomic) NSString *recipientId; -@property (nonatomic) NSData *identityKey; -@property (nonatomic) OWSFingerprint *fingerprint; -@property (nonatomic) NSString *contactName; -@property (nonatomic) OWSQRCodeScanningViewController *qrScanningController; - -@end - -#pragma mark - - -@implementation FingerprintViewScanController - -- (void)configureWithRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - self.recipientId = recipientId; - self.accountManager = [TSAccountManager sharedInstance]; - - OWSContactsManager *contactsManager = Environment.shared.contactsManager; - self.contactName = [contactsManager displayNameForPhoneIdentifier:recipientId]; - - OWSRecipientIdentity *_Nullable recipientIdentity = - [[OWSIdentityManager sharedManager] recipientIdentityForRecipientId:recipientId]; - OWSAssertDebug(recipientIdentity); - // By capturing the identity key when we enter these views, we prevent the edge case - // where the user verifies a key that we learned about while this view was open. - self.identityKey = recipientIdentity.identityKey; - - OWSFingerprintBuilder *builder = - [[OWSFingerprintBuilder alloc] initWithAccountManager:self.accountManager contactsManager:contactsManager]; - self.fingerprint = - [builder fingerprintWithTheirSignalId:recipientId theirIdentityKey:recipientIdentity.identityKey]; -} - -- (void)loadView -{ - [super loadView]; - - self.title = NSLocalizedString(@"SCAN_QR_CODE_VIEW_TITLE", @"Title for the 'scan QR code' view."); - - [self createViews]; -} - -- (void)createViews -{ - self.view.backgroundColor = UIColor.blackColor; - - self.qrScanningController = [OWSQRCodeScanningViewController new]; - self.qrScanningController.scanDelegate = self; - [self.view addSubview:self.qrScanningController.view]; - [self.qrScanningController.view autoPinWidthToSuperview]; - [self.qrScanningController.view autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:0.0f]; - - UIView *footer = [UIView new]; - footer.backgroundColor = [UIColor colorWithWhite:0.25f alpha:1.f]; - [self.view addSubview:footer]; - [footer autoPinWidthToSuperview]; - [footer autoPinEdgeToSuperviewEdge:ALEdgeBottom]; - [footer autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.qrScanningController.view]; - - UILabel *cameraInstructionLabel = [UILabel new]; - cameraInstructionLabel.text - = NSLocalizedString(@"SCAN_CODE_INSTRUCTIONS", @"label presented once scanning (camera) view is visible."); - cameraInstructionLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(14.f, 18.f)]; - cameraInstructionLabel.textColor = [UIColor whiteColor]; - cameraInstructionLabel.textAlignment = NSTextAlignmentCenter; - cameraInstructionLabel.numberOfLines = 0; - cameraInstructionLabel.lineBreakMode = NSLineBreakByWordWrapping; - [footer addSubview:cameraInstructionLabel]; - [cameraInstructionLabel autoPinWidthToSuperviewWithMargin:ScaleFromIPhone5To7Plus(16.f, 30.f)]; - CGFloat instructionsVMargin = ScaleFromIPhone5To7Plus(10.f, 20.f); - [cameraInstructionLabel autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.view withOffset:instructionsVMargin]; - [cameraInstructionLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:instructionsVMargin]; -} - -#pragma mark - Action - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - [self ows_askForCameraPermissions:^(BOOL granted) { - if (granted) { - // Camera stops capturing when "sharing" while in capture mode. - // Also, it's less obvious whats being "shared" at this point, - // so just disable sharing when in capture mode. - - OWSLogInfo(@"Showing Scanner"); - - [self.qrScanningController startCapture]; - } else { - [self.navigationController popViewControllerAnimated:YES]; - } - }]; -} - -#pragma mark - OWSQRScannerDelegate - -- (void)controller:(OWSQRCodeScanningViewController *)controller didDetectQRCodeWithData:(NSData *)data -{ - [self verifyCombinedFingerprintData:data]; -} - -- (void)verifyCombinedFingerprintData:(NSData *)combinedFingerprintData -{ - NSError *error; - if ([self.fingerprint matchesLogicalFingerprintsData:combinedFingerprintData error:&error]) { - [self showVerificationSucceeded]; - } else { - [self showVerificationFailedWithError:error]; - } -} - -- (void)showVerificationSucceeded -{ - [self.class showVerificationSucceeded:self - identityKey:self.identityKey - recipientId:self.recipientId - contactName:self.contactName - tag:self.logTag]; -} - -- (void)showVerificationFailedWithError:(NSError *)error -{ - - [self.class showVerificationFailedWithError:error - viewController:self - retryBlock:^{ - [self.qrScanningController startCapture]; - } - cancelBlock:^{ - [self.navigationController popViewControllerAnimated:YES]; - } - tag:self.logTag]; -} - -+ (void)showVerificationSucceeded:(UIViewController *)viewController - identityKey:(NSData *)identityKey - recipientId:(NSString *)recipientId - contactName:(NSString *)contactName - tag:(NSString *)tag -{ - OWSAssertDebug(viewController); - OWSAssertDebug(identityKey.length > 0); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(contactName.length > 0); - OWSAssertDebug(tag.length > 0); - - OWSLogInfo(@"%@ Successfully verified safety numbers.", tag); - - NSString *successTitle = NSLocalizedString(@"SUCCESSFUL_VERIFICATION_TITLE", nil); - NSString *descriptionFormat = NSLocalizedString( - @"SUCCESSFUL_VERIFICATION_DESCRIPTION", @"Alert body after verifying privacy with {{other user's name}}"); - NSString *successDescription = [NSString stringWithFormat:descriptionFormat, contactName]; - UIAlertController *alert = [UIAlertController alertControllerWithTitle:successTitle - message:successDescription - preferredStyle:UIAlertControllerStyleAlert]; - [alert - addAction:[UIAlertAction - actionWithTitle:NSLocalizedString(@"FINGERPRINT_SCAN_VERIFY_BUTTON", - @"Button that marks user as verified after a successful fingerprint scan.") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [OWSIdentityManager.sharedManager setVerificationState:OWSVerificationStateVerified - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:YES]; - [viewController dismissViewControllerAnimated:true completion:nil]; - }]]; - UIAlertAction *dismissAction = - [UIAlertAction actionWithTitle:CommonStrings.dismissButton - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [viewController dismissViewControllerAnimated:true completion:nil]; - }]; - [alert addAction:dismissAction]; - - [viewController presentAlert:alert]; -} - -+ (void)showVerificationFailedWithError:(NSError *)error - viewController:(UIViewController *)viewController - retryBlock:(void (^_Nullable)(void))retryBlock - cancelBlock:(void (^_Nonnull)(void))cancelBlock - tag:(NSString *)tag -{ - OWSAssertDebug(viewController); - OWSAssertDebug(cancelBlock); - OWSAssertDebug(tag.length > 0); - - OWSLogInfo(@"%@ Failed to verify safety numbers.", tag); - - NSString *_Nullable failureTitle; - if (error.code != OWSErrorCodeUserError) { - failureTitle = NSLocalizedString(@"FAILED_VERIFICATION_TITLE", @"alert title"); - } // else no title. We don't want to show a big scary "VERIFICATION FAILED" when it's just user error. - - UIAlertController *alert = [UIAlertController alertControllerWithTitle:failureTitle - message:error.localizedDescription - preferredStyle:UIAlertControllerStyleAlert]; - - if (retryBlock) { - [alert addAction:[UIAlertAction actionWithTitle:[CommonStrings retryButton] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - retryBlock(); - }]]; - } - - [alert addAction:[OWSAlerts cancelAction]]; - - [viewController presentAlert:alert]; - - OWSLogWarn(@"%@ Identity verification failed with error: %@", tag, error); -} - -- (void)dismissViewControllerAnimated:(BOOL)animated completion:(nullable void (^)(void))completion -{ - self.qrScanningController.view.hidden = YES; - - [super dismissViewControllerAnimated:animated completion:completion]; -} - -#pragma mark - Orientation - -- (UIInterfaceOrientationMask)supportedInterfaceOrientations -{ - return UIInterfaceOrientationMaskPortrait; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/GifPickerViewController.swift b/Session/Signal/GifPickerViewController.swift index 5e13ba1ab..f5c4711f5 100644 --- a/Session/Signal/GifPickerViewController.swift +++ b/Session/Signal/GifPickerViewController.swift @@ -35,7 +35,6 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect public weak var delegate: GifPickerViewControllerDelegate? let thread: TSThread - let messageSender: MessageSender let searchBar: SearchBar let layout: GifPickerLayout @@ -60,9 +59,8 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect } @objc - required init(thread: TSThread, messageSender: MessageSender) { + required init(thread: TSThread) { self.thread = thread - self.messageSender = messageSender self.searchBar = SearchBar() self.layout = GifPickerLayout() diff --git a/Session/Signal/GroupTableViewCell.swift b/Session/Signal/GroupTableViewCell.swift index 0f3e9871b..e8f9da488 100644 --- a/Session/Signal/GroupTableViewCell.swift +++ b/Session/Signal/GroupTableViewCell.swift @@ -7,15 +7,9 @@ import SignalUtilitiesKit @objc class GroupTableViewCell: UITableViewCell { - // MARK: - Dependencies - - private var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - // MARK: - - private let avatarView = AvatarImageView() +// private let avatarView = AvatarImageView() private let nameLabel = UILabel() private let subtitleLabel = UILabel() @@ -30,14 +24,14 @@ import SignalUtilitiesKit // Layout - avatarView.autoSetDimension(.width, toSize: CGFloat(kStandardAvatarSize)) - avatarView.autoPinToSquareAspectRatio() +// avatarView.autoSetDimension(.width, toSize: CGFloat(kStandardAvatarSize)) +// avatarView.autoPinToSquareAspectRatio() let textRows = UIStackView(arrangedSubviews: [nameLabel, subtitleLabel]) textRows.axis = .vertical textRows.alignment = .leading - let columns = UIStackView(arrangedSubviews: [avatarView, textRows]) + let columns = UIStackView(arrangedSubviews: [ textRows ]) columns.axis = .horizontal columns.alignment = .center columns.spacing = kContactCellAvatarTextMargin @@ -62,11 +56,11 @@ import SignalUtilitiesKit let groupMemberIds: [String] = thread.groupModel.groupMemberIds let groupMemberNames = groupMemberIds.map { (recipientId: String) in - contactsManager.displayName(forPhoneIdentifier: recipientId) + SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true)! }.joined(separator: ", ") self.subtitleLabel.text = groupMemberNames - self.avatarView.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: kStandardAvatarSize) +// self.avatarView.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: kStandardAvatarSize) } } diff --git a/Session/Signal/InviteFlow.swift b/Session/Signal/InviteFlow.swift deleted file mode 100644 index 0ba2b678f..000000000 --- a/Session/Signal/InviteFlow.swift +++ /dev/null @@ -1,271 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import Social -import ContactsUI -import MessageUI -import SignalUtilitiesKit - -@objc(OWSInviteFlow) -class InviteFlow: NSObject, MFMessageComposeViewControllerDelegate, MFMailComposeViewControllerDelegate, ContactsPickerDelegate { - enum Channel { - case message, mail, twitter - } - - let installUrl = "https://signal.org/install/" - let homepageUrl = "https://signal.org" - - @objc - let actionSheetController: UIAlertController - - @objc - let presentingViewController: UIViewController - - var channel: Channel? - - @objc - required init(presentingViewController: UIViewController) { - self.presentingViewController = presentingViewController - actionSheetController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - - super.init() - - actionSheetController.addAction(dismissAction()) - - if let messageAction = messageAction() { - actionSheetController.addAction(messageAction) - } - - if let mailAction = mailAction() { - actionSheetController.addAction(mailAction) - } - - if let tweetAction = tweetAction() { - actionSheetController.addAction(tweetAction) - } - } - - deinit { - Logger.verbose("[InviteFlow] deinit") - } - - // MARK: Twitter - - func canTweet() -> Bool { - return SLComposeViewController.isAvailable(forServiceType: SLServiceTypeTwitter) - } - - func tweetAction() -> UIAlertAction? { - guard canTweet() else { - Logger.info("Twitter not supported.") - return nil - } - - guard let twitterViewController = SLComposeViewController(forServiceType: SLServiceTypeTwitter) else { - Logger.error("unable to build twitter controller.") - return nil - } - - let tweetString = NSLocalizedString("SETTINGS_INVITE_TWITTER_TEXT", comment: "content of tweet when inviting via twitter - please do not translate URL") - twitterViewController.setInitialText(tweetString) - - let tweetUrl = URL(string: installUrl) - twitterViewController.add(tweetUrl) - twitterViewController.add(#imageLiteral(resourceName: "twitter_sharing_image")) - - let tweetTitle = NSLocalizedString("SHARE_ACTION_TWEET", comment: "action sheet item") - return UIAlertAction(title: tweetTitle, style: .default) { _ in - Logger.debug("Chose tweet") - - self.presentingViewController.present(twitterViewController, animated: true, completion: nil) - } - } - - func dismissAction() -> UIAlertAction { - return UIAlertAction(title: CommonStrings.dismissButton, style: .cancel) - } - - // MARK: ContactsPickerDelegate - - func contactsPicker(_: ContactsPicker, didSelectMultipleContacts contacts: [Contact]) { - Logger.debug("didSelectContacts:\(contacts)") - - guard let inviteChannel = channel else { - Logger.error("unexpected nil channel after returning from contact picker.") - self.presentingViewController.dismiss(animated: true) - return - } - - switch inviteChannel { - case .message: - let phoneNumbers: [String] = contacts.map { $0.userTextPhoneNumbers.first }.filter { $0 != nil }.map { $0! } - dismissAndSendSMSTo(phoneNumbers: phoneNumbers) - case .mail: - let recipients: [String] = contacts.map { $0.emails.first }.filter { $0 != nil }.map { $0! } - sendMailTo(emails: recipients) - default: - Logger.error("unexpected channel after returning from contact picker: \(inviteChannel)") - } - } - - func contactsPicker(_: ContactsPicker, shouldSelectContact contact: Contact) -> Bool { - guard let inviteChannel = channel else { - Logger.error("unexpected nil channel in contact picker.") - return true - } - - switch inviteChannel { - case .message: - return contact.userTextPhoneNumbers.count > 0 - case .mail: - return contact.emails.count > 0 - default: - Logger.error("unexpected channel after returning from contact picker: \(inviteChannel)") - } - return true - } - - func contactsPicker(_: ContactsPicker, contactFetchDidFail error: NSError) { - Logger.error("with error: \(error)") - self.presentingViewController.dismiss(animated: true) { - OWSAlerts.showErrorAlert(message: NSLocalizedString("ERROR_COULD_NOT_FETCH_CONTACTS", comment: "Error indicating that the phone's contacts could not be retrieved.")) - } - } - - func contactsPickerDidCancel(_: ContactsPicker) { - Logger.debug("") - self.presentingViewController.dismiss(animated: true) - } - - func contactsPicker(_: ContactsPicker, didSelectContact contact: Contact) { - owsFailDebug("InviteFlow only supports multi-select") - self.presentingViewController.dismiss(animated: true) - } - - // MARK: SMS - - func messageAction() -> UIAlertAction? { - guard MFMessageComposeViewController.canSendText() else { - Logger.info("Device cannot send text") - return nil - } - - let messageTitle = NSLocalizedString("SHARE_ACTION_MESSAGE", comment: "action sheet item to open native messages app") - return UIAlertAction(title: messageTitle, style: .default) { _ in - Logger.debug("Chose message.") - self.channel = .message - let picker = ContactsPicker(allowsMultipleSelection: true, subtitleCellType: .phoneNumber) - picker.contactsPickerDelegate = self - picker.title = NSLocalizedString("INVITE_FRIENDS_PICKER_TITLE", comment: "Navbar title") - let navigationController = OWSNavigationController(rootViewController: picker) - self.presentingViewController.present(navigationController, animated: true) - } - } - - public func dismissAndSendSMSTo(phoneNumbers: [String]) { - self.presentingViewController.dismiss(animated: true) { - if phoneNumbers.count > 1 { - let warning = UIAlertController(title: nil, - message: NSLocalizedString("INVITE_WARNING_MULTIPLE_INVITES_BY_TEXT", - comment: "Alert warning that sending an invite to multiple users will create a group message whose recipients will be able to see each other."), - preferredStyle: .alert) - warning.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_CONTINUE", - comment: "Label for 'continue' button."), - style: .default, handler: { _ in - self.sendSMSTo(phoneNumbers: phoneNumbers) - })) - warning.addAction(OWSAlerts.cancelAction) - self.presentingViewController.presentAlert(warning) - } else { - self.sendSMSTo(phoneNumbers: phoneNumbers) - } - } - } - - @objc - public func sendSMSTo(phoneNumbers: [String]) { - let messageComposeViewController = MFMessageComposeViewController() - messageComposeViewController.messageComposeDelegate = self - messageComposeViewController.recipients = phoneNumbers - - let inviteText = NSLocalizedString("SMS_INVITE_BODY", comment: "body sent to contacts when inviting to Install Signal") - messageComposeViewController.body = inviteText.appending(" \(self.installUrl)") - self.presentingViewController.present(messageComposeViewController, animated: true) - } - - // MARK: MessageComposeViewControllerDelegate - - func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) { - self.presentingViewController.dismiss(animated: true) { - switch result { - case .failed: - let warning = UIAlertController(title: nil, message: NSLocalizedString("SEND_INVITE_FAILURE", comment: "Alert body after invite failed"), preferredStyle: .alert) - warning.addAction(UIAlertAction(title: CommonStrings.dismissButton, style: .default, handler: nil)) - self.presentingViewController.present(warning, animated: true, completion: nil) - case .sent: - Logger.debug("user successfully invited their friends via SMS.") - case .cancelled: - Logger.debug("user cancelled message invite") - } - } - } - - // MARK: Mail - - func mailAction() -> UIAlertAction? { - guard MFMailComposeViewController.canSendMail() else { - Logger.info("Device cannot send mail") - return nil - } - - let mailActionTitle = NSLocalizedString("SHARE_ACTION_MAIL", comment: "action sheet item to open native mail app") - return UIAlertAction(title: mailActionTitle, style: .default) { _ in - Logger.debug("Chose mail.") - self.channel = .mail - - let picker = ContactsPicker(allowsMultipleSelection: true, subtitleCellType: .email) - picker.contactsPickerDelegate = self - picker.title = NSLocalizedString("INVITE_FRIENDS_PICKER_TITLE", comment: "Navbar title") - let navigationController = OWSNavigationController(rootViewController: picker) - self.presentingViewController.present(navigationController, animated: true) - } - } - - func sendMailTo(emails recipientEmails: [String]) { - let mailComposeViewController = MFMailComposeViewController() - mailComposeViewController.mailComposeDelegate = self - mailComposeViewController.setBccRecipients(recipientEmails) - - let subject = NSLocalizedString("EMAIL_INVITE_SUBJECT", comment: "subject of email sent to contacts when inviting to install Signal") - let bodyFormat = NSLocalizedString("EMAIL_INVITE_BODY", comment: "body of email sent to contacts when inviting to install Signal. Embeds {{link to install Signal}} and {{link to the Signal home page}}") - let body = String.init(format: bodyFormat, installUrl, homepageUrl) - mailComposeViewController.setSubject(subject) - mailComposeViewController.setMessageBody(body, isHTML: false) - - self.presentingViewController.dismiss(animated: true) { - self.presentingViewController.present(mailComposeViewController, animated: true) - } - } - - // MARK: MailComposeViewControllerDelegate - - func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { - self.presentingViewController.dismiss(animated: true) { - switch result { - case .failed: - let warning = UIAlertController(title: nil, message: NSLocalizedString("SEND_INVITE_FAILURE", comment: "Alert body after invite failed"), preferredStyle: .alert) - warning.addAction(UIAlertAction(title: CommonStrings.dismissButton, style: .default, handler: nil)) - self.presentingViewController.present(warning, animated: true, completion: nil) - case .sent: - Logger.debug("user successfully invited their friends via mail.") - case .saved: - Logger.debug("user saved mail invite.") - case .cancelled: - Logger.debug("user cancelled mail invite.") - } - } - } - -} diff --git a/Session/Signal/LegacyNotificationsAdaptee.swift b/Session/Signal/LegacyNotificationsAdaptee.swift index 15bccc839..6d92bd199 100644 --- a/Session/Signal/LegacyNotificationsAdaptee.swift +++ b/Session/Signal/LegacyNotificationsAdaptee.swift @@ -176,7 +176,7 @@ extension LegacyNotificationPresenterAdaptee: NotificationPresenterAdaptee { } let checkForCancel = category == .incomingMessage - if checkForCancel && hasReceivedSyncMessageRecently { + if checkForCancel { assert(userInfo[AppNotificationUserInfoKey.threadId] != nil) notification.fireDate = Date(timeIntervalSinceNow: kNotificationDelayForRemoteRead) notification.timeZone = NSTimeZone.local diff --git a/Session/Signal/MediaPageViewController.swift b/Session/Signal/MediaPageViewController.swift index 591be5823..d7138511a 100644 --- a/Session/Signal/MediaPageViewController.swift +++ b/Session/Signal/MediaPageViewController.swift @@ -587,7 +587,6 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou let conversationStyle = ConversationStyle(thread: thread) fetchedItem = ConversationInteractionViewItem(interaction: message, isGroupThread: thread.isGroupThread(), - isRSSFeed: false, transaction: transaction, conversationStyle: conversationStyle) } @@ -670,10 +669,6 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou // MARK: Dynamic Header - private var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - private func senderName(message: TSMessage) -> String { switch message { case let incomingMessage as TSIncomingMessage: diff --git a/Session/Signal/MessageActions.swift b/Session/Signal/MessageActions.swift index b8eaffd2d..03bdcb109 100644 --- a/Session/Signal/MessageActions.swift +++ b/Session/Signal/MessageActions.swift @@ -93,9 +93,8 @@ class ConversationViewItemActions: NSObject { var actions: [MenuAction] = [] let isGroup = conversationViewItem.isGroupThread; - let isRSSFeed = conversationViewItem.isRSSFeed; - if shouldAllowReply && !isRSSFeed { + if shouldAllowReply { let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate) actions.append(replyAction) } @@ -105,7 +104,7 @@ class ConversationViewItemActions: NSObject { actions.append(copyTextAction) } - if isGroup && !isRSSFeed && conversationViewItem.interaction is TSIncomingMessage { + if isGroup && conversationViewItem.interaction is TSIncomingMessage { let copyPublicKeyAction = MessageActionBuilder.copyPublicKey(conversationViewItem: conversationViewItem, delegate: delegate) actions.append(copyPublicKeyAction) } @@ -132,9 +131,8 @@ class ConversationViewItemActions: NSObject { var actions: [MenuAction] = [] let isGroup = conversationViewItem.isGroupThread; - let isRSSFeed = conversationViewItem.isRSSFeed; - if shouldAllowReply && !isRSSFeed { + if shouldAllowReply { let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate) actions.append(replyAction) } @@ -150,7 +148,7 @@ class ConversationViewItemActions: NSObject { } } - if isGroup && !isRSSFeed && conversationViewItem.interaction is TSIncomingMessage { + if isGroup && conversationViewItem.interaction is TSIncomingMessage { let copyPublicKeyAction = MessageActionBuilder.copyPublicKey(conversationViewItem: conversationViewItem, delegate: delegate) actions.append(copyPublicKeyAction) } @@ -182,9 +180,8 @@ class ConversationViewItemActions: NSObject { } let isGroup = conversationViewItem.isGroupThread; - let isRSSFeed = conversationViewItem.isRSSFeed; - if isGroup && !isRSSFeed && conversationViewItem.interaction is TSIncomingMessage { + if isGroup && conversationViewItem.interaction is TSIncomingMessage { let copyPublicKeyAction = MessageActionBuilder.copyPublicKey(conversationViewItem: conversationViewItem, delegate: delegate) actions.append(copyPublicKeyAction) } diff --git a/Session/Signal/MessageDetailViewController.swift b/Session/Signal/MessageDetailViewController.swift index d6f82c5fd..f752c5391 100644 --- a/Session/Signal/MessageDetailViewController.swift +++ b/Session/Signal/MessageDetailViewController.swift @@ -18,7 +18,7 @@ protocol MessageDetailViewDelegate: AnyObject { } @objc -class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDelegate, OWSMessageBubbleViewDelegate, ContactShareViewHelperDelegate { +class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDelegate, OWSMessageBubbleViewDelegate { @objc weak var delegate: MessageDetailViewDelegate? @@ -52,18 +52,12 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele var conversationStyle: ConversationStyle - private var contactShareViewHelper: ContactShareViewHelper! - // MARK: Dependencies var preferences: OWSPreferences { return Environment.shared.preferences } - var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - // MARK: Initializers @available(*, unavailable, message:"use other constructor instead.") @@ -86,8 +80,6 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele override func viewDidLoad() { super.viewDidLoad() - self.contactShareViewHelper = ContactShareViewHelper(contactsManager: contactsManager) - contactShareViewHelper.delegate = self do { try updateMessageToLatest() @@ -614,27 +606,6 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele mediaGallery.presentDetailView(fromViewController: self, mediaAttachment: attachmentStream, replacingView: imageView) } - func didTapContactShare(_ viewItem: ConversationViewItem) { - guard let contactShare = viewItem.contactShare else { - owsFailDebug("missing contact.") - return - } - let contactViewController = ContactViewController(contactShare: contactShare) - self.navigationController?.pushViewController(contactViewController, animated: true) - } - - func didTapSendMessage(toContactShare contactShare: ContactShareViewModel) { - contactShareViewHelper.sendMessage(contactShare: contactShare, fromViewController: self) - } - - func didTapSendInvite(toContactShare contactShare: ContactShareViewModel) { - contactShareViewHelper.showInviteContact(contactShare: contactShare, fromViewController: self) - } - - func didTapShowAddToContactUI(forContactShare contactShare: ContactShareViewModel) { - contactShareViewHelper.showAddToContacts(contactShare: contactShare, fromViewController: self) - } - var audioAttachmentPlayer: OWSAudioPlayer? func didTapAudioViewItem(_ viewItem: ConversationViewItem, attachmentStream: TSAttachmentStream) { diff --git a/Session/Signal/MessageFetcherJob.swift b/Session/Signal/MessageFetcherJob.swift deleted file mode 100644 index 408a4e0f9..000000000 --- a/Session/Signal/MessageFetcherJob.swift +++ /dev/null @@ -1,175 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit -import SignalUtilitiesKit - -@objc(OWSMessageFetcherJob) -public class MessageFetcherJob: NSObject { - - private var timer: Timer? - - @objc - public override init() { - super.init() - - SwiftSingletons.register(self) - } - - // MARK: Singletons - - private var networkManager: TSNetworkManager { - return SSKEnvironment.shared.networkManager - } - - private var messageReceiver: OWSMessageReceiver { - return SSKEnvironment.shared.messageReceiver - } - - private var signalService: OWSSignalService { - return OWSSignalService.sharedInstance() - } - - // MARK: - - @discardableResult - public func run() -> Promise { - let promise = fetchUndeliveredMessages().then { promises -> Promise in - let promises = promises.map { promise -> Promise in - return promise.then { envelopes -> Promise in - for envelope in envelopes { - Logger.info("Envelope received.") - do { - let envelopeData = try envelope.serializedData() - self.messageReceiver.handleReceivedEnvelopeData(envelopeData) - } catch { - owsFailDebug("Failed to serialize envelope.") - } - self.acknowledgeDelivery(envelope: envelope) - } - return Promise.value(()) - } - } - return when(resolved: promises).asVoid() - } - promise.retainUntilComplete() - return promise - } - - @objc - @discardableResult - public func run() -> AnyPromise { - return AnyPromise(run() as Promise) - } - - // use in DEBUG or wherever you can't receive push notifications to poll for messages. - // Do not use in production. - public func startRunLoop(timeInterval: Double) { - Logger.error("Starting message fetch polling. This should not be used in production.") - timer = WeakTimer.scheduledTimer(timeInterval: timeInterval, target: self, userInfo: nil, repeats: true) {[weak self] _ in - let _: Promise? = self?.run() - return - } - } - - public func stopRunLoop() { - timer?.invalidate() - timer = nil - } - - private func parseMessagesResponse(responseObject: Any?) -> (envelopes: [SSKProtoEnvelope], more: Bool)? { - guard let responseObject = responseObject else { - Logger.error("response object was surpringly nil") - return nil - } - - guard let responseDict = responseObject as? [String: Any] else { - Logger.error("response object was not a dictionary") - return nil - } - - guard let messageDicts = responseDict["messages"] as? [[String: Any]] else { - Logger.error("messages object was not a list of dictionaries") - return nil - } - - let moreMessages = { () -> Bool in - if let responseMore = responseDict["more"] as? Bool { - return responseMore - } else { - Logger.warn("more object was not a bool. Assuming no more") - return false - } - }() - - let envelopes: [SSKProtoEnvelope] = messageDicts.compactMap { buildEnvelope(messageDict: $0) } - - return ( - envelopes: envelopes, - more: moreMessages - ) - } - - private func buildEnvelope(messageDict: [String: Any]) -> SSKProtoEnvelope? { - do { - let params = ParamParser(dictionary: messageDict) - - let typeInt: Int32 = try params.required(key: "type") - guard let type: SSKProtoEnvelope.SSKProtoEnvelopeType = SSKProtoEnvelope.SSKProtoEnvelopeType(rawValue: typeInt) else { - Logger.error("`type` was invalid: \(typeInt)") - throw ParamParser.ParseError.invalidFormat("type") - } - - guard let timestamp: UInt64 = try params.required(key: "timestamp") else { - Logger.error("`timestamp` was invalid: \(typeInt)") - throw ParamParser.ParseError.invalidFormat("timestamp") - } - - let builder = SSKProtoEnvelope.builder(type: type, timestamp: timestamp) - - if let source: String = try params.optional(key: "source") { - builder.setSource(source) - } - - if let sourceDevice: UInt32 = try params.optional(key: "sourceDevice") { - builder.setSourceDevice(sourceDevice) - } - - if let legacyMessage = try params.optionalBase64EncodedData(key: "message") { - builder.setLegacyMessage(legacyMessage) - } - if let content = try params.optionalBase64EncodedData(key: "content") { - builder.setContent(content) - } - if let serverTimestamp: UInt64 = try params.optional(key: "serverTimestamp") { - builder.setServerTimestamp(serverTimestamp) - } - if let serverGuid: String = try params.optional(key: "guid") { - builder.setServerGuid(serverGuid) - } - - return try builder.build() - } catch { - owsFailDebug("error building envelope: \(error)") - return nil - } - } - - private func fetchUndeliveredMessages() -> Promise>> { - let userPublickKey = getUserHexEncodedPublicKey() // Can be missing in rare cases - guard !userPublickKey.isEmpty else { return Promise.value(Set()) } - return SnodeAPI.getMessages(for: userPublickKey).map2 { promises -> Set> in - return Set(promises.map { promise -> Promise<[SSKProtoEnvelope]> in - return promise.map2 { rawMessages -> [SSKProtoEnvelope] in - return rawMessages.compactMap { SSKProtoEnvelope.from($0) } - } - }) - } - } - - private func acknowledgeDelivery(envelope: SSKProtoEnvelope) { - // Do nothing - } -} diff --git a/Session/Signal/MessageRecipientStatusUtils.swift b/Session/Signal/MessageRecipientStatusUtils.swift index dcf6daefe..5e7f8638e 100644 --- a/Session/Signal/MessageRecipientStatusUtils.swift +++ b/Session/Signal/MessageRecipientStatusUtils.swift @@ -110,10 +110,6 @@ public class MessageRecipientStatusUtils: NSObject { // Use the "long" version of this message here. return (.failed, NSLocalizedString("MESSAGE_STATUS_FAILED", comment: "status message for failed messages")) case .sending: - if outgoingMessage.isCalculatingPoW { - return (.calculatingPoW, NSLocalizedString("Calculating proof of work", comment: "")) - } - if outgoingMessage.hasAttachments() { return (.uploading, NSLocalizedString("MESSAGE_STATUS_UPLOADING", comment: "status message while attachment is uploading")) diff --git a/Session/Signal/OWSAddToContactViewController.h b/Session/Signal/OWSAddToContactViewController.h deleted file mode 100644 index 80d652900..000000000 --- a/Session/Signal/OWSAddToContactViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSTableViewController.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSAddToContactViewController : OWSTableViewController - -- (void)configureWithRecipientId:(NSString *)recipientId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/OWSAddToContactViewController.m b/Session/Signal/OWSAddToContactViewController.m deleted file mode 100644 index 46a2c9d8d..000000000 --- a/Session/Signal/OWSAddToContactViewController.m +++ /dev/null @@ -1,212 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSAddToContactViewController.h" -#import -#import -#import -#import - -@import ContactsUI; - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSAddToContactViewController () - -@property (nonatomic) NSString *recipientId; - -@property (nonatomic, readonly) OWSContactsManager *contactsManager; -@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; - -@end - -#pragma mark - - -@implementation OWSAddToContactViewController - -- (instancetype)init -{ - self = [super init]; - if (!self) { - return self; - } - - [self commonInit]; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder:aDecoder]; - if (!self) { - return self; - } - - [self commonInit]; - - return self; -} - -- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if (!self) { - return self; - } - - [self commonInit]; - - return self; -} - -- (void)commonInit -{ - _contactsManager = Environment.shared.contactsManager; - _contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self]; -} - -- (void)configureWithRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - _recipientId = recipientId; -} - -#pragma mark - ContactEditingDelegate - -- (void)didFinishEditingContact -{ - OWSLogDebug(@""); - [self dismissViewControllerAnimated:NO - completion:^{ - [self.navigationController popViewControllerAnimated:YES]; - }]; -} - -#pragma mark - CNContactViewControllerDelegate - -- (void)contactViewController:(CNContactViewController *)viewController - didCompleteWithContact:(nullable CNContact *)contact -{ - if (contact) { - // Saving normally returns you to the "Show Contact" view - // which we're not interested in, so we skip it here. There is - // an unfortunate blip of the "Show Contact" view on slower devices. - OWSLogDebug(@"completed editing contact."); - [self dismissViewControllerAnimated:NO - completion:^{ - [self.navigationController popViewControllerAnimated:YES]; - }]; - } else { - OWSLogDebug(@"canceled editing contact."); - [self dismissViewControllerAnimated:YES - completion:^{ - [self.navigationController popViewControllerAnimated:YES]; - }]; - } -} - -#pragma mark - ContactsViewHelperDelegate - -- (void)contactsViewHelperDidUpdateContacts -{ - [self updateTableContents]; -} - -#pragma mark - View Lifecycle - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - self.title = NSLocalizedString(@"CONVERSATION_SETTINGS_ADD_TO_EXISTING_CONTACT", - @"Label for 'new contact' button in conversation settings view."); - - [self updateTableContents]; -} - -- (nullable NSString *)displayNameForContact:(Contact *)contact -{ - OWSAssertDebug(contact); - - if (contact.fullName.length > 0) { - return contact.fullName; - } - - for (NSString *email in contact.emails) { - if (email.length > 0) { - return email; - } - } - for (NSString *phoneNumber in contact.userTextPhoneNumbers) { - if (phoneNumber.length > 0) { - return phoneNumber; - } - } - - return nil; -} - -- (void)updateTableContents -{ - OWSTableContents *contents = [OWSTableContents new]; - contents.title = NSLocalizedString(@"CONVERSATION_SETTINGS", @"title for conversation settings screen"); - - __weak OWSAddToContactViewController *weakSelf = self; - - OWSTableSection *section = [OWSTableSection new]; - section.headerTitle = NSLocalizedString( - @"EDIT_GROUP_CONTACTS_SECTION_TITLE", @"a title for the contacts section of the 'new/update group' view."); - - for (Contact *contact in self.contactsViewHelper.contactsManager.allContacts) { - NSString *_Nullable displayName = [self displayNameForContact:contact]; - if (displayName.length < 1) { - continue; - } - - // TODO: Confirm with nancy if this will work. - NSString *cellName = [NSString stringWithFormat:@"contact.%@", NSUUID.UUID.UUIDString]; - [section addItem:[OWSTableItem disclosureItemWithText:displayName - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, cellName) - actionBlock:^{ - [weakSelf presentContactViewControllerForContact:contact]; - }]]; - } - [contents addSection:section]; - - self.contents = contents; - [self.tableView reloadData]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; -} - -#pragma mark - Actions - -- (void)presentContactViewControllerForContact:(Contact *)contact -{ - OWSAssertDebug(contact); - OWSAssertDebug(self.recipientId); - - if (!self.contactsManager.supportsContactEditing) { - OWSFailDebug(@"Contact editing not supported"); - return; - } - CNContact *_Nullable cnContact = [self.contactsManager cnContactWithId:contact.cnContactId]; - if (!cnContact) { - OWSFailDebug(@"Could not load system contact."); - return; - } - [self.contactsViewHelper presentContactViewControllerForRecipientId:self.recipientId - fromViewController:self - editImmediately:YES - addToExistingCnContact:cnContact]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/OWSAnalytics.swift b/Session/Signal/OWSAnalytics.swift deleted file mode 100644 index d083a34ce..000000000 --- a/Session/Signal/OWSAnalytics.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit - -func FormatAnalyticsLocation(file: String, function: String) -> NSString { - return "\((file as NSString).lastPathComponent):\(function)" as NSString -} - -func OWSProdError(_ eventName: String, file: String, function: String, line: Int32) { - let location = FormatAnalyticsLocation(file: file, function: function) - OWSAnalytics - .logEvent(eventName, severity: .error, parameters: nil, location: location.utf8String!, line:line) -} - -func OWSProdInfo(_ eventName: String, file: String, function: String, line: Int32) { - let location = FormatAnalyticsLocation(file: file, function: function) - OWSAnalytics - .logEvent(eventName, severity: .info, parameters: nil, location: location.utf8String!, line:line) -} diff --git a/Session/Signal/OWSBackupExportJob.m b/Session/Signal/OWSBackupExportJob.m index 54669197c..46dcb1b99 100644 --- a/Session/Signal/OWSBackupExportJob.m +++ b/Session/Signal/OWSBackupExportJob.m @@ -411,25 +411,7 @@ NS_ASSUME_NONNULL_BEGIN self.backupIO = [[OWSBackupIO alloc] initWithJobTempDirPath:self.jobTempDirPath]; - // We need to verify that we have a valid account. - // Otherwise, if we re-register on another device, we - // continue to backup on our old device, overwriting - // backups from the new device. - // - // We use an arbitrary request that requires authentication - // to verify our account state. - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - TSRequest *currentSignedPreKey = [OWSRequestFactory currentSignedPreKeyRequest]; - [[TSNetworkManager sharedManager] makeRequest:currentSignedPreKey - success:^(NSURLSessionDataTask *task, NSDictionary *responseObject) { - resolve(@(1)); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - // TODO: We may want to surface this in the UI. - OWSLogError(@"could not verify account status: %@.", error); - resolve(error); - }]; - }]; + return [AnyPromise promiseWithValue:@(1)]; } - (AnyPromise *)fetchAllRecords diff --git a/Session/Signal/OWSBackupSettingsViewController.m b/Session/Signal/OWSBackupSettingsViewController.m index 6b9d33212..d00b30a4d 100644 --- a/Session/Signal/OWSBackupSettingsViewController.m +++ b/Session/Signal/OWSBackupSettingsViewController.m @@ -5,7 +5,7 @@ #import "OWSBackupSettingsViewController.h" #import "OWSBackup.h" #import "Session-Swift.h" -#import "ThreadUtil.h" + #import #import #import diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index 1d53d98d8..e10b9c7c6 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -4,22 +4,19 @@ #import "OWSConversationSettingsViewController.h" #import "BlockListUIUtils.h" -#import "ContactsViewHelper.h" -#import "FingerprintViewController.h" -#import "OWSAddToContactViewController.h" + + + #import "OWSBlockingManager.h" #import "OWSSoundSettingsViewController.h" -#import "PhoneNumber.h" -#import "ShowGroupMembersViewController.h" + #import "Session-Swift.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" -#import "UpdateGroupViewController.h" #import #import #import -#import -#import + #import #import #import @@ -27,7 +24,7 @@ #import #import #import -#import + #import #import #import @@ -42,8 +39,7 @@ NS_ASSUME_NONNULL_BEGIN const CGFloat kIconViewLength = 24; -@interface OWSConversationSettingsViewController () 0); @@ -1031,24 +823,6 @@ static CGRect oldframe; return stackView; } -- (void)conversationNameTouched:(UIGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized) { - if (self.isGroupThread) { - CGPoint location = [sender locationInView:self.avatarView]; - if (CGRectContainsPoint(self.avatarView.bounds, location)) { - [self showUpdateGroupView:UpdateGroupMode_EditGroupAvatar]; - } else { - [self showUpdateGroupView:UpdateGroupMode_EditGroupName]; - } - } else { - if (self.contactsManager.supportsContactEditing) { - [self presentContactViewController]; - } - } - } -} - - (UIImageView *)viewForIconWithName:(NSString *)iconName { UIImage *icon = [UIImage imageNamed:iconName]; @@ -1102,11 +876,15 @@ static CGRect oldframe; createdInExistingGroup:NO]; [infoMessage saveWithTransaction:transaction]; + // TODO TODO TODO + + /* OWSDisappearingMessagesConfigurationMessage *message = [[OWSDisappearingMessagesConfigurationMessage alloc] initWithConfiguration:self.disappearingMessagesConfiguration thread:self.thread]; [self.messageSenderJobQueue addMessage:message transaction:transaction]; + */ }]; } } @@ -1122,14 +900,6 @@ static CGRect oldframe; }]; } -- (void)showVerificationView -{ - NSString *recipientId = self.thread.contactIdentifier; - OWSAssertDebug(recipientId.length > 0); - - [FingerprintViewController presentFromViewController:self recipientId:recipientId]; -} - - (void)showGroupMembersView { TSGroupThread *thread = (TSGroupThread *)self.thread; @@ -1137,57 +907,6 @@ static CGRect oldframe; [self.navigationController pushViewController:groupMembersVC animated:YES]; } -- (void)showUpdateGroupView:(UpdateGroupMode)mode -{ - OWSAssertDebug(self.conversationSettingsViewDelegate); - - UpdateGroupViewController *updateGroupViewController = [UpdateGroupViewController new]; - updateGroupViewController.conversationSettingsViewDelegate = self.conversationSettingsViewDelegate; - updateGroupViewController.thread = (TSGroupThread *)self.thread; - updateGroupViewController.mode = mode; - [self.navigationController pushViewController:updateGroupViewController animated:YES]; -} - -- (void)presentContactViewController -{ - if (!self.contactsManager.supportsContactEditing) { - OWSFailDebug(@"Contact editing not supported"); - return; - } - if (![self.thread isKindOfClass:[TSContactThread class]]) { - OWSFailDebug(@"unexpected thread: %@", [self.thread class]); - return; - } - - TSContactThread *contactThread = (TSContactThread *)self.thread; - [self.contactsViewHelper presentContactViewControllerForRecipientId:contactThread.contactIdentifier - fromViewController:self - editImmediately:YES]; -} - -- (void)presentAddToContactViewControllerWithRecipientId:(NSString *)recipientId -{ - if (!self.contactsManager.supportsContactEditing) { - // Should not expose UI that lets the user get here. - OWSFailDebug(@"Contact editing not supported."); - return; - } - - if (!self.contactsManager.isSystemContactsAuthorized) { - [self.contactsViewHelper presentMissingContactAccessAlertControllerFromViewController:self]; - return; - } - - OWSAddToContactViewController *viewController = [OWSAddToContactViewController new]; - [viewController configureWithRecipientId:recipientId]; - [self.navigationController pushViewController:viewController animated:YES]; -} - -- (void)didTapEditButton -{ - [self presentContactViewController]; -} - - (void)editGroup { LKEditClosedGroupVC *editClosedGroupVC = [[LKEditClosedGroupVC alloc] initWithThreadID:self.thread.uniqueId]; @@ -1218,7 +937,7 @@ static CGRect oldframe; { if (self.isGroupThread) { TSGroupThread *groupThread = (TSGroupThread *)self.thread; - return !groupThread.isLocalUserInGroup; + return !groupThread.isCurrentUserInGroup; } return NO; @@ -1233,14 +952,6 @@ static CGRect oldframe; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [[LKClosedGroupsProtocol leaveGroupWithPublicKey:groupPublicKey transaction:transaction] retainUntilComplete]; }]; - } else { - TSOutgoingMessage *message = - [TSOutgoingMessage outgoingMessageInThread:gThread groupMetaMessage:TSGroupMetaMessageQuit expiresInSeconds:0]; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - [gThread leaveGroupWithTransaction:transaction]; - }]; } [self.navigationController popViewControllerAnimated:YES]; @@ -1273,8 +984,6 @@ static CGRect oldframe; [BlockListUIUtils showBlockThreadActionSheet:self.thread fromViewController:self blockingManager:self.blockingManager - contactsManager:self.contactsManager - messageSender:self.messageSender completionBlock:^(BOOL isBlocked) { // Update switch state if user cancels action. blockConversationSwitch.on = isBlocked; @@ -1290,7 +999,6 @@ static CGRect oldframe; [BlockListUIUtils showUnblockThreadActionSheet:self.thread fromViewController:self blockingManager:self.blockingManager - contactsManager:self.contactsManager completionBlock:^(BOOL isBlocked) { // Update switch state if user cancels action. blockConversationSwitch.on = isBlocked; @@ -1498,7 +1206,6 @@ static CGRect oldframe; [alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { dispatch_async(dispatch_get_main_queue(), ^{ [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [thread addSessionRestoreDevice:thread.contactIdentifier transaction:transaction]; [LKSessionManagementProtocol startSessionResetInThread:thread transaction:transaction]; }]; [weakSelf.navigationController popViewControllerAnimated:YES]; diff --git a/Session/Signal/OWSDeviceTableViewCell.h b/Session/Signal/OWSDeviceTableViewCell.h deleted file mode 100644 index 0db516612..000000000 --- a/Session/Signal/OWSDeviceTableViewCell.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSDeviceTableViewCell : UITableViewCell - -@property (nonatomic) UILabel *nameLabel; -@property (nonatomic) UILabel *linkedLabel; -@property (nonatomic) UILabel *lastSeenLabel; - -- (void)configureWithDevice:(OWSDevice *)device; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/OWSDeviceTableViewCell.m b/Session/Signal/OWSDeviceTableViewCell.m deleted file mode 100644 index e967f5825..000000000 --- a/Session/Signal/OWSDeviceTableViewCell.m +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDeviceTableViewCell.h" -#import "DateUtil.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSDeviceTableViewCell - -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier -{ - if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { - [self configure]; - } - return self; -} - -- (void)configure -{ - self.preservesSuperviewLayoutMargins = YES; - self.contentView.preservesSuperviewLayoutMargins = YES; - - self.nameLabel = [UILabel new]; - self.linkedLabel = [UILabel new]; - self.lastSeenLabel = [UILabel new]; - - UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:@[ - self.nameLabel, - self.linkedLabel, - self.lastSeenLabel, - ]]; - stackView.axis = UILayoutConstraintAxisVertical; - stackView.alignment = UIStackViewAlignmentLeading; - stackView.spacing = 2; - [self.contentView addSubview:stackView]; - [stackView ows_autoPinToSuperviewMargins]; -} - -- (void)configureWithDevice:(OWSDevice *)device -{ - OWSAssertDebug(device); - - [OWSTableItem configureCell:self]; - - self.nameLabel.font = UIFont.ows_dynamicTypeBodyFont; - self.linkedLabel.font = UIFont.ows_dynamicTypeCaption1Font; - self.lastSeenLabel.font = UIFont.ows_dynamicTypeCaption1Font; - - self.nameLabel.textColor = Theme.primaryColor; - self.linkedLabel.textColor = Theme.secondaryColor; - self.lastSeenLabel.textColor = Theme.secondaryColor; - - self.nameLabel.text = device.displayName; - - NSString *linkedFormatString - = NSLocalizedString(@"DEVICE_LINKED_AT_LABEL", @"{{Short Date}} when device was linked."); - self.linkedLabel.text = - [NSString stringWithFormat:linkedFormatString, [DateUtil.dateFormatter stringFromDate:device.createdAt]]; - - NSString *lastSeenFormatString = NSLocalizedString( - @"DEVICE_LAST_ACTIVE_AT_LABEL", @"{{Short Date}} when device last communicated with Signal Server."); - - NSDate *displayedLastSeenAt; - // lastSeenAt is stored at day granularity. At midnight UTC. - // Making it likely that when you first link a device it will - // be "last seen" the day before it was created, which looks broken. - if ([device.lastSeenAt compare:device.createdAt] == NSOrderedDescending) { - displayedLastSeenAt = device.lastSeenAt; - } else { - displayedLastSeenAt = device.createdAt; - } - - self.lastSeenLabel.text = - [NSString stringWithFormat:lastSeenFormatString, [DateUtil.dateFormatter stringFromDate:displayedLastSeenAt]]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/OWSOrphanDataCleaner.m b/Session/Signal/OWSOrphanDataCleaner.m index f21ba3aff..6d6e1e909 100644 --- a/Session/Signal/OWSOrphanDataCleaner.m +++ b/Session/Signal/OWSOrphanDataCleaner.m @@ -9,7 +9,7 @@ #import #import #import -#import + #import #import #import diff --git a/Session/Signal/Pastelog.h b/Session/Signal/Pastelog.h deleted file mode 100644 index 0d46da066..000000000 --- a/Session/Signal/Pastelog.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^SubmitDebugLogsCompletion)(void); - -@interface Pastelog : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -+ (void)submitLogs; -+ (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/Pastelog.m b/Session/Signal/Pastelog.m deleted file mode 100644 index 8596239ff..000000000 --- a/Session/Signal/Pastelog.m +++ /dev/null @@ -1,647 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "Pastelog.h" -#import "Session-Swift.h" -#import "ThreadUtil.h" -#import "zlib.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^UploadDebugLogsSuccess)(NSURL *url); -typedef void (^UploadDebugLogsFailure)(NSString *localizedErrorMessage); - -#pragma mark - - -@class DebugLogUploader; - -typedef void (^DebugLogUploadSuccess)(DebugLogUploader *uploader, NSURL *url); -typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error); - -@interface DebugLogUploader : NSObject - -@property (nonatomic) NSURL *fileUrl; -@property (nonatomic) NSString *mimeType; -@property (nonatomic, nullable) DebugLogUploadSuccess success; -@property (nonatomic, nullable) DebugLogUploadFailure failure; - -@end - -#pragma mark - - -@implementation DebugLogUploader - -- (void)dealloc -{ - OWSLogVerbose(@""); -} - -- (void)uploadFileWithURL:(NSURL *)fileUrl - mimeType:(NSString *)mimeType - success:(DebugLogUploadSuccess)success - failure:(DebugLogUploadFailure)failure -{ - OWSAssertDebug(fileUrl); - OWSAssertDebug(mimeType.length > 0); - OWSAssertDebug(success); - OWSAssertDebug(failure); - - self.fileUrl = fileUrl; - self.mimeType = mimeType; - self.success = success; - self.failure = failure; - - [self getUploadParameters]; -} - -- (void)getUploadParameters -{ - __weak DebugLogUploader *weakSelf = self; - - NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; - AFHTTPSessionManager *sessionManager = - [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf]; - sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer]; - sessionManager.responseSerializer = [AFJSONResponseSerializer serializer]; - NSString *urlString = @"https://debuglogs.org/"; - [sessionManager GET:urlString - parameters:nil - headers:nil - progress:nil - success:^(NSURLSessionDataTask *task, id _Nullable responseObject) { - DebugLogUploader *strongSelf = weakSelf; - if (!strongSelf) { - return; - } - - if (![responseObject isKindOfClass:[NSDictionary class]]) { - OWSLogError(@"Invalid response: %@, %@", urlString, responseObject); - [strongSelf - failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; - return; - } - NSString *uploadUrl = responseObject[@"url"]; - if (![uploadUrl isKindOfClass:[NSString class]] || uploadUrl.length < 1) { - OWSLogError(@"Invalid response: %@, %@", urlString, responseObject); - [strongSelf - failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; - return; - } - NSDictionary *fields = responseObject[@"fields"]; - if (![fields isKindOfClass:[NSDictionary class]] || fields.count < 1) { - OWSLogError(@"Invalid response: %@, %@", urlString, responseObject); - [strongSelf - failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; - return; - } - for (NSString *fieldName in fields) { - NSString *fieldValue = fields[fieldName]; - if (![fieldName isKindOfClass:[NSString class]] || fieldName.length < 1 - || ![fieldValue isKindOfClass:[NSString class]] || fieldValue.length < 1) { - OWSLogError(@"Invalid response: %@, %@", urlString, responseObject); - [strongSelf failWithError:OWSErrorWithCodeDescription( - OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; - return; - } - } - NSString *_Nullable uploadKey = fields[@"key"]; - if (![uploadKey isKindOfClass:[NSString class]] || uploadKey.length < 1) { - OWSLogError(@"Invalid response: %@, %@", urlString, responseObject); - [strongSelf - failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")]; - return; - } - - // Add a file extension to the upload's key. - NSString *fileExtension = strongSelf.fileUrl.lastPathComponent.pathExtension; - if (fileExtension.length < 1) { - OWSLogError(@"Invalid file url: %@, %@", urlString, responseObject); - [strongSelf - failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid file url")]; - return; - } - uploadKey = [uploadKey stringByAppendingPathExtension:fileExtension]; - NSMutableDictionary *updatedFields = [fields mutableCopy]; - updatedFields[@"key"] = uploadKey; - - [strongSelf uploadFileWithUploadUrl:uploadUrl fields:updatedFields uploadKey:uploadKey]; - } - failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) { - OWSLogError(@"failed: %@", urlString); - [weakSelf failWithError:error]; - }]; -} - -- (void)uploadFileWithUploadUrl:(NSString *)uploadUrl fields:(NSDictionary *)fields uploadKey:(NSString *)uploadKey -{ - OWSAssertDebug(uploadUrl.length > 0); - OWSAssertDebug(fields); - OWSAssertDebug(uploadKey.length > 0); - - __weak DebugLogUploader *weakSelf = self; - NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; - AFHTTPSessionManager *sessionManager = - [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf]; - sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer]; - sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer]; - [sessionManager POST:uploadUrl - parameters:@{} - headers:nil - constructingBodyWithBlock:^(id formData) { - for (NSString *fieldName in fields) { - NSString *fieldValue = fields[fieldName]; - [formData appendPartWithFormData:[fieldValue dataUsingEncoding:NSUTF8StringEncoding] name:fieldName]; - } - [formData appendPartWithFormData:[weakSelf.mimeType dataUsingEncoding:NSUTF8StringEncoding] - name:@"content-type"]; - - NSError *error; - BOOL success = [formData appendPartWithFileURL:weakSelf.fileUrl - name:@"file" - fileName:weakSelf.fileUrl.lastPathComponent - mimeType:weakSelf.mimeType - error:&error]; - if (!success || error) { - OWSLogError(@"failed: %@, error: %@", uploadUrl, error); - } - } - progress:nil - success:^(NSURLSessionDataTask *task, id _Nullable responseObject) { - OWSLogVerbose(@"Response: %@, %@", uploadUrl, responseObject); - - NSString *urlString = [NSString stringWithFormat:@"https://debuglogs.org/%@", uploadKey]; - [self succeedWithUrl:[NSURL URLWithString:urlString]]; - } - failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) { - OWSLogError(@"upload: %@ failed with error: %@", uploadUrl, error); - [weakSelf failWithError:error]; - }]; -} - -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response -{ - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - - NSInteger statusCode = httpResponse.statusCode; - // We'll accept any 2xx status code. - NSInteger statusCodeClass = statusCode - (statusCode % 100); - if (statusCodeClass != 200) { - OWSLogError(@"statusCode: %zd, %zd", statusCode, statusCodeClass); - OWSLogError(@"headers: %@", httpResponse.allHeaderFields); - [self failWithError:[NSError errorWithDomain:@"PastelogKit" - code:10001 - userInfo:@{ NSLocalizedDescriptionKey : @"Invalid response code." }]]; - } -} - -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error -{ - OWSLogVerbose(@""); - - [self failWithError:error]; -} - -- (void)failWithError:(NSError *)error -{ - OWSAssertDebug(error); - - OWSLogError(@"%@", error); - - DispatchMainThreadSafe(^{ - // Call the completions exactly once. - if (self.failure) { - self.failure(self, error); - } - self.success = nil; - self.failure = nil; - }); -} - -- (void)succeedWithUrl:(NSURL *)url -{ - OWSAssertDebug(url); - - OWSLogVerbose(@"%@", url); - - DispatchMainThreadSafe(^{ - // Call the completions exactly once. - if (self.success) { - self.success(self, url); - } - self.success = nil; - self.failure = nil; - }); -} - -@end - -#pragma mark - - -@interface Pastelog () - -@property (nonatomic) UIAlertController *loadingAlert; - -@property (nonatomic) DebugLogUploader *currentUploader; - -@end - -#pragma mark - - -@implementation Pastelog - -+ (instancetype)sharedManager -{ - static Pastelog *sharedMyManager = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedMyManager = [[self alloc] initDefault]; - }); - return sharedMyManager; -} - -- (instancetype)initDefault -{ - self = [super init]; - - if (!self) { - return self; - } - - OWSSingletonAssert(); - - return self; -} - -#pragma mark - Dependencies - -- (YapDatabaseConnection *)dbConnection -{ - return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection; -} - -- (TSAccountManager *)tsAccountManager -{ - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - - return SSKEnvironment.shared.tsAccountManager; -} - -#pragma mark - - -+ (void)submitLogs -{ - [self submitLogsWithCompletion:nil]; -} - -+ (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completionParam -{ - SubmitDebugLogsCompletion completion = ^{ - if (completionParam) { - // Wait a moment. If PasteLog opens a URL, it needs a moment to complete. - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), completionParam); - } - }; - - [[self sharedManager] uploadLogsWithUIWithSuccess:^(NSURL *url) { - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.") - message:NSLocalizedString(@"DEBUG_LOG_ALERT_MESSAGE", @"Message of the debug log alert.") - preferredStyle:UIAlertControllerStyleAlert]; - [alert - addAction:[UIAlertAction - actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL", - @"Label for the 'email debug log' option of the debug log alert.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_email") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [Pastelog.sharedManager submitEmail:url]; - - completion(); - }]]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK", - @"Label for the 'copy link' option of the debug log alert.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"copy_link") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - UIPasteboard *pb = [UIPasteboard generalPasteboard]; - [pb setString:url.absoluteString]; - - completion(); - }]]; -#ifdef DEBUG - [alert - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF", - @"Label for the 'send to self' option of the debug log alert.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_to_self") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [Pastelog.sharedManager sendToSelf:url]; - }]]; - [alert addAction:[UIAlertAction actionWithTitle: - NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD", - @"Label for the 'send to last thread' option of the debug log alert.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_to_last_thread") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [Pastelog.sharedManager sendToMostRecentThread:url]; - }]]; -#endif - [alert - addAction: - [UIAlertAction actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT", - @"Label for the 'Open a Bug Report' option of the debug log alert.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"submit_bug_report") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [Pastelog.sharedManager prepareRedirection:url completion:completion]; - }]]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SHARE", - @"Label for the 'Share' option of the debug log alert.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"share") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [AttachmentSharing showShareUIForText:url.absoluteString - completion:completion]; - }]]; - [alert addAction:[OWSAlerts cancelAction]]; - UIViewController *presentingViewController - = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; - [presentingViewController presentAlert:alert animated:NO]; - }]; -} - -- (void)uploadLogsWithUIWithSuccess:(UploadDebugLogsSuccess)successParam { - OWSAssertIsOnMainThread(); - - [ModalActivityIndicatorViewController - presentFromViewController:UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts - canCancel:YES - backgroundBlock:^(ModalActivityIndicatorViewController *modalActivityIndicator) { - [self - uploadLogsWithSuccess:^(NSURL *url) { - OWSAssertIsOnMainThread(); - - if (modalActivityIndicator.wasCancelled) { - return; - } - - [modalActivityIndicator dismissWithCompletion:^{ - OWSAssertIsOnMainThread(); - - successParam(url); - }]; - } - failure:^(NSString *localizedErrorMessage) { - OWSAssertIsOnMainThread(); - - if (modalActivityIndicator.wasCancelled) { - return; - } - - [modalActivityIndicator dismissWithCompletion:^{ - OWSAssertIsOnMainThread(); - - [Pastelog showFailureAlertWithMessage:localizedErrorMessage]; - }]; - }]; - }]; -} - -- (void)uploadLogsWithSuccess:(UploadDebugLogsSuccess)successParam failure:(UploadDebugLogsFailure)failureParam { - OWSAssertDebug(successParam); - OWSAssertDebug(failureParam); - - // Ensure that we call the completions on the main thread. - UploadDebugLogsSuccess success = ^(NSURL *url) { - DispatchMainThreadSafe(^{ - successParam(url); - }); - }; - UploadDebugLogsFailure failure = ^(NSString *localizedErrorMessage) { - DispatchMainThreadSafe(^{ - failureParam(localizedErrorMessage); - }); - }; - - // Phase 1. Make a local copy of all of the log files. - NSDateFormatter *dateFormatter = [NSDateFormatter new]; - [dateFormatter setLocale:[NSLocale currentLocale]]; - [dateFormatter setDateFormat:@"yyyy.MM.dd hh.mm.ss"]; - NSString *dateString = [dateFormatter stringFromDate:[NSDate new]]; - NSString *logsName = [[dateString stringByAppendingString:@" "] stringByAppendingString:NSUUID.UUID.UUIDString]; - NSString *tempDirectory = OWSTemporaryDirectory(); - NSString *zipFilePath = - [tempDirectory stringByAppendingPathComponent:[logsName stringByAppendingPathExtension:@"zip"]]; - NSString *zipDirPath = [tempDirectory stringByAppendingPathComponent:logsName]; - [OWSFileSystem ensureDirectoryExists:zipDirPath]; - - NSArray *logFilePaths = DebugLogger.sharedLogger.allLogFilePaths; - if (logFilePaths.count < 1) { - failure(NSLocalizedString(@"DEBUG_LOG_ALERT_NO_LOGS", @"Error indicating that no debug logs could be found.")); - return; - } - - for (NSString *logFilePath in logFilePaths) { - NSString *copyFilePath = [zipDirPath stringByAppendingPathComponent:logFilePath.lastPathComponent]; - NSError *error; - [[NSFileManager defaultManager] copyItemAtPath:logFilePath toPath:copyFilePath error:&error]; - if (error) { - failure(NSLocalizedString( - @"DEBUG_LOG_ALERT_COULD_NOT_COPY_LOGS", @"Error indicating that the debug logs could not be copied.")); - return; - } - [OWSFileSystem protectFileOrFolderAtPath:copyFilePath]; - } - - // Phase 2. Zip up the log files. - BOOL zipSuccess = [SSZipArchive createZipFileAtPath:zipFilePath - withContentsOfDirectory:zipDirPath - keepParentDirectory:YES - compressionLevel:Z_DEFAULT_COMPRESSION - password:nil - AES:NO - progressHandler:nil]; - if (!zipSuccess) { - failure(NSLocalizedString( - @"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS", @"Error indicating that the debug logs could not be packaged.")); - return; - } - - [OWSFileSystem protectFileOrFolderAtPath:zipFilePath]; - [OWSFileSystem deleteFile:zipDirPath]; - - // Phase 3. Upload the log files. - - __weak Pastelog *weakSelf = self; - self.currentUploader = [DebugLogUploader new]; - [self.currentUploader uploadFileWithURL:[NSURL fileURLWithPath:zipFilePath] - mimeType:OWSMimeTypeApplicationZip - success:^(DebugLogUploader *uploader, NSURL *url) { - if (uploader != weakSelf.currentUploader) { - // Ignore events from obsolete uploaders. - return; - } - [OWSFileSystem deleteFile:zipFilePath]; - success(url); - } - failure:^(DebugLogUploader *uploader, NSError *error) { - if (uploader != weakSelf.currentUploader) { - // Ignore events from obsolete uploaders. - return; - } - [OWSFileSystem deleteFile:zipFilePath]; - failure(NSLocalizedString( - @"DEBUG_LOG_ALERT_ERROR_UPLOADING_LOG", @"Error indicating that a debug log could not be uploaded.")); - }]; -} - -+ (void)showFailureAlertWithMessage:(NSString *)message -{ - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", - @"Title of the alert shown for failures while uploading debug logs.") - message:message - preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"ok") - style:UIAlertActionStyleDefault - handler:nil]]; - UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; - [presentingViewController presentAlert:alert animated:NO]; -} - -#pragma mark Logs submission - -- (void)submitEmail:(NSURL *)url -{ - NSString *emailAddress = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_EMAIL"]; - - NSMutableString *body = [NSMutableString new]; - - [body appendFormat:@"Tell us about the issue: \n\n\n"]; - - size_t size; - sysctlbyname("hw.machine", NULL, &size, NULL, 0); - char *machine = malloc(size); - sysctlbyname("hw.machine", machine, &size, NULL, 0); - NSString *platform = [NSString stringWithUTF8String:machine]; - free(machine); - - [body appendFormat:@"Device: %@ (%@)\n", UIDevice.currentDevice.model, platform]; - [body appendFormat:@"iOS Version: %@ \n", [UIDevice currentDevice].systemVersion]; - [body appendFormat:@"Signal Version: %@ \n", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]; - [body appendFormat:@"Log URL: %@ \n", url]; - - NSString *escapedBody = - [body stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; - NSString *urlString = - [NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=%@", emailAddress, escapedBody]; - - BOOL success = [UIApplication.sharedApplication openURL:[NSURL URLWithString:urlString]]; - if (!success) { - OWSLogError(@"Could not open Email app."); - [OWSAlerts showErrorAlertWithMessage:NSLocalizedString(@"DEBUG_LOG_COULD_NOT_EMAIL", - @"Error indicating that the app could not launch the Email app.")]; - } -} - -- (void)prepareRedirection:(NSURL *)url completion:(SubmitDebugLogsCompletion)completion -{ - OWSAssertDebug(completion); - - UIPasteboard *pb = [UIPasteboard generalPasteboard]; - [pb setString:url.absoluteString]; - - UIAlertController *alert = - [UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE", - @"Title of the alert before redirecting to GitHub Issues.") - message:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_MESSAGE", - @"Message of the alert before redirecting to GitHub Issues.") - preferredStyle:UIAlertControllerStyleAlert]; - [alert - addAction:[UIAlertAction - actionWithTitle:NSLocalizedString(@"OK", @"") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"ok") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - [UIApplication.sharedApplication - openURL:[NSURL - URLWithString:[[NSBundle mainBundle] - objectForInfoDictionaryKey:@"LOGS_URL"]]]; - - completion(); - }]]; - UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; - [presentingViewController presentAlert:alert animated:NO]; -} - -- (void)sendToSelf:(NSURL *)url -{ - if (![self.tsAccountManager isRegistered]) { - return; - } - NSString *recipientId = [TSAccountManager localNumber]; - - DispatchMainThreadSafe(^{ - __block TSThread *thread = nil; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; - }]; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [ThreadUtil enqueueMessageWithText:url.absoluteString - inThread:thread - quotedReplyModel:nil - linkPreviewDraft:nil - transaction:transaction]; - }]; - }); - - // Also copy to pasteboard. - [[UIPasteboard generalPasteboard] setString:url.absoluteString]; -} - -- (void)sendToMostRecentThread:(NSURL *)url -{ - if (![self.tsAccountManager isRegistered]) { - return; - } - - __block TSThread *thread = nil; - [OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:TSInboxGroup]; - }]; - DispatchMainThreadSafe(^{ - if (thread) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [ThreadUtil enqueueMessageWithText:url.absoluteString - inThread:thread - quotedReplyModel:nil - linkPreviewDraft:nil - transaction:transaction]; - }]; - } else { - [Pastelog showFailureAlertWithMessage:@"Could not find last thread."]; - } - }); - - // Also copy to pasteboard. - [[UIPasteboard generalPasteboard] setString:url.absoluteString]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/PinEntryView.h b/Session/Signal/PinEntryView.h deleted file mode 100644 index 83b562abd..000000000 --- a/Session/Signal/PinEntryView.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class PinEntryView; - -@protocol PinEntryViewDelegate - -- (void)pinEntryView:(PinEntryView *)entryView submittedPinCode:(NSString *)pinCode; -- (void)pinEntryViewForgotPinLinkTapped:(PinEntryView *)entryView; - -@optional -- (void)pinEntryView:(PinEntryView *)entryView pinCodeDidChange:(NSString *)pinCode; - -@end - -@interface PinEntryView : UIView - -@property (nonatomic, weak, nullable) id delegate; -@property (nonatomic, readonly) BOOL hasValidPin; -@property (nullable, nonatomic) NSString *instructionsText; -@property (nullable, nonatomic) NSAttributedString *attributedInstructionsText; -@property (nonatomic, readonly) UIFont *boldLabelFont; - -- (void)clearText; -- (BOOL)makePinTextFieldFirstResponder; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/PinEntryView.m b/Session/Signal/PinEntryView.m deleted file mode 100644 index 1ceaa224f..000000000 --- a/Session/Signal/PinEntryView.m +++ /dev/null @@ -1,227 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "PinEntryView.h" -#import "Session-Swift.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface PinEntryView () - -@property (nonatomic) UITextField *pinTextfield; -@property (nonatomic) OWSFlatButton *submitButton; -@property (nonatomic) UILabel *instructionsLabel; - -@end - -@implementation PinEntryView : UIView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (!self) { - return self; - } - - [self createContents]; - - return self; -} - -#pragma mark - view creation -- (UIFont *)labelFont -{ - return [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(14.f, 16.f)]; -} - -- (UIFont *)boldLabelFont -{ - return [UIFont ows_boldFontWithSize:ScaleFromIPhone5To7Plus(14.f, 16.f)]; -} - -- (UILabel *)createLabelWithText:(nullable NSString *)text -{ - UILabel *label = [UILabel new]; - label.textColor = [Theme primaryColor]; - label.text = text; - label.font = self.labelFont; - label.numberOfLines = 0; - label.lineBreakMode = NSLineBreakByWordWrapping; - label.textAlignment = NSTextAlignmentCenter; - [self addSubview:label]; - return label; -} - -- (void)createPinTextfield -{ - if (UIDevice.currentDevice.isShorterThanIPhone5) { - self.pinTextfield = [DismissableTextField new]; - } else { - self.pinTextfield = [OWSTextField new]; - } - - self.pinTextfield.textColor = [Theme primaryColor]; - self.pinTextfield.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(30.f, 36.f)]; - self.pinTextfield.textAlignment = NSTextAlignmentCenter; - self.pinTextfield.keyboardType = UIKeyboardTypeNumberPad; - self.pinTextfield.delegate = self; - self.pinTextfield.secureTextEntry = YES; - self.pinTextfield.textAlignment = NSTextAlignmentCenter; - [self addSubview:self.pinTextfield]; -} - -- (UILabel *)createForgotLink -{ - UILabel *label = [UILabel new]; - label.textColor = [UIColor ows_materialBlueColor]; - NSString *text = NSLocalizedString( - @"REGISTER_2FA_FORGOT_PIN", @"Label for 'I forgot my PIN' link in the 2FA registration view."); - label.attributedText = [[NSAttributedString alloc] - initWithString:text - attributes:@{ - NSForegroundColorAttributeName : [UIColor ows_materialBlueColor], - NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) - }]; - label.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(14.f, 16.f)]; - label.numberOfLines = 0; - label.lineBreakMode = NSLineBreakByWordWrapping; - label.textAlignment = NSTextAlignmentCenter; - label.userInteractionEnabled = YES; - [label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(forgotPinLinkTapped:)]]; - [self addSubview:label]; - return label; -} - -- (void)createSubmitButton -{ - const CGFloat kSubmitButtonHeight = 47.f; - // NOTE: We use ows_signalBrandBlueColor instead of ows_materialBlueColor - // throughout the onboarding flow to be consistent with the headers. - OWSFlatButton *submitButton = - [OWSFlatButton buttonWithTitle:NSLocalizedString(@"REGISTER_2FA_SUBMIT_BUTTON", - @"Label for 'submit' button in the 2FA registration view.") - font:[OWSFlatButton fontForHeight:kSubmitButtonHeight] - titleColor:[UIColor whiteColor] - backgroundColor:[UIColor ows_signalBrandBlueColor] - target:self - selector:@selector(submitButtonWasPressed)]; - self.submitButton = submitButton; - [self addSubview:submitButton]; - [self.submitButton autoSetDimension:ALDimensionHeight toSize:kSubmitButtonHeight]; -} - -- (nullable NSString *)instructionsText -{ - return self.instructionsLabel.text; -} - -- (void)setInstructionsText:(nullable NSString *)instructionsText -{ - self.instructionsLabel.text = instructionsText; -} - -- (nullable NSAttributedString *)attributedInstructionsText -{ - return self.instructionsLabel.attributedText; -} - -- (void)setAttributedInstructionsText:(nullable NSAttributedString *)attributedInstructionsText -{ - self.instructionsLabel.attributedText = attributedInstructionsText; -} - -- (void)createContents -{ - const CGFloat kVSpacing = ScaleFromIPhone5To7Plus(12, 30); - - UILabel *instructionsLabel = [self createLabelWithText:nil]; - self.instructionsLabel = instructionsLabel; - [instructionsLabel autoPinTopToSuperviewMarginWithInset:kVSpacing]; - [instructionsLabel autoPinWidthToSuperview]; - - UILabel *createForgotLink = [self createForgotLink]; - [createForgotLink autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:instructionsLabel withOffset:5]; - [createForgotLink autoPinWidthToSuperview]; - - [self createPinTextfield]; - [self.pinTextfield autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:createForgotLink withOffset:kVSpacing]; - [self.pinTextfield autoPinWidthToSuperview]; - - UIView *underscoreView = [UIView new]; - underscoreView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1.f]; - [self addSubview:underscoreView]; - [underscoreView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.pinTextfield withOffset:3]; - [underscoreView autoPinWidthToSuperview]; - [underscoreView autoSetDimension:ALDimensionHeight toSize:1.f]; - - [self createSubmitButton]; - [self.submitButton autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:underscoreView withOffset:kVSpacing]; - [self.submitButton autoPinWidthToSuperview]; - [self updateIsSubmitEnabled]; -} - -#pragma mark - UITextFieldDelegate - -- (BOOL)textField:(UITextField *)textField - shouldChangeCharactersInRange:(NSRange)range - replacementString:(NSString *)insertionText -{ - - [ViewControllerUtils ows2FAPINTextField:textField - shouldChangeCharactersInRange:range - replacementString:insertionText]; - - [self updateIsSubmitEnabled]; - - if (self.delegate && [self.delegate respondsToSelector:@selector(pinEntryView:pinCodeDidChange:)]) { - [self.delegate pinEntryView:self pinCodeDidChange:textField.text]; - } - - return NO; -} - -- (void)updateIsSubmitEnabled; -{ - [self.submitButton setEnabled:self.hasValidPin]; -} - -- (BOOL)makePinTextFieldFirstResponder -{ - return [self.pinTextfield becomeFirstResponder]; -} - -- (BOOL)hasValidPin -{ - return self.pinTextfield.text.length >= kMin2FAPinLength; -} - -- (void)clearText -{ - self.pinTextfield.text = @""; - [self updateIsSubmitEnabled]; -} - -#pragma mark - Events - -- (void)submitButtonWasPressed -{ - [self.delegate pinEntryView:self submittedPinCode:self.pinTextfield.text]; -} - -- (void)forgotPinLinkTapped:(UIGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized) { - [self.delegate pinEntryViewForgotPinLinkTapped:self]; - } -} - - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/PrivacySettingsTableViewController.m b/Session/Signal/PrivacySettingsTableViewController.m index 3a904983a..038ff6c60 100644 --- a/Session/Signal/PrivacySettingsTableViewController.m +++ b/Session/Signal/PrivacySettingsTableViewController.m @@ -3,16 +3,16 @@ // #import "PrivacySettingsTableViewController.h" -#import "BlockListViewController.h" + #import "Session-Swift.h" #import #import #import -#import + #import #import #import -#import +#import #import #import @@ -83,22 +83,7 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s OWSTableContents *contents = [OWSTableContents new]; __weak PrivacySettingsTableViewController *weakSelf = self; - - // Loki: Original code - // ======== -// OWSTableSection *blocklistSection = [OWSTableSection new]; -// blocklistSection.headerTitle -// = NSLocalizedString(@"SETTINGS_BLOCK_LIST_TITLE", @"Label for the block list section of the settings view"); -// [blocklistSection -// addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"SETTINGS_BLOCK_LIST_TITLE", -// @"Label for the block list section of the settings view") -// accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", @"blocklist"] -// actionBlock:^{ -// [weakSelf showBlocklist]; -// }]]; -// [contents addSection:blocklistSection]; -// - // ======== + OWSTableSection *readReceiptsSection = [OWSTableSection new]; readReceiptsSection.headerTitle = NSLocalizedString(@"SETTINGS_READ_RECEIPT", @"Label for the 'read receipts' setting."); @@ -189,104 +174,6 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s selector:@selector(didToggleScreenSecuritySwitch:)]]; [contents addSection:screenSecuritySection]; - // Loki: Original code - // ======== -// // Allow calls to connect directly vs. using TURN exclusively -// OWSTableSection *callingSection = [OWSTableSection new]; -// callingSection.headerTitle -// = NSLocalizedString(@"SETTINGS_SECTION_TITLE_CALLING", @"settings topic header for table section"); -// callingSection.footerTitle = NSLocalizedString(@"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE_DETAIL", -// @"User settings section footer, a detailed explanation"); -// [callingSection addItem:[OWSTableItem switchItemWithText:NSLocalizedString( -// @"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE", -// @"Table cell label") -// accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", -// @"calling_hide_ip_address"] -// isOnBlock:^{ -// return [Environment.shared.preferences doCallsHideIPAddress]; -// } -// isEnabledBlock:^{ -// return YES; -// } -// target:weakSelf -// selector:@selector(didToggleCallsHideIPAddressSwitch:)]]; -// [contents addSection:callingSection]; -// -// if (CallUIAdapter.isCallkitDisabledForLocale) { -// // Hide all CallKit-related prefs; CallKit is disabled. -// } else if (@available(iOS 11, *)) { -// OWSTableSection *callKitSection = [OWSTableSection new]; -// [callKitSection -// addItem:[OWSTableItem switchItemWithText:NSLocalizedString( -// @"SETTINGS_PRIVACY_CALLKIT_SYSTEM_CALL_LOG_PREFERENCE_TITLE", -// @"Short table cell label") -// accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", @"callkit_history"] -// isOnBlock:^{ -// return [Environment.shared.preferences isSystemCallLogEnabled]; -// } -// isEnabledBlock:^{ -// return YES; -// } -// target:weakSelf -// selector:@selector(didToggleEnableSystemCallLogSwitch:)]]; -// callKitSection.footerTitle = NSLocalizedString( -// @"SETTINGS_PRIVACY_CALLKIT_SYSTEM_CALL_LOG_PREFERENCE_DESCRIPTION", @"Settings table section footer."); -// [contents addSection:callKitSection]; -// } else if (@available(iOS 10, *)) { -// OWSTableSection *callKitSection = [OWSTableSection new]; -// callKitSection.footerTitle -// = NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_DESCRIPTION", @"Settings table section footer."); -// [callKitSection -// addItem:[OWSTableItem switchItemWithText:NSLocalizedString( -// @"SETTINGS_PRIVACY_CALLKIT_TITLE", @"Short table cell label") -// accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", @"callkit"] -// isOnBlock:^{ -// return [Environment.shared.preferences isCallKitEnabled]; -// } -// isEnabledBlock:^{ -// return YES; -// } -// target:weakSelf -// selector:@selector(didToggleEnableCallKitSwitch:)]]; -// if (self.preferences.isCallKitEnabled) { -// [callKitSection -// addItem:[OWSTableItem switchItemWithText:NSLocalizedString(@"SETTINGS_PRIVACY_CALLKIT_PRIVACY_TITLE", -// @"Label for 'CallKit privacy' preference") -// accessibilityIdentifier:[NSString -// stringWithFormat:@"settings.privacy.%@", @"callkit_privacy"] -// isOnBlock:^{ -// return (BOOL) ![Environment.shared.preferences isCallKitPrivacyEnabled]; -// } -// isEnabledBlock:^{ -// return YES; -// } -// target:weakSelf -// selector:@selector(didToggleEnableCallKitPrivacySwitch:)]]; -// } -// [contents addSection:callKitSection]; -// } -// -// OWSTableSection *twoFactorAuthSection = [OWSTableSection new]; -// twoFactorAuthSection.headerTitle = NSLocalizedString( -// @"SETTINGS_TWO_FACTOR_AUTH_TITLE", @"Title for the 'two factor auth' section of the privacy settings."); -// [twoFactorAuthSection -// addItem: -// [OWSTableItem -// disclosureItemWithText:NSLocalizedString(@"SETTINGS_TWO_FACTOR_AUTH_ITEM", -// @"Label for the 'two factor auth' item of the privacy settings.") -// detailText: -// ([OWS2FAManager.sharedManager is2FAEnabled] -// ? NSLocalizedString(@"SETTINGS_TWO_FACTOR_AUTH_ENABLED", -// @"Indicates that 'two factor auth' is enabled in the privacy settings.") -// : NSLocalizedString(@"SETTINGS_TWO_FACTOR_AUTH_DISABLED", -// @"Indicates that 'two factor auth' is disabled in the privacy settings.")) -// accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", @"2fa"] -// actionBlock:^{ -// [weakSelf show2FASettings]; -// }]]; -// [contents addSection:twoFactorAuthSection]; -// ======== - OWSTableSection *historyLogsSection = [OWSTableSection new]; historyLogsSection.headerTitle = NSLocalizedString(@"SETTINGS_HISTORYLOG_TITLE", @"Section header"); [historyLogsSection @@ -297,99 +184,6 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s }]]; [contents addSection:historyLogsSection]; -// Loki: Original code -// ======== -// OWSTableSection *unidentifiedDeliveryIndicatorsSection = [OWSTableSection new]; -// unidentifiedDeliveryIndicatorsSection.headerTitle -// = NSLocalizedString(@"SETTINGS_UNIDENTIFIED_DELIVERY_SECTION_TITLE", @"table section label"); -// [unidentifiedDeliveryIndicatorsSection -// addItem:[OWSTableItem -// itemWithCustomCellBlock:^UITableViewCell * { -// UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 -// reuseIdentifier:@"UITableViewCellStyleValue1"]; -// [OWSTableItem configureCell:cell]; -// cell.preservesSuperviewLayoutMargins = YES; -// cell.contentView.preservesSuperviewLayoutMargins = YES; -// cell.selectionStyle = UITableViewCellSelectionStyleNone; -// -// UILabel *label = [UILabel new]; -// label.text -// = NSLocalizedString(@"SETTINGS_UNIDENTIFIED_DELIVERY_SHOW_INDICATORS", @"switch label"); -// label.font = [UIFont ows_regularFontWithSize:18.f]; -// label.textColor = [Theme primaryColor]; -// [label setContentHuggingHorizontalHigh]; -// -// UIImage *icon = [UIImage imageNamed:@"ic_secret_sender_indicator"]; -// UIImageView *iconView = [[UIImageView alloc] -// initWithImage:[icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; -// iconView.tintColor = Theme.secondaryColor; -// [iconView setContentHuggingHorizontalHigh]; -// -// UIView *spacer = [UIView new]; -// [spacer setContentHuggingHorizontalLow]; -// -// UISwitch *cellSwitch = [UISwitch new]; -// cell.accessoryView = cellSwitch; -// [cellSwitch setOn:Environment.shared.preferences.shouldShowUnidentifiedDeliveryIndicators]; -// [cellSwitch addTarget:weakSelf -// action:@selector(didToggleUDShowIndicatorsSwitch:) -// forControlEvents:UIControlEventValueChanged]; -// [cellSwitch setContentHuggingHorizontalHigh]; -// cellSwitch.accessibilityIdentifier = -// [NSString stringWithFormat:@"settings.privacy.%@", @"sealed_sender"]; -// -// UIStackView *stackView = -// [[UIStackView alloc] initWithArrangedSubviews:@[ label, iconView, spacer, cellSwitch ]]; -// stackView.axis = UILayoutConstraintAxisHorizontal; -// stackView.spacing = 10; -// stackView.alignment = UIStackViewAlignmentCenter; -// -// [cell.contentView addSubview:stackView]; -// [stackView ows_autoPinToSuperviewMargins]; -// return cell; -// } -// customRowHeight:UITableViewAutomaticDimension -// actionBlock:^{ -// NSURL *url = [NSURL URLWithString:kSealedSenderInfoURL]; -// OWSCAssertDebug(url); -// [UIApplication.sharedApplication openURL:url]; -// }]]; -// -// unidentifiedDeliveryIndicatorsSection.footerTitle -// = NSLocalizedString(@"SETTINGS_UNIDENTIFIED_DELIVERY_SHOW_INDICATORS_FOOTER", @"table section footer"); -// [contents addSection:unidentifiedDeliveryIndicatorsSection]; -// -// OWSTableSection *unidentifiedDeliveryUnrestrictedSection = [OWSTableSection new]; -// OWSTableItem *unrestrictedAccessItem = [OWSTableItem -// switchItemWithText:NSLocalizedString(@"SETTINGS_UNIDENTIFIED_DELIVERY_UNRESTRICTED_ACCESS", @"switch label") -// accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", @"sealed_sender_unrestricted"] -// isOnBlock:^{ -// return [SSKEnvironment.shared.udManager shouldAllowUnrestrictedAccessLocal]; -// } -// isEnabledBlock:^{ -// return YES; -// } -// target:weakSelf -// selector:@selector(didToggleUDUnrestrictedAccessSwitch:)]; -// [unidentifiedDeliveryUnrestrictedSection addItem:unrestrictedAccessItem]; -// unidentifiedDeliveryUnrestrictedSection.footerTitle -// = NSLocalizedString(@"SETTINGS_UNIDENTIFIED_DELIVERY_UNRESTRICTED_ACCESS_FOOTER", @"table section footer"); -// [contents addSection:unidentifiedDeliveryUnrestrictedSection]; -// -// OWSTableSection *unidentifiedDeliveryLearnMoreSection = [OWSTableSection new]; -// [unidentifiedDeliveryLearnMoreSection -// addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"SETTINGS_UNIDENTIFIED_DELIVERY_LEARN_MORE", -// @"Label for a link to more info about unidentified delivery.") -// accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", -// @"sealed_sender_learn_more"] -// actionBlock:^{ -// NSURL *url = [NSURL URLWithString:kSealedSenderInfoURL]; -// OWSCAssertDebug(url); -// [UIApplication.sharedApplication openURL:url]; -// }]]; -// [contents addSection:unidentifiedDeliveryLearnMoreSection]; -// ======== - OWSTableSection *linkPreviewsSection = [OWSTableSection new]; [linkPreviewsSection addItem:[OWSTableItem switchItemWithText:NSLocalizedString(@"SETTINGS_LINK_PREVIEWS", @@ -414,12 +208,6 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s #pragma mark - Events -- (void)showBlocklist -{ - BlockListViewController *vc = [BlockListViewController new]; - [self.navigationController pushViewController:vc animated:YES]; -} - - (void)clearHistoryLogs { UIAlertController *alert = diff --git a/Session/Signal/PushRegistrationManager.swift b/Session/Signal/PushRegistrationManager.swift index ceee373c3..fc8b2f600 100644 --- a/Session/Signal/PushRegistrationManager.swift +++ b/Session/Signal/PushRegistrationManager.swift @@ -17,14 +17,10 @@ public enum PushRegistrationError: Error { /** * Singleton used to integrate with push notification services - registration and routing received remote notifications. */ -@objc public class PushRegistrationManager: NSObject, PKPushRegistryDelegate { +@objc public class PushRegistrationManager: NSObject { // MARK: - Dependencies - private var messageFetcherJob: MessageFetcherJob { - return AppEnvironment.shared.messageFetcherJob - } - private var notificationPresenter: NotificationPresenter { return AppEnvironment.shared.notificationPresenter } @@ -91,34 +87,6 @@ public enum PushRegistrationError: Error { vanillaTokenResolver.reject(error) } - // MARK: PKPushRegistryDelegate - voIP Push Token - - public func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) { - Logger.info("") - assert(type == .voIP) - AppReadiness.runNowOrWhenAppDidBecomeReady { - (self.messageFetcherJob.run() as Promise).retainUntilComplete() - } - } - - public func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { - Logger.info("") - assert(type == .voIP) - assert(credentials.type == .voIP) - guard let voipTokenResolver = self.voipTokenResolver else { - owsFailDebug("fulfillVoipTokenPromise was unexpectedly nil") - return - } - - voipTokenResolver.fulfill(credentials.token) - } - - public func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) { - // It's not clear when this would happen. We've never previously handled it, but we should at - // least start learning if it happens. - owsFailDebug("Invalid state") - } - // MARK: helpers // User notification settings must be registered *before* AppDelegate will @@ -200,55 +168,6 @@ public enum PushRegistrationError: Error { self.vanillaTokenPromise = nil } } - - private func registerForVoipPushToken() -> Promise { - AssertIsOnMainThread() - Logger.info("") - - guard self.voipTokenPromise == nil else { - let promise = self.voipTokenPromise! - assert(promise.isPending) - return promise.map { $0.hexEncodedString } - } - - // No pending voip token yet. Create a new promise - let (promise, resolver) = Promise.pending() - self.voipTokenPromise = promise - self.voipTokenResolver = resolver - - if self.voipRegistry == nil { - // We don't create the voip registry in init, because it immediately requests the voip token, - // potentially before we're ready to handle it. - let voipRegistry = PKPushRegistry(queue: nil) - self.voipRegistry = voipRegistry - voipRegistry.desiredPushTypes = [.voIP] - voipRegistry.delegate = self - } - - guard let voipRegistry = self.voipRegistry else { - owsFailDebug("failed to initialize voipRegistry") - resolver.reject(PushRegistrationError.assertionError(description: "failed to initialize voipRegistry")) - return promise.map { _ in - // coerce expected type of returned promise - we don't really care about the value, - // since this promise has been rejected. In practice this shouldn't happen - String() - } - } - - // If we've already completed registering for a voip token, resolve it immediately, - // rather than waiting for the delegate method to be called. - if let voipTokenData = voipRegistry.pushToken(for: .voIP) { - Logger.info("using pre-registered voIP token") - resolver.fulfill(voipTokenData) - } - - return promise.map { (voipTokenData: Data) -> String in - Logger.info("successfully registered for voip push notifications") - return voipTokenData.hexEncodedString - }.ensure { - self.voipTokenPromise = nil - } - } } // We transmit pushToken data as hex encoded string to the server diff --git a/Session/Signal/SafetyNumberConfirmationAlert.swift b/Session/Signal/SafetyNumberConfirmationAlert.swift deleted file mode 100644 index 4167a99a3..000000000 --- a/Session/Signal/SafetyNumberConfirmationAlert.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit - -@objc -public class SafetyNumberConfirmationAlert: NSObject { - - private let contactsManager: OWSContactsManager - private let primaryStorage: OWSPrimaryStorage - - init(contactsManager: OWSContactsManager) { - self.contactsManager = contactsManager - self.primaryStorage = OWSPrimaryStorage.shared() - } - - @objc - 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, beforePresentationHandler: nil) - } - - @objc - public class func presentAlertIfNecessary(recipientId: String, confirmationText: String, contactsManager: OWSContactsManager, completion: @escaping (Bool) -> Void, beforePresentationHandler: (() -> Void)? = nil) -> Bool { - return self.presentAlertIfNecessary(recipientIds: [recipientId], confirmationText: confirmationText, contactsManager: contactsManager, completion: completion, beforePresentationHandler: beforePresentationHandler) - } - - @objc - public class func presentAlertIfNecessary(recipientIds: [String], confirmationText: String, contactsManager: OWSContactsManager, completion: @escaping (Bool) -> Void) -> Bool { - return self.presentAlertIfNecessary(recipientIds: recipientIds, confirmationText: confirmationText, contactsManager: contactsManager, completion: completion, beforePresentationHandler: nil) - } - - @objc - public class func presentAlertIfNecessary(recipientIds: [String], confirmationText: String, contactsManager: OWSContactsManager, completion: @escaping (Bool) -> Void, beforePresentationHandler: (() -> Void)? = nil) -> Bool { - return SafetyNumberConfirmationAlert(contactsManager: contactsManager).presentIfNecessary(recipientIds: recipientIds, - confirmationText: confirmationText, - completion: completion, - beforePresentationHandler: beforePresentationHandler) - } - - /** - * Shows confirmation dialog if at least one of the recipient id's is not confirmed. - * - * @returns true if an alert was shown - * false if there were no unconfirmed identities - */ - public func presentIfNecessary(recipientIds: [String], confirmationText: String, completion: @escaping (Bool) -> Void, beforePresentationHandler: (() -> Void)? = nil) -> Bool { - - guard let untrustedIdentity = untrustedIdentityForSending(recipientIds: recipientIds) else { - // No identities to confirm, no alert to present. - return false - } - - let displayName = contactsManager.displayName(forPhoneIdentifier: untrustedIdentity.recipientId) - - let titleFormat = NSLocalizedString("CONFIRM_SENDING_TO_CHANGED_IDENTITY_TITLE_FORMAT", - comment: "Action sheet title presented when a user's SN has recently changed. Embeds {{contact's name or phone number}}") - let title = String(format: titleFormat, displayName) - - let bodyFormat = NSLocalizedString("CONFIRM_SENDING_TO_CHANGED_IDENTITY_BODY_FORMAT", - comment: "Action sheet body presented when a user's SN has recently changed. Embeds {{contact's name or phone number}}") - let body = String(format: bodyFormat, displayName) - - let actionSheet = UIAlertController(title: title, message: body, preferredStyle: .actionSheet) - - let confirmAction = UIAlertAction(title: confirmationText, style: .default) { _ in - Logger.info("Confirmed identity: \(untrustedIdentity)") - - self.primaryStorage.newDatabaseConnection().asyncReadWrite { (transaction) in - OWSIdentityManager.shared().setVerificationState(.default, identityKey: untrustedIdentity.identityKey, recipientId: untrustedIdentity.recipientId, isUserInitiatedChange: true, transaction: transaction) - DispatchQueue.main.async { - completion(true) - } - } - } - actionSheet.addAction(confirmAction) - - let showSafetyNumberAction = UIAlertAction(title: NSLocalizedString("VERIFY_PRIVACY", comment: "Label for button or row which allows users to verify the safety number of another user."), style: .default) { _ in - Logger.info("Opted to show Safety Number for identity: \(untrustedIdentity)") - - self.presentSafetyNumberViewController(theirIdentityKey: untrustedIdentity.identityKey, - theirRecipientId: untrustedIdentity.recipientId, - theirDisplayName: displayName, - completion: { completion(false) }) - - } - actionSheet.addAction(showSafetyNumberAction) - - // We can't use the default `OWSAlerts.cancelAction` because we need to specify that the completion - // handler is called. - let cancelAction = UIAlertAction(title: CommonStrings.cancelButton, style: .cancel) { _ in - Logger.info("user canceled.") - completion(false) - } - actionSheet.addAction(cancelAction) - - beforePresentationHandler?() - - UIApplication.shared.frontmostViewController?.presentAlert(actionSheet) - return true - } - - public func presentSafetyNumberViewController(theirIdentityKey: Data, theirRecipientId: String, theirDisplayName: String, completion: (() -> Void)? = nil) { - guard let fromViewController = UIApplication.shared.frontmostViewController else { - Logger.info("Missing frontmostViewController") - return - } - FingerprintViewController.present(from: fromViewController, recipientId: theirRecipientId) - } - - private func untrustedIdentityForSending(recipientIds: [String]) -> OWSRecipientIdentity? { - return recipientIds.compactMap { - OWSIdentityManager.shared().untrustedIdentityForSending(toRecipientId: $0) - }.first - } -} diff --git a/Session/Signal/SessionResetJob.swift b/Session/Signal/SessionResetJob.swift index 4f802addf..19df92994 100644 --- a/Session/Signal/SessionResetJob.swift +++ b/Session/Signal/SessionResetJob.swift @@ -97,10 +97,6 @@ public class SessionResetOperation: OWSOperation, DurableOperation { return SSKEnvironment.shared.primaryStorage } - var messageSender: MessageSender { - return SSKEnvironment.shared.messageSender - } - // MARK: var firstAttempt = true @@ -108,19 +104,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation { override public func run() { assert(self.durableOperationDelegate != nil) - /* Loki: Original code - * We don't want to delete the session. Ref: SignalServiceKit/Loki/Docs/SessionReset.md - * ================ - if firstAttempt { - Storage.writeSync { transaction in - Logger.info("deleting sessions for recipient: \(self.recipientId)") - self.primaryStorage.deleteAllSessions(forContact: self.recipientId, protocolContext: transaction) - } - firstAttempt = false - } - * ================ - */ - + /* let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.contactThread) firstly { @@ -157,6 +141,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation { Logger.error("sending error: \(error.localizedDescription)") self.reportError(error) }.retainUntilComplete() + */ } override public func didSucceed() { diff --git a/Session/Signal/ShowGroupMembersViewController.h b/Session/Signal/ShowGroupMembersViewController.h deleted file mode 100644 index de4c64267..000000000 --- a/Session/Signal/ShowGroupMembersViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSTableViewController.h" - -@class TSGroupThread; - -@interface ShowGroupMembersViewController : OWSTableViewController - -- (void)configWithThread:(TSGroupThread *)thread; - -@end diff --git a/Session/Signal/ShowGroupMembersViewController.m b/Session/Signal/ShowGroupMembersViewController.m deleted file mode 100644 index b42f5b096..000000000 --- a/Session/Signal/ShowGroupMembersViewController.m +++ /dev/null @@ -1,478 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "ShowGroupMembersViewController.h" -#import "Session-Swift.h" -#import "SignalApp.h" -#import "ViewControllerUtils.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -@import ContactsUI; - -NS_ASSUME_NONNULL_BEGIN - -@interface ShowGroupMembersViewController () - -@property (nonatomic, readonly) TSGroupThread *thread; -@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; - -@property (nonatomic, nullable) NSSet *memberRecipientIds; - -@end - -#pragma mark - - -@implementation ShowGroupMembersViewController - -- (instancetype)init -{ - self = [super init]; - if (!self) { - return self; - } - - [self commonInit]; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder:aDecoder]; - if (!self) { - return self; - } - - [self commonInit]; - - return self; -} - - -- (void)commonInit -{ - _contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self]; - - self.tableView.rowHeight = UITableViewAutomaticDimension; - self.tableView.estimatedRowHeight = 60; - - [self observeNotifications]; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)observeNotifications -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(identityStateDidChange:) - name:kNSNotificationName_IdentityStateDidChange - object:nil]; -} - -- (void)configWithThread:(TSGroupThread *)thread -{ - - _thread = thread; - - OWSAssertDebug(self.thread); - OWSAssertDebug(self.thread.groupModel); - OWSAssertDebug(self.thread.groupModel.groupMemberIds); - - self.memberRecipientIds = [NSSet setWithArray:self.thread.groupModel.groupMemberIds]; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - OWSAssertDebug([self.navigationController isKindOfClass:[OWSNavigationController class]]); - - self.title = _thread.groupModel.groupName; - - self.tableView.rowHeight = UITableViewAutomaticDimension; - self.tableView.estimatedRowHeight = 45; - - [self updateTableContents]; -} - -#pragma mark - Table Contents - -- (void)updateTableContents -{ - OWSAssertDebug(self.thread); - - OWSTableContents *contents = [OWSTableContents new]; - - __weak ShowGroupMembersViewController *weakSelf = self; - ContactsViewHelper *helper = self.contactsViewHelper; - - OWSTableSection *membersSection = [OWSTableSection new]; - - // Group Members - - // If there are "no longer verified" members of the group, - // highlight them in a special section. - NSArray *noLongerVerifiedRecipientIds = [self noLongerVerifiedRecipientIds]; - if (noLongerVerifiedRecipientIds.count > 0) { - OWSTableSection *noLongerVerifiedSection = [OWSTableSection new]; - noLongerVerifiedSection.headerTitle = NSLocalizedString(@"GROUP_MEMBERS_SECTION_TITLE_NO_LONGER_VERIFIED", - @"Title for the 'no longer verified' section of the 'group members' view."); - membersSection.headerTitle = NSLocalizedString( - @"GROUP_MEMBERS_SECTION_TITLE_MEMBERS", @"Title for the 'members' section of the 'group members' view."); - [noLongerVerifiedSection - addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"GROUP_MEMBERS_RESET_NO_LONGER_VERIFIED", - @"Label for the button that clears all verification " - @"errors in the 'group members' view.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"no_longer_verified") - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - [weakSelf offerResetAllNoLongerVerified]; - }]]; - [self addMembers:noLongerVerifiedRecipientIds toSection:noLongerVerifiedSection useVerifyAction:YES]; - [contents addSection:noLongerVerifiedSection]; - } - - NSMutableSet *memberRecipientIds = [self.memberRecipientIds mutableCopy]; - [memberRecipientIds removeObject:[helper localNumber]]; - [self addMembers:memberRecipientIds.allObjects toSection:membersSection useVerifyAction:NO]; - [contents addSection:membersSection]; - - self.contents = contents; -} - -- (void)addMembers:(NSArray *)recipientIds - toSection:(OWSTableSection *)section - useVerifyAction:(BOOL)useVerifyAction -{ - OWSAssertDebug(recipientIds); - OWSAssertDebug(section); - - __weak ShowGroupMembersViewController *weakSelf = self; - ContactsViewHelper *helper = self.contactsViewHelper; - // Sort the group members using contacts manager. - NSArray *sortedRecipientIds = [recipientIds sortedArrayUsingComparator:^NSComparisonResult( - NSString *recipientIdA, NSString *recipientIdB) { - SignalAccount *signalAccountA = [helper.contactsManager fetchOrBuildSignalAccountForRecipientId:recipientIdA]; - SignalAccount *signalAccountB = [helper.contactsManager fetchOrBuildSignalAccountForRecipientId:recipientIdB]; - return [helper.contactsManager compareSignalAccount:signalAccountA withSignalAccount:signalAccountB]; - }]; - for (NSString *recipientId in sortedRecipientIds) { - [section addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - ShowGroupMembersViewController *strongSelf = weakSelf; - OWSCAssertDebug(strongSelf); - - ContactTableViewCell *cell = [ContactTableViewCell new]; - OWSVerificationState verificationState = - [[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId]; - BOOL isVerified = verificationState == OWSVerificationStateVerified; - BOOL isNoLongerVerified = verificationState == OWSVerificationStateNoLongerVerified; - BOOL isBlocked = [helper isRecipientIdBlocked:recipientId]; - if (isNoLongerVerified) { - cell.accessoryMessage = NSLocalizedString(@"CONTACT_CELL_IS_NO_LONGER_VERIFIED", - @"An indicator that a contact is no longer verified."); - } else if (isBlocked) { - cell.accessoryMessage = NSLocalizedString( - @"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked."); - } - - [cell configureWithRecipientId:recipientId]; - - if (isVerified) { - [cell setAttributedSubtitle:cell.verifiedSubtitle]; - } else { - [cell setAttributedSubtitle:nil]; - } - - NSString *cellName = [NSString stringWithFormat:@"user.%@", recipientId]; - cell.accessibilityIdentifier - = ACCESSIBILITY_IDENTIFIER_WITH_NAME(ShowGroupMembersViewController, cellName); - - return cell; - } - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - if (useVerifyAction) { - [weakSelf showSafetyNumberView:recipientId]; - } else { - [weakSelf didSelectRecipientId:recipientId]; - } - }]]; - } -} - -- (void)offerResetAllNoLongerVerified -{ - OWSAssertIsOnMainThread(); - - UIAlertController *actionSheet = [UIAlertController - alertControllerWithTitle:nil - message:NSLocalizedString(@"GROUP_MEMBERS_RESET_NO_LONGER_VERIFIED_ALERT_MESSAGE", - @"Label for the 'reset all no-longer-verified group members' confirmation alert.") - preferredStyle:UIAlertControllerStyleAlert]; - - __weak ShowGroupMembersViewController *weakSelf = self; - UIAlertAction *verifyAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"ok") - style:UIAlertActionStyleDestructive - handler:^(UIAlertAction *_Nonnull action) { - [weakSelf resetAllNoLongerVerified]; - }]; - [actionSheet addAction:verifyAction]; - [actionSheet addAction:[OWSAlerts cancelAction]]; - - [self presentAlert:actionSheet]; -} - -- (void)resetAllNoLongerVerified -{ - OWSAssertIsOnMainThread(); - - OWSIdentityManager *identityManger = [OWSIdentityManager sharedManager]; - NSArray *recipientIds = [self noLongerVerifiedRecipientIds]; - for (NSString *recipientId in recipientIds) { - OWSVerificationState verificationState = [identityManger verificationStateForRecipientId:recipientId]; - if (verificationState == OWSVerificationStateNoLongerVerified) { - NSData *identityKey = [identityManger identityKeyForRecipientId:recipientId]; - if (identityKey.length < 1) { - OWSFailDebug(@"Missing identity key for: %@", recipientId); - continue; - } - [identityManger setVerificationState:OWSVerificationStateDefault - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:YES]; - } - } - - [self updateTableContents]; -} - -// Returns a collection of the group members who are "no longer verified". -- (NSArray *)noLongerVerifiedRecipientIds -{ - NSMutableArray *result = [NSMutableArray new]; - for (NSString *recipientId in self.thread.recipientIdentifiers) { - if ([[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId] - == OWSVerificationStateNoLongerVerified) { - [result addObject:recipientId]; - } - } - return [result copy]; -} - -- (void)didSelectRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - ContactsViewHelper *helper = self.contactsViewHelper; - SignalAccount *_Nullable signalAccount = [helper fetchSignalAccountForRecipientId:recipientId]; - - UIAlertController *actionSheet = - [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; - - if (self.contactsViewHelper.contactsManager.supportsContactEditing) { - NSString *contactInfoTitle = signalAccount - ? NSLocalizedString(@"GROUP_MEMBERS_VIEW_CONTACT_INFO", @"Button label for the 'show contact info' button") - : NSLocalizedString( - @"GROUP_MEMBERS_ADD_CONTACT_INFO", @"Button label to add information to an unknown contact"); - [actionSheet - addAction:[UIAlertAction actionWithTitle:contactInfoTitle - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"show_contact_info") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [self showContactInfoViewForRecipientId:recipientId]; - }]]; - } - - BOOL isBlocked; - if (signalAccount) { - isBlocked = [helper isRecipientIdBlocked:signalAccount.recipientId]; - if (isBlocked) { - [actionSheet - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_BUTTON", - @"Button label for the 'unblock' button") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"unblock") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [BlockListUIUtils - showUnblockSignalAccountActionSheet:signalAccount - fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager - completionBlock:^(BOOL ignore) { - [self updateTableContents]; - }]; - }]]; - } else { - [actionSheet - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BLOCK_LIST_BLOCK_BUTTON", - @"Button label for the 'block' button") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"block") - style:UIAlertActionStyleDestructive - handler:^(UIAlertAction *_Nonnull action) { - [BlockListUIUtils - showBlockSignalAccountActionSheet:signalAccount - fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager - completionBlock:^(BOOL ignore) { - [self updateTableContents]; - }]; - }]]; - } - } else { - isBlocked = [helper isRecipientIdBlocked:recipientId]; - if (isBlocked) { - [actionSheet - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_BUTTON", - @"Button label for the 'unblock' button") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"unblock") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [BlockListUIUtils - showUnblockPhoneNumberActionSheet:recipientId - fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager - completionBlock:^(BOOL ignore) { - [self updateTableContents]; - }]; - }]]; - } else { - [actionSheet - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BLOCK_LIST_BLOCK_BUTTON", - @"Button label for the 'block' button") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"block") - style:UIAlertActionStyleDestructive - handler:^(UIAlertAction *_Nonnull action) { - [BlockListUIUtils - showBlockPhoneNumberActionSheet:recipientId - fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager - completionBlock:^(BOOL ignore) { - [self updateTableContents]; - }]; - }]]; - } - } - - if (!isBlocked) { - [actionSheet - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"GROUP_MEMBERS_SEND_MESSAGE", - @"Button label for the 'send message to group member' button") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_message") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [self showConversationViewForRecipientId:recipientId]; - }]]; - [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"GROUP_MEMBERS_CALL", - @"Button label for the 'call group member' button") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"call") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [self callMember:recipientId]; - }]]; - [actionSheet - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"VERIFY_PRIVACY", - @"Label for button or row which allows users to verify the " - @"safety number of another user.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"safety_numbers") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [self showSafetyNumberView:recipientId]; - }]]; - } - - [actionSheet addAction:[OWSAlerts cancelAction]]; - - [self presentAlert:actionSheet]; -} - -- (void)showContactInfoViewForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - [self.contactsViewHelper presentContactViewControllerForRecipientId:recipientId - fromViewController:self - editImmediately:NO]; -} - -- (void)showConversationViewForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - [SignalApp.sharedApp presentConversationForRecipientId:recipientId - action:ConversationViewActionCompose - animated:YES]; -} - -- (void)callMember:(NSString *)recipientId -{ - [SignalApp.sharedApp presentConversationForRecipientId:recipientId - action:ConversationViewActionAudioCall - animated:YES]; -} - -- (void)showSafetyNumberView:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - [FingerprintViewController presentFromViewController:self recipientId:recipientId]; -} - -#pragma mark - ContactsViewHelperDelegate - -- (void)contactsViewHelperDidUpdateContacts -{ - [self updateTableContents]; -} - -- (BOOL)shouldHideLocalNumber -{ - return YES; -} - -#pragma mark - ContactEditingDelegate - -- (void)didFinishEditingContact -{ - OWSLogDebug(@""); - [self dismissViewControllerAnimated:YES completion:nil]; -} - -#pragma mark - CNContactViewControllerDelegate - -- (void)contactViewController:(CNContactViewController *)viewController - didCompleteWithContact:(nullable CNContact *)contact -{ - OWSLogDebug(@"done editing contact."); - [self dismissViewControllerAnimated:YES completion:nil]; -} - -#pragma mark - Notifications - -- (void)identityStateDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [self updateTableContents]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/SignalApp.m b/Session/Signal/SignalApp.m index cfa9e745c..bf5e6ef07 100644 --- a/Session/Signal/SignalApp.m +++ b/Session/Signal/SignalApp.m @@ -6,7 +6,6 @@ #import "AppDelegate.h" #import "ConversationViewController.h" #import "Session-Swift.h" -#import "SignalsNavigationController.h" #import #import #import @@ -178,8 +177,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)showHomeView { HomeVC *homeView = [HomeVC new]; - SignalsNavigationController *navigationController = - [[SignalsNavigationController alloc] initWithRootViewController:homeView]; + UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:homeView]; AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; appDelegate.window.rootViewController = navigationController; OWSAssertDebug([navigationController.topViewController isKindOfClass:[HomeVC class]]); diff --git a/Session/Signal/SignalsNavigationController.h b/Session/Signal/SignalsNavigationController.h deleted file mode 100644 index 7d8b6a041..000000000 --- a/Session/Signal/SignalsNavigationController.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "OWSNavigationController.h" - -@interface SignalsNavigationController : OWSNavigationController - -@end diff --git a/Session/Signal/SignalsNavigationController.m b/Session/Signal/SignalsNavigationController.m deleted file mode 100644 index 66ac3f02e..000000000 --- a/Session/Signal/SignalsNavigationController.m +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SignalsNavigationController.h" -#import "Session-Swift.h" -#import -#import -#import -#import - -static double const STALLED_PROGRESS = 0.9; - -@interface SignalsNavigationController () - -@property (nonatomic) UIProgressView *socketStatusView; -@property (nonatomic) NSTimer *updateStatusTimer; - -@end - -#pragma mark - - -@implementation SignalsNavigationController - -- (void)viewDidLoad { - [super viewDidLoad]; - - // Do any additional setup after loading the view. - [self initializeObserver]; - [self updateSocketStatusView]; -} - -- (void)initializeSocketStatusBar { - if (!_socketStatusView) { - _socketStatusView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; - } - - CGRect bar = self.navigationBar.frame; - _socketStatusView.frame = CGRectMake(0, bar.size.height - 1.0f, self.view.frame.size.width, 1.0f); - _socketStatusView.progress = 0.0f; - _socketStatusView.progressTintColor = [UIColor ows_fadedBlueColor]; - - /** Loki: Original code - if (![_socketStatusView superview]) { - [self.navigationBar addSubview:_socketStatusView]; - } - */ -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -#pragma mark - Socket Status Notifications - -- (void)initializeObserver { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(OWSWebSocketStateDidChange) - name:kNSNotification_OWSWebSocketStateDidChange - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(isCensorshipCircumventionActiveDidChange:) - name:kNSNotificationName_IsCensorshipCircumventionActiveDidChange - object:nil]; -} - -- (void)isCensorshipCircumventionActiveDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [self updateSocketStatusView]; -} - -- (void)OWSWebSocketStateDidChange -{ - OWSAssertIsOnMainThread(); - - [self updateSocketStatusView]; -} - -- (void)updateSocketStatusView { - OWSAssertIsOnMainThread(); - - if ([OWSSignalService sharedInstance].isCensorshipCircumventionActive) { - [_updateStatusTimer invalidate]; - [_socketStatusView removeFromSuperview]; - _socketStatusView = nil; - return; - } - - switch (TSSocketManager.shared.highestSocketState) { - case OWSWebSocketStateClosed: - if (_socketStatusView == nil) { - [self initializeSocketStatusBar]; - [_updateStatusTimer invalidate]; - _updateStatusTimer = [NSTimer weakScheduledTimerWithTimeInterval:0.5 - target:self - selector:@selector(updateProgress) - userInfo:nil - repeats:YES]; - - } else if (_socketStatusView.progress >= STALLED_PROGRESS) { - [_updateStatusTimer invalidate]; - } - break; - case OWSWebSocketStateConnecting: - // Do nothing. - break; - case OWSWebSocketStateOpen: - [_updateStatusTimer invalidate]; - [_socketStatusView removeFromSuperview]; - _socketStatusView = nil; - break; - } -} - -- (void)updateProgress { - double progress = _socketStatusView.progress + 0.05; - _socketStatusView.progress = (float) MIN(progress, STALLED_PROGRESS); -} - -@end diff --git a/Session/Signal/UpdateGroupViewController.h b/Session/Signal/UpdateGroupViewController.h deleted file mode 100644 index efee19c7d..000000000 --- a/Session/Signal/UpdateGroupViewController.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSConversationSettingsViewDelegate.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSGroupThread; - -typedef NS_ENUM(NSUInteger, UpdateGroupMode) { - UpdateGroupMode_Default = 0, - UpdateGroupMode_EditGroupName, - UpdateGroupMode_EditGroupAvatar, -}; - -@interface UpdateGroupViewController : OWSViewController - -@property (nonatomic, weak) id conversationSettingsViewDelegate; - -// This property _must_ be set before the view is presented. -@property (nonatomic) TSGroupThread *thread; - -@property (nonatomic) UpdateGroupMode mode; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/UpdateGroupViewController.m b/Session/Signal/UpdateGroupViewController.m deleted file mode 100644 index 26ffdd171..000000000 --- a/Session/Signal/UpdateGroupViewController.m +++ /dev/null @@ -1,558 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "UpdateGroupViewController.h" -#import "AddToGroupViewController.h" -#import "AvatarViewHelper.h" -#import "OWSNavigationController.h" -#import "Session-Swift.h" -#import "ViewControllerUtils.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface UpdateGroupViewController () - -@property (nonatomic, readonly) OWSMessageSender *messageSender; -@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; -@property (nonatomic, readonly) AvatarViewHelper *avatarViewHelper; - -@property (nonatomic, readonly) OWSTableViewController *tableViewController; -@property (nonatomic, readonly) AvatarImageView *avatarView; -@property (nonatomic, readonly) UITextField *groupNameTextField; - -@property (nonatomic, nullable) UIImage *groupAvatar; -@property (nonatomic, nullable) NSSet *previousMemberRecipientIds; -@property (nonatomic) NSMutableSet *memberRecipientIds; -@property (nonatomic) NSMutableSet *removedRecipientIds; - -@property (nonatomic) BOOL hasUnsavedChanges; - -@end - -#pragma mark - - -@implementation UpdateGroupViewController - -- (instancetype)init -{ - self = [super init]; - if (!self) { - return self; - } - - [self commonInit]; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder:aDecoder]; - if (!self) { - return self; - } - - [self commonInit]; - - return self; -} - -- (void)commonInit -{ - _messageSender = SSKEnvironment.shared.messageSender; - _contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self]; - _avatarViewHelper = [AvatarViewHelper new]; - _avatarViewHelper.delegate = self; - - self.memberRecipientIds = [NSMutableSet new]; - self.removedRecipientIds = [NSMutableSet new]; -} - -#pragma mark - View Lifecycle - -- (void)loadView -{ - [super loadView]; - - OWSAssertDebug(self.thread); - OWSAssertDebug(self.thread.groupModel); - OWSAssertDebug(self.thread.groupModel.groupMemberIds); - - self.view.backgroundColor = Theme.backgroundColor; - - [self.memberRecipientIds addObjectsFromArray:self.thread.groupModel.groupMemberIds]; - self.previousMemberRecipientIds = [NSSet setWithArray:self.thread.groupModel.groupMemberIds]; - - self.title = NSLocalizedString(@"EDIT_GROUP_DEFAULT_TITLE", @"The navbar title for the 'update group' view."); - - // First section. - - UIView *firstSection = [self firstSectionHeader]; - [self.view addSubview:firstSection]; - [firstSection autoSetDimension:ALDimensionHeight toSize:100.f]; - [firstSection autoPinWidthToSuperview]; - [firstSection autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:0.0f]; - - _tableViewController = [OWSTableViewController new]; - _tableViewController.delegate = self; - [self.view addSubview:self.tableViewController.view]; - [self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeLeading]; - [self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing]; - [_tableViewController.view autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:firstSection]; - [self autoPinViewToBottomOfViewControllerOrKeyboard:self.tableViewController.view avoidNotch:NO]; - self.tableViewController.tableView.rowHeight = UITableViewAutomaticDimension; - self.tableViewController.tableView.estimatedRowHeight = 60; - - [self updateTableContents]; -} - -- (void)setHasUnsavedChanges:(BOOL)hasUnsavedChanges -{ - _hasUnsavedChanges = hasUnsavedChanges; - - [self updateNavigationBar]; -} - -- (void)updateNavigationBar -{ - self.navigationItem.rightBarButtonItem = (self.hasUnsavedChanges - ? [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"EDIT_GROUP_UPDATE_BUTTON", - @"The title for the 'update group' button.") - style:UIBarButtonItemStylePlain - target:self - action:@selector(updateGroupPressed) - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"update")] - : nil); -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - switch (self.mode) { - case UpdateGroupMode_EditGroupName: - [self.groupNameTextField becomeFirstResponder]; - break; - case UpdateGroupMode_EditGroupAvatar: - [self showChangeAvatarUI]; - break; - default: - break; - } - // Only perform these actions the first time the view appears. - self.mode = UpdateGroupMode_Default; -} - -- (UIView *)firstSectionHeader -{ - OWSAssertDebug(self.thread); - OWSAssertDebug(self.thread.groupModel); - - UIView *firstSectionHeader = [UIView new]; - firstSectionHeader.userInteractionEnabled = YES; - [firstSectionHeader - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(headerWasTapped:)]]; - firstSectionHeader.backgroundColor = [Theme backgroundColor]; - UIView *threadInfoView = [UIView new]; - [firstSectionHeader addSubview:threadInfoView]; - [threadInfoView autoPinWidthToSuperviewWithMargin:16.f]; - [threadInfoView autoPinHeightToSuperviewWithMargin:16.f]; - - AvatarImageView *avatarView = [AvatarImageView new]; - _avatarView = avatarView; - - [threadInfoView addSubview:avatarView]; - [avatarView autoVCenterInSuperview]; - [avatarView autoPinLeadingToSuperviewMargin]; - [avatarView autoSetDimension:ALDimensionWidth toSize:kLargeAvatarSize]; - [avatarView autoSetDimension:ALDimensionHeight toSize:kLargeAvatarSize]; - _groupAvatar = self.thread.groupModel.groupImage; - [self updateAvatarView]; - - UITextField *groupNameTextField = [OWSTextField new]; - _groupNameTextField = groupNameTextField; - self.groupNameTextField.text = [self.thread.groupModel.groupName ows_stripped]; - groupNameTextField.textColor = [Theme primaryColor]; - groupNameTextField.font = [UIFont ows_dynamicTypeTitle2Font]; - groupNameTextField.placeholder - = NSLocalizedString(@"NEW_GROUP_NAMEGROUP_REQUEST_DEFAULT", @"Placeholder text for group name field"); - groupNameTextField.delegate = self; - [groupNameTextField addTarget:self - action:@selector(groupNameDidChange:) - forControlEvents:UIControlEventEditingChanged]; - [threadInfoView addSubview:groupNameTextField]; - [groupNameTextField autoVCenterInSuperview]; - [groupNameTextField autoPinTrailingToSuperviewMargin]; - [groupNameTextField autoPinLeadingToTrailingEdgeOfView:avatarView offset:16.f]; - SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, groupNameTextField); - - [avatarView - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(avatarTouched:)]]; - avatarView.userInteractionEnabled = YES; - SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, avatarView); - - return firstSectionHeader; -} - -- (void)headerWasTapped:(UIGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized) { - [self.groupNameTextField becomeFirstResponder]; - } -} - -- (void)avatarTouched:(UIGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized) { - [self showChangeAvatarUI]; - } -} - -#pragma mark - Table Contents - -- (void)updateTableContents -{ - OWSAssertDebug(self.thread); - - OWSTableContents *contents = [OWSTableContents new]; - - __weak UpdateGroupViewController *weakSelf = self; - ContactsViewHelper *contactsViewHelper = self.contactsViewHelper; - - // Group Members - - OWSTableSection *section = [OWSTableSection new]; - section.headerTitle = NSLocalizedString( - @"EDIT_GROUP_MEMBERS_SECTION_TITLE", @"a title for the members section of the 'new/update group' view."); - - [section addItem:[OWSTableItem - disclosureItemWithText:NSLocalizedString(@"EDIT_GROUP_MEMBERS_ADD_MEMBER", - @"Label for the cell that lets you add a new member to a group.") - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - AddToGroupViewController *viewController = [AddToGroupViewController new]; - viewController.addToGroupDelegate = weakSelf; - [weakSelf.navigationController pushViewController:viewController animated:YES]; - }]]; - - NSMutableSet *memberRecipientIds = [self.memberRecipientIds mutableCopy]; - [memberRecipientIds removeObject:[contactsViewHelper localNumber]]; - for (NSString *recipientId in [memberRecipientIds.allObjects sortedArrayUsingSelector:@selector(compare:)]) { - [section - addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - UpdateGroupViewController *strongSelf = weakSelf; - OWSCAssertDebug(strongSelf); - - ContactTableViewCell *cell = [ContactTableViewCell new]; - BOOL isPreviousMember = [strongSelf.previousMemberRecipientIds containsObject:recipientId]; - BOOL isBlocked = [contactsViewHelper isRecipientIdBlocked:recipientId]; - if (isPreviousMember) { - if (isBlocked) { - cell.accessoryMessage = NSLocalizedString( - @"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked."); - } else { - cell.selectionStyle = UITableViewCellSelectionStyleNone; - } - } else { - // In the "members" section, we label "new" members as such when editing an existing - // group. - // - // The only way a "new" member could be blocked is if we blocked them on a linked device - // while in this dialog. We don't need to worry about that edge case. - cell.accessoryMessage = NSLocalizedString(@"EDIT_GROUP_NEW_MEMBER_LABEL", - @"An indicator that a user is a new member of the group."); - } - - [cell configureWithRecipientId:recipientId]; - - // TODO: Confirm with nancy if this will work. - NSString *cellName = [NSString stringWithFormat:@"member.%@", recipientId]; - cell.accessibilityIdentifier - = ACCESSIBILITY_IDENTIFIER_WITH_NAME(UpdateGroupViewController, cellName); - - return cell; - } - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - SignalAccount *_Nullable signalAccount = - [contactsViewHelper fetchSignalAccountForRecipientId:recipientId]; - BOOL isPreviousMember = [weakSelf.previousMemberRecipientIds containsObject:recipientId]; - BOOL isBlocked = [contactsViewHelper isRecipientIdBlocked:recipientId]; - if (isPreviousMember) { - if (isBlocked) { - if (signalAccount) { - [weakSelf showUnblockAlertForSignalAccount:signalAccount]; - } else { - [weakSelf showUnblockAlertForRecipientId:recipientId]; - } - } else { - [OWSAlerts - showAlertWithTitle: - NSLocalizedString(@"UPDATE_GROUP_CANT_REMOVE_MEMBERS_ALERT_TITLE", - @"Title for alert indicating that group members can't be removed.") - message:NSLocalizedString( - @"UPDATE_GROUP_CANT_REMOVE_MEMBERS_ALERT_MESSAGE", - @"Title for alert indicating that group members can't " - @"be removed.")]; - } - } else { - [weakSelf removeRecipientId:recipientId]; - } - }]]; - } - [contents addSection:section]; - - self.tableViewController.contents = contents; -} - -- (void)showUnblockAlertForSignalAccount:(SignalAccount *)signalAccount -{ - OWSAssertDebug(signalAccount); - - __weak UpdateGroupViewController *weakSelf = self; - [BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount - fromViewController:self - blockingManager:self.contactsViewHelper.blockingManager - contactsManager:self.contactsViewHelper.contactsManager - completionBlock:^(BOOL isBlocked) { - if (!isBlocked) { - [weakSelf updateTableContents]; - } - }]; -} - -- (void)showUnblockAlertForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - __weak UpdateGroupViewController *weakSelf = self; - [BlockListUIUtils showUnblockPhoneNumberActionSheet:recipientId - fromViewController:self - blockingManager:self.contactsViewHelper.blockingManager - contactsManager:self.contactsViewHelper.contactsManager - completionBlock:^(BOOL isBlocked) { - if (!isBlocked) { - [weakSelf updateTableContents]; - } - }]; -} - -- (void)removeRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - [self.memberRecipientIds removeObject:recipientId]; - [self.removedRecipientIds addObject:recipientId]; - [self updateTableContents]; -} - -#pragma mark - Methods - -- (void)updateGroup -{ - OWSAssertDebug(self.conversationSettingsViewDelegate); - - NSString *groupName = [self.groupNameTextField.text ows_stripped]; - TSGroupModel *groupModel = [[TSGroupModel alloc] initWithTitle:groupName - memberIds:self.memberRecipientIds.allObjects - image:self.groupAvatar - groupId:self.thread.groupModel.groupId - groupType:self.thread.groupModel.groupType - adminIds:self.thread.groupModel.groupAdminIds]; - [self.conversationSettingsViewDelegate groupWasUpdated:groupModel]; -} - -#pragma mark - Group Avatar - -- (void)showChangeAvatarUI -{ - [self.groupNameTextField resignFirstResponder]; - - [self.avatarViewHelper showChangeAvatarUI]; -} - -- (void)setGroupAvatar:(nullable UIImage *)groupAvatar -{ - OWSAssertIsOnMainThread(); - - _groupAvatar = groupAvatar; - - self.hasUnsavedChanges = YES; - - [self updateAvatarView]; -} - -- (void)updateAvatarView -{ - UIImage *_Nullable groupAvatar = self.groupAvatar; - if (!groupAvatar) { - groupAvatar = [[[OWSGroupAvatarBuilder alloc] initWithThread:self.thread diameter:kLargeAvatarSize] build]; - } - self.avatarView.image = groupAvatar; -} - -#pragma mark - Event Handling - -- (void)backButtonPressed -{ - [self.groupNameTextField resignFirstResponder]; - - if (!self.hasUnsavedChanges) { - // If user made no changes, return to conversation settings view. - [self.navigationController popViewControllerAnimated:YES]; - return; - } - - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"EDIT_GROUP_VIEW_UNSAVED_CHANGES_TITLE", - @"The alert title if user tries to exit update group view without saving changes.") - message: - NSLocalizedString(@"EDIT_GROUP_VIEW_UNSAVED_CHANGES_MESSAGE", - @"The alert message if user tries to exit update group view without saving changes.") - preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"ALERT_SAVE", - @"The label for the 'save' button in action sheets.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"save") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - OWSAssertDebug(self.conversationSettingsViewDelegate); - - [self updateGroup]; - - [self.conversationSettingsViewDelegate - popAllConversationSettingsViewsWithCompletion:nil]; - }]]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"ALERT_DONT_SAVE", - @"The label for the 'don't save' button in action sheets.") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dont_save") - style:UIAlertActionStyleDestructive - handler:^(UIAlertAction *action) { - [self.navigationController popViewControllerAnimated:YES]; - }]]; - [self presentAlert:alert]; -} - -- (void)updateGroupPressed -{ - OWSAssertDebug(self.conversationSettingsViewDelegate); - - [self updateGroup]; - - [self.conversationSettingsViewDelegate popAllConversationSettingsViewsWithCompletion:nil]; -} - -- (void)groupNameDidChange:(id)sender -{ - self.hasUnsavedChanges = YES; -} - -#pragma mark - Text Field Delegate - -- (BOOL)textFieldShouldReturn:(UITextField *)textField -{ - [self.groupNameTextField resignFirstResponder]; - return NO; -} - -#pragma mark - OWSTableViewControllerDelegate - -- (void)tableViewWillBeginDragging -{ - [self.groupNameTextField resignFirstResponder]; -} - -#pragma mark - ContactsViewHelperDelegate - -- (void)contactsViewHelperDidUpdateContacts -{ - [self updateTableContents]; -} - -- (BOOL)shouldHideLocalNumber -{ - return YES; -} - -#pragma mark - AvatarViewHelperDelegate - -- (nullable NSString *)avatarActionSheetTitle -{ - return NSLocalizedString( - @"NEW_GROUP_ADD_PHOTO_ACTION", @"Action Sheet title prompting the user for a group avatar"); -} - -- (void)avatarDidChange:(UIImage *)image -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(image); - - self.groupAvatar = image; -} - -- (UIViewController *)fromViewController -{ - return self; -} - -- (BOOL)hasClearAvatarAction -{ - return NO; -} - -#pragma mark - AddToGroupViewControllerDelegate - -- (void)recipientIdWasAdded:(NSString *)recipientId -{ - [self.memberRecipientIds addObject:recipientId]; - self.hasUnsavedChanges = YES; - [self updateTableContents]; -} - -- (BOOL)isRecipientGroupMember:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - return [self.memberRecipientIds containsObject:recipientId]; -} - -#pragma mark - OWSNavigationView - -- (BOOL)shouldCancelNavigationBack -{ - BOOL result = self.hasUnsavedChanges; - if (result) { - [self backButtonPressed]; - } - return result; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/UserNotificationsAdaptee.swift b/Session/Signal/UserNotificationsAdaptee.swift index f434705af..e5b9b7409 100644 --- a/Session/Signal/UserNotificationsAdaptee.swift +++ b/Session/Signal/UserNotificationsAdaptee.swift @@ -125,7 +125,7 @@ extension UserNotificationPresenterAdaptee: NotificationPresenterAdaptee { let trigger: UNNotificationTrigger? let checkForCancel = category == .incomingMessage - if checkForCancel && hasReceivedSyncMessageRecently { + if checkForCancel { assert(userInfo[AppNotificationUserInfoKey.threadId] != nil) trigger = UNTimeIntervalNotificationTrigger(timeInterval: kNotificationDelayForRemoteRead, repeats: false) } else { diff --git a/Session/Signal/WebRTCCallMessageHandler.swift b/Session/Signal/WebRTCCallMessageHandler.swift index 918b9b49d..3c037e0a1 100644 --- a/Session/Signal/WebRTCCallMessageHandler.swift +++ b/Session/Signal/WebRTCCallMessageHandler.swift @@ -21,61 +21,8 @@ public class WebRTCCallMessageHandler: NSObject/*, OWSCallMessageHandler*/ { // MARK: - Dependencies - private var messageSender : MessageSender - { - return SSKEnvironment.shared.messageSender - } - private var accountManager : AccountManager { return AppEnvironment.shared.accountManager } - -// private var callService : CallService -// { -// return AppEnvironment.shared.callService -// } - - // MARK: - Call Handlers - -// public func receivedOffer(_ offer: SSKProtoCallMessageOffer, from callerId: String) { -// AssertIsOnMainThread() -// -// let thread = TSContactThread.getOrCreateThread(contactId: callerId) -// self.callService.handleReceivedOffer(thread: thread, callId: offer.id, sessionDescription: offer.sessionDescription) -// } -// -// public func receivedAnswer(_ answer: SSKProtoCallMessageAnswer, from callerId: String) { -// AssertIsOnMainThread() -// -// let thread = TSContactThread.getOrCreateThread(contactId: callerId) -// self.callService.handleReceivedAnswer(thread: thread, callId: answer.id, sessionDescription: answer.sessionDescription) -// } -// -// public func receivedIceUpdate(_ iceUpdate: SSKProtoCallMessageIceUpdate, from callerId: String) { -// AssertIsOnMainThread() -// -// let thread = TSContactThread.getOrCreateThread(contactId: callerId) -// -// // Discrepency between our protobuf's sdpMlineIndex, which is unsigned, -// // while the RTC iOS API requires a signed int. -// let lineIndex = Int32(iceUpdate.sdpMlineIndex) -// -// self.callService.handleRemoteAddedIceCandidate(thread: thread, callId: iceUpdate.id, sdp: iceUpdate.sdp, lineIndex: lineIndex, mid: iceUpdate.sdpMid) -// } -// -// public func receivedHangup(_ hangup: SSKProtoCallMessageHangup, from callerId: String) { -// AssertIsOnMainThread() -// -// let thread = TSContactThread.getOrCreateThread(contactId: callerId) -// self.callService.handleRemoteHangup(thread: thread, callId: hangup.id) -// } -// -// public func receivedBusy(_ busy: SSKProtoCallMessageBusy, from callerId: String) { -// AssertIsOnMainThread() -// -// let thread = TSContactThread.getOrCreateThread(contactId: callerId) -// self.callService.handleRemoteBusy(thread: thread, callId: busy.id) -// } - } diff --git a/Session/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift index 5fb96a3e6..6786fd876 100644 --- a/Session/Utilities/BackgroundPoller.swift +++ b/Session/Utilities/BackgroundPoller.swift @@ -9,7 +9,8 @@ public final class BackgroundPoller : NSObject { @objc(pollWithCompletionHandler:) public static func poll(completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { var promises: [Promise] = [] - promises.append(AppEnvironment.shared.messageFetcherJob.run()) // FIXME: It'd be nicer to just use Poller directly + // TODO TODO TODO +// promises.append(AppEnvironment.shared.messageFetcherJob.run()) // FIXME: It'd be nicer to just use Poller directly closedGroupPoller = ClosedGroupPoller() promises.append(contentsOf: closedGroupPoller.pollOnce()) var openGroups: [String:OpenGroup] = [:] diff --git a/Session/View Controllers/BaseVC.swift b/Session/View Controllers/BaseVC.swift index 9dd73ba23..ed234fead 100644 --- a/Session/View Controllers/BaseVC.swift +++ b/Session/View Controllers/BaseVC.swift @@ -24,7 +24,6 @@ class BaseVC : UIViewController { override func viewDidLoad() { setNeedsStatusBarAppearanceUpdate() - NotificationCenter.default.addObserver(self, selector: #selector(handleUnexpectedDeviceLinkRequestReceivedNotification(_:)), name: .unexpectedDeviceLinkRequestReceived, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleAppModeChangedNotification(_:)), name: .appModeChanged, object: nil) } @@ -71,15 +70,6 @@ class BaseVC : UIViewController { NotificationCenter.default.removeObserver(self) } - @objc private func handleUnexpectedDeviceLinkRequestReceivedNotification(_ notification: Notification) { - guard DeviceLinkingUtilities.shouldShowUnexpectedDeviceLinkRequestReceivedAlert else { return } - DispatchQueue.main.async { - let alert = UIAlertController(title: "Device Link Request Received", message: "Open the device link screen by going to \"Settings\" > \"Devices\" > \"Link a Device\" to link your devices.", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - } - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { // TODO: Post an appModeChanged notification? } diff --git a/Session/View Controllers/DeviceLinkingModal.swift b/Session/View Controllers/DeviceLinkingModal.swift deleted file mode 100644 index bddec1370..000000000 --- a/Session/View Controllers/DeviceLinkingModal.swift +++ /dev/null @@ -1,256 +0,0 @@ -import NVActivityIndicatorView - -@objc(LKDeviceLinkingModal) -final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { - private let mode: Mode - private let delegate: DeviceLinkingModalDelegate? - private var deviceLink: DeviceLink? - private var hasAuthorizedDeviceLink = false - - // MARK: Types - enum Mode : String { case master, slave } - - // MARK: Components - private lazy var spinner = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: Colors.text, padding: nil) - - private lazy var qrCodeImageViewContainer: UIView = { - let result = UIView() - result.addSubview(qrCodeImageView) - qrCodeImageView.pin(.top, to: .top, of: result) - qrCodeImageView.pin(.bottom, to: .bottom, of: result) - qrCodeImageView.center(.horizontal, in: result) - return result - }() - - private lazy var qrCodeImageView: UIImageView = { - let result = UIImageView() - result.contentMode = .scaleAspectFit - let size: CGFloat = 128 - result.set(.width, to: size) - result.set(.height, to: size) - return result - }() - - private lazy var titleLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = .boldSystemFont(ofSize: Values.mediumFontSize) - result.numberOfLines = 0 - result.lineBreakMode = .byWordWrapping - result.textAlignment = .center - return result - }() - - private lazy var subtitleLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = .systemFont(ofSize: Values.smallFontSize) - result.numberOfLines = 0 - result.lineBreakMode = .byWordWrapping - result.textAlignment = .center - return result - }() - - private lazy var mnemonicLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = .systemFont(ofSize: Values.smallFontSize) - result.numberOfLines = 0 - result.lineBreakMode = .byWordWrapping - result.textAlignment = .center - return result - }() - - private lazy var buttonStackView: UIStackView = { - let result = UIStackView(arrangedSubviews: [ cancelButton, authorizeButton ]) - result.axis = .horizontal - result.spacing = Values.mediumSpacing - result.distribution = .fillEqually - return result - }() - - private lazy var authorizeButton: UIButton = { - let result = UIButton() - result.set(.height, to: Values.mediumButtonHeight) - result.layer.cornerRadius = Values.modalButtonCornerRadius - result.backgroundColor = Colors.accent - result.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize) - result.setTitleColor(Colors.text, for: UIControl.State.normal) - result.setTitle(NSLocalizedString("modal_link_device_master_mode_authorize_button_title", comment: ""), for: UIControl.State.normal) - return result - }() - - private lazy var mainStackView: UIStackView = { - let result = UIStackView(arrangedSubviews: [ titleLabel, subtitleLabel, mnemonicLabel, buttonStackView ]) - result.spacing = Values.largeSpacing - result.axis = .vertical - return result - }() - - // MARK: Lifecycle - init(mode: Mode, delegate: DeviceLinkingModalDelegate?) { - self.mode = mode - if mode == .slave { - guard delegate != nil else { preconditionFailure("Missing delegate for device linking modal in slave mode.") } - } - self.delegate = delegate - super.init(nibName: nil, bundle: nil) - } - - @objc(initWithMode:delegate:) - convenience init(modeAsString: String, delegate: DeviceLinkingModalDelegate?) { - guard let mode = Mode(rawValue: modeAsString) else { preconditionFailure("Invalid mode: \(modeAsString).") } - self.init(mode: mode, delegate: delegate) - } - - required init?(coder: NSCoder) { preconditionFailure() } - override init(nibName: String?, bundle: Bundle?) { preconditionFailure() } - - override func viewDidLoad() { - super.viewDidLoad() - switch mode { - case .master: let _ = DeviceLinkingSession.startListeningForLinkingRequests(with: self) - case .slave: let _ = DeviceLinkingSession.startListeningForLinkingAuthorization(with: self) - } - } - - override func populateContentView() { - switch mode { - case .master: mainStackView.insertArrangedSubview(qrCodeImageViewContainer, at: 0) - case .slave: mainStackView.insertArrangedSubview(spinner, at: 0) - } - contentView.addSubview(mainStackView) - switch mode { - case .master: - let hexEncodedPublicKey = getUserHexEncodedPublicKey() - qrCodeImageView.image = QRCode.generate(for: hexEncodedPublicKey, hasBackground: true) - case .slave: - spinner.set(.height, to: 64) - spinner.startAnimating() - } - titleLabel.text = { - switch mode { - case .master: return NSLocalizedString("modal_link_device_master_mode_title_1", comment: "") - case .slave: return NSLocalizedString("modal_link_device_slave_mode_title_1", comment: "") - } - }() - subtitleLabel.text = { - switch mode { - case .master: return NSLocalizedString("modal_link_device_master_mode_explanation_1", comment: "") - case .slave: return NSLocalizedString("modal_link_device_slave_mode_explanation_1", comment: "") - } - }() - mnemonicLabel.isHidden = (mode == .master) - if mode == .slave { - let hexEncodedPublicKey = getUserHexEncodedPublicKey().removing05PrefixIfNeeded() - mnemonicLabel.text = Mnemonic.hash(hexEncodedString: hexEncodedPublicKey) - } - authorizeButton.addTarget(self, action: #selector(authorizeDeviceLink), for: UIControl.Event.touchUpInside) - authorizeButton.isHidden = true - mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing) - mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) - contentView.pin(.trailing, to: .trailing, of: mainStackView, withInset: Values.largeSpacing) - contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.largeSpacing) - } - - // MARK: Device Linking - func requestUserAuthorization(for deviceLink: DeviceLink) { - self.deviceLink = deviceLink - qrCodeImageViewContainer.isHidden = true - titleLabel.text = NSLocalizedString("modal_link_device_master_mode_title_2", comment: "") - subtitleLabel.text = NSLocalizedString("modal_link_device_master_mode_explanation_2", comment: "") - let hexEncodedPublicKey = deviceLink.slave.publicKey.removing05PrefixIfNeeded() - mnemonicLabel.text = Mnemonic.hash(hexEncodedString: hexEncodedPublicKey) - mnemonicLabel.isHidden = false - authorizeButton.isHidden = false - } - - @objc private func authorizeDeviceLink() { - guard !hasAuthorizedDeviceLink else { return } - hasAuthorizedDeviceLink = true - mainStackView.removeArrangedSubview(qrCodeImageViewContainer) - mainStackView.insertArrangedSubview(spinner, at: 0) - spinner.set(.height, to: 64) - spinner.startAnimating() - titleLabel.text = NSLocalizedString("modal_link_device_master_mode_title_3", comment: "") - subtitleLabel.text = NSLocalizedString("modal_link_device_master_mode_explanation_3", comment: "") - mnemonicLabel.isHidden = true - buttonStackView.isHidden = true - let deviceLink = self.deviceLink! - DeviceLinkingSession.current!.markLinkingRequestAsProcessed() - DeviceLinkingSession.current!.stopListeningForLinkingRequests() - let linkingAuthorizationMessage = DeviceLinkingUtilities.getLinkingAuthorizationMessage(for: deviceLink) - let master = DeviceLink.Device(publicKey: deviceLink.master.publicKey, signature: linkingAuthorizationMessage.masterSignature) - let signedDeviceLink = DeviceLink(between: master, and: deviceLink.slave) - FileServerAPI.addDeviceLink(signedDeviceLink).done(on: DispatchQueue.main) { [weak self] in - SSKEnvironment.shared.messageSender.send(linkingAuthorizationMessage, success: { - let slavePublicKey = deviceLink.slave.publicKey - Storage.writeSync { transaction in - let thread = TSContactThread.getOrCreateThread(withContactId: slavePublicKey, transaction: transaction) - thread.save(with: transaction) - } - let _ = SSKEnvironment.shared.syncManager.syncAllGroups().ensure { - // Closed groups first because we prefer the session request mechanism - // to the AFR mechanism - let _ = SSKEnvironment.shared.syncManager.syncAllContacts() - } - let _ = SSKEnvironment.shared.syncManager.syncAllOpenGroups() - DispatchQueue.main.async { - self?.dismiss(animated: true, completion: nil) - self?.delegate?.handleDeviceLinkAuthorized(signedDeviceLink) - } - }, failure: { error in - print("[Loki] Failed to send device link authorization message.") - let _ = FileServerAPI.removeDeviceLink(signedDeviceLink) // Attempt to roll back - DispatchQueue.main.async { - self?.close() - let alert = UIAlertController(title: "Device Linking Failed", message: "Please check your internet connection and try again", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) - self?.presentingViewController?.present(alert, animated: true, completion: nil) - } - }) - }.catch { [weak self] error in - print("[Loki] Failed to add device link due to error: \(error).") - DispatchQueue.main.async { - self?.close() // TODO: Show a message to the user - let alert = UIAlertController(title: "Device Linking Failed", message: "Please check your internet connection and try again", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) - self?.presentingViewController?.present(alert, animated: true, completion: nil) - } - } - } - - func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) { - let session = DeviceLinkingSession.current! - session.stopListeningForLinkingAuthorization() - spinner.stopAnimating() - spinner.isHidden = true - titleLabel.text = NSLocalizedString("modal_link_device_slave_mode_title_2", comment: "") - subtitleLabel.text = NSLocalizedString("modal_link_device_slave_mode_explanation_2", comment: "") - mnemonicLabel.isHidden = true - buttonStackView.isHidden = true - FileServerAPI.addDeviceLink(deviceLink).catch { error in - print("[Loki] Failed to add device link due to error: \(error).") - } - Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { _ in - self.dismiss(animated: true) { - self.delegate?.handleDeviceLinkAuthorized(deviceLink) - } - } - } - - @objc override func close() { - guard let session = DeviceLinkingSession.current else { - return print("[Loki] Device linking session missing.") // Should never occur - } - session.stopListeningForLinkingRequests() - session.markLinkingRequestAsProcessed() // Only relevant in master mode - delegate?.handleDeviceLinkingModalDismissed() // Only relevant in slave mode - if let deviceLink = deviceLink { - Storage.writeSync { transaction in - OWSPrimaryStorage.shared().removePreKeyBundle(forContact: deviceLink.slave.publicKey, transaction: transaction) - } - } - dismiss(animated: true, completion: nil) - } -} diff --git a/Session/View Controllers/DeviceLinkingModalDelegate.swift b/Session/View Controllers/DeviceLinkingModalDelegate.swift deleted file mode 100644 index f8586401f..000000000 --- a/Session/View Controllers/DeviceLinkingModalDelegate.swift +++ /dev/null @@ -1,12 +0,0 @@ - -@objc protocol DeviceLinkingModalDelegate { - - func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) - func handleDeviceLinkingModalDismissed() -} - -extension DeviceLinkingModalDelegate { - - func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) { /* Do nothing */ } - func handleDeviceLinkingModalDismissed() { /* Do nothing */ } -} diff --git a/Session/View Controllers/DeviceLinksVC.swift b/Session/View Controllers/DeviceLinksVC.swift deleted file mode 100644 index 8eccf4017..000000000 --- a/Session/View Controllers/DeviceLinksVC.swift +++ /dev/null @@ -1,234 +0,0 @@ - -// MARK: - Device Links View Controller - -@objc(LKDeviceLinksVC) -final class DeviceLinksVC : BaseVC, UITableViewDataSource, UITableViewDelegate, DeviceLinkingModalDelegate, DeviceNameModalDelegate { - private var deviceLinks: [DeviceLink] = [] { didSet { updateUI() } } - - // MARK: Components - private lazy var tableView: UITableView = { - let result = UITableView() - result.dataSource = self - result.delegate = self - result.register(Cell.self, forCellReuseIdentifier: "Cell") - result.separatorStyle = .none - result.backgroundColor = .clear - return result - }() - - private lazy var callToActionView : UIStackView = { - let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text - explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) - explanationLabel.numberOfLines = 0 - explanationLabel.lineBreakMode = .byWordWrapping - explanationLabel.textAlignment = .center - explanationLabel.text = NSLocalizedString("vc_linked_devices_empty_state_message", comment: "") - let linkNewDeviceButton = Button(style: .prominentOutline, size: .large) - linkNewDeviceButton.setTitle(NSLocalizedString("vc_linked_devices_empty_state_button_title", comment: ""), for: UIControl.State.normal) - linkNewDeviceButton.addTarget(self, action: #selector(linkNewDevice), for: UIControl.Event.touchUpInside) - linkNewDeviceButton.set(.width, to: 196) - let result = UIStackView(arrangedSubviews: [ explanationLabel, linkNewDeviceButton ]) - result.axis = .vertical - result.spacing = Values.mediumSpacing - result.alignment = .center - return result - }() - - // MARK: Lifecycle - override func viewDidLoad() { - super.viewDidLoad() - setUpGradientBackground() - setUpNavBarStyle() - setNavBarTitle(NSLocalizedString("vc_linked_devices_title", comment: "")) - // Set up link new device button - let linkNewDeviceButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(linkNewDevice)) - linkNewDeviceButton.tintColor = Colors.text - navigationItem.rightBarButtonItem = linkNewDeviceButton - // Set up constraints - view.addSubview(tableView) - tableView.pin(to: view) - view.addSubview(callToActionView) - callToActionView.center(.horizontal, in: view) - let verticalCenteringConstraint = callToActionView.center(.vertical, in: view) - verticalCenteringConstraint.constant = -16 // Makes things appear centered visually - // Perform initial update - updateDeviceLinks() - } - - // MARK: Data - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return deviceLinks.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! Cell - let selectedBackgroundView = UIView() - selectedBackgroundView.backgroundColor = Colors.cellSelected - cell.selectedBackgroundView = selectedBackgroundView - let device = deviceLinks[indexPath.row].other - cell.device = device - return cell - } - - // MARK: Updating - private func updateDeviceLinks() { - let storage = OWSPrimaryStorage.shared() - let userHexEncodedPublicKey = getUserHexEncodedPublicKey() - var deviceLinks: [DeviceLink] = [] - storage.dbReadConnection.read { transaction in - deviceLinks = storage.getDeviceLinks(for: userHexEncodedPublicKey, in: transaction).sorted { lhs, rhs in - return lhs.other.publicKey > rhs.other.publicKey - } - } - self.deviceLinks = deviceLinks - } - - private func updateUI() { - tableView.reloadData() - UIView.animate(withDuration: 0.25) { - self.callToActionView.isHidden = !self.deviceLinks.isEmpty - } - } - - func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) { - // The modal already dismisses itself - updateDeviceLinks() - } - - func handleDeviceLinkingModalDismissed() { - // Do nothing - } - - // MARK: Interaction - @objc private func linkNewDevice() { - if deviceLinks.isEmpty { - let deviceLinkingModal = DeviceLinkingModal(mode: .master, delegate: self) - deviceLinkingModal.modalPresentationStyle = .overFullScreen - deviceLinkingModal.modalTransitionStyle = .crossDissolve - present(deviceLinkingModal, animated: true, completion: nil) - } else { - let alert = UIAlertController(title: NSLocalizedString("vc_linked_devices_multi_device_limit_reached_modal_title", comment: ""), message: NSLocalizedString("It's currently not allowed to link more than one device.", comment: ""), preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) - present(alert, animated: true, completion: nil) - } - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - defer { tableView.deselectRow(at: indexPath, animated: true) } - let deviceLink = deviceLinks[indexPath.row] - let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - sheet.addAction(UIAlertAction(title: NSLocalizedString("vc_device_list_bottom_sheet_change_name_button_title", comment: ""), style: .default) { [weak self] _ in - guard let self = self else { return } - let deviceNameModal = DeviceNameModal() - deviceNameModal.device = deviceLink.other - deviceNameModal.delegate = self - deviceNameModal.modalPresentationStyle = .overFullScreen - deviceNameModal.modalTransitionStyle = .crossDissolve - self.present(deviceNameModal, animated: true, completion: nil) - }) - sheet.addAction(UIAlertAction(title: NSLocalizedString("vc_device_list_bottom_sheet_unlink_device_button_title", comment: ""), style: .destructive) { [weak self] _ in - self?.removeDeviceLink(deviceLink) - }) - sheet.addAction(UIAlertAction(title: NSLocalizedString("cancel", comment: ""), style: .cancel) { _ in }) - present(sheet, animated: true, completion: nil) - } - - @objc func handleDeviceNameChanged(to name: String, for device: DeviceLink.Device) { - dismiss(animated: true, completion: nil) - updateUI() - } - - private func removeDeviceLink(_ deviceLink: DeviceLink) { - FileServerAPI.removeDeviceLink(deviceLink).done { [weak self] in - let linkedDevicePublicKey = deviceLink.other.publicKey - guard let thread = TSContactThread.fetch(uniqueId: TSContactThread.threadId(fromContactId: linkedDevicePublicKey)) else { return } - let unlinkDeviceMessage = UnlinkDeviceMessage(thread: thread) - SSKEnvironment.shared.messageSender.send(unlinkDeviceMessage, success: { - let storage = OWSPrimaryStorage.shared() - Storage.writeSync { transaction in - storage.removePreKeyBundle(forContact: linkedDevicePublicKey, transaction: transaction) - storage.deleteAllSessions(forContact: linkedDevicePublicKey, protocolContext: transaction) - for groupPublicKey in Storage.getUserClosedGroupPublicKeys() { - // TODO: Possibly re-implement in the future - // ClosedGroupsProtocol.removeMembers([ linkedDevicePublicKey ], from: groupPublicKey, using: transaction) - } - } - }, failure: { _ in - print("[Loki] Failed to send unlink device message.") - let storage = OWSPrimaryStorage.shared() - Storage.writeSync { transaction in - storage.removePreKeyBundle(forContact: linkedDevicePublicKey, transaction: transaction) - storage.deleteAllSessions(forContact: linkedDevicePublicKey, protocolContext: transaction) - for groupPublicKey in Storage.getUserClosedGroupPublicKeys() { - // TODO: Possibly re-implement in the future - // ClosedGroupsProtocol.removeMembers([ linkedDevicePublicKey ], from: groupPublicKey, using: transaction) - } - } - }) - self?.updateDeviceLinks() - }.catch { [weak self] _ in - let alert = UIAlertController(title: "Couldn't Unlink Device", message: "Please check your internet connection and try again", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), accessibilityIdentifier: nil, style: .default, handler: nil)) - self?.present(alert, animated: true, completion: nil) - } - } -} - -// MARK: - Cell - -private extension DeviceLinksVC { - - final class Cell : UITableViewCell { - var device: DeviceLink.Device! { didSet { update() } } - - // MARK: Components - private lazy var titleLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = .boldSystemFont(ofSize: Values.mediumFontSize) - result.lineBreakMode = .byTruncatingTail - return result - }() - - private lazy var subtitleLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = .systemFont(ofSize: Values.smallFontSize) - result.lineBreakMode = .byTruncatingTail - return result - }() - - // MARK: Initialization - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setUpViewHierarchy() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setUpViewHierarchy() - } - - private func setUpViewHierarchy() { - backgroundColor = Colors.cellBackground - let stackView = UIStackView(arrangedSubviews: [ titleLabel, subtitleLabel ]) - stackView.axis = .vertical - stackView.distribution = .equalCentering - stackView.spacing = Values.verySmallSpacing - stackView.set(.height, to: 44) - contentView.addSubview(stackView) - stackView.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing) - stackView.pin(.top, to: .top, of: contentView, withInset: 12) - contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.largeSpacing) - contentView.pin(.bottom, to: .bottom, of: stackView, withInset: 12) - stackView.set(.width, to: UIScreen.main.bounds.width - 2 * Values.largeSpacing) - } - - // MARK: Updating - private func update() { - titleLabel.text = device.displayName - subtitleLabel.text = Mnemonic.hash(hexEncodedString: device.publicKey.removing05PrefixIfNeeded()) - } - } -} diff --git a/Session/View Controllers/DeviceNameModal.swift b/Session/View Controllers/DeviceNameModal.swift deleted file mode 100644 index 76b3f808b..000000000 --- a/Session/View Controllers/DeviceNameModal.swift +++ /dev/null @@ -1,103 +0,0 @@ - -@objc(LKDeviceNameModal) -final class DeviceNameModal : Modal { - @objc public var device: DeviceLink.Device! - @objc public var delegate: DeviceNameModalDelegate? - - // MARK: Components - private lazy var nameTextField: UITextField = { - let result = UITextField() - result.textColor = Colors.text - result.font = .systemFont(ofSize: Values.mediumFontSize) - result.textAlignment = .center - let placeholder = NSMutableAttributedString(string: NSLocalizedString("modal_edit_device_name_text_field_hint", comment: "")) - placeholder.addAttribute(.foregroundColor, value: Colors.text.withAlphaComponent(Values.unimportantElementOpacity), range: NSRange(location: 0, length: placeholder.length)) - result.attributedPlaceholder = placeholder - result.tintColor = Colors.accent - result.keyboardAppearance = .dark - return result - }() - - // MARK: Lifecycle - override func viewDidLoad() { - super.viewDidLoad() - let notificationCenter = NotificationCenter.default - notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillChangeFrameNotification(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) - notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillHideNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) - } - - override func populateContentView() { - // Set up title label - let titleLabel = UILabel() - titleLabel.textColor = Colors.text - titleLabel.font = .boldSystemFont(ofSize: Values.mediumFontSize) - titleLabel.text = "Change Device Name" - titleLabel.numberOfLines = 0 - titleLabel.lineBreakMode = .byWordWrapping - titleLabel.textAlignment = .center - // Set up explanation label - let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text - explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) - explanationLabel.text = "Enter the new display name for your device below" - explanationLabel.numberOfLines = 0 - explanationLabel.textAlignment = .center - explanationLabel.lineBreakMode = .byWordWrapping - // Set up OK button - let okButton = UIButton() - okButton.set(.height, to: Values.mediumButtonHeight) - okButton.layer.cornerRadius = Values.modalButtonCornerRadius - okButton.backgroundColor = Colors.accent - okButton.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize) - okButton.setTitleColor(Colors.text, for: UIControl.State.normal) - okButton.setTitle(NSLocalizedString("OK", comment: ""), for: UIControl.State.normal) - okButton.addTarget(self, action: #selector(changeName), for: UIControl.Event.touchUpInside) - // Set up button stack view - let buttonStackView = UIStackView(arrangedSubviews: [ cancelButton, okButton ]) - buttonStackView.axis = .horizontal - buttonStackView.spacing = Values.mediumSpacing - buttonStackView.distribution = .fillEqually - // Set up main stack view - let stackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel, nameTextField, buttonStackView ]) - stackView.axis = .vertical - stackView.spacing = Values.largeSpacing - contentView.addSubview(stackView) - stackView.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing) - stackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) - contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.largeSpacing) - contentView.pin(.bottom, to: .bottom, of: stackView, withInset: Values.largeSpacing) - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - // MARK: Updating - @objc private func handleKeyboardWillChangeFrameNotification(_ notification: Notification) { - guard let newHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height else { return } - verticalCenteringConstraint.constant = -(newHeight / 2) - UIView.animate(withDuration: 0.25) { - self.view.layoutIfNeeded() - } - } - - @objc private func handleKeyboardWillHideNotification(_ notification: Notification) { - verticalCenteringConstraint.constant = 0 - UIView.animate(withDuration: 0.25) { - self.view.layoutIfNeeded() - } - } - - // MARK: Interaction - @objc private func changeName() { - let name = nameTextField.text!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - if !name.isEmpty { - UserDefaults.standard[.slaveDeviceName(device.publicKey)] = name - delegate?.handleDeviceNameChanged(to: name, for: device) - } else { - let alert = UIAlertController(title: "Error", message: "Please pick a name", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), accessibilityIdentifier: nil, style: .default, handler: nil)) - present(alert, animated: true, completion: nil) - } - } -} diff --git a/Session/View Controllers/DeviceNameModalDelegate.swift b/Session/View Controllers/DeviceNameModalDelegate.swift deleted file mode 100644 index ad67f8237..000000000 --- a/Session/View Controllers/DeviceNameModalDelegate.swift +++ /dev/null @@ -1,5 +0,0 @@ - -@objc protocol DeviceNameModalDelegate { - - func handleDeviceNameChanged(to name: String, for device: DeviceLink.Device) -} diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index 37cd7d0bc..faa2f36e2 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -96,8 +96,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol // Set up seed reminder view if needed let userDefaults = UserDefaults.standard let hasViewedSeed = userDefaults[.hasViewedSeed] - let isMasterDevice = userDefaults.isMasterDevice - if !hasViewedSeed && isMasterDevice { + if !hasViewedSeed { view.addSubview(seedReminderView) seedReminderView.pin(.leading, to: .leading, of: view) seedReminderView.pin(.top, to: .top, of: view) @@ -108,7 +107,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol tableView.delegate = self view.addSubview(tableView) tableView.pin(.leading, to: .leading, of: view) - if !hasViewedSeed && isMasterDevice { + if !hasViewedSeed { tableViewTopConstraint = tableView.pin(.top, to: .bottom, of: seedReminderView) } else { tableViewTopConstraint = tableView.pin(.top, to: .top, of: view, withInset: Values.smallSpacing) @@ -283,13 +282,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol let profilePictureSize = Values.verySmallProfilePictureSize let profilePictureView = ProfilePictureView() profilePictureView.size = profilePictureSize - let userHexEncodedPublicKey: String - if let masterHexEncodedPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] { - userHexEncodedPublicKey = masterHexEncodedPublicKey - } else { - userHexEncodedPublicKey = getUserHexEncodedPublicKey() - } - profilePictureView.hexEncodedPublicKey = userHexEncodedPublicKey + profilePictureView.hexEncodedPublicKey = getUserHexEncodedPublicKey() profilePictureView.update() profilePictureView.set(.width, to: profilePictureSize) profilePictureView.set(.height, to: profilePictureSize) @@ -413,10 +406,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol } delete.backgroundColor = Colors.destructive if thread is TSContactThread { - var publicKey: String! - Storage.read { transaction in - publicKey = OWSPrimaryStorage.shared().getMasterHexEncodedPublicKey(for: thread.contactIdentifier()!, in: transaction) ?? thread.contactIdentifier()! - } + let publicKey = thread.contactIdentifier()! let blockingManager = SSKEnvironment.shared.blockingManager let isBlocked = blockingManager.isRecipientIdBlocked(publicKey) let block = UITableViewRowAction(style: .normal, title: NSLocalizedString("BLOCK_LIST_BLOCK_BUTTON", comment: "")) { _, _ in diff --git a/Session/View Controllers/JoinPublicChatVC.swift b/Session/View Controllers/JoinPublicChatVC.swift index a816986d8..6697054f8 100644 --- a/Session/View Controllers/JoinPublicChatVC.swift +++ b/Session/View Controllers/JoinPublicChatVC.swift @@ -133,7 +133,7 @@ final class JoinPublicChatVC : BaseVC, UIPageViewControllerDataSource, UIPageVie isJoining = true let channelID: UInt64 = 1 let urlAsString = url.absoluteString - let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey() + let userPublicKey = getUserHexEncodedPublicKey() let profileManager = OWSProfileManager.shared() let displayName = profileManager.profileNameForRecipient(withID: userPublicKey) let profilePictureURL = profileManager.profilePictureURL() @@ -148,8 +148,6 @@ final class JoinPublicChatVC : BaseVC, UIPageViewControllerDataSource, UIPageVie let _ = OpenGroupAPI.setDisplayName(to: displayName, on: urlAsString) let _ = OpenGroupAPI.setProfilePictureURL(to: profilePictureURL, using: profileKey, on: urlAsString) let _ = OpenGroupAPI.join(channelID, on: urlAsString) - let syncManager = SSKEnvironment.shared.syncManager - let _ = syncManager.syncAllOpenGroups() self?.presentingViewController!.dismiss(animated: true, completion: nil) } .catch(on: DispatchQueue.main) { [weak self] error in diff --git a/Session/View Controllers/LandingVC.swift b/Session/View Controllers/LandingVC.swift index f7f2a52c7..5bb68763d 100644 --- a/Session/View Controllers/LandingVC.swift +++ b/Session/View Controllers/LandingVC.swift @@ -1,5 +1,5 @@ -final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate { +final class LandingVC : BaseVC { private var fakeChatViewContentOffset: CGPoint! // MARK: Components @@ -25,14 +25,6 @@ final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate return result }() - private lazy var linkButton: Button = { - let result = Button(style: .regularBorderless, size: .small) - result.setTitle(NSLocalizedString("vc_landing_link_button_title", comment: ""), for: UIControl.State.normal) - result.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize) - result.addTarget(self, action: #selector(linkDevice), for: UIControl.Event.touchUpInside) - return result - }() - // MARK: Lifecycle override func viewDidLoad() { super.viewDidLoad() @@ -59,11 +51,6 @@ final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate // Set up link button container let linkButtonContainer = UIView() linkButtonContainer.set(.height, to: Values.onboardingButtonBottomOffset) -// linkButtonContainer.addSubview(linkButton) -// linkButton.pin(.leading, to: .leading, of: linkButtonContainer, withInset: Values.massiveSpacing) -// linkButton.pin(.top, to: .top, of: linkButtonContainer) -// linkButtonContainer.pin(.trailing, to: .trailing, of: linkButton, withInset: Values.massiveSpacing) -// linkButtonContainer.pin(.bottom, to: .bottom, of: linkButton, withInset: isIPhone5OrSmaller ? 6 : 10) // Set up button stack view let buttonStackView = UIStackView(arrangedSubviews: [ registerButton, restoreButton ]) buttonStackView.axis = .vertical @@ -83,13 +70,6 @@ final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate view.addSubview(mainStackView) mainStackView.pin(to: view) topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true - // Show device unlinked alert if needed - if UserDefaults.standard[.wasUnlinked] { - let alert = UIAlertController(title: "Device Unlinked", message: NSLocalizedString("vc_landing_device_unlinked_modal_title", comment: ""), preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), accessibilityIdentifier: nil, style: .default, handler: nil)) - present(alert, animated: true, completion: nil) - UserDefaults.removeAll() - } } override func viewDidDisappear(_ animated: Bool) { @@ -118,58 +98,9 @@ final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate navigationController!.pushViewController(restoreVC, animated: true) } - @objc private func linkDevice() { - let linkDeviceVC = LinkDeviceVC() - linkDeviceVC.delegate = self - let navigationController = OWSNavigationController(rootViewController: linkDeviceVC) - present(navigationController, animated: true, completion: nil) - } - - // MARK: Device Linking - func requestDeviceLink(with hexEncodedPublicKey: String) { - guard ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) else { - let alert = UIAlertController(title: NSLocalizedString("invalid_session_id", comment: ""), message: "Please make sure the Session ID you entered is correct and try again.", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), accessibilityIdentifier: nil, style: .default, handler: nil)) - return present(alert, animated: true, completion: nil) - } - let seed = Randomness.generateRandomBytes(16) - preconditionFailure("This code path shouldn't be invoked.") - let keyPair = Curve25519.generateKeyPair() - let identityManager = OWSIdentityManager.shared() - let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection - databaseConnection.setObject(seed.toHexString(), forKey: "LKLokiSeed", inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) - databaseConnection.setObject(keyPair, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) - TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair.hexEncodedPublicKey - TSAccountManager.sharedInstance().didRegister() - let appDelegate = UIApplication.shared.delegate as! AppDelegate - appDelegate.startPollerIfNeeded() - let deviceLinkingModal = DeviceLinkingModal(mode: .slave, delegate: self) - deviceLinkingModal.modalPresentationStyle = .overFullScreen - deviceLinkingModal.modalTransitionStyle = .crossDissolve - self.present(deviceLinkingModal, animated: true, completion: nil) - let linkingRequestMessage = DeviceLinkingUtilities.getLinkingRequestMessage(for: hexEncodedPublicKey) - ThreadUtil.enqueue(linkingRequestMessage) - } - - func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) { - UserDefaults.standard[.masterHexEncodedPublicKey] = deviceLink.master.publicKey - fakeChatViewContentOffset = fakeChatView.contentOffset - DispatchQueue.main.async { - self.fakeChatView.contentOffset = self.fakeChatViewContentOffset - } - let homeVC = HomeVC() - navigationController!.setViewControllers([ homeVC ], animated: true) - } - - func handleDeviceLinkingModalDismissed() { - let appDelegate = UIApplication.shared.delegate as! AppDelegate - appDelegate.stopPoller() - TSAccountManager.sharedInstance().resetForReregistration() - } - // MARK: Convenience private func setUserInteractionEnabled(_ isEnabled: Bool) { - [ registerButton, restoreButton, linkButton ].forEach { + [ registerButton, restoreButton ].forEach { $0.isUserInteractionEnabled = isEnabled } } diff --git a/Session/View Controllers/NewClosedGroupVC.swift b/Session/View Controllers/NewClosedGroupVC.swift index b550b1edd..027b85f06 100644 --- a/Session/View Controllers/NewClosedGroupVC.swift +++ b/Session/View Controllers/NewClosedGroupVC.swift @@ -149,14 +149,6 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat } @objc private func createClosedGroup() { - if ClosedGroupsProtocol.isSharedSenderKeysEnabled { - createSSKClosedGroup() - } else { - createLegacyClosedGroup() - } - } - - private func createSSKClosedGroup() { func showError(title: String, message: String = "") { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) @@ -176,16 +168,15 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat } let selectedContacts = self.selectedContacts ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in - FileServerAPI.getDeviceLinks(associatedWith: selectedContacts).then2 { _ -> Promise in - var promise: Promise! - Storage.writeSync { transaction in - promise = ClosedGroupsProtocol.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) - } - return promise - }.done(on: DispatchQueue.main) { thread in + var promise: Promise! + Storage.writeSync { transaction in + promise = ClosedGroupsProtocol.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) + } + let _ = promise.done(on: DispatchQueue.main) { thread in self?.presentingViewController?.dismiss(animated: true, completion: nil) SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false) - }.catch(on: DispatchQueue.main) { _ in + } + promise.catch(on: DispatchQueue.main) { _ in self?.dismiss(animated: true, completion: nil) // Dismiss the loader let title = "Couldn't Create Group" let message = "Please check your internet connection and try again." @@ -195,57 +186,6 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat } } } - - private func createLegacyClosedGroup() { - func showError(title: String, message: String = "") { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) - presentAlert(alert) - } - guard let name = nameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), name.count > 0 else { - return showError(title: NSLocalizedString("vc_create_closed_group_group_name_missing_error", comment: "")) - } - guard name.count < 64 else { - return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) - } - guard selectedContacts.count >= 1 else { - return showError(title: "Please pick at least 1 group member") - } - guard selectedContacts.count < 10 else { // Minus one because we're going to include self later - return showError(title: NSLocalizedString("vc_create_closed_group_too_many_group_members_error", comment: "")) - } - let userPublicKey = getUserHexEncodedPublicKey() - let storage = OWSPrimaryStorage.shared() - var masterPublicKey = "" - storage.dbReadConnection.read { transaction in - masterPublicKey = storage.getMasterHexEncodedPublicKey(for: userPublicKey, in: transaction) ?? userPublicKey - } - let members = selectedContacts + [ masterPublicKey ] - let admins = [ masterPublicKey ] - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(Randomness.generateRandomBytes(kGroupIdLength).toHexString()) - let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) - let thread = TSGroupThread.getOrCreateThread(with: group) - OWSProfileManager.shared().addThread(toProfileWhitelist: thread) - ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] modalActivityIndicator in - let message = TSOutgoingMessage(in: thread, groupMetaMessage: .new, expiresInSeconds: 0) - message.update(withCustomMessage: "Closed group created") - DispatchQueue.main.async { - SSKEnvironment.shared.messageSender.send(message, success: { - DispatchQueue.main.async { - self?.presentingViewController?.dismiss(animated: true, completion: nil) - SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false) - } - }, failure: { error in - let message = TSErrorMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, failedMessageType: .groupCreationFailed) - message.save() - DispatchQueue.main.async { - self?.presentingViewController?.dismiss(animated: true, completion: nil) - SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false) - } - }) - } - } - } @objc private func createNewPrivateChat() { presentingViewController?.dismiss(animated: true, completion: nil) diff --git a/Session/View Controllers/NewPrivateChatVC.swift b/Session/View Controllers/NewPrivateChatVC.swift index 672d1c7da..9e0c46beb 100644 --- a/Session/View Controllers/NewPrivateChatVC.swift +++ b/Session/View Controllers/NewPrivateChatVC.swift @@ -147,14 +147,6 @@ final class NewPrivateChatVC : BaseVC, UIPageViewControllerDataSource, UIPageVie private final class EnterPublicKeyVC : UIViewController { weak var newPrivateChatVC: NewPrivateChatVC! - private lazy var userPublicKey: String = { - if let masterHexEncodedPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] { - return masterHexEncodedPublicKey - } else { - return getUserHexEncodedPublicKey() - } - }() - // MARK: Components private let publicKeyTextView = TextView(placeholder: NSLocalizedString("vc_enter_public_key_text_field_hint", comment: "")) @@ -186,7 +178,7 @@ private final class EnterPublicKeyVC : UIViewController { userPublicKeyLabel.numberOfLines = 0 userPublicKeyLabel.textAlignment = .center userPublicKeyLabel.lineBreakMode = .byCharWrapping - userPublicKeyLabel.text = userPublicKey + userPublicKeyLabel.text = getUserHexEncodedPublicKey() // Set up share button let shareButton = Button(style: .unimportant, size: .medium) shareButton.setTitle(NSLocalizedString("share", comment: ""), for: UIControl.State.normal) @@ -239,7 +231,7 @@ private final class EnterPublicKeyVC : UIViewController { // MARK: Interaction @objc private func copyPublicKey() { - UIPasteboard.general.string = userPublicKey + UIPasteboard.general.string = getUserHexEncodedPublicKey() copyButton.isUserInteractionEnabled = false UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { self.copyButton.setTitle("Copied", for: UIControl.State.normal) @@ -248,7 +240,7 @@ private final class EnterPublicKeyVC : UIViewController { } @objc private func sharePublicKey() { - let shareVC = UIActivityViewController(activityItems: [ userPublicKey ], applicationActivities: nil) + let shareVC = UIActivityViewController(activityItems: [ getUserHexEncodedPublicKey() ], applicationActivities: nil) newPrivateChatVC.navigationController!.present(shareVC, animated: true, completion: nil) } diff --git a/Session/View Controllers/QRCodeVC.swift b/Session/View Controllers/QRCodeVC.swift index 6f347595a..3a24506bb 100644 --- a/Session/View Controllers/QRCodeVC.swift +++ b/Session/View Controllers/QRCodeVC.swift @@ -137,14 +137,6 @@ private final class ViewMyQRCodeVC : UIViewController { weak var qrCodeVC: QRCodeVC! private var bottomConstraint: NSLayoutConstraint! - private lazy var userHexEncodedPublicKey: String = { - if let masterHexEncodedPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] { - return masterHexEncodedPublicKey - } else { - return getUserHexEncodedPublicKey() - } - }() - // MARK: Lifecycle override func viewDidLoad() { // Remove background color @@ -160,7 +152,7 @@ private final class ViewMyQRCodeVC : UIViewController { titleLabel.set(.height, to: isIPhone5OrSmaller ? CGFloat(40) : Values.massiveFontSize) // Set up QR code image view let qrCodeImageView = UIImageView() - let qrCode = QRCode.generate(for: userHexEncodedPublicKey, hasBackground: true) + let qrCode = QRCode.generate(for: getUserHexEncodedPublicKey(), hasBackground: true) qrCodeImageView.image = qrCode qrCodeImageView.contentMode = .scaleAspectFit qrCodeImageView.set(.height, to: isIPhone5OrSmaller ? 180 : 240) @@ -218,7 +210,7 @@ private final class ViewMyQRCodeVC : UIViewController { // MARK: Interaction @objc private func shareQRCode() { - let qrCode = QRCode.generate(for: userHexEncodedPublicKey, hasBackground: true) + let qrCode = QRCode.generate(for: getUserHexEncodedPublicKey(), hasBackground: true) let shareVC = UIActivityViewController(activityItems: [ qrCode ], applicationActivities: nil) qrCodeVC.navigationController!.present(shareVC, animated: true, completion: nil) } diff --git a/Session/View Controllers/SettingsVC.swift b/Session/View Controllers/SettingsVC.swift index 35099394b..615645038 100644 --- a/Session/View Controllers/SettingsVC.swift +++ b/Session/View Controllers/SettingsVC.swift @@ -4,14 +4,6 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { private var displayNameToBeUploaded: String? private var isEditingDisplayName = false { didSet { handleIsEditingDisplayNameChanged() } } - private lazy var userHexEncodedPublicKey: String = { - if let masterHexEncodedPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] { - return masterHexEncodedPublicKey - } else { - return getUserHexEncodedPublicKey() - } - }() - // MARK: Components private lazy var profilePictureView: ProfilePictureView = { let result = ProfilePictureView() @@ -71,10 +63,10 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { // Set up profile picture view let profilePictureTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showEditProfilePictureUI)) profilePictureView.addGestureRecognizer(profilePictureTapGestureRecognizer) - profilePictureView.hexEncodedPublicKey = userHexEncodedPublicKey + profilePictureView.hexEncodedPublicKey = getUserHexEncodedPublicKey() profilePictureView.update() // Set up display name label - displayNameLabel.text = OWSProfileManager.shared().profileNameForRecipient(withID: userHexEncodedPublicKey) + displayNameLabel.text = OWSProfileManager.shared().profileNameForRecipient(withID: getUserHexEncodedPublicKey()) // Set up display name container let displayNameContainer = UIView() displayNameContainer.addSubview(displayNameLabel) @@ -99,7 +91,7 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { publicKeyLabel.numberOfLines = 0 publicKeyLabel.textAlignment = .center publicKeyLabel.lineBreakMode = .byCharWrapping - publicKeyLabel.text = userHexEncodedPublicKey + publicKeyLabel.text = getUserHexEncodedPublicKey() // Set up share button let shareButton = Button(style: .regular, size: .medium) shareButton.setTitle(NSLocalizedString("share", comment: ""), for: UIControl.State.normal) @@ -178,23 +170,19 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { button.set(.height, to: Values.settingButtonHeight) return button } - var result = [ + return [ getSeparator(), getSettingButton(withTitle: NSLocalizedString("vc_settings_privacy_button_title", comment: ""), color: Colors.text, action: #selector(showPrivacySettings)), getSeparator(), getSettingButton(withTitle: NSLocalizedString("vc_settings_notifications_button_title", comment: ""), color: Colors.text, action: #selector(showNotificationSettings)), getSeparator(), - getSettingButton(withTitle: "Invite", color: Colors.text, action: #selector(sendInvitation)) + getSettingButton(withTitle: "Invite", color: Colors.text, action: #selector(sendInvitation)), + getSeparator(), + getSettingButton(withTitle: NSLocalizedString("vc_settings_recovery_phrase_button_title", comment: ""), color: Colors.text, action: #selector(showSeed)), + getSeparator(), + getSettingButton(withTitle: NSLocalizedString("vc_settings_clear_all_data_button_title", comment: ""), color: Colors.destructive, action: #selector(clearAllData)), + getSeparator() ] - let isMasterDevice = UserDefaults.standard.isMasterDevice - if isMasterDevice { - result.append(getSeparator()) - result.append(getSettingButton(withTitle: NSLocalizedString("vc_settings_recovery_phrase_button_title", comment: ""), color: Colors.text, action: #selector(showSeed))) - } - result.append(getSeparator()) - result.append(getSettingButton(withTitle: NSLocalizedString("vc_settings_clear_all_data_button_title", comment: ""), color: Colors.destructive, action: #selector(clearAllData))) - result.append(getSeparator()) - return result } // MARK: General @@ -283,8 +271,8 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { } private func updateProfile(isUpdatingDisplayName: Bool, isUpdatingProfilePicture: Bool) { - let displayName = displayNameToBeUploaded ?? OWSProfileManager.shared().profileNameForRecipient(withID: userHexEncodedPublicKey) - let profilePicture = profilePictureToBeUploaded ?? OWSProfileManager.shared().profileAvatar(forRecipientId: userHexEncodedPublicKey) + let displayName = displayNameToBeUploaded ?? OWSProfileManager.shared().profileNameForRecipient(withID: getUserHexEncodedPublicKey()) + let profilePicture = profilePictureToBeUploaded ?? OWSProfileManager.shared().profileAvatar(forRecipientId: getUserHexEncodedPublicKey()) ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] modalActivityIndicator in OWSProfileManager.shared().updateLocalProfileName(displayName, avatarImage: profilePicture, success: { DispatchQueue.main.async { @@ -372,7 +360,7 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { } @objc private func copyPublicKey() { - UIPasteboard.general.string = userHexEncodedPublicKey + UIPasteboard.general.string = getUserHexEncodedPublicKey() copyButton.isUserInteractionEnabled = false UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { self.copyButton.setTitle("Copied", for: UIControl.State.normal) @@ -381,7 +369,7 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { } @objc private func sharePublicKey() { - let shareVC = UIActivityViewController(activityItems: [ userHexEncodedPublicKey ], applicationActivities: nil) + let shareVC = UIActivityViewController(activityItems: [ getUserHexEncodedPublicKey() ], applicationActivities: nil) navigationController!.present(shareVC, animated: true, completion: nil) } @@ -394,14 +382,9 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { let notificationSettingsVC = NotificationSettingsViewController() navigationController!.pushViewController(notificationSettingsVC, animated: true) } - - @objc private func showLinkedDevices() { - let deviceLinksVC = DeviceLinksVC() - navigationController!.pushViewController(deviceLinksVC, animated: true) - } @objc private func sendInvitation() { - let invitation = "Hey, I've been using Session to chat with complete privacy and security. Come join me! Download it at https://getsession.org/. My Session ID is \(userHexEncodedPublicKey)!" + let invitation = "Hey, I've been using Session to chat with complete privacy and security. Come join me! Download it at https://getsession.org/. My Session ID is \(getUserHexEncodedPublicKey())!" let shareVC = UIActivityViewController(activityItems: [ invitation ], applicationActivities: nil) navigationController!.present(shareVC, animated: true, completion: nil) } diff --git a/SessionMessagingKit/Sending & Receiving/Notification+MessageSender.swift b/SessionMessagingKit/Sending & Receiving/Notification+MessageSender.swift index b5f9d68b2..0f59dee57 100644 --- a/SessionMessagingKit/Sending & Receiving/Notification+MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/Notification+MessageSender.swift @@ -7,3 +7,12 @@ public extension Notification.Name { static let messageSent = Notification.Name("messageSent") static let messageSendingFailed = Notification.Name("messageSendingFailed") } + +@objc public extension NSNotification { + + @objc static let encryptingMessage = Notification.Name.encryptingMessage.rawValue as NSString + @objc static let calculatingMessagePoW = Notification.Name.calculatingMessagePoW.rawValue as NSString + @objc static let messageSending = Notification.Name.messageSending.rawValue as NSString + @objc static let messageSent = Notification.Name.messageSent.rawValue as NSString + @objc static let messageSendingFailed = Notification.Name.messageSendingFailed.rawValue as NSString +} diff --git a/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift b/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift index 59725a6f7..653d24930 100644 --- a/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift +++ b/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift @@ -27,7 +27,7 @@ public enum SharedSenderKeys { } // MARK: Private/Internal API - internal static func generateRatchet(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) -> ClosedGroupRatchet { + public static func generateRatchet(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) -> ClosedGroupRatchet { let rootChainKey = Data.getSecureRandomData(ofSize: 32)!.toHexString() let ratchet = ClosedGroupRatchet(chainKey: rootChainKey, keyIndex: 0, messageKeys: []) Configuration.shared.storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: ratchet, in: .current, using: transaction) diff --git a/SessionProtocolKit/Storage.swift b/SessionProtocolKit/Storage.swift index f684c90dc..b61c5bdb1 100644 --- a/SessionProtocolKit/Storage.swift +++ b/SessionProtocolKit/Storage.swift @@ -7,6 +7,7 @@ public protocol SessionProtocolKitStorageProtocol { func with(_ work: @escaping (Any) -> Void) + func getUserKeyPair() -> ECKeyPair? func getClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, from collection: ClosedGroupRatchetCollectionType) -> ClosedGroupRatchet? func setClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, ratchet: ClosedGroupRatchet, in collection: ClosedGroupRatchetCollectionType, using transaction: Any) } diff --git a/SessionPushNotificationExtension/NotificationServiceExtension.swift b/SessionPushNotificationExtension/NotificationServiceExtension.swift index b9ceead2e..55ae73836 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtension.swift +++ b/SessionPushNotificationExtension/NotificationServiceExtension.swift @@ -13,7 +13,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler - notificationContent = (request.content.mutableCopy() as? UNMutableNotificationContent) + notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent var isMainAppActive = false if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") { @@ -31,10 +31,10 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { // Modify the notification content here... let base64EncodedData = notificationContent.userInfo["ENCRYPTED_DATA"] as! String let data = Data(base64Encoded: base64EncodedData)! - let decrypter = SSKEnvironment.shared.messageDecrypter - let messageManager = SSKEnvironment.shared.messageManager if let envelope = try? MessageWrapper.unwrap(data: data), let data = try? envelope.serializedData() { - let wasReceivedByUD = self.wasReceivedByUD(envelope: envelope) + // TODO TODO TODO + + /* decrypter.decryptEnvelope(envelope, envelopeData: data, successBlock: { result, transaction in @@ -49,6 +49,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { self.completeWithFailure(content: notificationContent) } ) + */ } else { self.completeWithFailure(content: notificationContent) } @@ -56,6 +57,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } } + /* func handleDecryptionResult(result: OWSMessageDecryptResult, notificationContent: UNMutableNotificationContent, transaction: YapDatabaseReadWriteTransaction) { let contentProto = try? SSKProtoContent.parseData(result.plaintextData!) var thread: TSThread @@ -131,6 +133,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { self.contentHandler!(notificationContent) } } + */ func handleMentionIfNecessary(rawMessageBody: String, threadID: String, transaction: YapDatabaseReadWriteTransaction) -> String { var string = rawMessageBody diff --git a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h index 75494b4e4..cd60f743f 100644 --- a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h +++ b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h @@ -13,7 +13,7 @@ #import #import #import -#import + #import #import #import @@ -23,5 +23,4 @@ #import #import #import -#import #import diff --git a/SessionShareExtension/ShareViewController.swift b/SessionShareExtension/ShareViewController.swift index c2b757a9a..675680472 100644 --- a/SessionShareExtension/ShareViewController.swift +++ b/SessionShareExtension/ShareViewController.swift @@ -207,8 +207,6 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed // We don't need to use the TSSocketManager in the SAE. - Environment.shared.contactsManager.fetchSystemContactsOnceIfAlreadyAuthorized() - // We don't need to fetch messages in the SAE. // We don't need to use OWSSyncPushTokensJob in the SAE. @@ -793,22 +791,6 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed if let data = value as? Data { let customFileName = "Contact.vcf" - var isConvertibleToContactShare = false - - // Although we don't support contacts _yet_, when we do we'll want to make - // sure they are shared with a reasonable filename. - if ShareViewController.itemMatchesSpecificUtiType(itemProvider: itemProvider, - utiType: kUTTypeVCard as String) { - - if Contact(vCardData: data) != nil { - isConvertibleToContactShare = true - } else { - Logger.error("could not parse vcard.") - let writeError = ShareViewControllerError.assertionError(description: "Could not parse vcard data.") - resolver.reject(writeError) - return - } - } let customFileExtension = MIMETypeUtil.fileExtension(forUTIType: srcUtiType) guard let tempFilePath = OWSFileSystem.writeData(toTemporaryFile: data, fileExtension: customFileExtension) else { @@ -821,7 +803,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed itemUrl: fileUrl, utiType: srcUtiType, customFileName: customFileName, - isConvertibleToContactShare: isConvertibleToContactShare)) + isConvertibleToContactShare: false)) } else if let string = value as? String { Logger.debug("string provider: \(string)") guard let data = string.filterStringForDisplay().data(using: String.Encoding.utf8) else { diff --git a/SessionUtilitiesKit/AnyPromise+Retaining.swift b/SessionUtilitiesKit/AnyPromise+Retaining.swift deleted file mode 100644 index a561f6ce2..000000000 --- a/SessionUtilitiesKit/AnyPromise+Retaining.swift +++ /dev/null @@ -1,13 +0,0 @@ -import PromiseKit - -public extension AnyPromise { - - @objc - func retainUntilComplete() { - var retainCycle: AnyPromise? = self - _ = self.ensure { - assert(retainCycle != nil) - retainCycle = nil - } - } -} diff --git a/SessionUtilitiesKit/Promise+Retaining.swift b/SessionUtilitiesKit/Promise+Retaining.swift new file mode 100644 index 000000000..fc1ef5d90 --- /dev/null +++ b/SessionUtilitiesKit/Promise+Retaining.swift @@ -0,0 +1,46 @@ +import PromiseKit + +public extension AnyPromise { + + @objc + func retainUntilComplete() { + var retainCycle: AnyPromise? = self + _ = self.ensure { + assert(retainCycle != nil) + retainCycle = nil + } + } +} + +public extension PMKFinalizer { + + func retainUntilComplete() { + var retainCycle: PMKFinalizer? = self + self.finally { + assert(retainCycle != nil) + retainCycle = nil + } + } +} + +public extension Promise { + + func retainUntilComplete() { + var retainCycle: Promise? = self + _ = self.ensure { + assert(retainCycle != nil) + retainCycle = nil + } + } +} + +public extension Guarantee { + + func retainUntilComplete() { + var retainCycle: Guarantee? = self + _ = self.done { _ in + assert(retainCycle != nil) + retainCycle = nil + } + } +} diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 1b030eda4..419ee0233 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -9,25 +9,16 @@ /* Begin PBXBuildFile section */ 10AC6C7D50A0C865C5E4779B /* Pods_SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71CFEDD2D3C54277731012DF /* Pods_SessionUIKit.framework */; }; 2400888E239F30A600305217 /* SessionRestorationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2400888D239F30A600305217 /* SessionRestorationView.swift */; }; - 3403B95D20EA9527001A1F44 /* OWSContactShareButtonsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */; }; 340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC87B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.m */; }; 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC87C204DAC8C007AEB0F /* NotificationSettingsViewController.m */; }; - 340FC8AB204DAC8D007AEB0F /* DomainFrontingCountryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */; }; 340FC8AC204DAC8D007AEB0F /* PrivacySettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC87E204DAC8C007AEB0F /* PrivacySettingsTableViewController.m */; }; 340FC8AE204DAC8D007AEB0F /* OWSSoundSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC883204DAC8C007AEB0F /* OWSSoundSettingsViewController.m */; }; 340FC8B0204DAC8D007AEB0F /* AddToBlockListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC886204DAC8C007AEB0F /* AddToBlockListViewController.m */; }; - 340FC8B1204DAC8D007AEB0F /* BlockListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC887204DAC8C007AEB0F /* BlockListViewController.m */; }; - 340FC8B2204DAC8D007AEB0F /* AdvancedSettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC88C204DAC8C007AEB0F /* AdvancedSettingsTableViewController.m */; }; 340FC8B4204DAC8D007AEB0F /* OWSBackupSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC88E204DAC8C007AEB0F /* OWSBackupSettingsViewController.m */; }; 340FC8B5204DAC8D007AEB0F /* AboutTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC893204DAC8C007AEB0F /* AboutTableViewController.m */; }; 340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */; }; 340FC8B7204DAC8D007AEB0F /* OWSConversationSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */; }; 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */; }; - 340FC8B9204DAC8D007AEB0F /* UpdateGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC89C204DAC8D007AEB0F /* UpdateGroupViewController.m */; }; - 340FC8BA204DAC8D007AEB0F /* FingerprintViewScanController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC89F204DAC8D007AEB0F /* FingerprintViewScanController.m */; }; - 340FC8BB204DAC8D007AEB0F /* OWSAddToContactViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8A1204DAC8D007AEB0F /* OWSAddToContactViewController.m */; }; - 340FC8BC204DAC8D007AEB0F /* FingerprintViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */; }; - 340FC8BD204DAC8D007AEB0F /* ShowGroupMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8A6204DAC8D007AEB0F /* ShowGroupMembersViewController.m */; }; 34129B8621EF877A005457A8 /* LinkPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34129B8521EF8779005457A8 /* LinkPreviewView.swift */; }; 341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 341341EE2187467900192D59 /* ConversationViewModel.m */; }; 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */; }; @@ -57,7 +48,6 @@ 347850571FD86544007B8332 /* SAEFailedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 347850561FD86544007B8332 /* SAEFailedViewController.swift */; }; 348570A820F67575004FF32B /* OWSMessageHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 348570A620F67574004FF32B /* OWSMessageHeaderView.m */; }; 3488F9362191CC4000E524CC /* ConversationMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488F9352191CC4000E524CC /* ConversationMediaView.swift */; }; - 348BB25D20A0C5530047AEC2 /* ContactShareViewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348BB25C20A0C5530047AEC2 /* ContactShareViewHelper.swift */; }; 3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496744C2076768700080B5F /* OWSMessageBubbleView.m */; }; 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496744E2076ACCE00080B5F /* LongTextViewController.swift */; }; 3496955C219B605E00DCFE74 /* ImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34969559219B605E00DCFE74 /* ImagePickerController.swift */; }; @@ -77,9 +67,6 @@ 34AC0A23211C829F00997B47 /* OWSLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 34AC0A21211C829E00997B47 /* OWSLabel.m */; }; 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B0796B1FCF46B000E248C2 /* MainAppContext.m */; }; 34B3F8751E8DF1700035BE1A /* CallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F83B1E8DF1700035BE1A /* CallViewController.swift */; }; - 34B3F8771E8DF1700035BE1A /* ContactsPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F83E1E8DF1700035BE1A /* ContactsPicker.swift */; }; - 34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */; }; - 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */; }; 34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */; }; 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */; }; 34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */; }; @@ -90,7 +77,6 @@ 34C3C78F2040A4F70000134C /* sonarping.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 34C3C78E2040A4F70000134C /* sonarping.mp3 */; }; 34C4E2572118957600BEA353 /* OWSWebRTCDataProtos.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C4E2552118957600BEA353 /* OWSWebRTCDataProtos.pb.swift */; }; 34C4E2582118957600BEA353 /* WebRTCProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C4E2562118957600BEA353 /* WebRTCProto.swift */; }; - 34CA631B2097806F00E526A0 /* OWSContactShareView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CA631A2097806E00E526A0 /* OWSContactShareView.m */; }; 34CF0787203E6B78005C4D61 /* busy_tone_ansi.caf in Resources */ = {isa = PBXBuildFile; fileRef = 34CF0783203E6B77005C4D61 /* busy_tone_ansi.caf */; }; 34CF0788203E6B78005C4D61 /* ringback_tone_ansi.caf in Resources */ = {isa = PBXBuildFile; fileRef = 34CF0784203E6B77005C4D61 /* ringback_tone_ansi.caf */; }; 34CF078A203E6B78005C4D61 /* end_call_tone_cept.caf in Resources */ = {isa = PBXBuildFile; fileRef = 34CF0786203E6B78005C4D61 /* end_call_tone_cept.caf */; }; @@ -102,7 +88,6 @@ 34D1F0871F8678AA0066283D /* ConversationViewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0701F8678AA0066283D /* ConversationViewItem.m */; }; 34D1F0881F8678AA0066283D /* ConversationViewLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0721F8678AA0066283D /* ConversationViewLayout.m */; }; 34D1F0A91F867BFC0066283D /* ConversationViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0971F867BFC0066283D /* ConversationViewCell.m */; }; - 34D1F0AB1F867BFC0066283D /* OWSContactOffersCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F09B1F867BFC0066283D /* OWSContactOffersCell.m */; }; 34D1F0AE1F867BFC0066283D /* OWSMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0A21F867BFC0066283D /* OWSMessageCell.m */; }; 34D1F0B01F867BFC0066283D /* OWSSystemMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0A61F867BFC0066283D /* OWSSystemMessageCell.m */; }; 34D1F0B41F86D31D0066283D /* ConversationCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0B31F86D31D0066283D /* ConversationCollectionView.m */; }; @@ -112,13 +97,11 @@ 34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */; }; 34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; }; 34D920E720E179C200D51158 /* OWSMessageFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D920E620E179C200D51158 /* OWSMessageFooterView.m */; }; - 34D99C931F2937CC00D284D6 /* OWSAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */; }; 34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */; }; 34DBF003206BD5A500025978 /* OWSMessageTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DBEFFF206BD5A400025978 /* OWSMessageTextView.m */; }; 34DBF004206BD5A500025978 /* OWSBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DBF001206BD5A500025978 /* OWSBubbleView.m */; }; 34DBF007206C3CB200025978 /* OWSBubbleShapeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DBF006206C3CB200025978 /* OWSBubbleShapeView.m */; }; 34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */; }; - 34E88D262098C5AE00A608F4 /* ContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E88D252098C5AE00A608F4 /* ContactViewController.swift */; }; 34EA69402194933900702471 /* MediaDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EA693F2194933900702471 /* MediaDownloadView.swift */; }; 34EA69422194DE8000702471 /* MediaUploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EA69412194DE7F00702471 /* MediaUploadView.swift */; }; 34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; }; @@ -131,14 +114,11 @@ 450DF2051E0D74AC003D14BE /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2041E0D74AC003D14BE /* Platform.swift */; }; 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */; }; 451166C01FD86B98000739BA /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451166BF1FD86B98000739BA /* AccountManager.swift */; }; - 4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451764291DE939FD00EDB8B9 /* ContactCell.swift */; }; 451A13B11E13DED2000A50FD /* AppNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A13B01E13DED2000A50FD /* AppNotifications.swift */; }; 4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4520D8D41D417D8E00123472 /* Photos.framework */; }; 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */; }; - 452B999020A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */; }; 452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; }; 452EC6DF205E9E30000E787C /* MediaGalleryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */; }; - 452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */; }; 4535186B1FC635DD00210559 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4535186A1FC635DD00210559 /* ShareViewController.swift */; }; 4535186E1FC635DD00210559 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4535186C1FC635DD00210559 /* MainInterface.storyboard */; }; 453518721FC635DD00210559 /* SessionShareExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 453518681FC635DD00210559 /* SessionShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -148,14 +128,11 @@ 455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DB1F1FEA0000F86704 /* Metal.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 4574A5D61DD6704700C6B692 /* CallService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4574A5D51DD6704700C6B692 /* CallService.swift */; }; - 4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */; }; 45794E861E00620000066731 /* CallUIAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45794E851E00620000066731 /* CallUIAdapter.swift */; }; 457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457F671A20746193000EABCD /* QuotedReplyPreview.swift */; }; 45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 4585C4681ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */; }; 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */; }; 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; - 459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */; }; 45A2F005204473A3002E978A /* NewMessage.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45A2F004204473A3002E978A /* NewMessage.aifc */; }; 45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */; }; 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; @@ -192,8 +169,6 @@ 45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; }; 45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */; }; 45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */; }; - 45D308AD2049A439000189E4 /* PinEntryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 45D308AC2049A439000189E4 /* PinEntryView.m */; }; - 45DDA6242090CEB500DE97F8 /* ConversationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DDA6232090CEB500DE97F8 /* ConversationHeaderView.swift */; }; 45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */; }; 45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; }; 45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; }; @@ -206,7 +181,6 @@ 45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */; }; 4C04392A220A9EC800BAEA63 /* VoiceNoteLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C043929220A9EC800BAEA63 /* VoiceNoteLock.swift */; }; 4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; }; - 4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */; }; 4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */; }; 4C21D5D6223A9DC500EF8A77 /* UIAlerts+iOS9.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */; }; 4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */; }; @@ -222,7 +196,6 @@ 4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */; }; 4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */; }; 4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB5F26820F7D060004D1B42 /* MessageActions.swift */; }; - 4CC0B59C20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */; }; 4CC1ECF9211A47CE00CC13BE /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; }; 4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC613352227A00400E21A3A /* ConversationSearch.swift */; }; @@ -273,9 +246,6 @@ B6F509971AA53F760068F56A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; }; B6FE7EB71ADD62FA00A6D22F /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */; }; B80A579F23DFF1F300876683 /* NewClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */; }; - B80C6B572384A56D00FDBC8B /* DeviceLinksVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */; }; - B80C6B592384C4E700FDBC8B /* DeviceNameModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */; }; - B80C6B5B2384C7F900FDBC8B /* DeviceNameModalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */; }; B82B40882399EB0E00A248E7 /* LandingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B40872399EB0E00A248E7 /* LandingVC.swift */; }; B82B408A2399EC0600A248E7 /* FakeChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B40892399EC0600A248E7 /* FakeChatView.swift */; }; B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408B239A068800A248E7 /* RegisterVC.swift */; }; @@ -293,15 +263,16 @@ B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; B879D449247E1BE300DB3608 /* PathVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B879D448247E1BE300DB3608 /* PathVC.swift */; }; - B885D5F4233491AB00EE0D8E /* DeviceLinkingModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */; }; B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A62398B23E00211ABE /* QRCodeVC.swift */; }; B886B4A92398BA1500211ABE /* QRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A82398BA1500211ABE /* QRCode.swift */; }; B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */; }; B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; }; - B894D0712339D6F300B4D94D /* DeviceLinkingModalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */; }; B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; }; B8B26C8F234D629C004ED98C /* MentionCandidateSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */; }; B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BB82A4238F627000BA5194 /* HomeVC.swift */; }; + B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C2B2C72563685C00551B4D /* CircleView.swift */; }; + B8C2B332256376F000551B4D /* ThreadUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B8C2B331256376F000551B4D /* ThreadUtil.m */; }; + B8C2B3442563782400551B4D /* ThreadUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = B8C2B33B2563770800551B4D /* ThreadUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8CCF6352396005F0091D419 /* SpaceMono-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B8CCF6342396005F0091D419 /* SpaceMono-Regular.ttf */; }; B8CCF63723961D6D0091D419 /* NewPrivateChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */; }; B8CCF63F23975CFB0091D419 /* JoinPublicChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */; }; @@ -358,14 +329,12 @@ C33FD9C3255A54EF00E217F9 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C33FD9C4255A54EF00E217F9 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; }; C33FD9C5255A54EF00E217F9 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; }; - C33FDC20255A581F00E217F9 /* OWSOutgoingCallMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA66255A57F900E217F9 /* OWSOutgoingCallMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC21255A581F00E217F9 /* OWSPrimaryStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */; }; C33FDC23255A581F00E217F9 /* SSKPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA69255A57F900E217F9 /* SSKPreferences.swift */; }; C33FDC25255A581F00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */; }; C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */; }; C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */; }; - C33FDC28255A581F00E217F9 /* Array+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6E255A57FA00E217F9 /* Array+Description.swift */; }; C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */; }; C33FDC2A255A581F00E217F9 /* TSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA70255A57FA00E217F9 /* TSMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC2B255A581F00E217F9 /* OWSReadReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */; }; @@ -373,70 +342,43 @@ C33FDC2D255A581F00E217F9 /* ECKeyPair+Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */; }; C33FDC2E255A581F00E217F9 /* ClosedGroupsProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */; }; C33FDC2F255A581F00E217F9 /* OWSSyncManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC30255A581F00E217F9 /* OWSSyncGroupsRequestMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA76255A57FB00E217F9 /* OWSSyncGroupsRequestMessage.m */; }; - C33FDC31255A581F00E217F9 /* Contact.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA77255A57FB00E217F9 /* Contact.m */; }; - C33FDC32255A581F00E217F9 /* SSKWebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA78255A57FB00E217F9 /* SSKWebSocket.swift */; }; C33FDC33255A581F00E217F9 /* TSGroupThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA79255A57FB00E217F9 /* TSGroupThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC34255A581F00E217F9 /* NSRegularExpression+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */; }; C33FDC35255A581F00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC36255A581F00E217F9 /* Debugging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7C255A57FB00E217F9 /* Debugging.swift */; }; - C33FDC37255A581F00E217F9 /* OWSCensorshipConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7D255A57FB00E217F9 /* OWSCensorshipConfiguration.m */; }; C33FDC38255A581F00E217F9 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7E255A57FB00E217F9 /* Mention.swift */; }; C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */; }; C33FDC3A255A581F00E217F9 /* OWSDisappearingMessagesJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA81255A57FC00E217F9 /* MentionsManager.swift */; }; - C33FDC3D255A581F00E217F9 /* Promise+retainUntilComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA83255A57FC00E217F9 /* Promise+retainUntilComplete.swift */; }; - C33FDC3E255A581F00E217F9 /* ContactsUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA84255A57FC00E217F9 /* ContactsUpdater.m */; }; C33FDC3F255A581F00E217F9 /* OWSPrimaryStorage+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */; }; C33FDC40255A581F00E217F9 /* OWSDisappearingMessagesFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */; }; C33FDC41255A581F00E217F9 /* TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */; }; C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC43255A581F00E217F9 /* OWSAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA89255A57FD00E217F9 /* OWSAnalytics.m */; }; - C33FDC44255A581F00E217F9 /* PhoneNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8A255A57FD00E217F9 /* PhoneNumber.m */; }; C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8B255A57FD00E217F9 /* AppVersion.m */; }; C33FDC46255A581F00E217F9 /* PublicChatPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */; }; - C33FDC47255A581F00E217F9 /* OWSReceiptsForSenderMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA8D255A57FD00E217F9 /* OWSReceiptsForSenderMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; }; - C33FDC49255A581F00E217F9 /* NSTimer+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8F255A57FD00E217F9 /* NSTimer+OWS.m */; }; C33FDC4A255A582000E217F9 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; }; - C33FDC4B255A582000E217F9 /* LKSyncOpenGroupsMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA91255A57FD00E217F9 /* LKSyncOpenGroupsMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC4E255A582000E217F9 /* Data+Streaming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */; }; C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA96255A57FE00E217F9 /* OWSDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */; }; C33FDC52255A582000E217F9 /* RotateSignedKeyOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA98255A57FE00E217F9 /* RotateSignedKeyOperation.swift */; }; C33FDC53255A582000E217F9 /* OutageDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA99255A57FE00E217F9 /* OutageDetection.swift */; }; - C33FDC54255A582000E217F9 /* OWSLinkedDeviceReadReceipt.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9A255A57FE00E217F9 /* OWSLinkedDeviceReadReceipt.m */; }; - C33FDC55255A582000E217F9 /* OWSProvisioningMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9B255A57FE00E217F9 /* OWSProvisioningMessage.m */; }; - C33FDC56255A582000E217F9 /* OWSSyncContactsMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9C255A57FE00E217F9 /* OWSSyncContactsMessage.m */; }; C33FDC57255A582000E217F9 /* OWSContactsOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */; }; - C33FDC59255A582000E217F9 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9F255A57FF00E217F9 /* NetworkManager.swift */; }; C33FDC5A255A582000E217F9 /* OWSRecipientIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC5B255A582000E217F9 /* TSYapDatabaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC5C255A582000E217F9 /* OWSAddToContactsOfferMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA2255A57FF00E217F9 /* OWSAddToContactsOfferMessage.m */; }; - C33FDC5D255A582000E217F9 /* OWSAddToContactsOfferMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA3255A57FF00E217F9 /* OWSAddToContactsOfferMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC5E255A582000E217F9 /* SSKProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA4255A57FF00E217F9 /* SSKProto.swift */; }; - C33FDC5F255A582000E217F9 /* OWSRequestMaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA5255A57FF00E217F9 /* OWSRequestMaker.swift */; }; - C33FDC60255A582000E217F9 /* OWSLinkedDeviceReadReceipt.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA6255A57FF00E217F9 /* OWSLinkedDeviceReadReceipt.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; }; - C33FDC63255A582000E217F9 /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA9255A580000E217F9 /* Mnemonic.swift */; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; - C33FDC65255A582000E217F9 /* OWSWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAB255A580000E217F9 /* OWSWebSocket.m */; }; - C33FDC67255A582000E217F9 /* OWSDeviceProvisioner.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAAD255A580000E217F9 /* OWSDeviceProvisioner.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC68255A582000E217F9 /* OWSReceiptsForSenderMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAE255A580000E217F9 /* OWSReceiptsForSenderMessage.m */; }; C33FDC69255A582000E217F9 /* String+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAF255A580000E217F9 /* String+Trimming.swift */; }; C33FDC6A255A582000E217F9 /* ProvisioningProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB0255A580000E217F9 /* ProvisioningProto.swift */; }; C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; }; - C33FDC6C255A582000E217F9 /* TSNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB2255A580000E217F9 /* TSNetworkManager.m */; }; C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB3255A580000E217F9 /* TSContactThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC6F255A582000E217F9 /* TSNetworkManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB5255A580000E217F9 /* TSNetworkManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC70255A582000E217F9 /* SyncMessagesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB6255A580100E217F9 /* SyncMessagesProtocol.swift */; }; C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */; }; C33FDC72255A582000E217F9 /* NSArray+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB8255A580100E217F9 /* NSArray+Functional.m */; }; C33FDC73255A582000E217F9 /* OWSStorage+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC74255A582000E217F9 /* OWSWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDABA255A580100E217F9 /* OWSWebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC75255A582000E217F9 /* OWSGroupsOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDABB255A580100E217F9 /* OWSGroupsOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC77255A582000E217F9 /* OWSOutgoingReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC78255A582000E217F9 /* TSConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDABE255A580100E217F9 /* TSConstants.m */; }; @@ -445,24 +387,11 @@ C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC2255A580200E217F9 /* TSAttachment.m */; }; C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC3255A580200E217F9 /* OWSDispatch.m */; }; C33FDC7E255A582000E217F9 /* TSAttachmentStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */; }; - C33FDC7F255A582000E217F9 /* OWSCountryMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC5255A580200E217F9 /* OWSCountryMetadata.m */; }; C33FDC80255A582000E217F9 /* Fingerprint.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC6255A580200E217F9 /* Fingerprint.pb.swift */; }; - C33FDC81255A582000E217F9 /* OWSSignalService.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAC7255A580200E217F9 /* OWSSignalService.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC82255A582000E217F9 /* OWSCensorshipConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAC8255A580200E217F9 /* OWSCensorshipConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC83255A582000E217F9 /* OWSContact.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAC9255A580200E217F9 /* OWSContact.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC84255A582000E217F9 /* LokiMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACA255A580200E217F9 /* LokiMessage.swift */; }; - C33FDC85255A582000E217F9 /* CDSSigningCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACB255A580200E217F9 /* CDSSigningCertificate.m */; }; C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; }; - C33FDC88255A582000E217F9 /* OWSVerificationStateSyncMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACE255A580300E217F9 /* OWSVerificationStateSyncMessage.m */; }; C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC8A255A582000E217F9 /* CDSQuote.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAD0255A580300E217F9 /* CDSQuote.m */; }; - C33FDC8B255A582000E217F9 /* OWSDynamicOutgoingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAD1255A580300E217F9 /* OWSDynamicOutgoingMessage.m */; }; - C33FDC8C255A582000E217F9 /* Contact.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD2255A580300E217F9 /* Contact.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC8D255A582000E217F9 /* TSThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD3255A580300E217F9 /* TSThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC8E255A582000E217F9 /* EncryptionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAD4255A580300E217F9 /* EncryptionUtilities.swift */; }; C33FDC8F255A582000E217F9 /* TSQuotedMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC90255A582000E217F9 /* OWSAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD6255A580300E217F9 /* OWSAnalytics.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC91255A582000E217F9 /* OWSDeviceProvisioner.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAD7255A580300E217F9 /* OWSDeviceProvisioner.m */; }; C33FDC92255A582000E217F9 /* OWSGroupsOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAD8255A580300E217F9 /* OWSGroupsOutputStream.m */; }; C33FDC93255A582000E217F9 /* OWSDisappearingMessagesConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC94255A582000E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -473,95 +402,63 @@ C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDADF255A580400E217F9 /* PublicChatManager.swift */; }; C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE0255A580400E217F9 /* ByteParser.m */; }; C33FDC9B255A582000E217F9 /* OWSReadTracking.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE1255A580400E217F9 /* OWSReadTracking.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC9C255A582000E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE2255A580400E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC9E255A582000E217F9 /* TSAttachmentStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC9F255A582000E217F9 /* OWSAddToProfileWhitelistOfferMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE5255A580400E217F9 /* OWSAddToProfileWhitelistOfferMessage.m */; }; C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE6255A580400E217F9 /* TSInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA1255A582000E217F9 /* TSErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE7255A580500E217F9 /* TSErrorMessage.m */; }; C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA3255A582000E217F9 /* SSKMessageSenderJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */; }; C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCA5255A582000E217F9 /* OWSDeviceProvisioningCodeService.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAEB255A580500E217F9 /* OWSDeviceProvisioningCodeService.m */; }; C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEC255A580500E217F9 /* SignalRecipient.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCA8255A582000E217F9 /* OWSFingerprintBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAEE255A580500E217F9 /* OWSFingerprintBuilder.m */; }; C33FDCA9255A582000E217F9 /* NSData+Image.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAEF255A580500E217F9 /* NSData+Image.m */; }; - C33FDCAA255A582000E217F9 /* ContactsUpdater.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAF0255A580500E217F9 /* ContactsUpdater.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCAB255A582000E217F9 /* OWSThumbnailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */; }; C33FDCAC255A582000E217F9 /* ProxiedContentDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */; }; C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */; }; C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF4255A580600E217F9 /* SSKEnvironment.m */; }; - C33FDCAF255A582000E217F9 /* OWSAnalyticsEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAF5255A580600E217F9 /* OWSAnalyticsEvents.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCB0255A582000E217F9 /* OWSIncomingSentMessageTranscript.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAF6255A580600E217F9 /* OWSIncomingSentMessageTranscript.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */; }; - C33FDCB2255A582000E217F9 /* OWSSyncGroupsRequestMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAF8255A580600E217F9 /* OWSSyncGroupsRequestMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF9255A580600E217F9 /* TSContactThread.m */; }; - C33FDCB4255A582000E217F9 /* LKDeviceLinkMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFA255A580600E217F9 /* LKDeviceLinkMessage.m */; }; C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */; }; C33FDCB6255A582000E217F9 /* MIMETypeUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; }; C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */; }; - C33FDCBA255A582000E217F9 /* OWSRequestBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB00255A580600E217F9 /* OWSRequestBuilder.m */; }; C33FDCBB255A582000E217F9 /* AppReadiness.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB01255A580700E217F9 /* AppReadiness.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCBC255A582000E217F9 /* TSCall.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB02255A580700E217F9 /* TSCall.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCBF255A582000E217F9 /* OWSFingerprint.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB05255A580700E217F9 /* OWSFingerprint.m */; }; - C33FDCC0255A582000E217F9 /* OWSRequestBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB06255A580700E217F9 /* OWSRequestBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; }; - C33FDCC2255A582000E217F9 /* OWSProfileKeyMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB08255A580700E217F9 /* OWSProfileKeyMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB09255A580700E217F9 /* NSError+MessageSending.m */; }; C33FDCC4255A582000E217F9 /* TSGroupModel.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0A255A580700E217F9 /* TSGroupModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCC5255A582000E217F9 /* OWSVerificationStateChangeMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB0B255A580700E217F9 /* OWSVerificationStateChangeMessage.m */; }; - C33FDCC6255A582000E217F9 /* CDSQuote.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0C255A580700E217F9 /* CDSQuote.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCC7255A582000E217F9 /* NSArray+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB0D255A580800E217F9 /* NSArray+OWS.m */; }; C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0E255A580800E217F9 /* NSError+MessageSending.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCC9255A582000E217F9 /* DeviceLinkingSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB0F255A580800E217F9 /* DeviceLinkingSession.swift */; }; - C33FDCCA255A582000E217F9 /* OWSBatchMessageProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB10255A580800E217F9 /* OWSBatchMessageProcessor.m */; }; C33FDCCC255A582000E217F9 /* NSString+SSK.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB12255A580800E217F9 /* NSString+SSK.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCCD255A582000E217F9 /* LKUnlinkDeviceMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB13255A580800E217F9 /* LKUnlinkDeviceMessage.m */; }; C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCD0255A582000E217F9 /* OWSDisappearingMessagesConfigurationMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB16255A580800E217F9 /* OWSDisappearingMessagesConfigurationMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB17255A580800E217F9 /* FunctionalUtil.m */; }; - C33FDCD2255A582000E217F9 /* OWSSignalService.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB18255A580800E217F9 /* OWSSignalService.m */; }; C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB19255A580900E217F9 /* GroupUtilities.swift */; }; C33FDCD4255A582000E217F9 /* OWSPrimaryStorage+Calling.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1A255A580900E217F9 /* OWSPrimaryStorage+Calling.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCD5255A582000E217F9 /* OWSDeviceProvisioningCodeService.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1B255A580900E217F9 /* OWSDeviceProvisioningCodeService.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD6255A582000E217F9 /* UIImage+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1C255A580900E217F9 /* UIImage+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD7255A582000E217F9 /* OWSReadReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD8255A582000E217F9 /* OWSIncomingMessageFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */; }; - C33FDCD9255A582000E217F9 /* DeviceLinkingUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB1F255A580900E217F9 /* DeviceLinkingUtilities.swift */; }; C33FDCDA255A582000E217F9 /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; }; - C33FDCDB255A582000E217F9 /* OWS2FAManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB21255A580900E217F9 /* OWS2FAManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCDC255A582000E217F9 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; }; - C33FDCDE255A582000E217F9 /* OWSOutgoingSentMessageTranscript.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB24255A580900E217F9 /* OWSOutgoingSentMessageTranscript.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE0255A582000E217F9 /* FingerprintProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB26255A580A00E217F9 /* FingerprintProto.swift */; }; - C33FDCE1255A582000E217F9 /* OWSEndSessionMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB27255A580A00E217F9 /* OWSEndSessionMessage.m */; }; - C33FDCE2255A582000E217F9 /* OWSOutgoingCallMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB28255A580A00E217F9 /* OWSOutgoingCallMessage.m */; }; C33FDCE3255A582000E217F9 /* NSData+Image.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB29255A580A00E217F9 /* NSData+Image.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE4255A582000E217F9 /* OWSIncompleteCallsJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2A255A580A00E217F9 /* OWSIncompleteCallsJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE5255A582000E217F9 /* OWSProvisioningCipher.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */; }; C33FDCE6255A582000E217F9 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE7255A582000E217F9 /* OWSDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2D255A580A00E217F9 /* OWSDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE8255A582000E217F9 /* OWSEndSessionMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2E255A580A00E217F9 /* OWSEndSessionMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE9255A582000E217F9 /* ContactsManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCEA255A582000E217F9 /* OWSDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB30255A580A00E217F9 /* OWSDevice.m */; }; C33FDCEB255A582000E217F9 /* SSKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB31255A580A00E217F9 /* SSKEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */; }; C33FDCED255A582000E217F9 /* Provisioning.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB33255A580B00E217F9 /* Provisioning.pb.swift */; }; C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */; }; - C33FDCEF255A582000E217F9 /* OWSContactDiscoveryOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB35255A580B00E217F9 /* OWSContactDiscoveryOperation.swift */; }; C33FDCF0255A582000E217F9 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; }; C33FDCF1255A582000E217F9 /* Storage+SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */; }; C33FDCF2255A582000E217F9 /* OWSBackgroundTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCF4255A582000E217F9 /* Poller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3A255A580B00E217F9 /* Poller.swift */; }; C33FDCF5255A582000E217F9 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCF7255A582000E217F9 /* OWSProfileKeyMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3D255A580B00E217F9 /* OWSProfileKeyMessage.m */; }; C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3F255A580C00E217F9 /* String+SSK.swift */; }; C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */; }; C33FDCFB255A582000E217F9 /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */; }; - C33FDCFC255A582000E217F9 /* OWSCountryMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB42255A580C00E217F9 /* OWSCountryMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCFD255A582000E217F9 /* YapDatabaseConnection+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */; }; C33FDCFE255A582000E217F9 /* OWSContactsOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */; }; C33FDCFF255A582000E217F9 /* NSString+SSK.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB45255A580C00E217F9 /* NSString+SSK.m */; }; @@ -569,7 +466,6 @@ C33FDD01255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD02255A582000E217F9 /* TSOutgoingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB49255A580C00E217F9 /* WeakTimer.swift */; }; - C33FDD04255A582000E217F9 /* SignalServiceClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB4A255A580C00E217F9 /* SignalServiceClient.swift */; }; C33FDD05255A582000E217F9 /* OWSChunkedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */; }; C33FDD06255A582000E217F9 /* AppVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4C255A580D00E217F9 /* AppVersion.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD09255A582000E217F9 /* SSKJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -580,22 +476,16 @@ C33FDD0E255A582000E217F9 /* DataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB54255A580D00E217F9 /* DataSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0F255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */; }; C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */; }; - C33FDD11255A582000E217F9 /* OWSSyncContactsMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB57255A580D00E217F9 /* OWSSyncContactsMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */; }; C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB59255A580E00E217F9 /* OWSFailedAttachmentDownloadsJob.m */; }; C33FDD14255A582000E217F9 /* OWSUDManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5A255A580E00E217F9 /* OWSUDManager.swift */; }; C33FDD15255A582000E217F9 /* YapDatabaseTransaction+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */; }; C33FDD16255A582000E217F9 /* NSArray+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD17255A582000E217F9 /* TSErrorMessage_privateConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD18255A582000E217F9 /* ContactParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5E255A580E00E217F9 /* ContactParser.swift */; }; C33FDD19255A582000E217F9 /* YapDatabaseConnection+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD1A255A582000E217F9 /* TSMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB60255A580E00E217F9 /* TSMessage.m */; }; - C33FDD1B255A582000E217F9 /* LKUnlinkDeviceMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB61255A580E00E217F9 /* LKUnlinkDeviceMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD1C255A582000E217F9 /* OWSProvisioningCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB62255A580E00E217F9 /* OWSProvisioningCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD1D255A582000E217F9 /* OWSDynamicOutgoingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB63255A580E00E217F9 /* OWSDynamicOutgoingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */; }; - C33FDD1F255A582000E217F9 /* OWSSyncConfigurationMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB65255A580F00E217F9 /* OWSSyncConfigurationMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD20255A582000E217F9 /* ContactDiscoveryService.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB66255A580F00E217F9 /* ContactDiscoveryService.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD21255A582000E217F9 /* OWSMediaGalleryFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD22255A582000E217F9 /* ContentProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB68255A580F00E217F9 /* ContentProxy.swift */; }; C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB69255A580F00E217F9 /* FeatureFlags.swift */; }; @@ -603,55 +493,37 @@ C33FDD25255A582000E217F9 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */; }; C33FDD27255A582000E217F9 /* TSPreKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD28255A582000E217F9 /* SSKProtoPrekeyBundleMessage+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6E255A580F00E217F9 /* SSKProtoPrekeyBundleMessage+Loki.swift */; }; C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */; }; C33FDD2A255A582000E217F9 /* OWSMessageServiceParams.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB70255A580F00E217F9 /* OWSMessageServiceParams.m */; }; C33FDD2B255A582000E217F9 /* OWSMediaGalleryFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */; }; - C33FDD2C255A582000E217F9 /* DeviceLinkIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB72255A581000E217F9 /* DeviceLinkIndex.swift */; }; C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB73255A581000E217F9 /* TSGroupModel.m */; }; C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */; }; C33FDD2F255A582000E217F9 /* AppReadiness.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB75255A581000E217F9 /* AppReadiness.m */; }; - C33FDD30255A582000E217F9 /* ClosedGroupUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB76255A581000E217F9 /* ClosedGroupUtilities.swift */; }; C33FDD31255A582000E217F9 /* NSUserDefaults+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */; }; C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB78255A581000E217F9 /* OWSOperation.m */; }; - C33FDD33255A582000E217F9 /* PhoneNumberUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB79255A581000E217F9 /* PhoneNumberUtil.m */; }; C33FDD34255A582000E217F9 /* NotificationsProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD36255A582000E217F9 /* OWSVerificationStateChangeMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7C255A581000E217F9 /* OWSVerificationStateChangeMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD38255A582000E217F9 /* TSPreKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */; }; C33FDD39255A582000E217F9 /* FullTextSearchFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */; }; C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB80255A581100E217F9 /* Notification+Loki.swift */; }; C33FDD3B255A582000E217F9 /* UIImage+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB81255A581100E217F9 /* UIImage+OWS.m */; }; - C33FDD3C255A582000E217F9 /* MessageWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB82255A581100E217F9 /* MessageWrapper.swift */; }; C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB83255A581100E217F9 /* TSQuotedMessage.m */; }; - C33FDD3E255A582000E217F9 /* OWSIncomingSentMessageTranscript.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB84255A581100E217F9 /* OWSIncomingSentMessageTranscript.m */; }; C33FDD3F255A582000E217F9 /* AppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB85255A581100E217F9 /* AppContext.m */; }; - C33FDD40255A582000E217F9 /* OWSRequestFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB86255A581100E217F9 /* OWSRequestFactory.m */; }; C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB87255A581100E217F9 /* JobQueue.swift */; }; C33FDD42255A582000E217F9 /* TSAccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB88255A581200E217F9 /* TSAccountManager.m */; }; - C33FDD43255A582000E217F9 /* FileServerAPI+Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB89255A581200E217F9 /* FileServerAPI+Deprecated.swift */; }; C33FDD44255A582000E217F9 /* AppContext.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8A255A581200E217F9 /* AppContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */; }; C33FDD46255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD47255A582000E217F9 /* DeviceLinkingSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8D255A581200E217F9 /* DeviceLinkingSessionDelegate.swift */; }; - C33FDD48255A582000E217F9 /* OWSContact+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8E255A581200E217F9 /* OWSContact+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; }; C33FDD4B255A582000E217F9 /* ProtoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB91255A581200E217F9 /* ProtoUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD4C255A582000E217F9 /* OWSDeviceProvisioningService.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB92255A581200E217F9 /* OWSDeviceProvisioningService.m */; }; C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */; }; C33FDD4E255A582000E217F9 /* TSAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB94255A581300E217F9 /* TSAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD4F255A582000E217F9 /* Storage+Collections.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB95255A581300E217F9 /* Storage+Collections.swift */; }; - C33FDD50255A582000E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB96255A581300E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.m */; }; - C33FDD51255A582000E217F9 /* OWSDisappearingMessagesConfigurationMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB97255A581300E217F9 /* OWSDisappearingMessagesConfigurationMessage.m */; }; - C33FDD52255A582000E217F9 /* DeviceNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB98255A581300E217F9 /* DeviceNames.swift */; }; C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; }; - C33FDD54255A582000E217F9 /* OWS2FAManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9A255A581300E217F9 /* OWS2FAManager.m */; }; C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD57255A582000E217F9 /* OWSCallMessageHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD58255A582000E217F9 /* TSAttachmentPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */; }; - C33FDD59255A582000E217F9 /* TTLUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9F255A581400E217F9 /* TTLUtilities.swift */; }; C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD5C255A582000E217F9 /* PhoneNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA2255A581400E217F9 /* PhoneNumber.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */; }; C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */; }; C33FDD5F255A582000E217F9 /* SignalServiceProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA5255A581400E217F9 /* SignalServiceProfile.swift */; }; @@ -659,15 +531,10 @@ C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */; }; C33FDD63255A582000E217F9 /* OWSIdentityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */; }; C33FDD65255A582000E217F9 /* OWSFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAB255A581500E217F9 /* OWSFileSystem.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD66255A582000E217F9 /* Data+SecureRandom.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBAC255A581500E217F9 /* Data+SecureRandom.swift */; }; C33FDD67255A582000E217F9 /* OWSRecordTranscriptJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD68255A582000E217F9 /* SignalAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAE255A581500E217F9 /* SignalAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD69255A582000E217F9 /* OWSAnalyticsEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBAF255A581500E217F9 /* OWSAnalyticsEvents.m */; }; C33FDD6A255A582000E217F9 /* TSErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB0255A581500E217F9 /* TSErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD6B255A582000E217F9 /* TSSocketManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB1255A581500E217F9 /* TSSocketManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD6D255A582000E217F9 /* OWSOutgoingNullMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB3255A581500E217F9 /* OWSOutgoingNullMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */; }; - C33FDD6F255A582000E217F9 /* OWSSyncGroupsMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB5255A581600E217F9 /* OWSSyncGroupsMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD70255A582000E217F9 /* DataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB6255A581600E217F9 /* DataSource.m */; }; C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB7255A581600E217F9 /* SignalRecipient.m */; }; C33FDD72255A582000E217F9 /* TSThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB8255A581600E217F9 /* TSThread.m */; }; @@ -675,94 +542,55 @@ C33FDD74255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD76255A582000E217F9 /* SSKKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */; }; - C33FDD77255A582000E217F9 /* OWSAddToProfileWhitelistOfferMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBBD255A581600E217F9 /* OWSAddToProfileWhitelistOfferMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD79255A582000E217F9 /* OWSHTTPSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBF255A581700E217F9 /* OWSHTTPSecurityPolicy.m */; }; - C33FDD7A255A582000E217F9 /* OWSRequestFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC0255A581700E217F9 /* OWSRequestFactory.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD7B255A582000E217F9 /* GeneralUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */; }; C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC2255A581700E217F9 /* SSKAsserts.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD7D255A582000E217F9 /* AnyPromise+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC3255A581700E217F9 /* AnyPromise+Conversion.swift */; }; - C33FDD7E255A582000E217F9 /* TypingIndicatorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC4255A581700E217F9 /* TypingIndicatorMessage.swift */; }; - C33FDD82255A582000E217F9 /* OWSFingerprint.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC8255A581700E217F9 /* OWSFingerprint.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */; }; C33FDD84255A582000E217F9 /* LKGroupUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */; }; C33FDD88255A582000E217F9 /* OWSMessageServiceParams.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD89255A582000E217F9 /* OWSFingerprintBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCF255A581800E217F9 /* OWSFingerprintBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD8A255A582000E217F9 /* OnionRequestAPI+Encryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD0255A581800E217F9 /* OnionRequestAPI+Encryption.swift */; }; - C33FDD8B255A582000E217F9 /* DeviceLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD1255A581800E217F9 /* DeviceLink.swift */; }; - C33FDD8C255A582000E217F9 /* OWSUnknownContactBlockOfferMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBD2255A581800E217F9 /* OWSUnknownContactBlockOfferMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */; }; - C33FDD8E255A582000E217F9 /* OWSBatchMessageProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBD4255A581900E217F9 /* OWSBatchMessageProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD8F255A582000E217F9 /* OWSOutgoingSentMessageTranscript.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD5255A581900E217F9 /* OWSOutgoingSentMessageTranscript.m */; }; C33FDD90255A582000E217F9 /* OWSUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */; }; C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */; }; - C33FDD93255A582000E217F9 /* OWSVerificationStateSyncMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBD9255A581900E217F9 /* OWSVerificationStateSyncMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD94255A582000E217F9 /* Dictionary+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDA255A581900E217F9 /* Dictionary+Description.swift */; }; - C33FDD95255A582000E217F9 /* OWSDevicesService.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBDB255A581900E217F9 /* OWSDevicesService.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD96255A582000E217F9 /* ContactDiscoveryService.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDC255A581900E217F9 /* ContactDiscoveryService.m */; }; C33FDD97255A582000E217F9 /* OWSDisappearingMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */; }; C33FDD98255A582000E217F9 /* LokiPushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */; }; - C33FDD99255A582000E217F9 /* LKSyncOpenGroupsMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDF255A581A00E217F9 /* LKSyncOpenGroupsMessage.m */; }; - C33FDD9A255A582000E217F9 /* OWSBlockedPhoneNumbersMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE0255A581A00E217F9 /* OWSBlockedPhoneNumbersMessage.m */; }; C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */; }; - C33FDD9C255A582000E217F9 /* OWSUnknownContactBlockOfferMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE2255A581A00E217F9 /* OWSUnknownContactBlockOfferMessage.m */; }; - C33FDD9D255A582000E217F9 /* CDSSigningCertificate.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBE3255A581A00E217F9 /* CDSSigningCertificate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD9E255A582000E217F9 /* OWSOutgoingSyncMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBE4255A581A00E217F9 /* OWSOutgoingSyncMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD9F255A582000E217F9 /* OWSDevicesService.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE5255A581A00E217F9 /* OWSDevicesService.m */; }; - C33FDDA0255A582000E217F9 /* OWSOutgoingNullMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE6255A581A00E217F9 /* OWSOutgoingNullMessage.m */; }; - C33FDDA1255A582000E217F9 /* NSTimer+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBE7255A581A00E217F9 /* NSTimer+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDA2255A582000E217F9 /* Storage+OnionRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE8255A581A00E217F9 /* Storage+OnionRequests.swift */; }; C33FDDA3255A582000E217F9 /* TSInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE9255A581A00E217F9 /* TSInteraction.m */; }; - C33FDDA4255A582000E217F9 /* SessionRequestMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEA255A581A00E217F9 /* SessionRequestMessage.swift */; }; C33FDDA5255A582000E217F9 /* OWSBlockingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */; }; - C33FDDA7255A582000E217F9 /* ClosedGroupParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBED255A581B00E217F9 /* ClosedGroupParser.swift */; }; - C33FDDA8255A582000E217F9 /* ClosedGroupUpdateMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEE255A581B00E217F9 /* ClosedGroupUpdateMessage.swift */; }; C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDAA255A582000E217F9 /* LokiDatabaseUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */; }; C33FDDAB255A582000E217F9 /* OWSIdentityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDAD255A582000E217F9 /* OWSBlockedPhoneNumbersMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF3255A581B00E217F9 /* OWSBlockedPhoneNumbersMessage.h */; }; C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */; }; - C33FDDAF255A582000E217F9 /* OWSDeviceProvisioningService.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF5255A581B00E217F9 /* OWSDeviceProvisioningService.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB1255A582000E217F9 /* OWSIncompleteCallsJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF7255A581C00E217F9 /* OWSIncompleteCallsJob.m */; }; C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB3255A582000E217F9 /* OWSError.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF9255A581C00E217F9 /* OWSError.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDB4255A582000E217F9 /* PhoneNumberUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBFA255A581C00E217F9 /* PhoneNumberUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB5255A582000E217F9 /* Storage+PublicChats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */; }; C33FDDB7255A582000E217F9 /* OWSPrimaryStorage+Calling.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */; }; C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDB9255A582000E217F9 /* OWSOutgoingSyncMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFF255A581C00E217F9 /* OWSOutgoingSyncMessage.m */; }; - C33FDDBA255A582000E217F9 /* OWSSyncGroupsMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC00255A581C00E217F9 /* OWSSyncGroupsMessage.m */; }; C33FDDBB255A582000E217F9 /* TSGroupThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC01255A581C00E217F9 /* TSGroupThread.m */; }; C33FDDBC255A582000E217F9 /* OWSPrimaryStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */; }; C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC03255A581D00E217F9 /* ByteParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDBE255A582000E217F9 /* DecryptionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC04255A581D00E217F9 /* DecryptionUtilities.swift */; }; C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC06255A581D00E217F9 /* SignalAccount.m */; }; C33FDDC1255A582000E217F9 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */; }; C33FDDC2255A582000E217F9 /* SignalService.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC08255A581D00E217F9 /* SignalService.pb.swift */; }; - C33FDDC3255A582000E217F9 /* AccountServiceClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC09255A581D00E217F9 /* AccountServiceClient.swift */; }; - C33FDDC4255A582000E217F9 /* OWSContact.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0A255A581D00E217F9 /* OWSContact.m */; }; C33FDDC5255A582000E217F9 /* OWSError.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0B255A581D00E217F9 /* OWSError.m */; }; C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */; }; - C33FDDC7255A582000E217F9 /* OWSProvisioningMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC0D255A581E00E217F9 /* OWSProvisioningMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDC9255A582000E217F9 /* LKDeviceLinkMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC0F255A581E00E217F9 /* LKDeviceLinkMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDCA255A582000E217F9 /* ProofOfWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC10255A581E00E217F9 /* ProofOfWork.swift */; }; - C33FDDCB255A582000E217F9 /* TSSocketManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC11255A581E00E217F9 /* TSSocketManager.m */; }; C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC12255A581E00E217F9 /* TSConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDCD255A582000E217F9 /* OWSAttachmentDownloads.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */; }; C33FDDCF255A582000E217F9 /* TSAttachment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC15255A581E00E217F9 /* TSAttachment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC16255A581E00E217F9 /* FunctionalUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDD1255A582000E217F9 /* SharedSenderKeysImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC17255A581F00E217F9 /* SharedSenderKeysImplementation.swift */; }; C33FDDD2255A582000E217F9 /* TSAttachmentPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC19255A581F00E217F9 /* OWSQueues.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */; }; C33FDDD6255A582000E217F9 /* TSCall.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1C255A581F00E217F9 /* TSCall.m */; }; - C33FDDD7255A582000E217F9 /* OWSSyncConfigurationMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1D255A581F00E217F9 /* OWSSyncConfigurationMessage.m */; }; C33FDDD8255A582000E217F9 /* OWSUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */; }; - C33FDDD9255A582000E217F9 /* LokiSessionResetImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1F255A581F00E217F9 /* LokiSessionResetImplementation.swift */; }; + C33FDDD9255A582000E217F9 /* LokiSessionRestorationImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */; }; C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */; }; C3402FE52559036600EA6424 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; }; C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */; }; @@ -804,14 +632,11 @@ C37F54BA255BB2D8002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54CB255BB53F002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54DC255BB84A002AEA92 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; }; - C38EEF0A255B49A8007E1867 /* SSKProtoEnvelope+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EEF09255B49A8007E1867 /* SSKProtoEnvelope+Conversion.swift */; }; - C38EEFD6255B5BA2007E1867 /* OldSnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EEFD5255B5BA2007E1867 /* OldSnodeAPI.swift */; }; + C38EEF0A255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */; }; C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C38EF00E255B61DC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C38EF216255B6D3B007E1867 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF212255B6D3A007E1867 /* Theme.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF217255B6D3B007E1867 /* OWSConversationColor.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF213255B6D3A007E1867 /* OWSConversationColor.m */; }; C38EF218255B6D3B007E1867 /* Theme.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF214255B6D3A007E1867 /* Theme.m */; }; - C38EF219255B6D3B007E1867 /* OWSConversationColor.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF215255B6D3A007E1867 /* OWSConversationColor.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF223255B6D5D007E1867 /* AttachmentSharing.m */; }; C38EF229255B6D5D007E1867 /* SignalAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF224255B6D5D007E1867 /* SignalAttachment.swift */; }; C38EF22A255B6D5D007E1867 /* AttachmentSharing.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF225255B6D5D007E1867 /* AttachmentSharing.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -830,10 +655,6 @@ C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF240255B6D67007E1867 /* UIView+OWS.swift */; }; C38EF24E255B6D67007E1867 /* Collection+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF241255B6D67007E1867 /* Collection+OWS.swift */; }; C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF242255B6D67007E1867 /* UIColor+OWS.m */; }; - C38EF25F255B6D6F007E1867 /* OWSSyncManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF25A255B6D6E007E1867 /* OWSSyncManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF260255B6D6F007E1867 /* OWSContactsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF25B255B6D6E007E1867 /* OWSContactsManager.m */; }; - C38EF261255B6D6F007E1867 /* OWSSyncManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF25C255B6D6E007E1867 /* OWSSyncManager.m */; }; - C38EF262255B6D6F007E1867 /* OWSContactsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF25D255B6D6E007E1867 /* OWSContactsManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF272255B6D7A007E1867 /* OWSResaveCollectionDBMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */; }; C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */; }; C38EF274255B6D7A007E1867 /* OWSResaveCollectionDBMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -860,7 +681,6 @@ C38EF2C4255B6DA6007E1867 /* OWSContactOffersInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2C0255B6DA6007E1867 /* OWSContactOffersInteraction.m */; }; C38EF2C5255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */; }; C38EF2D4255B6DAF007E1867 /* OWSProfileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */; }; - C38EF2D5255B6DAF007E1867 /* ProfileFetcherJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D0255B6DAE007E1867 /* ProfileFetcherJob.swift */; }; C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; C38EF2D7255B6DAF007E1867 /* OWSProfileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF2D8255B6DAF007E1867 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -870,13 +690,9 @@ C38EF30F255B6DBF007E1867 /* AppPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E5255B6DB9007E1867 /* AppPreferences.swift */; }; C38EF310255B6DBF007E1867 /* DebugLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E6255B6DBA007E1867 /* DebugLogger.m */; }; C38EF311255B6DBF007E1867 /* OWSScrubbingLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF312255B6DBF007E1867 /* OWSGroupAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E8255B6DBA007E1867 /* OWSGroupAvatarBuilder.m */; }; C38EF313255B6DBF007E1867 /* OWSUnreadIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF314255B6DBF007E1867 /* OWSAvatarBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2EA255B6DBA007E1867 /* OWSAvatarBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF315255B6DBF007E1867 /* OWSGroupAvatarBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2EB255B6DBA007E1867 /* OWSGroupAvatarBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF316255B6DBF007E1867 /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */; }; C38EF317255B6DBF007E1867 /* DisplayableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2ED255B6DBB007E1867 /* DisplayableText.swift */; }; - C38EF318255B6DBF007E1867 /* OWSAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EE255B6DBB007E1867 /* OWSAvatarBuilder.m */; }; C38EF319255B6DBF007E1867 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EF255B6DBB007E1867 /* Weak.swift */; }; C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */; }; C38EF31B255B6DBF007E1867 /* OWSPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -885,12 +701,10 @@ C38EF320255B6DBF007E1867 /* OWSScrubbingLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */; }; C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */; }; C38EF322255B6DBF007E1867 /* DebugLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F8255B6DBC007E1867 /* DebugLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF323255B6DBF007E1867 /* OWSContactAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F9255B6DBC007E1867 /* OWSContactAvatarBuilder.m */; }; C38EF324255B6DBF007E1867 /* Bench.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FA255B6DBD007E1867 /* Bench.swift */; }; C38EF325255B6DBF007E1867 /* OWSWindowManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF326255B6DBF007E1867 /* ConversationStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */; }; C38EF327255B6DBF007E1867 /* BlockListUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */; }; - C38EF328255B6DBF007E1867 /* OWSContactAvatarBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FE255B6DBD007E1867 /* OWSContactAvatarBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF300255B6DBD007E1867 /* UIUtil.m */; }; C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF301255B6DBD007E1867 /* OWSFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF32D255B6DBF007E1867 /* BlockListUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -903,26 +717,18 @@ C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF30A255B6DBE007E1867 /* UIUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF335255B6DBF007E1867 /* BlockListCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF30B255B6DBE007E1867 /* BlockListCache.swift */; }; C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF33F255B6DC5007E1867 /* SheetViewController.swift */; }; - C38EF35A255B6DCC007E1867 /* ViewControllerUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF340255B6DC5007E1867 /* ViewControllerUtils.m */; }; C38EF35B255B6DCC007E1867 /* SelectThreadViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */; }; C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF343255B6DC5007E1867 /* OWSNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF344255B6DC5007E1867 /* OWSViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF35F255B6DCC007E1867 /* SelectRecipientViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */; }; - C38EF360255B6DCC007E1867 /* ReturnToCallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF346255B6DC6007E1867 /* ReturnToCallViewController.swift */; }; - C38EF361255B6DCC007E1867 /* EditContactShareNameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF347255B6DC6007E1867 /* EditContactShareNameViewController.swift */; }; - C38EF362255B6DCC007E1867 /* ContactShareApprovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF348255B6DC7007E1867 /* ContactShareApprovalViewController.swift */; }; C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */; }; - C38EF364255B6DCC007E1867 /* NewNonContactConversationViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34A255B6DC7007E1867 /* NewNonContactConversationViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF365255B6DCC007E1867 /* OWSTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF34B255B6DC8007E1867 /* OWSTableViewController.m */; }; C38EF366255B6DCC007E1867 /* ScreenLockViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34C255B6DC8007E1867 /* ScreenLockViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF367255B6DCC007E1867 /* OWSTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34D255B6DC8007E1867 /* OWSTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF369255B6DCC007E1867 /* ViewControllerUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34F255B6DC9007E1867 /* ViewControllerUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF36A255B6DCC007E1867 /* NewNonContactConversationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF350255B6DC9007E1867 /* NewNonContactConversationViewController.m */; }; C38EF36B255B6DCC007E1867 /* ScreenLockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF351255B6DC9007E1867 /* ScreenLockViewController.m */; }; C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */; }; C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF36E255B6DCC007E1867 /* ContactFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF354255B6DCB007E1867 /* ContactFieldView.swift */; }; C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF355255B6DCB007E1867 /* OWSViewController.m */; }; C38EF370255B6DCC007E1867 /* OWSNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF356255B6DCB007E1867 /* OWSNavigationController.m */; }; C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */; }; @@ -938,7 +744,6 @@ C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */; }; C38EF39B255B6DDA007E1867 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */; }; C38EF39C255B6DDA007E1867 /* OWSQuotedReplyModel.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF39D255B6DDA007E1867 /* ContactShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF399255B6DD9007E1867 /* ContactShareViewModel.swift */; }; C38EF39E255B6DDA007E1867 /* OWSQuotedReplyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */; }; C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */; }; C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */; }; @@ -960,16 +765,13 @@ C38EF3F0255B6DF7007E1867 /* ThreadViewHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF3F1255B6DF7007E1867 /* OWSSearchBar.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF3F2255B6DF7007E1867 /* DisappearingTimerConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */; }; - C38EF3F3255B6DF7007E1867 /* ContactsViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3D5255B6DEF007E1867 /* ContactsViewHelper.m */; }; C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3D6255B6DEF007E1867 /* ContactCellView.m */; }; C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF3D7255B6DF0007E1867 /* OWSTextField.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF3D8255B6DF0007E1867 /* OWSTextView.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */; }; - C38EF3F8255B6DF7007E1867 /* ContactsViewHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF3DA255B6DF1007E1867 /* ContactsViewHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */; }; C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */; }; C38EF3FB255B6DF7007E1867 /* UIAlertController+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */; }; - C38EF3FC255B6DF7007E1867 /* AvatarImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3DE255B6DF2007E1867 /* AvatarImageView.swift */; }; C38EF3FD255B6DF7007E1867 /* OWSTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3DF255B6DF2007E1867 /* OWSTextView.m */; }; C38EF3FE255B6DF7007E1867 /* OWSTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E0255B6DF3007E1867 /* OWSTextField.m */; }; C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E1255B6DF3007E1867 /* TappableView.swift */; }; @@ -986,7 +788,6 @@ C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */; }; C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */; }; C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EE255B6DF6007E1867 /* GradientView.swift */; }; - C38EF481255B752E007E1867 /* SystemContactsFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF259255B6D6E007E1867 /* SystemContactsFetcher.swift */; }; C38EF48A255B7E3F007E1867 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; }; C396DAEF2518408B00FF6DC5 /* ParsingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAE82518408900FF6DC5 /* ParsingState.swift */; }; C396DAF02518408B00FF6DC5 /* String+Lines.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAE92518408A00FF6DC5 /* String+Lines.swift */; }; @@ -1023,7 +824,7 @@ C3A721902558C0CD0043A11F /* FileServerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7218F2558C0CD0043A11F /* FileServerAPI.swift */; }; C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */; }; C3A7222A2558C1E40043A11F /* DotNetAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A722292558C1E40043A11F /* DotNetAPI.swift */; }; - C3A7225E2558C38D0043A11F /* AnyPromise+Retaining.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7225D2558C38D0043A11F /* AnyPromise+Retaining.swift */; }; + C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */; }; C3A722802558C4E10043A11F /* AttachmentStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7227F2558C4E10043A11F /* AttachmentStream.swift */; }; C3A722922558C8940043A11F /* OpenGroupAPIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */; }; C3A7229C2558E4310043A11F /* OpenGroupMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */; }; @@ -1274,45 +1075,27 @@ 264033E641846B67E0CB21B0 /* Pods-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUtilitiesKit/Pods-SessionUtilitiesKit.debug.xcconfig"; sourceTree = ""; }; 264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalMessaging.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3303495F6651CE2F3CC9693B /* Pods-SessionUtilities.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUtilities.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUtilities/Pods-SessionUtilities.app store release.xcconfig"; sourceTree = ""; }; - 3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactShareButtonsView.m; sourceTree = ""; }; - 3403B95C20EA9527001A1F44 /* OWSContactShareButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactShareButtonsView.h; sourceTree = ""; }; 340FC87B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationSettingsOptionsViewController.m; sourceTree = ""; }; 340FC87C204DAC8C007AEB0F /* NotificationSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationSettingsViewController.m; sourceTree = ""; }; - 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DomainFrontingCountryViewController.m; sourceTree = ""; }; 340FC87E204DAC8C007AEB0F /* PrivacySettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrivacySettingsTableViewController.m; sourceTree = ""; }; 340FC87F204DAC8C007AEB0F /* OWSBackupSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupSettingsViewController.h; sourceTree = ""; }; - 340FC881204DAC8C007AEB0F /* AdvancedSettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdvancedSettingsTableViewController.h; sourceTree = ""; }; 340FC883204DAC8C007AEB0F /* OWSSoundSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSoundSettingsViewController.m; sourceTree = ""; }; 340FC884204DAC8C007AEB0F /* AboutTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutTableViewController.h; sourceTree = ""; }; 340FC886204DAC8C007AEB0F /* AddToBlockListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddToBlockListViewController.m; sourceTree = ""; }; - 340FC887204DAC8C007AEB0F /* BlockListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlockListViewController.m; sourceTree = ""; }; 340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQRCodeScanningViewController.h; sourceTree = ""; }; - 340FC889204DAC8C007AEB0F /* DomainFrontingCountryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DomainFrontingCountryViewController.h; sourceTree = ""; }; 340FC88A204DAC8C007AEB0F /* NotificationSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationSettingsViewController.h; sourceTree = ""; }; 340FC88B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationSettingsOptionsViewController.h; sourceTree = ""; }; - 340FC88C204DAC8C007AEB0F /* AdvancedSettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdvancedSettingsTableViewController.m; sourceTree = ""; }; 340FC88E204DAC8C007AEB0F /* OWSBackupSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupSettingsViewController.m; sourceTree = ""; }; 340FC88F204DAC8C007AEB0F /* PrivacySettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivacySettingsTableViewController.h; sourceTree = ""; }; - 340FC890204DAC8C007AEB0F /* BlockListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockListViewController.h; sourceTree = ""; }; 340FC892204DAC8C007AEB0F /* AddToBlockListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddToBlockListViewController.h; sourceTree = ""; }; 340FC893204DAC8C007AEB0F /* AboutTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutTableViewController.m; sourceTree = ""; }; 340FC894204DAC8C007AEB0F /* OWSSoundSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSoundSettingsViewController.h; sourceTree = ""; }; 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQRCodeScanningViewController.m; sourceTree = ""; }; - 340FC898204DAC8D007AEB0F /* OWSAddToContactViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAddToContactViewController.h; sourceTree = ""; }; 340FC899204DAC8D007AEB0F /* OWSConversationSettingsViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsViewDelegate.h; sourceTree = ""; }; 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSConversationSettingsViewController.m; sourceTree = ""; }; 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddToGroupViewController.m; sourceTree = ""; }; - 340FC89C204DAC8D007AEB0F /* UpdateGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UpdateGroupViewController.m; sourceTree = ""; }; - 340FC89D204DAC8D007AEB0F /* FingerprintViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FingerprintViewController.h; sourceTree = ""; }; - 340FC89E204DAC8D007AEB0F /* ShowGroupMembersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShowGroupMembersViewController.h; sourceTree = ""; }; - 340FC89F204DAC8D007AEB0F /* FingerprintViewScanController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FingerprintViewScanController.m; sourceTree = ""; }; 340FC8A0204DAC8D007AEB0F /* OWSConversationSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsViewController.h; sourceTree = ""; }; - 340FC8A1204DAC8D007AEB0F /* OWSAddToContactViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAddToContactViewController.m; sourceTree = ""; }; - 340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FingerprintViewController.m; sourceTree = ""; }; - 340FC8A3204DAC8D007AEB0F /* UpdateGroupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateGroupViewController.h; sourceTree = ""; }; 340FC8A4204DAC8D007AEB0F /* AddToGroupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddToGroupViewController.h; sourceTree = ""; }; - 340FC8A5204DAC8D007AEB0F /* FingerprintViewScanController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FingerprintViewScanController.h; sourceTree = ""; }; - 340FC8A6204DAC8D007AEB0F /* ShowGroupMembersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShowGroupMembersViewController.m; sourceTree = ""; }; 34129B8521EF8779005457A8 /* LinkPreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkPreviewView.swift; sourceTree = ""; }; 341341ED2187467900192D59 /* ConversationViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversationViewModel.h; sourceTree = ""; }; 341341EE2187467900192D59 /* ConversationViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationViewModel.m; sourceTree = ""; }; @@ -1349,7 +1132,6 @@ 348570A620F67574004FF32B /* OWSMessageHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageHeaderView.m; sourceTree = ""; }; 348570A720F67574004FF32B /* OWSMessageHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageHeaderView.h; sourceTree = ""; }; 3488F9352191CC4000E524CC /* ConversationMediaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConversationMediaView.swift; sourceTree = ""; }; - 348BB25C20A0C5530047AEC2 /* ContactShareViewHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactShareViewHelper.swift; sourceTree = ""; }; 3496744B2076768600080B5F /* OWSMessageBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageBubbleView.h; sourceTree = ""; }; 3496744C2076768700080B5F /* OWSMessageBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageBubbleView.m; sourceTree = ""; }; 3496744E2076ACCE00080B5F /* LongTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongTextViewController.swift; sourceTree = ""; }; @@ -1378,10 +1160,6 @@ 34B0796C1FCF46B000E248C2 /* MainAppContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainAppContext.h; sourceTree = ""; }; 34B0796E1FD07B1E00E248C2 /* SignalShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SignalShareExtension.entitlements; sourceTree = ""; }; 34B3F83B1E8DF1700035BE1A /* CallViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallViewController.swift; sourceTree = ""; }; - 34B3F83E1E8DF1700035BE1A /* ContactsPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsPicker.swift; sourceTree = ""; }; - 34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InviteFlow.swift; sourceTree = ""; }; - 34B3F86D1E8DF1700035BE1A /* SignalsNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalsNavigationController.h; sourceTree = ""; }; - 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalsNavigationController.m; sourceTree = ""; }; 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = ""; }; 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorInteraction.swift; sourceTree = ""; }; 34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorCell.swift; sourceTree = ""; }; @@ -1393,8 +1171,6 @@ 34C4E2552118957600BEA353 /* OWSWebRTCDataProtos.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSWebRTCDataProtos.pb.swift; sourceTree = ""; }; 34C4E2562118957600BEA353 /* WebRTCProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebRTCProto.swift; sourceTree = ""; }; 34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageDetailViewController.swift; sourceTree = ""; }; - 34CA63192097806E00E526A0 /* OWSContactShareView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactShareView.h; sourceTree = ""; }; - 34CA631A2097806E00E526A0 /* OWSContactShareView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactShareView.m; sourceTree = ""; }; 34CF0783203E6B77005C4D61 /* busy_tone_ansi.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = busy_tone_ansi.caf; path = Session/Meta/AudioFiles/busy_tone_ansi.caf; sourceTree = SOURCE_ROOT; }; 34CF0784203E6B77005C4D61 /* ringback_tone_ansi.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ringback_tone_ansi.caf; path = Session/Meta/AudioFiles/ringback_tone_ansi.caf; sourceTree = SOURCE_ROOT; }; 34CF0786203E6B78005C4D61 /* end_call_tone_cept.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = end_call_tone_cept.caf; path = Session/Meta/AudioFiles/end_call_tone_cept.caf; sourceTree = SOURCE_ROOT; }; @@ -1412,8 +1188,6 @@ 34D1F0721F8678AA0066283D /* ConversationViewLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationViewLayout.m; sourceTree = ""; }; 34D1F0961F867BFC0066283D /* ConversationViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversationViewCell.h; sourceTree = ""; }; 34D1F0971F867BFC0066283D /* ConversationViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationViewCell.m; sourceTree = ""; }; - 34D1F09A1F867BFC0066283D /* OWSContactOffersCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactOffersCell.h; sourceTree = ""; }; - 34D1F09B1F867BFC0066283D /* OWSContactOffersCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactOffersCell.m; sourceTree = ""; }; 34D1F0A11F867BFC0066283D /* OWSMessageCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageCell.h; sourceTree = ""; }; 34D1F0A21F867BFC0066283D /* OWSMessageCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageCell.m; sourceTree = ""; }; 34D1F0A51F867BFC0066283D /* OWSSystemMessageCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSystemMessageCell.h; sourceTree = ""; }; @@ -1431,7 +1205,6 @@ 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = ""; }; 34D920E520E179C100D51158 /* OWSMessageFooterView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageFooterView.h; sourceTree = ""; }; 34D920E620E179C200D51158 /* OWSMessageFooterView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageFooterView.m; sourceTree = ""; }; - 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSAnalytics.swift; sourceTree = ""; }; 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = ""; }; 34DBEFFF206BD5A400025978 /* OWSMessageTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageTextView.m; sourceTree = ""; }; 34DBF000206BD5A400025978 /* OWSMessageTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageTextView.h; sourceTree = ""; }; @@ -1440,7 +1213,6 @@ 34DBF005206C3CB100025978 /* OWSBubbleShapeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBubbleShapeView.h; sourceTree = ""; }; 34DBF006206C3CB200025978 /* OWSBubbleShapeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBubbleShapeView.m; sourceTree = ""; }; 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioProgressView.swift; sourceTree = ""; }; - 34E88D252098C5AE00A608F4 /* ContactViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactViewController.swift; sourceTree = ""; }; 34EA693F2194933900702471 /* MediaDownloadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaDownloadView.swift; sourceTree = ""; }; 34EA69412194DE7F00702471 /* MediaUploadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaUploadView.swift; sourceTree = ""; }; 34F308A01ECB469700BB7697 /* OWSBezierPathView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBezierPathView.h; sourceTree = ""; }; @@ -1457,14 +1229,11 @@ 450DF2041E0D74AC003D14BE /* Platform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = ""; }; 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = UserNotificationsAdaptee.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 451166BF1FD86B98000739BA /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = ""; }; - 451764291DE939FD00EDB8B9 /* ContactCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactCell.swift; sourceTree = ""; }; 451A13B01E13DED2000A50FD /* AppNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppNotifications.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldHelper.swift; sourceTree = ""; }; - 452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactShareToExistingContactViewController.swift; sourceTree = ""; }; 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutboundCallInitiator.swift; sourceTree = ""; }; 452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryViewController.swift; sourceTree = ""; }; - 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageFetcherJob.swift; sourceTree = ""; }; 453518681FC635DD00210559 /* SessionShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 4535186A1FC635DD00210559 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; 4535186D1FC635DD00210559 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; @@ -1475,17 +1244,12 @@ 455A16DB1F1FEA0000F86704 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; 455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 4574A5D51DD6704700C6B692 /* CallService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CallService.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 4579431C1E7C8CE9008ED0C0 /* Pastelog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pastelog.h; sourceTree = ""; }; - 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pastelog.m; sourceTree = ""; }; 45794E851E00620000066731 /* CallUIAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallUIAdapter.swift; sourceTree = ""; }; 457F671A20746193000EABCD /* QuotedReplyPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuotedReplyPreview.swift; sourceTree = ""; }; 45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; - 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafetyNumberConfirmationAlert.swift; sourceTree = ""; }; 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerConnectionClient.swift; sourceTree = ""; }; 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioningURLParser.h; sourceTree = ""; }; 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioningURLParser.m; sourceTree = ""; }; - 459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceTableViewCell.h; sourceTree = ""; }; - 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceTableViewCell.m; sourceTree = ""; }; 45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Session/Meta/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; }; 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupTableViewCell.swift; sourceTree = ""; }; 45A6DAD51EBBF85500893231 /* ReminderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReminderView.swift; sourceTree = ""; }; @@ -1525,9 +1289,6 @@ 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Session/Signal/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; }; 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncPushTokensJob.swift; sourceTree = ""; }; 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionResetJob.swift; sourceTree = ""; }; - 45D308AB2049A439000189E4 /* PinEntryView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PinEntryView.h; sourceTree = ""; }; - 45D308AC2049A439000189E4 /* PinEntryView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PinEntryView.m; sourceTree = ""; }; - 45DDA6232090CEB500DE97F8 /* ConversationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationHeaderView.swift; sourceTree = ""; }; 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompareSafetyNumbersActivity.swift; sourceTree = ""; }; 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabel.swift; sourceTree = ""; }; 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = ""; }; @@ -1538,7 +1299,6 @@ 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalCall.swift; sourceTree = ""; }; 4C043929220A9EC800BAEA63 /* VoiceNoteLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceNoteLock.swift; sourceTree = ""; }; 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = ""; }; - 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = ""; }; 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoGridViewCell.swift; sourceTree = ""; }; 4C1D2337218B6BA000A0598F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIAlerts+iOS9.m"; sourceTree = ""; }; @@ -1555,7 +1315,6 @@ 4CA46F4B219CCC630038ABDE /* CaptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptionView.swift; sourceTree = ""; }; 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureViewController.swift; sourceTree = ""; }; 4CB5F26820F7D060004D1B42 /* MessageActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActions.swift; sourceTree = ""; }; - 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationConfigurationSyncOperation.swift; sourceTree = ""; }; 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateNag.swift; sourceTree = ""; }; 4CC613352227A00400E21A3A /* ConversationSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearch.swift; sourceTree = ""; }; @@ -1632,9 +1391,6 @@ B6B226961BE4B7D200860F4D /* ContactsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsUI.framework; path = System/Library/Frameworks/ContactsUI.framework; sourceTree = SDKROOT; }; B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = System/Library/Frameworks/PushKit.framework; sourceTree = SDKROOT; }; B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewClosedGroupVC.swift; sourceTree = ""; }; - B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinksVC.swift; sourceTree = ""; }; - B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceNameModal.swift; sourceTree = ""; }; - B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceNameModalDelegate.swift; sourceTree = ""; }; B82B40872399EB0E00A248E7 /* LandingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandingVC.swift; sourceTree = ""; }; B82B40892399EC0600A248E7 /* FakeChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeChatView.swift; sourceTree = ""; }; B82B408B239A068800A248E7 /* RegisterVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterVC.swift; sourceTree = ""; }; @@ -1656,13 +1412,11 @@ B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; B879D448247E1BE300DB3608 /* PathVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathVC.swift; sourceTree = ""; }; B879D44A247E1D9200DB3608 /* PathStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathStatusView.swift; sourceTree = ""; }; - B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModal.swift; sourceTree = ""; }; B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraints.swift"; sourceTree = ""; }; B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = ""; }; B886B4A82398BA1500211ABE /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = ""; }; B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMembersVC.swift; sourceTree = ""; }; B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeWrapperVC.swift; sourceTree = ""; }; - B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModalDelegate.swift; sourceTree = ""; }; B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = ""; }; B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionCandidateSelectionView.swift; sourceTree = ""; }; B8B5BCEB2394D869003823C9 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; @@ -1675,6 +1429,9 @@ B8BB82B423947F2D00BA5194 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; B8BB82B82394911B00BA5194 /* Separator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Separator.swift; sourceTree = ""; }; B8BB82BD2394D4CE00BA5194 /* Fonts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; + B8C2B2C72563685C00551B4D /* CircleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleView.swift; sourceTree = ""; }; + B8C2B331256376F000551B4D /* ThreadUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ThreadUtil.m; sourceTree = ""; }; + B8C2B33B2563770800551B4D /* ThreadUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadUtil.h; sourceTree = ""; }; B8C9689023FA1401005F64E0 /* AppMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMode.swift; sourceTree = ""; }; B8CCF6342396005F0091D419 /* SpaceMono-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SpaceMono-Regular.ttf"; sourceTree = ""; }; B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPrivateChatVC.swift; sourceTree = ""; }; @@ -1713,14 +1470,12 @@ C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignalUtilitiesKit.h; sourceTree = ""; }; C33FD9AE255A548A00E217F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C33FDA66255A57F900E217F9 /* OWSOutgoingCallMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingCallMessage.h; sourceTree = ""; }; C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPrimaryStorage.h; sourceTree = ""; }; C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBlockingManager.m; sourceTree = ""; }; C33FDA69255A57F900E217F9 /* SSKPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKPreferences.swift; sourceTree = ""; }; C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingConfigurationUpdateInfoMessage.m; sourceTree = ""; }; C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoUtils.m; sourceTree = ""; }; C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "YapDatabase+Promise.swift"; sourceTree = ""; }; - C33FDA6E255A57FA00E217F9 /* Array+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Description.swift"; sourceTree = ""; }; C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityManager.swift; sourceTree = ""; }; C33FDA70255A57FA00E217F9 /* TSMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSMessage.h; sourceTree = ""; }; C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSReadReceiptManager.m; sourceTree = ""; }; @@ -1728,70 +1483,43 @@ C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ECKeyPair+Hexadecimal.swift"; sourceTree = ""; }; C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupsProtocol.swift; sourceTree = ""; }; C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSyncManagerProtocol.h; sourceTree = ""; }; - C33FDA76255A57FB00E217F9 /* OWSSyncGroupsRequestMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSyncGroupsRequestMessage.m; sourceTree = ""; }; - C33FDA77255A57FB00E217F9 /* Contact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Contact.m; sourceTree = ""; }; - C33FDA78255A57FB00E217F9 /* SSKWebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKWebSocket.swift; sourceTree = ""; }; C33FDA79255A57FB00E217F9 /* TSGroupThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSGroupThread.h; sourceTree = ""; }; C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+SSK.swift"; sourceTree = ""; }; C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeyReceivingErrorMessage.h; sourceTree = ""; }; C33FDA7C255A57FB00E217F9 /* Debugging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Debugging.swift; sourceTree = ""; }; - C33FDA7D255A57FB00E217F9 /* OWSCensorshipConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSCensorshipConfiguration.m; sourceTree = ""; }; C33FDA7E255A57FB00E217F9 /* Mention.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mention.swift; sourceTree = ""; }; C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecordTranscriptJob.m; sourceTree = ""; }; C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingMessagesJob.h; sourceTree = ""; }; C33FDA81255A57FC00E217F9 /* MentionsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MentionsManager.swift; sourceTree = ""; }; - C33FDA83255A57FC00E217F9 /* Promise+retainUntilComplete.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+retainUntilComplete.swift"; sourceTree = ""; }; - C33FDA84255A57FC00E217F9 /* ContactsUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsUpdater.m; sourceTree = ""; }; C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OWSPrimaryStorage+Loki.swift"; sourceTree = ""; }; C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesFinder.m; sourceTree = ""; }; C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicators.swift; sourceTree = ""; }; C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseTransaction+OWS.h"; sourceTree = ""; }; - C33FDA89255A57FD00E217F9 /* OWSAnalytics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAnalytics.m; sourceTree = ""; }; - C33FDA8A255A57FD00E217F9 /* PhoneNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhoneNumber.m; sourceTree = ""; }; C33FDA8B255A57FD00E217F9 /* AppVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppVersion.m; sourceTree = ""; }; C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicChatPoller.swift; sourceTree = ""; }; - C33FDA8D255A57FD00E217F9 /* OWSReceiptsForSenderMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSReceiptsForSenderMessage.h; sourceTree = ""; }; C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFileSystem.m; sourceTree = ""; }; - C33FDA8F255A57FD00E217F9 /* NSTimer+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+OWS.m"; sourceTree = ""; }; C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSYapDatabaseObject.m; sourceTree = ""; }; - C33FDA91255A57FD00E217F9 /* LKSyncOpenGroupsMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKSyncOpenGroupsMessage.h; sourceTree = ""; }; C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Streaming.swift"; sourceTree = ""; }; C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSChunkedOutputStream.h; sourceTree = ""; }; C33FDA96255A57FE00E217F9 /* OWSDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDispatch.h; sourceTree = ""; }; C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSIncomingMessage.m; sourceTree = ""; }; C33FDA98255A57FE00E217F9 /* RotateSignedKeyOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotateSignedKeyOperation.swift; sourceTree = ""; }; C33FDA99255A57FE00E217F9 /* OutageDetection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutageDetection.swift; sourceTree = ""; }; - C33FDA9A255A57FE00E217F9 /* OWSLinkedDeviceReadReceipt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSLinkedDeviceReadReceipt.m; sourceTree = ""; }; - C33FDA9B255A57FE00E217F9 /* OWSProvisioningMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProvisioningMessage.m; sourceTree = ""; }; - C33FDA9C255A57FE00E217F9 /* OWSSyncContactsMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSyncContactsMessage.m; sourceTree = ""; }; C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsOutputStream.h; sourceTree = ""; }; C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseDispatchQueue.swift; sourceTree = ""; }; - C33FDA9F255A57FF00E217F9 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSRecipientIdentity.h; sourceTree = ""; }; C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSYapDatabaseObject.h; sourceTree = ""; }; - C33FDAA2255A57FF00E217F9 /* OWSAddToContactsOfferMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAddToContactsOfferMessage.m; sourceTree = ""; }; - C33FDAA3255A57FF00E217F9 /* OWSAddToContactsOfferMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAddToContactsOfferMessage.h; sourceTree = ""; }; C33FDAA4255A57FF00E217F9 /* SSKProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKProto.swift; sourceTree = ""; }; - C33FDAA5255A57FF00E217F9 /* OWSRequestMaker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSRequestMaker.swift; sourceTree = ""; }; - C33FDAA6255A57FF00E217F9 /* OWSLinkedDeviceReadReceipt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkedDeviceReadReceipt.h; sourceTree = ""; }; C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+SignedPreKeyStore.h"; sourceTree = ""; }; C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = ""; }; - C33FDAA9255A580000E217F9 /* Mnemonic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = ""; }; C33FDAAA255A580000E217F9 /* NSObject+Casting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Casting.m"; sourceTree = ""; }; - C33FDAAB255A580000E217F9 /* OWSWebSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSWebSocket.m; sourceTree = ""; }; - C33FDAAD255A580000E217F9 /* OWSDeviceProvisioner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioner.h; sourceTree = ""; }; - C33FDAAE255A580000E217F9 /* OWSReceiptsForSenderMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSReceiptsForSenderMessage.m; sourceTree = ""; }; C33FDAAF255A580000E217F9 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = ""; }; C33FDAB0255A580000E217F9 /* ProvisioningProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProvisioningProto.swift; sourceTree = ""; }; C33FDAB1255A580000E217F9 /* OWSStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSStorage.m; sourceTree = ""; }; - C33FDAB2255A580000E217F9 /* TSNetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSNetworkManager.m; sourceTree = ""; }; C33FDAB3255A580000E217F9 /* TSContactThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSContactThread.h; sourceTree = ""; }; - C33FDAB5255A580000E217F9 /* TSNetworkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSNetworkManager.h; sourceTree = ""; }; - C33FDAB6255A580100E217F9 /* SyncMessagesProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncMessagesProtocol.swift; sourceTree = ""; }; C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFailedMessagesJob.m; sourceTree = ""; }; C33FDAB8255A580100E217F9 /* NSArray+Functional.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Functional.m"; sourceTree = ""; }; C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSStorage+Subclass.h"; sourceTree = ""; }; - C33FDABA255A580100E217F9 /* OWSWebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSWebSocket.h; sourceTree = ""; }; C33FDABB255A580100E217F9 /* OWSGroupsOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSGroupsOutputStream.h; sourceTree = ""; }; C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingReceiptManager.h; sourceTree = ""; }; C33FDABE255A580100E217F9 /* TSConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSConstants.m; sourceTree = ""; }; @@ -1800,24 +1528,11 @@ C33FDAC2255A580200E217F9 /* TSAttachment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachment.m; sourceTree = ""; }; C33FDAC3255A580200E217F9 /* OWSDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDispatch.m; sourceTree = ""; }; C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentStream.m; sourceTree = ""; }; - C33FDAC5255A580200E217F9 /* OWSCountryMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSCountryMetadata.m; sourceTree = ""; }; C33FDAC6255A580200E217F9 /* Fingerprint.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fingerprint.pb.swift; sourceTree = ""; }; - C33FDAC7255A580200E217F9 /* OWSSignalService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSignalService.h; sourceTree = ""; }; - C33FDAC8255A580200E217F9 /* OWSCensorshipConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCensorshipConfiguration.h; sourceTree = ""; }; - C33FDAC9255A580200E217F9 /* OWSContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContact.h; sourceTree = ""; }; - C33FDACA255A580200E217F9 /* LokiMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiMessage.swift; sourceTree = ""; }; - C33FDACB255A580200E217F9 /* CDSSigningCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDSSigningCertificate.m; sourceTree = ""; }; C33FDACD255A580200E217F9 /* SSKJobRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKJobRecord.m; sourceTree = ""; }; - C33FDACE255A580300E217F9 /* OWSVerificationStateSyncMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSVerificationStateSyncMessage.m; sourceTree = ""; }; C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAttachmentDownloads.h; sourceTree = ""; }; - C33FDAD0255A580300E217F9 /* CDSQuote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDSQuote.m; sourceTree = ""; }; - C33FDAD1255A580300E217F9 /* OWSDynamicOutgoingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDynamicOutgoingMessage.m; sourceTree = ""; }; - C33FDAD2255A580300E217F9 /* Contact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Contact.h; sourceTree = ""; }; C33FDAD3255A580300E217F9 /* TSThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSThread.h; sourceTree = ""; }; - C33FDAD4255A580300E217F9 /* EncryptionUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncryptionUtilities.swift; sourceTree = ""; }; C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSQuotedMessage.h; sourceTree = ""; }; - C33FDAD6255A580300E217F9 /* OWSAnalytics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAnalytics.h; sourceTree = ""; }; - C33FDAD7255A580300E217F9 /* OWSDeviceProvisioner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioner.m; sourceTree = ""; }; C33FDAD8255A580300E217F9 /* OWSGroupsOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSGroupsOutputStream.m; sourceTree = ""; }; C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingMessagesConfiguration.h; sourceTree = ""; }; C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingConfigurationUpdateInfoMessage.h; sourceTree = ""; }; @@ -1828,95 +1543,63 @@ C33FDADF255A580400E217F9 /* PublicChatManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicChatManager.swift; sourceTree = ""; }; C33FDAE0255A580400E217F9 /* ByteParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ByteParser.m; sourceTree = ""; }; C33FDAE1255A580400E217F9 /* OWSReadTracking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSReadTracking.h; sourceTree = ""; }; - C33FDAE2255A580400E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSReadReceiptsForLinkedDevicesMessage.h; sourceTree = ""; }; C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAttachmentStream.h; sourceTree = ""; }; - C33FDAE5255A580400E217F9 /* OWSAddToProfileWhitelistOfferMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAddToProfileWhitelistOfferMessage.m; sourceTree = ""; }; C33FDAE6255A580400E217F9 /* TSInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInteraction.h; sourceTree = ""; }; C33FDAE7255A580500E217F9 /* TSErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSErrorMessage.m; sourceTree = ""; }; C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageUtils.h; sourceTree = ""; }; C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKMessageSenderJobRecord.m; sourceTree = ""; }; C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupFragment.h; sourceTree = ""; }; - C33FDAEB255A580500E217F9 /* OWSDeviceProvisioningCodeService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioningCodeService.m; sourceTree = ""; }; C33FDAEC255A580500E217F9 /* SignalRecipient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalRecipient.h; sourceTree = ""; }; C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKMessageSenderJobRecord.h; sourceTree = ""; }; - C33FDAEE255A580500E217F9 /* OWSFingerprintBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFingerprintBuilder.m; sourceTree = ""; }; C33FDAEF255A580500E217F9 /* NSData+Image.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Image.m"; sourceTree = ""; }; - C33FDAF0255A580500E217F9 /* ContactsUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsUpdater.h; sourceTree = ""; }; C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSThumbnailService.swift; sourceTree = ""; }; C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxiedContentDownloader.swift; sourceTree = ""; }; C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+SessionStore.m"; sourceTree = ""; }; C33FDAF4255A580600E217F9 /* SSKEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKEnvironment.m; sourceTree = ""; }; - C33FDAF5255A580600E217F9 /* OWSAnalyticsEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAnalyticsEvents.h; sourceTree = ""; }; - C33FDAF6255A580600E217F9 /* OWSIncomingSentMessageTranscript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIncomingSentMessageTranscript.h; sourceTree = ""; }; C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+SignedPreKeyStore.m"; sourceTree = ""; }; - C33FDAF8255A580600E217F9 /* OWSSyncGroupsRequestMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSyncGroupsRequestMessage.h; sourceTree = ""; }; C33FDAF9255A580600E217F9 /* TSContactThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSContactThread.m; sourceTree = ""; }; - C33FDAFA255A580600E217F9 /* LKDeviceLinkMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKDeviceLinkMessage.m; sourceTree = ""; }; C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionMetaProtocol.swift; sourceTree = ""; }; C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIMETypeUtil.h; sourceTree = ""; }; C33FDAFD255A580600E217F9 /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = ""; }; C33FDAFE255A580600E217F9 /* OWSStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSStorage.h; sourceTree = ""; }; C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayNameUtilities.swift; sourceTree = ""; }; - C33FDB00255A580600E217F9 /* OWSRequestBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRequestBuilder.m; sourceTree = ""; }; C33FDB01255A580700E217F9 /* AppReadiness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppReadiness.h; sourceTree = ""; }; C33FDB02255A580700E217F9 /* TSCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSCall.h; sourceTree = ""; }; C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+SessionStore.h"; sourceTree = ""; }; - C33FDB05255A580700E217F9 /* OWSFingerprint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFingerprint.m; sourceTree = ""; }; - C33FDB06255A580700E217F9 /* OWSRequestBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSRequestBuilder.h; sourceTree = ""; }; C33FDB07255A580700E217F9 /* OWSBackupFragment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupFragment.m; sourceTree = ""; }; - C33FDB08255A580700E217F9 /* OWSProfileKeyMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProfileKeyMessage.h; sourceTree = ""; }; C33FDB09255A580700E217F9 /* NSError+MessageSending.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+MessageSending.m"; sourceTree = ""; }; C33FDB0A255A580700E217F9 /* TSGroupModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSGroupModel.h; sourceTree = ""; }; - C33FDB0B255A580700E217F9 /* OWSVerificationStateChangeMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSVerificationStateChangeMessage.m; sourceTree = ""; }; - C33FDB0C255A580700E217F9 /* CDSQuote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSQuote.h; sourceTree = ""; }; C33FDB0D255A580800E217F9 /* NSArray+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+OWS.m"; sourceTree = ""; }; C33FDB0E255A580800E217F9 /* NSError+MessageSending.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+MessageSending.h"; sourceTree = ""; }; - C33FDB0F255A580800E217F9 /* DeviceLinkingSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkingSession.swift; sourceTree = ""; }; - C33FDB10255A580800E217F9 /* OWSBatchMessageProcessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBatchMessageProcessor.m; sourceTree = ""; }; C33FDB12255A580800E217F9 /* NSString+SSK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SSK.h"; sourceTree = ""; }; - C33FDB13255A580800E217F9 /* LKUnlinkDeviceMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKUnlinkDeviceMessage.m; sourceTree = ""; }; C33FDB14255A580800E217F9 /* OWSMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMath.h; sourceTree = ""; }; - C33FDB16255A580800E217F9 /* OWSDisappearingMessagesConfigurationMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingMessagesConfigurationMessage.h; sourceTree = ""; }; C33FDB17255A580800E217F9 /* FunctionalUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FunctionalUtil.m; sourceTree = ""; }; - C33FDB18255A580800E217F9 /* OWSSignalService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSignalService.m; sourceTree = ""; }; C33FDB19255A580900E217F9 /* GroupUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupUtilities.swift; sourceTree = ""; }; C33FDB1A255A580900E217F9 /* OWSPrimaryStorage+Calling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+Calling.h"; sourceTree = ""; }; - C33FDB1B255A580900E217F9 /* OWSDeviceProvisioningCodeService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioningCodeService.h; sourceTree = ""; }; C33FDB1C255A580900E217F9 /* UIImage+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+OWS.h"; sourceTree = ""; }; C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSReadReceiptManager.h; sourceTree = ""; }; C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIncomingMessageFinder.m; sourceTree = ""; }; - C33FDB1F255A580900E217F9 /* DeviceLinkingUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkingUtilities.swift; sourceTree = ""; }; C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseSecondaryIndexes.m; sourceTree = ""; }; - C33FDB21255A580900E217F9 /* OWS2FAManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS2FAManager.h; sourceTree = ""; }; C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMediaUtils.swift; sourceTree = ""; }; - C33FDB24255A580900E217F9 /* OWSOutgoingSentMessageTranscript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingSentMessageTranscript.h; sourceTree = ""; }; C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseSecondaryIndexes.h; sourceTree = ""; }; C33FDB26255A580A00E217F9 /* FingerprintProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FingerprintProto.swift; sourceTree = ""; }; - C33FDB27255A580A00E217F9 /* OWSEndSessionMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSEndSessionMessage.m; sourceTree = ""; }; - C33FDB28255A580A00E217F9 /* OWSOutgoingCallMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingCallMessage.m; sourceTree = ""; }; C33FDB29255A580A00E217F9 /* NSData+Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Image.h"; sourceTree = ""; }; C33FDB2A255A580A00E217F9 /* OWSIncompleteCallsJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIncompleteCallsJob.h; sourceTree = ""; }; C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProvisioningCipher.m; sourceTree = ""; }; C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseView.h; sourceTree = ""; }; - C33FDB2D255A580A00E217F9 /* OWSDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDevice.h; sourceTree = ""; }; - C33FDB2E255A580A00E217F9 /* OWSEndSessionMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSEndSessionMessage.h; sourceTree = ""; }; C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsManagerProtocol.h; sourceTree = ""; }; - C33FDB30255A580A00E217F9 /* OWSDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDevice.m; sourceTree = ""; }; C33FDB31255A580A00E217F9 /* SSKEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKEnvironment.h; sourceTree = ""; }; C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKIncrementingIdFinder.swift; sourceTree = ""; }; C33FDB33255A580B00E217F9 /* Provisioning.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Provisioning.pb.swift; sourceTree = ""; }; C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupPoller.swift; sourceTree = ""; }; - C33FDB35255A580B00E217F9 /* OWSContactDiscoveryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSContactDiscoveryOperation.swift; sourceTree = ""; }; C33FDB36255A580B00E217F9 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+SnodeAPI.swift"; sourceTree = ""; }; C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackgroundTask.h; sourceTree = ""; }; C33FDB3A255A580B00E217F9 /* Poller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poller.swift; sourceTree = ""; }; C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OWS.h"; sourceTree = ""; }; - C33FDB3D255A580B00E217F9 /* OWSProfileKeyMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProfileKeyMessage.m; sourceTree = ""; }; C33FDB3F255A580C00E217F9 /* String+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SSK.swift"; sourceTree = ""; }; C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOSProto.swift; sourceTree = ""; }; C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIMETypeUtil.m; sourceTree = ""; }; - C33FDB42255A580C00E217F9 /* OWSCountryMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCountryMetadata.h; sourceTree = ""; }; C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YapDatabaseConnection+OWS.m"; sourceTree = ""; }; C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsOutputStream.m; sourceTree = ""; }; C33FDB45255A580C00E217F9 /* NSString+SSK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SSK.m"; sourceTree = ""; }; @@ -1924,7 +1607,6 @@ C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+PreKeyStore.h"; sourceTree = ""; }; C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSOutgoingMessage.h; sourceTree = ""; }; C33FDB49255A580C00E217F9 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = ""; }; - C33FDB4A255A580C00E217F9 /* SignalServiceClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalServiceClient.swift; sourceTree = ""; }; C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSChunkedOutputStream.m; sourceTree = ""; }; C33FDB4C255A580D00E217F9 /* AppVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppVersion.h; sourceTree = ""; }; C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKJobRecord.h; sourceTree = ""; }; @@ -1935,22 +1617,16 @@ C33FDB54255A580D00E217F9 /* DataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataSource.h; sourceTree = ""; }; C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeySendingErrorMessage.m; sourceTree = ""; }; C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSOutgoingMessage.m; sourceTree = ""; }; - C33FDB57255A580D00E217F9 /* OWSSyncContactsMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSyncContactsMessage.h; sourceTree = ""; }; C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+Loki.m"; sourceTree = ""; }; C33FDB59255A580E00E217F9 /* OWSFailedAttachmentDownloadsJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFailedAttachmentDownloadsJob.m; sourceTree = ""; }; C33FDB5A255A580E00E217F9 /* OWSUDManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSUDManager.swift; sourceTree = ""; }; C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YapDatabaseTransaction+OWS.m"; sourceTree = ""; }; C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Functional.h"; sourceTree = ""; }; C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSErrorMessage_privateConstructor.h; sourceTree = ""; }; - C33FDB5E255A580E00E217F9 /* ContactParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactParser.swift; sourceTree = ""; }; C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseConnection+OWS.h"; sourceTree = ""; }; C33FDB60255A580E00E217F9 /* TSMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessage.m; sourceTree = ""; }; - C33FDB61255A580E00E217F9 /* LKUnlinkDeviceMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKUnlinkDeviceMessage.h; sourceTree = ""; }; C33FDB62255A580E00E217F9 /* OWSProvisioningCipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProvisioningCipher.h; sourceTree = ""; }; - C33FDB63255A580E00E217F9 /* OWSDynamicOutgoingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDynamicOutgoingMessage.h; sourceTree = ""; }; C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreKeyRefreshOperation.swift; sourceTree = ""; }; - C33FDB65255A580F00E217F9 /* OWSSyncConfigurationMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSyncConfigurationMessage.h; sourceTree = ""; }; - C33FDB66255A580F00E217F9 /* ContactDiscoveryService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDiscoveryService.h; sourceTree = ""; }; C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMediaGalleryFinder.h; sourceTree = ""; }; C33FDB68255A580F00E217F9 /* ContentProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentProxy.swift; sourceTree = ""; }; C33FDB69255A580F00E217F9 /* FeatureFlags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = ""; }; @@ -1958,55 +1634,37 @@ C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LKUserDefaults.swift; sourceTree = ""; }; C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNotificationCenter+OWS.m"; sourceTree = ""; }; C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSPreKeyManager.h; sourceTree = ""; }; - C33FDB6E255A580F00E217F9 /* SSKProtoPrekeyBundleMessage+Loki.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SSKProtoPrekeyBundleMessage+Loki.swift"; sourceTree = ""; }; C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingReceiptManager.m; sourceTree = ""; }; C33FDB70255A580F00E217F9 /* OWSMessageServiceParams.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageServiceParams.m; sourceTree = ""; }; C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMediaGalleryFinder.m; sourceTree = ""; }; - C33FDB72255A581000E217F9 /* DeviceLinkIndex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkIndex.swift; sourceTree = ""; }; C33FDB73255A581000E217F9 /* TSGroupModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSGroupModel.m; sourceTree = ""; }; C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyErrorMessage.m; sourceTree = ""; }; C33FDB75255A581000E217F9 /* AppReadiness.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppReadiness.m; sourceTree = ""; }; - C33FDB76255A581000E217F9 /* ClosedGroupUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupUtilities.swift; sourceTree = ""; }; C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSUserDefaults+OWS.m"; sourceTree = ""; }; C33FDB78255A581000E217F9 /* OWSOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOperation.m; sourceTree = ""; }; - C33FDB79255A581000E217F9 /* PhoneNumberUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhoneNumberUtil.m; sourceTree = ""; }; C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationsProtocol.h; sourceTree = ""; }; - C33FDB7C255A581000E217F9 /* OWSVerificationStateChangeMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSVerificationStateChangeMessage.h; sourceTree = ""; }; C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSPreKeyManager.m; sourceTree = ""; }; C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullTextSearchFinder.swift; sourceTree = ""; }; C33FDB80255A581100E217F9 /* Notification+Loki.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Notification+Loki.swift"; sourceTree = ""; }; C33FDB81255A581100E217F9 /* UIImage+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+OWS.m"; sourceTree = ""; }; - C33FDB82255A581100E217F9 /* MessageWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageWrapper.swift; sourceTree = ""; }; C33FDB83255A581100E217F9 /* TSQuotedMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSQuotedMessage.m; sourceTree = ""; }; - C33FDB84255A581100E217F9 /* OWSIncomingSentMessageTranscript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIncomingSentMessageTranscript.m; sourceTree = ""; }; C33FDB85255A581100E217F9 /* AppContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppContext.m; sourceTree = ""; }; - C33FDB86255A581100E217F9 /* OWSRequestFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRequestFactory.m; sourceTree = ""; }; C33FDB87255A581100E217F9 /* JobQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JobQueue.swift; sourceTree = ""; }; C33FDB88255A581200E217F9 /* TSAccountManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAccountManager.m; sourceTree = ""; }; - C33FDB89255A581200E217F9 /* FileServerAPI+Deprecated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FileServerAPI+Deprecated.swift"; sourceTree = ""; }; C33FDB8A255A581200E217F9 /* AppContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppContext.h; sourceTree = ""; }; C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+SessionManagement.swift"; sourceTree = ""; }; C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeyErrorMessage.h; sourceTree = ""; }; - C33FDB8D255A581200E217F9 /* DeviceLinkingSessionDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkingSessionDelegate.swift; sourceTree = ""; }; - C33FDB8E255A581200E217F9 /* OWSContact+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSContact+Private.h"; sourceTree = ""; }; C33FDB8F255A581200E217F9 /* ParamParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParamParser.swift; sourceTree = ""; }; C33FDB91255A581200E217F9 /* ProtoUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProtoUtils.h; sourceTree = ""; }; - C33FDB92255A581200E217F9 /* OWSDeviceProvisioningService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioningService.m; sourceTree = ""; }; C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PreKeyBundle+jsonDict.m"; sourceTree = ""; }; C33FDB94255A581300E217F9 /* TSAccountManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAccountManager.h; sourceTree = ""; }; C33FDB95255A581300E217F9 /* Storage+Collections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+Collections.swift"; sourceTree = ""; }; - C33FDB96255A581300E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSReadReceiptsForLinkedDevicesMessage.m; sourceTree = ""; }; - C33FDB97255A581300E217F9 /* OWSDisappearingMessagesConfigurationMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesConfigurationMessage.m; sourceTree = ""; }; - C33FDB98255A581300E217F9 /* DeviceNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceNames.swift; sourceTree = ""; }; C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+keyFromIntLong.m"; sourceTree = ""; }; - C33FDB9A255A581300E217F9 /* OWS2FAManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FAManager.m; sourceTree = ""; }; C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSIncomingMessage.h; sourceTree = ""; }; C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCallMessageHandler.h; sourceTree = ""; }; C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentPointer.m; sourceTree = ""; }; - C33FDB9F255A581400E217F9 /* TTLUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TTLUtilities.swift; sourceTree = ""; }; C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageHeaders.h; sourceTree = ""; }; C33FDBA1255A581400E217F9 /* OWSOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOperation.h; sourceTree = ""; }; - C33FDBA2255A581400E217F9 /* PhoneNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhoneNumber.h; sourceTree = ""; }; C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionManagementProtocol.swift; sourceTree = ""; }; C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesConfiguration.m; sourceTree = ""; }; C33FDBA5255A581400E217F9 /* SignalServiceProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalServiceProfile.swift; sourceTree = ""; }; @@ -2014,15 +1672,10 @@ C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSLinkPreview.swift; sourceTree = ""; }; C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIdentityManager.m; sourceTree = ""; }; C33FDBAB255A581500E217F9 /* OWSFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSFileSystem.h; sourceTree = ""; }; - C33FDBAC255A581500E217F9 /* Data+SecureRandom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+SecureRandom.swift"; sourceTree = ""; }; C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSRecordTranscriptJob.h; sourceTree = ""; }; C33FDBAE255A581500E217F9 /* SignalAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalAccount.h; sourceTree = ""; }; - C33FDBAF255A581500E217F9 /* OWSAnalyticsEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAnalyticsEvents.m; sourceTree = ""; }; C33FDBB0255A581500E217F9 /* TSErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSErrorMessage.h; sourceTree = ""; }; - C33FDBB1255A581500E217F9 /* TSSocketManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSSocketManager.h; sourceTree = ""; }; - C33FDBB3255A581500E217F9 /* OWSOutgoingNullMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingNullMessage.h; sourceTree = ""; }; C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLSessionDataTask+StatusCode.m"; sourceTree = ""; }; - C33FDBB5255A581600E217F9 /* OWSSyncGroupsMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSyncGroupsMessage.h; sourceTree = ""; }; C33FDBB6255A581600E217F9 /* DataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataSource.m; sourceTree = ""; }; C33FDBB7255A581600E217F9 /* SignalRecipient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalRecipient.m; sourceTree = ""; }; C33FDBB8255A581600E217F9 /* TSThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSThread.m; sourceTree = ""; }; @@ -2030,94 +1683,55 @@ C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+keyFromIntLong.h"; sourceTree = ""; }; C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+Loki.h"; sourceTree = ""; }; C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKKeychainStorage.swift; sourceTree = ""; }; - C33FDBBD255A581600E217F9 /* OWSAddToProfileWhitelistOfferMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAddToProfileWhitelistOfferMessage.h; sourceTree = ""; }; C33FDBBF255A581700E217F9 /* OWSHTTPSecurityPolicy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSHTTPSecurityPolicy.m; sourceTree = ""; }; - C33FDBC0255A581700E217F9 /* OWSRequestFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSRequestFactory.h; sourceTree = ""; }; C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralUtilities.swift; sourceTree = ""; }; C33FDBC2255A581700E217F9 /* SSKAsserts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKAsserts.h; sourceTree = ""; }; - C33FDBC3255A581700E217F9 /* AnyPromise+Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AnyPromise+Conversion.swift"; sourceTree = ""; }; - C33FDBC4255A581700E217F9 /* TypingIndicatorMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorMessage.swift; sourceTree = ""; }; - C33FDBC8255A581700E217F9 /* OWSFingerprint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSFingerprint.h; sourceTree = ""; }; C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreatePreKeysOperation.swift; sourceTree = ""; }; C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKGroupUtilities.h; sourceTree = ""; }; C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyReceivingErrorMessage.m; sourceTree = ""; }; C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageServiceParams.h; sourceTree = ""; }; - C33FDBCF255A581800E217F9 /* OWSFingerprintBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSFingerprintBuilder.h; sourceTree = ""; }; - C33FDBD0255A581800E217F9 /* OnionRequestAPI+Encryption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OnionRequestAPI+Encryption.swift"; sourceTree = ""; }; - C33FDBD1255A581800E217F9 /* DeviceLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLink.swift; sourceTree = ""; }; - C33FDBD2255A581800E217F9 /* OWSUnknownContactBlockOfferMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSUnknownContactBlockOfferMessage.h; sourceTree = ""; }; C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSSignalAddress.swift; sourceTree = ""; }; - C33FDBD4255A581900E217F9 /* OWSBatchMessageProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBatchMessageProcessor.h; sourceTree = ""; }; - C33FDBD5255A581900E217F9 /* OWSOutgoingSentMessageTranscript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingSentMessageTranscript.m; sourceTree = ""; }; C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSUploadOperation.h; sourceTree = ""; }; C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageUtils.m; sourceTree = ""; }; C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOS.pb.swift; sourceTree = ""; }; - C33FDBD9255A581900E217F9 /* OWSVerificationStateSyncMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSVerificationStateSyncMessage.h; sourceTree = ""; }; C33FDBDA255A581900E217F9 /* Dictionary+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Description.swift"; sourceTree = ""; }; - C33FDBDB255A581900E217F9 /* OWSDevicesService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDevicesService.h; sourceTree = ""; }; - C33FDBDC255A581900E217F9 /* ContactDiscoveryService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactDiscoveryService.m; sourceTree = ""; }; C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesJob.m; sourceTree = ""; }; C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiPushNotificationManager.swift; sourceTree = ""; }; - C33FDBDF255A581A00E217F9 /* LKSyncOpenGroupsMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKSyncOpenGroupsMessage.m; sourceTree = ""; }; - C33FDBE0255A581A00E217F9 /* OWSBlockedPhoneNumbersMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBlockedPhoneNumbersMessage.m; sourceTree = ""; }; C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = ""; }; - C33FDBE2255A581A00E217F9 /* OWSUnknownContactBlockOfferMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUnknownContactBlockOfferMessage.m; sourceTree = ""; }; - C33FDBE3255A581A00E217F9 /* CDSSigningCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSSigningCertificate.h; sourceTree = ""; }; - C33FDBE4255A581A00E217F9 /* OWSOutgoingSyncMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingSyncMessage.h; sourceTree = ""; }; - C33FDBE5255A581A00E217F9 /* OWSDevicesService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDevicesService.m; sourceTree = ""; }; - C33FDBE6255A581A00E217F9 /* OWSOutgoingNullMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingNullMessage.m; sourceTree = ""; }; - C33FDBE7255A581A00E217F9 /* NSTimer+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+OWS.h"; sourceTree = ""; }; C33FDBE8255A581A00E217F9 /* Storage+OnionRequests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+OnionRequests.swift"; sourceTree = ""; }; C33FDBE9255A581A00E217F9 /* TSInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInteraction.m; sourceTree = ""; }; - C33FDBEA255A581A00E217F9 /* SessionRequestMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionRequestMessage.swift; sourceTree = ""; }; C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockingManager.h; sourceTree = ""; }; C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecipientIdentity.m; sourceTree = ""; }; - C33FDBED255A581B00E217F9 /* ClosedGroupParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupParser.swift; sourceTree = ""; }; - C33FDBEE255A581B00E217F9 /* ClosedGroupUpdateMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupUpdateMessage.swift; sourceTree = ""; }; C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageKeys.h; sourceTree = ""; }; C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiDatabaseUtilities.swift; sourceTree = ""; }; C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIdentityManager.h; sourceTree = ""; }; - C33FDBF3255A581B00E217F9 /* OWSBlockedPhoneNumbersMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockedPhoneNumbersMessage.h; sourceTree = ""; }; C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayNameUtilities2.swift; sourceTree = ""; }; - C33FDBF5255A581B00E217F9 /* OWSDeviceProvisioningService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioningService.h; sourceTree = ""; }; C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLSessionDataTask+StatusCode.h"; sourceTree = ""; }; C33FDBF7255A581C00E217F9 /* OWSIncompleteCallsJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIncompleteCallsJob.m; sourceTree = ""; }; C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+OWS.h"; sourceTree = ""; }; C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = ""; }; - C33FDBFA255A581C00E217F9 /* PhoneNumberUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhoneNumberUtil.h; sourceTree = ""; }; C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+PublicChats.swift"; sourceTree = ""; }; C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+Calling.m"; sourceTree = ""; }; C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+Functional.h"; sourceTree = ""; }; - C33FDBFF255A581C00E217F9 /* OWSOutgoingSyncMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingSyncMessage.m; sourceTree = ""; }; - C33FDC00255A581C00E217F9 /* OWSSyncGroupsMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSyncGroupsMessage.m; sourceTree = ""; }; C33FDC01255A581C00E217F9 /* TSGroupThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSGroupThread.m; sourceTree = ""; }; C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSPrimaryStorage.m; sourceTree = ""; }; C33FDC03255A581D00E217F9 /* ByteParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteParser.h; sourceTree = ""; }; - C33FDC04255A581D00E217F9 /* DecryptionUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecryptionUtilities.swift; sourceTree = ""; }; C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingMessagesFinder.h; sourceTree = ""; }; C33FDC06255A581D00E217F9 /* SignalAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalAccount.m; sourceTree = ""; }; C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = ""; }; C33FDC08255A581D00E217F9 /* SignalService.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalService.pb.swift; sourceTree = ""; }; - C33FDC09255A581D00E217F9 /* AccountServiceClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountServiceClient.swift; sourceTree = ""; }; - C33FDC0A255A581D00E217F9 /* OWSContact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContact.m; sourceTree = ""; }; C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = ""; }; C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInfoMessage.m; sourceTree = ""; }; - C33FDC0D255A581E00E217F9 /* OWSProvisioningMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProvisioningMessage.h; sourceTree = ""; }; - C33FDC0F255A581E00E217F9 /* LKDeviceLinkMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKDeviceLinkMessage.h; sourceTree = ""; }; - C33FDC10255A581E00E217F9 /* ProofOfWork.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProofOfWork.swift; sourceTree = ""; }; - C33FDC11255A581E00E217F9 /* TSSocketManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSSocketManager.m; sourceTree = ""; }; C33FDC12255A581E00E217F9 /* TSConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSConstants.h; sourceTree = ""; }; C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAttachmentDownloads.m; sourceTree = ""; }; C33FDC15255A581E00E217F9 /* TSAttachment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAttachment.h; sourceTree = ""; }; C33FDC16255A581E00E217F9 /* FunctionalUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionalUtil.h; sourceTree = ""; }; - C33FDC17255A581F00E217F9 /* SharedSenderKeysImplementation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedSenderKeysImplementation.swift; sourceTree = ""; }; C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAttachmentPointer.h; sourceTree = ""; }; C33FDC19255A581F00E217F9 /* OWSQueues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQueues.h; sourceTree = ""; }; C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackgroundTask.m; sourceTree = ""; }; C33FDC1C255A581F00E217F9 /* TSCall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSCall.m; sourceTree = ""; }; - C33FDC1D255A581F00E217F9 /* OWSSyncConfigurationMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSyncConfigurationMessage.m; sourceTree = ""; }; C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUploadOperation.m; sourceTree = ""; }; - C33FDC1F255A581F00E217F9 /* LokiSessionResetImplementation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiSessionResetImplementation.swift; sourceTree = ""; }; + C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiSessionRestorationImplementation.swift; sourceTree = ""; }; C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Encryption.swift"; sourceTree = ""; }; C3471F4125553A4D00297E91 /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = ""; }; C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Decryption.swift"; sourceTree = ""; }; @@ -2150,42 +1764,34 @@ C364535B252467900045C478 /* AudioUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUtilities.swift; sourceTree = ""; }; C37F53E8255BA9BB002AEA92 /* Environment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = ""; }; C37F5402255BA9ED002AEA92 /* Environment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = ""; }; - C38EEF09255B49A8007E1867 /* SSKProtoEnvelope+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SSKProtoEnvelope+Conversion.swift"; sourceTree = ""; }; - C38EEFD5255B5BA2007E1867 /* OldSnodeAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OldSnodeAPI.swift; sourceTree = ""; }; - C38EF212255B6D3A007E1867 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Theme.h; path = SignalUtilitiesKit/Theme.h; sourceTree = SOURCE_ROOT; }; - C38EF213255B6D3A007E1867 /* OWSConversationColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSConversationColor.m; path = SignalUtilitiesKit/OWSConversationColor.m; sourceTree = SOURCE_ROOT; }; - C38EF214255B6D3A007E1867 /* Theme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Theme.m; path = SignalUtilitiesKit/Theme.m; sourceTree = SOURCE_ROOT; }; - C38EF215255B6D3A007E1867 /* OWSConversationColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSConversationColor.h; path = SignalUtilitiesKit/OWSConversationColor.h; sourceTree = SOURCE_ROOT; }; - C38EF223255B6D5D007E1867 /* AttachmentSharing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AttachmentSharing.m; path = SignalUtilitiesKit/AttachmentSharing.m; sourceTree = SOURCE_ROOT; }; - C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = SignalUtilitiesKit/SignalAttachment.swift; sourceTree = SOURCE_ROOT; }; - C38EF225255B6D5D007E1867 /* AttachmentSharing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AttachmentSharing.h; path = SignalUtilitiesKit/AttachmentSharing.h; sourceTree = SOURCE_ROOT; }; - C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewDelegate.swift; path = SignalUtilitiesKit/ShareViewDelegate.swift; sourceTree = SOURCE_ROOT; }; - C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSVideoPlayer.swift; path = SignalUtilitiesKit/OWSVideoPlayer.swift; sourceTree = SOURCE_ROOT; }; - C38EF236255B6D65007E1867 /* UIViewController+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+OWS.h"; path = "SignalUtilitiesKit/UIViewController+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIDevice+featureSupport.swift"; path = "SignalUtilitiesKit/UIDevice+featureSupport.swift"; sourceTree = SOURCE_ROOT; }; - C38EF238255B6D66007E1867 /* UIFont+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIFont+OWS.m"; path = "SignalUtilitiesKit/UIFont+OWS.m"; sourceTree = SOURCE_ROOT; }; - C38EF239255B6D66007E1867 /* UIFont+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIFont+OWS.h"; path = "SignalUtilitiesKit/UIFont+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributedString+OWS.m"; path = "SignalUtilitiesKit/NSAttributedString+OWS.m"; sourceTree = SOURCE_ROOT; }; - C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+OWS.m"; path = "SignalUtilitiesKit/UIViewController+OWS.m"; sourceTree = SOURCE_ROOT; }; - C38EF23C255B6D66007E1867 /* UIColor+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIColor+OWS.h"; path = "SignalUtilitiesKit/UIColor+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF23D255B6D66007E1867 /* UIView+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+OWS.h"; path = "SignalUtilitiesKit/UIView+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF23E255B6D66007E1867 /* UIView+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+OWS.m"; path = "SignalUtilitiesKit/UIView+OWS.m"; sourceTree = SOURCE_ROOT; }; + C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SNProtoEnvelope+Conversion.swift"; sourceTree = ""; }; + C38EF212255B6D3A007E1867 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Theme.h; path = SignalUtilitiesKit/UI/Theme.h; sourceTree = SOURCE_ROOT; }; + C38EF214255B6D3A007E1867 /* Theme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Theme.m; path = SignalUtilitiesKit/UI/Theme.m; sourceTree = SOURCE_ROOT; }; + C38EF223255B6D5D007E1867 /* AttachmentSharing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AttachmentSharing.m; path = SignalUtilitiesKit/Utilities/AttachmentSharing.m; sourceTree = SOURCE_ROOT; }; + C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = SignalUtilitiesKit/Attachments/SignalAttachment.swift; sourceTree = SOURCE_ROOT; }; + C38EF225255B6D5D007E1867 /* AttachmentSharing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AttachmentSharing.h; path = SignalUtilitiesKit/Utilities/AttachmentSharing.h; sourceTree = SOURCE_ROOT; }; + C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewDelegate.swift; path = SignalUtilitiesKit/Utilities/ShareViewDelegate.swift; sourceTree = SOURCE_ROOT; }; + C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSVideoPlayer.swift; path = SignalUtilitiesKit/Utilities/OWSVideoPlayer.swift; sourceTree = SOURCE_ROOT; }; + C38EF236255B6D65007E1867 /* UIViewController+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+OWS.h"; path = "SignalUtilitiesKit/UI/UIViewController+OWS.h"; sourceTree = SOURCE_ROOT; }; + C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIDevice+featureSupport.swift"; path = "SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift"; sourceTree = SOURCE_ROOT; }; + C38EF238255B6D66007E1867 /* UIFont+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIFont+OWS.m"; path = "SignalUtilitiesKit/UI/UIFont+OWS.m"; sourceTree = SOURCE_ROOT; }; + C38EF239255B6D66007E1867 /* UIFont+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIFont+OWS.h"; path = "SignalUtilitiesKit/UI/UIFont+OWS.h"; sourceTree = SOURCE_ROOT; }; + C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributedString+OWS.m"; path = "SignalUtilitiesKit/Utilities/NSAttributedString+OWS.m"; sourceTree = SOURCE_ROOT; }; + C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+OWS.m"; path = "SignalUtilitiesKit/UI/UIViewController+OWS.m"; sourceTree = SOURCE_ROOT; }; + C38EF23C255B6D66007E1867 /* UIColor+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIColor+OWS.h"; path = "SignalUtilitiesKit/UI/UIColor+OWS.h"; sourceTree = SOURCE_ROOT; }; + C38EF23D255B6D66007E1867 /* UIView+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+OWS.h"; path = "SignalUtilitiesKit/UI/UIView+OWS.h"; sourceTree = SOURCE_ROOT; }; + C38EF23E255B6D66007E1867 /* UIView+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+OWS.m"; path = "SignalUtilitiesKit/UI/UIView+OWS.m"; sourceTree = SOURCE_ROOT; }; C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSAttributedString+OWS.h"; path = "SignalUtilitiesKit/NSAttributedString+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF240255B6D67007E1867 /* UIView+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+OWS.swift"; path = "SignalUtilitiesKit/UIView+OWS.swift"; sourceTree = SOURCE_ROOT; }; - C38EF241255B6D67007E1867 /* Collection+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Collection+OWS.swift"; path = "SignalUtilitiesKit/Collection+OWS.swift"; sourceTree = SOURCE_ROOT; }; - C38EF242255B6D67007E1867 /* UIColor+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIColor+OWS.m"; path = "SignalUtilitiesKit/UIColor+OWS.m"; sourceTree = SOURCE_ROOT; }; - C38EF259255B6D6E007E1867 /* SystemContactsFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SystemContactsFetcher.swift; path = SignalUtilitiesKit/SystemContactsFetcher.swift; sourceTree = SOURCE_ROOT; }; - C38EF25A255B6D6E007E1867 /* OWSSyncManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSyncManager.h; path = SignalUtilitiesKit/OWSSyncManager.h; sourceTree = SOURCE_ROOT; }; - C38EF25B255B6D6E007E1867 /* OWSContactsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSContactsManager.m; path = SignalUtilitiesKit/OWSContactsManager.m; sourceTree = SOURCE_ROOT; }; - C38EF25C255B6D6E007E1867 /* OWSSyncManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSyncManager.m; path = SignalUtilitiesKit/OWSSyncManager.m; sourceTree = SOURCE_ROOT; }; - C38EF25D255B6D6E007E1867 /* OWSContactsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSContactsManager.h; path = SignalUtilitiesKit/OWSContactsManager.h; sourceTree = SOURCE_ROOT; }; - C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSResaveCollectionDBMigration.m; path = SignalUtilitiesKit/OWSResaveCollectionDBMigration.m; sourceTree = SOURCE_ROOT; }; - C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigrationRunner.m; path = SignalUtilitiesKit/OWSDatabaseMigrationRunner.m; sourceTree = SOURCE_ROOT; }; - C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSResaveCollectionDBMigration.h; path = SignalUtilitiesKit/OWSResaveCollectionDBMigration.h; sourceTree = SOURCE_ROOT; }; - C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigrationRunner.h; path = SignalUtilitiesKit/OWSDatabaseMigrationRunner.h; sourceTree = SOURCE_ROOT; }; - C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; - C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; - C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SignalUtilitiesKit/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; + C38EF240255B6D67007E1867 /* UIView+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+OWS.swift"; path = "SignalUtilitiesKit/UI/UIView+OWS.swift"; sourceTree = SOURCE_ROOT; }; + C38EF241255B6D67007E1867 /* Collection+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Collection+OWS.swift"; path = "SignalUtilitiesKit/Utilities/Collection+OWS.swift"; sourceTree = SOURCE_ROOT; }; + C38EF242255B6D67007E1867 /* UIColor+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIColor+OWS.m"; path = "SignalUtilitiesKit/UI/UIColor+OWS.m"; sourceTree = SOURCE_ROOT; }; + C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSResaveCollectionDBMigration.m; path = SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.m; sourceTree = SOURCE_ROOT; }; + C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigrationRunner.m; path = SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.m; sourceTree = SOURCE_ROOT; }; + C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSResaveCollectionDBMigration.h; path = SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.h; sourceTree = SOURCE_ROOT; }; + C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigrationRunner.h; path = SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.h; sourceTree = SOURCE_ROOT; }; + C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; + C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; + C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SignalUtilitiesKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; C38EF283255B6D84007E1867 /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VersionMigrations.h; path = SignalUtilitiesKit/VersionMigrations.h; sourceTree = SOURCE_ROOT; }; C38EF284255B6D84007E1867 /* AppSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppSetup.h; path = SignalUtilitiesKit/AppSetup.h; sourceTree = SOURCE_ROOT; }; @@ -2195,145 +1801,126 @@ C38EF288255B6D85007E1867 /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSounds.h; path = SignalUtilitiesKit/OWSSounds.h; sourceTree = SOURCE_ROOT; }; C38EF289255B6D85007E1867 /* NoopCallMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NoopCallMessageHandler.swift; path = SignalUtilitiesKit/NoopCallMessageHandler.swift; sourceTree = SOURCE_ROOT; }; C38EF28B255B6D86007E1867 /* OWSSounds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSounds.m; path = SignalUtilitiesKit/OWSSounds.m; sourceTree = SOURCE_ROOT; }; - C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Identicon+ObjC.swift"; path = "SignalUtilitiesKit/Identicon+ObjC.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = SignalUtilitiesKit/PlaceholderIcon.swift; sourceTree = SOURCE_ROOT; }; - C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SignalUtilitiesKit/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; }; - C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Utilities.swift"; path = "SignalUtilitiesKit/UIView+Utilities.swift"; sourceTree = SOURCE_ROOT; }; + C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Identicon+ObjC.swift"; path = "SignalUtilitiesKit/UI/Identicon+ObjC.swift"; sourceTree = SOURCE_ROOT; }; + C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = SignalUtilitiesKit/UI/PlaceholderIcon.swift; sourceTree = SOURCE_ROOT; }; + C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SignalUtilitiesKit/UI/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; }; + C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; }; + C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIView+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = SignalUtilitiesKit/TSUnreadIndicatorInteraction.h; sourceTree = SOURCE_ROOT; }; C38EF2BF255B6DA6007E1867 /* OWSContactOffersInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSContactOffersInteraction.h; path = SignalUtilitiesKit/OWSContactOffersInteraction.h; sourceTree = SOURCE_ROOT; }; C38EF2C0255B6DA6007E1867 /* OWSContactOffersInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSContactOffersInteraction.m; path = SignalUtilitiesKit/OWSContactOffersInteraction.m; sourceTree = SOURCE_ROOT; }; C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = SignalUtilitiesKit/TSUnreadIndicatorInteraction.m; sourceTree = SOURCE_ROOT; }; - C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = SignalUtilitiesKit/OWSProfileManager.m; sourceTree = SOURCE_ROOT; }; - C38EF2D0255B6DAE007E1867 /* ProfileFetcherJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfileFetcherJob.swift; path = SignalUtilitiesKit/ProfileFetcherJob.swift; sourceTree = SOURCE_ROOT; }; - C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = SignalUtilitiesKit/OWSUserProfile.m; sourceTree = SOURCE_ROOT; }; - C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = SignalUtilitiesKit/OWSProfileManager.h; sourceTree = SOURCE_ROOT; }; - C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = SignalUtilitiesKit/OWSUserProfile.h; sourceTree = SOURCE_ROOT; }; + C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = "SignalUtilitiesKit/Remove Later/OWSProfileManager.m"; sourceTree = SOURCE_ROOT; }; + C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SignalUtilitiesKit/Remove Later/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; + C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = "SignalUtilitiesKit/Remove Later/OWSProfileManager.h"; sourceTree = SOURCE_ROOT; }; + C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = "SignalUtilitiesKit/Remove Later/OWSUserProfile.h"; sourceTree = SOURCE_ROOT; }; C38EF2E2255B6DB9007E1867 /* OWSScreenLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSScreenLock.swift; path = SignalUtilitiesKit/OWSScreenLock.swift; sourceTree = SOURCE_ROOT; }; C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUnreadIndicator.m; path = SignalUtilitiesKit/OWSUnreadIndicator.m; sourceTree = SOURCE_ROOT; }; C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FullTextSearcher.swift; path = SignalUtilitiesKit/FullTextSearcher.swift; sourceTree = SOURCE_ROOT; }; C38EF2E5255B6DB9007E1867 /* AppPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppPreferences.swift; path = SignalUtilitiesKit/AppPreferences.swift; sourceTree = SOURCE_ROOT; }; - C38EF2E6255B6DBA007E1867 /* DebugLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DebugLogger.m; path = SignalUtilitiesKit/DebugLogger.m; sourceTree = SOURCE_ROOT; }; - C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSScrubbingLogFormatter.h; path = SignalUtilitiesKit/OWSScrubbingLogFormatter.h; sourceTree = SOURCE_ROOT; }; - C38EF2E8255B6DBA007E1867 /* OWSGroupAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSGroupAvatarBuilder.m; path = SignalUtilitiesKit/OWSGroupAvatarBuilder.m; sourceTree = SOURCE_ROOT; }; + C38EF2E6255B6DBA007E1867 /* DebugLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DebugLogger.m; path = SignalUtilitiesKit/Utilities/DebugLogger.m; sourceTree = SOURCE_ROOT; }; + C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSScrubbingLogFormatter.h; path = SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.h; sourceTree = SOURCE_ROOT; }; C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUnreadIndicator.h; path = SignalUtilitiesKit/OWSUnreadIndicator.h; sourceTree = SOURCE_ROOT; }; - C38EF2EA255B6DBA007E1867 /* OWSAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAvatarBuilder.h; path = SignalUtilitiesKit/OWSAvatarBuilder.h; sourceTree = SOURCE_ROOT; }; - C38EF2EB255B6DBA007E1867 /* OWSGroupAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSGroupAvatarBuilder.h; path = SignalUtilitiesKit/OWSGroupAvatarBuilder.h; sourceTree = SOURCE_ROOT; }; C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProximityMonitoringManager.swift; path = SignalUtilitiesKit/ProximityMonitoringManager.swift; sourceTree = SOURCE_ROOT; }; - C38EF2ED255B6DBB007E1867 /* DisplayableText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisplayableText.swift; path = SignalUtilitiesKit/DisplayableText.swift; sourceTree = SOURCE_ROOT; }; - C38EF2EE255B6DBB007E1867 /* OWSAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAvatarBuilder.m; path = SignalUtilitiesKit/OWSAvatarBuilder.m; sourceTree = SOURCE_ROOT; }; - C38EF2EF255B6DBB007E1867 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SignalUtilitiesKit/Weak.swift; sourceTree = SOURCE_ROOT; }; - C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAnyTouchGestureRecognizer.m; path = SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.m; sourceTree = SOURCE_ROOT; }; + C38EF2ED255B6DBB007E1867 /* DisplayableText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisplayableText.swift; path = SignalUtilitiesKit/UI/DisplayableText.swift; sourceTree = SOURCE_ROOT; }; + C38EF2EF255B6DBB007E1867 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SignalUtilitiesKit/Utilities/Weak.swift; sourceTree = SOURCE_ROOT; }; + C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAnyTouchGestureRecognizer.m; path = SignalUtilitiesKit/UI/OWSAnyTouchGestureRecognizer.m; sourceTree = SOURCE_ROOT; }; C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSPreferences.h; path = SignalUtilitiesKit/OWSPreferences.h; sourceTree = SOURCE_ROOT; }; C38EF2F2255B6DBC007E1867 /* Searcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Searcher.swift; path = SignalUtilitiesKit/Searcher.swift; sourceTree = SOURCE_ROOT; }; - C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+OWS.swift"; path = "SignalUtilitiesKit/UIImage+OWS.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SignalUtilitiesKit/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; }; - C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSScrubbingLogFormatter.m; path = SignalUtilitiesKit/OWSScrubbingLogFormatter.m; sourceTree = SOURCE_ROOT; }; - C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAudioPlayer.m; path = SignalUtilitiesKit/OWSAudioPlayer.m; sourceTree = SOURCE_ROOT; }; - C38EF2F8255B6DBC007E1867 /* DebugLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebugLogger.h; path = SignalUtilitiesKit/DebugLogger.h; sourceTree = SOURCE_ROOT; }; - C38EF2F9255B6DBC007E1867 /* OWSContactAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSContactAvatarBuilder.m; path = SignalUtilitiesKit/OWSContactAvatarBuilder.m; sourceTree = SOURCE_ROOT; }; - C38EF2FA255B6DBD007E1867 /* Bench.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bench.swift; path = SignalUtilitiesKit/Bench.swift; sourceTree = SOURCE_ROOT; }; - C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSWindowManager.h; path = SignalUtilitiesKit/OWSWindowManager.h; sourceTree = SOURCE_ROOT; }; - C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationStyle.swift; path = SignalUtilitiesKit/ConversationStyle.swift; sourceTree = SOURCE_ROOT; }; - C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BlockListUIUtils.m; path = SignalUtilitiesKit/BlockListUIUtils.m; sourceTree = SOURCE_ROOT; }; - C38EF2FE255B6DBD007E1867 /* OWSContactAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSContactAvatarBuilder.h; path = SignalUtilitiesKit/OWSContactAvatarBuilder.h; sourceTree = SOURCE_ROOT; }; - C38EF300255B6DBD007E1867 /* UIUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UIUtil.m; path = SignalUtilitiesKit/UIUtil.m; sourceTree = SOURCE_ROOT; }; - C38EF301255B6DBD007E1867 /* OWSFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSFormat.h; path = SignalUtilitiesKit/OWSFormat.h; sourceTree = SOURCE_ROOT; }; - C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.h; sourceTree = SOURCE_ROOT; }; - C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlockListUIUtils.h; path = SignalUtilitiesKit/BlockListUIUtils.h; sourceTree = SOURCE_ROOT; }; + C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+OWS.swift"; path = "SignalUtilitiesKit/UI/UIImage+OWS.swift"; sourceTree = SOURCE_ROOT; }; + C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SignalUtilitiesKit/Utilities/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; }; + C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSScrubbingLogFormatter.m; path = SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.m; sourceTree = SOURCE_ROOT; }; + C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAudioPlayer.m; path = SignalUtilitiesKit/Utilities/OWSAudioPlayer.m; sourceTree = SOURCE_ROOT; }; + C38EF2F8255B6DBC007E1867 /* DebugLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebugLogger.h; path = SignalUtilitiesKit/Utilities/DebugLogger.h; sourceTree = SOURCE_ROOT; }; + C38EF2FA255B6DBD007E1867 /* Bench.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bench.swift; path = SignalUtilitiesKit/Utilities/Bench.swift; sourceTree = SOURCE_ROOT; }; + C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSWindowManager.h; path = SignalUtilitiesKit/UI/OWSWindowManager.h; sourceTree = SOURCE_ROOT; }; + C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationStyle.swift; path = SignalUtilitiesKit/UI/ConversationStyle.swift; sourceTree = SOURCE_ROOT; }; + C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BlockListUIUtils.m; path = SignalUtilitiesKit/UI/BlockListUIUtils.m; sourceTree = SOURCE_ROOT; }; + C38EF300255B6DBD007E1867 /* UIUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UIUtil.m; path = SignalUtilitiesKit/UI/UIUtil.m; sourceTree = SOURCE_ROOT; }; + C38EF301255B6DBD007E1867 /* OWSFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSFormat.h; path = SignalUtilitiesKit/Utilities/OWSFormat.h; sourceTree = SOURCE_ROOT; }; + C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = SignalUtilitiesKit/UI/OWSAnyTouchGestureRecognizer.h; sourceTree = SOURCE_ROOT; }; + C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlockListUIUtils.h; path = SignalUtilitiesKit/UI/BlockListUIUtils.h; sourceTree = SOURCE_ROOT; }; C38EF304255B6DBE007E1867 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = SignalUtilitiesKit/ImageCache.swift; sourceTree = SOURCE_ROOT; }; - C38EF305255B6DBE007E1867 /* OWSFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSFormat.m; path = SignalUtilitiesKit/OWSFormat.m; sourceTree = SOURCE_ROOT; }; - C38EF306255B6DBE007E1867 /* OWSWindowManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSWindowManager.m; path = SignalUtilitiesKit/OWSWindowManager.m; sourceTree = SOURCE_ROOT; }; - C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+OWS.swift"; path = "SignalUtilitiesKit/UIGestureRecognizer+OWS.swift"; sourceTree = SOURCE_ROOT; }; + C38EF305255B6DBE007E1867 /* OWSFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSFormat.m; path = SignalUtilitiesKit/Utilities/OWSFormat.m; sourceTree = SOURCE_ROOT; }; + C38EF306255B6DBE007E1867 /* OWSWindowManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSWindowManager.m; path = SignalUtilitiesKit/UI/OWSWindowManager.m; sourceTree = SOURCE_ROOT; }; + C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+OWS.swift"; path = "SignalUtilitiesKit/UI/UIGestureRecognizer+OWS.swift"; sourceTree = SOURCE_ROOT; }; C38EF308255B6DBE007E1867 /* OWSPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSPreferences.m; path = SignalUtilitiesKit/OWSPreferences.m; sourceTree = SOURCE_ROOT; }; C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceSleepManager.swift; path = SignalUtilitiesKit/DeviceSleepManager.swift; sourceTree = SOURCE_ROOT; }; - C38EF30A255B6DBE007E1867 /* UIUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UIUtil.h; path = SignalUtilitiesKit/UIUtil.h; sourceTree = SOURCE_ROOT; }; + C38EF30A255B6DBE007E1867 /* UIUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UIUtil.h; path = SignalUtilitiesKit/UI/UIUtil.h; sourceTree = SOURCE_ROOT; }; C38EF30B255B6DBE007E1867 /* BlockListCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockListCache.swift; path = SignalUtilitiesKit/BlockListCache.swift; sourceTree = SOURCE_ROOT; }; - C38EF33F255B6DC5007E1867 /* SheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SheetViewController.swift; path = SignalUtilitiesKit/SheetViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF340255B6DC5007E1867 /* ViewControllerUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ViewControllerUtils.m; path = SignalUtilitiesKit/ViewControllerUtils.m; sourceTree = SOURCE_ROOT; }; - C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectThreadViewController.h; path = SignalUtilitiesKit/SelectThreadViewController.h; sourceTree = SOURCE_ROOT; }; - C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SelectThreadViewController.m; path = SignalUtilitiesKit/SelectThreadViewController.m; sourceTree = SOURCE_ROOT; }; - C38EF343255B6DC5007E1867 /* OWSNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSNavigationController.h; path = SignalUtilitiesKit/OWSNavigationController.h; sourceTree = SOURCE_ROOT; }; - C38EF344255B6DC5007E1867 /* OWSViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSViewController.h; path = SignalUtilitiesKit/OWSViewController.h; sourceTree = SOURCE_ROOT; }; - C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SelectRecipientViewController.m; path = SignalUtilitiesKit/SelectRecipientViewController.m; sourceTree = SOURCE_ROOT; }; - C38EF346255B6DC6007E1867 /* ReturnToCallViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReturnToCallViewController.swift; path = SignalUtilitiesKit/ReturnToCallViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF347255B6DC6007E1867 /* EditContactShareNameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EditContactShareNameViewController.swift; path = SignalUtilitiesKit/EditContactShareNameViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF348255B6DC7007E1867 /* ContactShareApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContactShareApprovalViewController.swift; path = SignalUtilitiesKit/ContactShareApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModalActivityIndicatorViewController.swift; path = SignalUtilitiesKit/ModalActivityIndicatorViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF34A255B6DC7007E1867 /* NewNonContactConversationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NewNonContactConversationViewController.h; path = SignalUtilitiesKit/NewNonContactConversationViewController.h; sourceTree = SOURCE_ROOT; }; - C38EF34B255B6DC8007E1867 /* OWSTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSTableViewController.m; path = SignalUtilitiesKit/OWSTableViewController.m; sourceTree = SOURCE_ROOT; }; - C38EF34C255B6DC8007E1867 /* ScreenLockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenLockViewController.h; path = SignalUtilitiesKit/ScreenLockViewController.h; sourceTree = SOURCE_ROOT; }; - C38EF34D255B6DC8007E1867 /* OWSTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTableViewController.h; path = SignalUtilitiesKit/OWSTableViewController.h; sourceTree = SOURCE_ROOT; }; - C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectRecipientViewController.h; path = SignalUtilitiesKit/SelectRecipientViewController.h; sourceTree = SOURCE_ROOT; }; - C38EF34F255B6DC9007E1867 /* ViewControllerUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ViewControllerUtils.h; path = SignalUtilitiesKit/ViewControllerUtils.h; sourceTree = SOURCE_ROOT; }; - C38EF350255B6DC9007E1867 /* NewNonContactConversationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NewNonContactConversationViewController.m; path = SignalUtilitiesKit/NewNonContactConversationViewController.m; sourceTree = SOURCE_ROOT; }; - C38EF351255B6DC9007E1867 /* ScreenLockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ScreenLockViewController.m; path = SignalUtilitiesKit/ScreenLockViewController.m; sourceTree = SOURCE_ROOT; }; - C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingThreadPickerViewController.m; path = SignalUtilitiesKit/SharingThreadPickerViewController.m; sourceTree = SOURCE_ROOT; }; - C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingThreadPickerViewController.h; path = SignalUtilitiesKit/SharingThreadPickerViewController.h; sourceTree = SOURCE_ROOT; }; - C38EF354255B6DCB007E1867 /* ContactFieldView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContactFieldView.swift; path = SignalUtilitiesKit/ContactFieldView.swift; sourceTree = SOURCE_ROOT; }; - C38EF355255B6DCB007E1867 /* OWSViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSViewController.m; path = SignalUtilitiesKit/OWSViewController.m; sourceTree = SOURCE_ROOT; }; - C38EF356255B6DCB007E1867 /* OWSNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSNavigationController.m; path = SignalUtilitiesKit/OWSNavigationController.m; sourceTree = SOURCE_ROOT; }; - C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageApprovalViewController.swift; path = SignalUtilitiesKit/MessageApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF358255B6DCC007E1867 /* MediaMessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaMessageView.swift; path = SignalUtilitiesKit/MediaMessageView.swift; sourceTree = SOURCE_ROOT; }; - C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextToolbar.swift; path = SignalUtilitiesKit/AttachmentTextToolbar.swift; sourceTree = SOURCE_ROOT; }; - C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalInputAccessoryView.swift; path = SignalUtilitiesKit/AttachmentApprovalInputAccessoryView.swift; sourceTree = SOURCE_ROOT; }; - C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentItemCollection.swift; path = SignalUtilitiesKit/AttachmentItemCollection.swift; sourceTree = SOURCE_ROOT; }; - C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalViewController.swift; path = SignalUtilitiesKit/AttachmentApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextView.swift; path = SignalUtilitiesKit/AttachmentTextView.swift; sourceTree = SOURCE_ROOT; }; - C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionToolbar.swift; path = SignalUtilitiesKit/AttachmentCaptionToolbar.swift; sourceTree = SOURCE_ROOT; }; - C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentPrepViewController.swift; path = SignalUtilitiesKit/AttachmentPrepViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ApprovalRailCellView.swift; path = SignalUtilitiesKit/ApprovalRailCellView.swift; sourceTree = SOURCE_ROOT; }; - C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = SignalUtilitiesKit/AttachmentCaptionViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF33F255B6DC5007E1867 /* SheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SheetViewController.swift; path = SignalUtilitiesKit/UI/SheetViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectThreadViewController.h; path = SignalUtilitiesKit/UI/SelectThreadViewController.h; sourceTree = SOURCE_ROOT; }; + C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SelectThreadViewController.m; path = SignalUtilitiesKit/UI/SelectThreadViewController.m; sourceTree = SOURCE_ROOT; }; + C38EF343255B6DC5007E1867 /* OWSNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSNavigationController.h; path = SignalUtilitiesKit/UI/OWSNavigationController.h; sourceTree = SOURCE_ROOT; }; + C38EF344255B6DC5007E1867 /* OWSViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSViewController.h; path = SignalUtilitiesKit/UI/OWSViewController.h; sourceTree = SOURCE_ROOT; }; + C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SelectRecipientViewController.m; path = SignalUtilitiesKit/UI/SelectRecipientViewController.m; sourceTree = SOURCE_ROOT; }; + C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModalActivityIndicatorViewController.swift; path = SignalUtilitiesKit/UI/ModalActivityIndicatorViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF34B255B6DC8007E1867 /* OWSTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSTableViewController.m; path = SignalUtilitiesKit/UI/OWSTableViewController.m; sourceTree = SOURCE_ROOT; }; + C38EF34C255B6DC8007E1867 /* ScreenLockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenLockViewController.h; path = SignalUtilitiesKit/UI/ScreenLockViewController.h; sourceTree = SOURCE_ROOT; }; + C38EF34D255B6DC8007E1867 /* OWSTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTableViewController.h; path = SignalUtilitiesKit/UI/OWSTableViewController.h; sourceTree = SOURCE_ROOT; }; + C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectRecipientViewController.h; path = SignalUtilitiesKit/UI/SelectRecipientViewController.h; sourceTree = SOURCE_ROOT; }; + C38EF351255B6DC9007E1867 /* ScreenLockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ScreenLockViewController.m; path = SignalUtilitiesKit/UI/ScreenLockViewController.m; sourceTree = SOURCE_ROOT; }; + C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingThreadPickerViewController.m; path = SignalUtilitiesKit/UI/SharingThreadPickerViewController.m; sourceTree = SOURCE_ROOT; }; + C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingThreadPickerViewController.h; path = SignalUtilitiesKit/UI/SharingThreadPickerViewController.h; sourceTree = SOURCE_ROOT; }; + C38EF355255B6DCB007E1867 /* OWSViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSViewController.m; path = SignalUtilitiesKit/UI/OWSViewController.m; sourceTree = SOURCE_ROOT; }; + C38EF356255B6DCB007E1867 /* OWSNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSNavigationController.m; path = SignalUtilitiesKit/UI/OWSNavigationController.m; sourceTree = SOURCE_ROOT; }; + C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageApprovalViewController.swift; path = SignalUtilitiesKit/UI/MessageApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF358255B6DCC007E1867 /* MediaMessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaMessageView.swift; path = SignalUtilitiesKit/UI/MediaMessageView.swift; sourceTree = SOURCE_ROOT; }; + C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextToolbar.swift; path = SignalUtilitiesKit/UI/AttachmentTextToolbar.swift; sourceTree = SOURCE_ROOT; }; + C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalInputAccessoryView.swift; path = SignalUtilitiesKit/UI/AttachmentApprovalInputAccessoryView.swift; sourceTree = SOURCE_ROOT; }; + C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentItemCollection.swift; path = SignalUtilitiesKit/UI/AttachmentItemCollection.swift; sourceTree = SOURCE_ROOT; }; + C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalViewController.swift; path = SignalUtilitiesKit/UI/AttachmentApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextView.swift; path = SignalUtilitiesKit/UI/AttachmentTextView.swift; sourceTree = SOURCE_ROOT; }; + C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionToolbar.swift; path = SignalUtilitiesKit/UI/AttachmentCaptionToolbar.swift; sourceTree = SOURCE_ROOT; }; + C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentPrepViewController.swift; path = SignalUtilitiesKit/UI/AttachmentPrepViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ApprovalRailCellView.swift; path = SignalUtilitiesKit/UI/ApprovalRailCellView.swift; sourceTree = SOURCE_ROOT; }; + C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift; sourceTree = SOURCE_ROOT; }; C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadViewModel.swift; path = SignalUtilitiesKit/ThreadViewModel.swift; sourceTree = SOURCE_ROOT; }; C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = SignalUtilitiesKit/OWSQuotedReplyModel.h; sourceTree = SOURCE_ROOT; }; - C38EF399255B6DD9007E1867 /* ContactShareViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContactShareViewModel.swift; path = SignalUtilitiesKit/ContactShareViewModel.swift; sourceTree = SOURCE_ROOT; }; C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = SignalUtilitiesKit/OWSQuotedReplyModel.m; sourceTree = SOURCE_ROOT; }; - C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = SignalUtilitiesKit/ImageEditorTextViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = SignalUtilitiesKit/ImageEditorPinchGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = SignalUtilitiesKit/ImageEditorItem.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorStrokeItem.swift; path = SignalUtilitiesKit/ImageEditorStrokeItem.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPanGestureRecognizer.swift; path = SignalUtilitiesKit/ImageEditorPanGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTransform.swift; path = SignalUtilitiesKit/ImageEditorTransform.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrderedDictionary.swift; path = SignalUtilitiesKit/OrderedDictionary.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorView.swift; path = SignalUtilitiesKit/ImageEditorView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCropViewController.swift; path = SignalUtilitiesKit/ImageEditorCropViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorBrushViewController.swift; path = SignalUtilitiesKit/ImageEditorBrushViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPaletteView.swift; path = SignalUtilitiesKit/ImageEditorPaletteView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextItem.swift; path = SignalUtilitiesKit/ImageEditorTextItem.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorContents.swift; path = SignalUtilitiesKit/ImageEditorContents.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "OWSViewController+ImageEditor.swift"; path = "SignalUtilitiesKit/OWSViewController+ImageEditor.swift"; sourceTree = SOURCE_ROOT; }; - C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorModel.swift; path = SignalUtilitiesKit/ImageEditorModel.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCanvasView.swift; path = SignalUtilitiesKit/ImageEditorCanvasView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorTextViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; + C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = SignalUtilitiesKit/UI/ImageEditorItem.swift; sourceTree = SOURCE_ROOT; }; + C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorStrokeItem.swift; path = SignalUtilitiesKit/UI/ImageEditorStrokeItem.swift; sourceTree = SOURCE_ROOT; }; + C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPanGestureRecognizer.swift; path = SignalUtilitiesKit/UI/ImageEditorPanGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; + C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTransform.swift; path = SignalUtilitiesKit/UI/ImageEditorTransform.swift; sourceTree = SOURCE_ROOT; }; + C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrderedDictionary.swift; path = SignalUtilitiesKit/Utilities/OrderedDictionary.swift; sourceTree = SOURCE_ROOT; }; + C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorView.swift; path = SignalUtilitiesKit/UI/ImageEditorView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCropViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorCropViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorBrushViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorBrushViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPaletteView.swift; path = SignalUtilitiesKit/UI/ImageEditorPaletteView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextItem.swift; path = SignalUtilitiesKit/UI/ImageEditorTextItem.swift; sourceTree = SOURCE_ROOT; }; + C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorContents.swift; path = SignalUtilitiesKit/UI/ImageEditorContents.swift; sourceTree = SOURCE_ROOT; }; + C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "OWSViewController+ImageEditor.swift"; path = "SignalUtilitiesKit/UI/OWSViewController+ImageEditor.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorModel.swift; path = SignalUtilitiesKit/UI/ImageEditorModel.swift; sourceTree = SOURCE_ROOT; }; + C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCanvasView.swift; path = SignalUtilitiesKit/UI/ImageEditorCanvasView.swift; sourceTree = SOURCE_ROOT; }; C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadViewHelper.m; path = SignalUtilitiesKit/ThreadViewHelper.m; sourceTree = SOURCE_ROOT; }; C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; - C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSearchBar.h; path = SignalUtilitiesKit/OWSSearchBar.h; sourceTree = SOURCE_ROOT; }; - C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisappearingTimerConfigurationView.swift; path = SignalUtilitiesKit/DisappearingTimerConfigurationView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3D5255B6DEF007E1867 /* ContactsViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactsViewHelper.m; path = SignalUtilitiesKit/ContactsViewHelper.m; sourceTree = SOURCE_ROOT; }; - C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = SignalUtilitiesKit/ContactCellView.m; sourceTree = SOURCE_ROOT; }; - C38EF3D7255B6DF0007E1867 /* OWSTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextField.h; path = SignalUtilitiesKit/OWSTextField.h; sourceTree = SOURCE_ROOT; }; - C38EF3D8255B6DF0007E1867 /* OWSTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextView.h; path = SignalUtilitiesKit/OWSTextView.h; sourceTree = SOURCE_ROOT; }; - C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSNavigationBar.swift; path = SignalUtilitiesKit/OWSNavigationBar.swift; sourceTree = SOURCE_ROOT; }; - C38EF3DA255B6DF1007E1867 /* ContactsViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactsViewHelper.h; path = SignalUtilitiesKit/ContactsViewHelper.h; sourceTree = SOURCE_ROOT; }; - C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSLayerView.swift; path = SignalUtilitiesKit/OWSLayerView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DirectionalPanGestureRecognizer.swift; path = SignalUtilitiesKit/DirectionalPanGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; - C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIAlertController+OWS.swift"; path = "SignalUtilitiesKit/UIAlertController+OWS.swift"; sourceTree = SOURCE_ROOT; }; - C38EF3DE255B6DF2007E1867 /* AvatarImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AvatarImageView.swift; path = SignalUtilitiesKit/AvatarImageView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3DF255B6DF2007E1867 /* OWSTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSTextView.m; path = SignalUtilitiesKit/OWSTextView.m; sourceTree = SOURCE_ROOT; }; - C38EF3E0255B6DF3007E1867 /* OWSTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSTextField.m; path = SignalUtilitiesKit/OWSTextField.m; sourceTree = SOURCE_ROOT; }; - C38EF3E1255B6DF3007E1867 /* TappableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableView.swift; path = SignalUtilitiesKit/TappableView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E2255B6DF3007E1867 /* GalleryRailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GalleryRailView.swift; path = SignalUtilitiesKit/GalleryRailView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E3255B6DF4007E1867 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoPlayerView.swift; path = SignalUtilitiesKit/VideoPlayerView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSearchBar.h; path = SignalUtilitiesKit/UI/OWSSearchBar.h; sourceTree = SOURCE_ROOT; }; + C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisappearingTimerConfigurationView.swift; path = SignalUtilitiesKit/UI/DisappearingTimerConfigurationView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = "SignalUtilitiesKit/Remove Later/ContactCellView.m"; sourceTree = SOURCE_ROOT; }; + C38EF3D7255B6DF0007E1867 /* OWSTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextField.h; path = SignalUtilitiesKit/UI/OWSTextField.h; sourceTree = SOURCE_ROOT; }; + C38EF3D8255B6DF0007E1867 /* OWSTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextView.h; path = SignalUtilitiesKit/UI/OWSTextView.h; sourceTree = SOURCE_ROOT; }; + C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSNavigationBar.swift; path = SignalUtilitiesKit/UI/OWSNavigationBar.swift; sourceTree = SOURCE_ROOT; }; + C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSLayerView.swift; path = SignalUtilitiesKit/UI/OWSLayerView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DirectionalPanGestureRecognizer.swift; path = SignalUtilitiesKit/UI/DirectionalPanGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; + C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIAlertController+OWS.swift"; path = "SignalUtilitiesKit/Utilities/UIAlertController+OWS.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3DF255B6DF2007E1867 /* OWSTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSTextView.m; path = SignalUtilitiesKit/UI/OWSTextView.m; sourceTree = SOURCE_ROOT; }; + C38EF3E0255B6DF3007E1867 /* OWSTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSTextField.m; path = SignalUtilitiesKit/UI/OWSTextField.m; sourceTree = SOURCE_ROOT; }; + C38EF3E1255B6DF3007E1867 /* TappableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableView.swift; path = SignalUtilitiesKit/UI/TappableView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3E2255B6DF3007E1867 /* GalleryRailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GalleryRailView.swift; path = SignalUtilitiesKit/UI/GalleryRailView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3E3255B6DF4007E1867 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoPlayerView.swift; path = SignalUtilitiesKit/UI/VideoPlayerView.swift; sourceTree = SOURCE_ROOT; }; C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CommonStrings.swift; path = SignalUtilitiesKit/CommonStrings.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E5255B6DF4007E1867 /* ContactCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactCellView.h; path = SignalUtilitiesKit/ContactCellView.h; sourceTree = SOURCE_ROOT; }; - C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactTableViewCell.h; path = SignalUtilitiesKit/ContactTableViewCell.h; sourceTree = SOURCE_ROOT; }; - C38EF3E7255B6DF5007E1867 /* OWSButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSButton.swift; path = SignalUtilitiesKit/OWSButton.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAlerts.swift; path = SignalUtilitiesKit/OWSAlerts.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E9255B6DF6007E1867 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = SignalUtilitiesKit/Toast.swift; sourceTree = SOURCE_ROOT; }; - C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSearchBar.m; path = SignalUtilitiesKit/OWSSearchBar.m; sourceTree = SOURCE_ROOT; }; - C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactTableViewCell.m; path = SignalUtilitiesKit/ContactTableViewCell.m; sourceTree = SOURCE_ROOT; }; - C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSFlatButton.swift; path = SignalUtilitiesKit/OWSFlatButton.swift; sourceTree = SOURCE_ROOT; }; - C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = SignalUtilitiesKit/TappableStackView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3EE255B6DF6007E1867 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = SignalUtilitiesKit/GradientView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3E5255B6DF4007E1867 /* ContactCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactCellView.h; path = "SignalUtilitiesKit/Remove Later/ContactCellView.h"; sourceTree = SOURCE_ROOT; }; + C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactTableViewCell.h; path = "SignalUtilitiesKit/Remove Later/ContactTableViewCell.h"; sourceTree = SOURCE_ROOT; }; + C38EF3E7255B6DF5007E1867 /* OWSButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSButton.swift; path = SignalUtilitiesKit/UI/OWSButton.swift; sourceTree = SOURCE_ROOT; }; + C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAlerts.swift; path = SignalUtilitiesKit/UI/OWSAlerts.swift; sourceTree = SOURCE_ROOT; }; + C38EF3E9255B6DF6007E1867 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = SignalUtilitiesKit/UI/Toast.swift; sourceTree = SOURCE_ROOT; }; + C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSearchBar.m; path = SignalUtilitiesKit/UI/OWSSearchBar.m; sourceTree = SOURCE_ROOT; }; + C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactTableViewCell.m; path = "SignalUtilitiesKit/Remove Later/ContactTableViewCell.m"; sourceTree = SOURCE_ROOT; }; + C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSFlatButton.swift; path = SignalUtilitiesKit/UI/OWSFlatButton.swift; sourceTree = SOURCE_ROOT; }; + C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = SignalUtilitiesKit/UI/TappableStackView.swift; sourceTree = SOURCE_ROOT; }; + C38EF3EE255B6DF6007E1867 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = SignalUtilitiesKit/UI/GradientView.swift; sourceTree = SOURCE_ROOT; }; C38EF458255B710A007E1867 /* SignalUtilitiesKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalUtilitiesKit-Prefix.pch"; sourceTree = ""; }; C396469C2509D3ED00B0B9F5 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; C396469D2509D3F400B0B9F5 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; @@ -2375,7 +1962,7 @@ C3A7218F2558C0CD0043A11F /* FileServerAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileServerAPI.swift; sourceTree = ""; }; C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AnyPromise+Conversion.swift"; sourceTree = ""; }; C3A722292558C1E40043A11F /* DotNetAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotNetAPI.swift; sourceTree = ""; }; - C3A7225D2558C38D0043A11F /* AnyPromise+Retaining.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AnyPromise+Retaining.swift"; sourceTree = ""; }; + C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Retaining.swift"; sourceTree = ""; }; C3A7227F2558C4E10043A11F /* AttachmentStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentStream.swift; sourceTree = ""; }; C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIDelegate.swift; sourceTree = ""; }; C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupMessage+Conversion.swift"; sourceTree = ""; }; @@ -2739,7 +2326,6 @@ 34D1F0951F867BFC0066283D /* Cells */, 34D1F0B21F86D31D0066283D /* ConversationCollectionView.h */, 34D1F0B31F86D31D0066283D /* ConversationCollectionView.m */, - 45DDA6232090CEB500DE97F8 /* ConversationHeaderView.swift */, 34D1F0671F8678AA0066283D /* ConversationInputTextView.h */, 34D1F0681F8678AA0066283D /* ConversationInputTextView.m */, 34D1F0691F8678AA0066283D /* ConversationInputToolbar.h */, @@ -2784,12 +2370,6 @@ 34DBF006206C3CB200025978 /* OWSBubbleShapeView.m */, 34DBF002206BD5A500025978 /* OWSBubbleView.h */, 34DBF001206BD5A500025978 /* OWSBubbleView.m */, - 34D1F09A1F867BFC0066283D /* OWSContactOffersCell.h */, - 34D1F09B1F867BFC0066283D /* OWSContactOffersCell.m */, - 3403B95C20EA9527001A1F44 /* OWSContactShareButtonsView.h */, - 3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */, - 34CA63192097806E00E526A0 /* OWSContactShareView.h */, - 34CA631A2097806E00E526A0 /* OWSContactShareView.m */, 34D1F0B51F87F8850066283D /* OWSGenericAttachmentView.h */, 34D1F0B61F87F8850066283D /* OWSGenericAttachmentView.m */, 34AC0A22211C829E00997B47 /* OWSLabel.h */, @@ -2857,12 +2437,10 @@ 34C4E2562118957600BEA353 /* WebRTCProto.swift */, 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */, 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */, - 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */, 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */, A5509EC91A69AB8B00ABA4BC /* Main.storyboard */, 3430FE171F7751D4000EC51B /* GiphyAPI.swift */, 34D1F0511F7E8EA30066283D /* GiphyDownloader.swift */, - 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */, 4CEB78C72178EBAB00F315D2 /* OWSSessionResetJobRecord.h */, 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */, 451166BF1FD86B98000739BA /* AccountManager.swift */, @@ -2880,12 +2458,6 @@ 340FC893204DAC8C007AEB0F /* AboutTableViewController.m */, 340FC892204DAC8C007AEB0F /* AddToBlockListViewController.h */, 340FC886204DAC8C007AEB0F /* AddToBlockListViewController.m */, - 340FC881204DAC8C007AEB0F /* AdvancedSettingsTableViewController.h */, - 340FC88C204DAC8C007AEB0F /* AdvancedSettingsTableViewController.m */, - 340FC890204DAC8C007AEB0F /* BlockListViewController.h */, - 340FC887204DAC8C007AEB0F /* BlockListViewController.m */, - 340FC889204DAC8C007AEB0F /* DomainFrontingCountryViewController.h */, - 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */, 340FC88B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.h */, 340FC87B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.m */, 340FC88A204DAC8C007AEB0F /* NotificationSettingsViewController.h */, @@ -2900,15 +2472,10 @@ 340FC87E204DAC8C007AEB0F /* PrivacySettingsTableViewController.m */, 34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */, 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */, - 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */, - 348BB25C20A0C5530047AEC2 /* ContactShareViewHelper.swift */, - 34B3F83E1E8DF1700035BE1A /* ContactsPicker.swift */, - 34E88D252098C5AE00A608F4 /* ContactViewController.swift */, 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */, 34D1F04F1F7D45A60066283D /* GifPickerCell.swift */, 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */, 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */, - 34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */, 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */, 3496744E2076ACCE00080B5F /* LongTextViewController.swift */, 45B9EE9A200E91FB005D2F2D /* MediaDetailViewController.h */, @@ -2918,7 +2485,6 @@ 454A84032059C787008B8C75 /* MediaTileViewController.swift */, 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */, 34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */, - 452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */, 4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */, 34969559219B605E00DCFE74 /* ImagePickerController.swift */, 3496955A219B605E00DCFE74 /* PhotoCollectionPickerController.swift */, @@ -2927,22 +2493,12 @@ 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */, 3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */, 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */, - 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */, - 34B3F86D1E8DF1700035BE1A /* SignalsNavigationController.h */, - 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */, 340FC8A4204DAC8D007AEB0F /* AddToGroupViewController.h */, 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */, - 340FC89D204DAC8D007AEB0F /* FingerprintViewController.h */, - 340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */, - 340FC8A5204DAC8D007AEB0F /* FingerprintViewScanController.h */, - 340FC89F204DAC8D007AEB0F /* FingerprintViewScanController.m */, - 340FC898204DAC8D007AEB0F /* OWSAddToContactViewController.h */, - 340FC8A1204DAC8D007AEB0F /* OWSAddToContactViewController.m */, 340FC8A0204DAC8D007AEB0F /* OWSConversationSettingsViewController.h */, 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */, 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */, 4CA46F4B219CCC630038ABDE /* CaptionView.swift */, - 451764291DE939FD00EDB8B9 /* ContactCell.swift */, 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */, 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */, 34129B8521EF8779005457A8 /* LinkPreviewView.swift */, @@ -2950,13 +2506,9 @@ 34386A53207D271C009F5D9C /* NeverClearView.swift */, 34F308A01ECB469700BB7697 /* OWSBezierPathView.h */, 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */, - 459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */, - 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */, 34330AA11E79686200DF2FB9 /* OWSProgressView.h */, 34330AA21E79686200DF2FB9 /* OWSProgressView.m */, 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */, - 45D308AB2049A439000189E4 /* PinEntryView.h */, - 45D308AC2049A439000189E4 /* PinEntryView.m */, 457F671A20746193000EABCD /* QuotedReplyPreview.swift */, 45A6DAD51EBBF85500893231 /* ReminderView.swift */, 450D19111F85236600970622 /* RemoteVideoView.h */, @@ -2980,7 +2532,6 @@ B90418E5183E9DD40038554A /* DateUtil.m */, 34B0796C1FCF46B000E248C2 /* MainAppContext.h */, 34B0796B1FCF46B000E248C2 /* MainAppContext.m */, - 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */, 344825C4211390C700DB4BD8 /* OWSOrphanDataCleaner.h */, 344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */, 34D2CCD82062E7D000CB1A14 /* OWSScreenLockUI.h */, @@ -2993,17 +2544,11 @@ 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */, 4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */, 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */, - 4579431C1E7C8CE9008ED0C0 /* Pastelog.h */, - 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */, 450DF2041E0D74AC003D14BE /* Platform.swift */, 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */, 4CC613352227A00400E21A3A /* ConversationSearch.swift */, 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */, 340FC899204DAC8D007AEB0F /* OWSConversationSettingsViewDelegate.h */, - 340FC89E204DAC8D007AEB0F /* ShowGroupMembersViewController.h */, - 340FC8A6204DAC8D007AEB0F /* ShowGroupMembersViewController.m */, - 340FC8A3204DAC8D007AEB0F /* UpdateGroupViewController.h */, - 340FC89C204DAC8D007AEB0F /* UpdateGroupViewController.m */, 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */, 3448BFC01EDF0EA7005B2D69 /* ConversationView */, 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */, @@ -3146,11 +2691,6 @@ isa = PBXGroup; children = ( C354E75923FE2A7600CE22E3 /* BaseVC.swift */, - B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */, - B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */, - B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */, - B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */, - B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */, B82B408D239DC00D00A248E7 /* DisplayNameVC.swift */, C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */, B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */, @@ -3330,240 +2870,67 @@ C33FD9AC255A548A00E217F9 /* SignalUtilitiesKit */ = { isa = PBXGroup; children = ( + C33FD9B7255A54A300E217F9 /* Meta */, C3CA3B11255CF17200F4C6D4 /* Utilities */, - C33FDC09255A581D00E217F9 /* AccountServiceClient.swift */, - C33FDBC3255A581700E217F9 /* AnyPromise+Conversion.swift */, + C3851CD225624B060061EEB0 /* UI */, + C3851CE3256250FA0061EEB0 /* Remove Later */, + C38BBA17255E327A0041B9A3 /* Move to main app */, + C38BBA0B255E31EC0041B9A3 /* Attachments */, + C38BBA0C255E32020041B9A3 /* Threads */, + C38BBA0D255E321C0041B9A3 /* Messages */, + C38BBA0E255E32440041B9A3 /* Database */, C33FDB8A255A581200E217F9 /* AppContext.h */, C33FDB85255A581100E217F9 /* AppContext.m */, C33FDB01255A580700E217F9 /* AppReadiness.h */, C33FDB75255A581000E217F9 /* AppReadiness.m */, C33FDB4C255A580D00E217F9 /* AppVersion.h */, - C38EF215255B6D3A007E1867 /* OWSConversationColor.h */, - C38EF213255B6D3A007E1867 /* OWSConversationColor.m */, - C38EF212255B6D3A007E1867 /* Theme.h */, - C38EF225255B6D5D007E1867 /* AttachmentSharing.h */, - C38EF223255B6D5D007E1867 /* AttachmentSharing.m */, - C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */, - C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */, - C38EF241255B6D67007E1867 /* Collection+OWS.swift */, C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */, - C38EF3DE255B6DF2007E1867 /* AvatarImageView.swift */, C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */, - C38EF3E5255B6DF4007E1867 /* ContactCellView.h */, - C38EF3D6255B6DEF007E1867 /* ContactCellView.m */, - C38EF3DA255B6DF1007E1867 /* ContactsViewHelper.h */, - C38EF3D5255B6DEF007E1867 /* ContactsViewHelper.m */, - C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */, - C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */, - C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */, - C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */, - C38EF3E2255B6DF3007E1867 /* GalleryRailView.swift */, - C38EF3EE255B6DF6007E1867 /* GradientView.swift */, - C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */, - C38EF3E7255B6DF5007E1867 /* OWSButton.swift */, - C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */, - C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */, - C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */, - C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */, - C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */, - C38EF3D7255B6DF0007E1867 /* OWSTextField.h */, - C38EF3E0255B6DF3007E1867 /* OWSTextField.m */, - C38EF3D8255B6DF0007E1867 /* OWSTextView.h */, - C38EF3DF255B6DF2007E1867 /* OWSTextView.m */, - C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */, - C38EF3E1255B6DF3007E1867 /* TappableView.swift */, C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, - C38EF3E9255B6DF6007E1867 /* Toast.swift */, - C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */, - C38EF3E3255B6DF4007E1867 /* VideoPlayerView.swift */, - C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */, - C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */, - C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */, - C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */, - C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */, - C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */, - C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */, - C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */, - C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */, - C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */, - C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */, - C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */, - C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */, - C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */, - C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */, - C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */, - C38EF25D255B6D6E007E1867 /* OWSContactsManager.h */, - C38EF25B255B6D6E007E1867 /* OWSContactsManager.m */, - C38EF399255B6DD9007E1867 /* ContactShareViewModel.swift */, C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */, - C38EF354255B6DCB007E1867 /* ContactFieldView.swift */, - C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */, - C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */, - C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */, - C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */, - C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */, - C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */, - C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */, - C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */, - C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */, - C38EF348255B6DC7007E1867 /* ContactShareApprovalViewController.swift */, - C38EF347255B6DC6007E1867 /* EditContactShareNameViewController.swift */, - C38EF358255B6DCC007E1867 /* MediaMessageView.swift */, - C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */, - C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */, - C38EF34A255B6DC7007E1867 /* NewNonContactConversationViewController.h */, - C38EF350255B6DC9007E1867 /* NewNonContactConversationViewController.m */, - C38EF343255B6DC5007E1867 /* OWSNavigationController.h */, - C38EF356255B6DCB007E1867 /* OWSNavigationController.m */, - C38EF34D255B6DC8007E1867 /* OWSTableViewController.h */, - C38EF34B255B6DC8007E1867 /* OWSTableViewController.m */, - C38EF344255B6DC5007E1867 /* OWSViewController.h */, - C38EF355255B6DCB007E1867 /* OWSViewController.m */, - C38EF346255B6DC6007E1867 /* ReturnToCallViewController.swift */, - C38EF34C255B6DC8007E1867 /* ScreenLockViewController.h */, - C38EF351255B6DC9007E1867 /* ScreenLockViewController.m */, - C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */, - C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */, - C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */, - C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */, - C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */, - C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */, - C38EF33F255B6DC5007E1867 /* SheetViewController.swift */, - C38EF34F255B6DC9007E1867 /* ViewControllerUtils.h */, - C38EF340255B6DC5007E1867 /* ViewControllerUtils.m */, C38EF2E5255B6DB9007E1867 /* AppPreferences.swift */, - C38EF2FA255B6DBD007E1867 /* Bench.swift */, C38EF30B255B6DBE007E1867 /* BlockListCache.swift */, - C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */, - C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */, - C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */, - C38EF2F8255B6DBC007E1867 /* DebugLogger.h */, - C38EF2E6255B6DBA007E1867 /* DebugLogger.m */, C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */, - C38EF2ED255B6DBB007E1867 /* DisplayableText.swift */, C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */, C38EF304255B6DBE007E1867 /* ImageCache.swift */, - C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */, - C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */, - C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */, - C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */, - C38EF2EA255B6DBA007E1867 /* OWSAvatarBuilder.h */, - C38EF2EE255B6DBB007E1867 /* OWSAvatarBuilder.m */, - C38EF2FE255B6DBD007E1867 /* OWSContactAvatarBuilder.h */, - C38EF2F9255B6DBC007E1867 /* OWSContactAvatarBuilder.m */, - C38EF301255B6DBD007E1867 /* OWSFormat.h */, - C38EF305255B6DBE007E1867 /* OWSFormat.m */, - C38EF2EB255B6DBA007E1867 /* OWSGroupAvatarBuilder.h */, - C38EF2E8255B6DBA007E1867 /* OWSGroupAvatarBuilder.m */, C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */, C38EF308255B6DBE007E1867 /* OWSPreferences.m */, C38EF2E2255B6DB9007E1867 /* OWSScreenLock.swift */, - C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */, - C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */, C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */, C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */, - C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */, - C38EF306255B6DBE007E1867 /* OWSWindowManager.m */, C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */, - C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */, - C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */, - C38EF30A255B6DBE007E1867 /* UIUtil.h */, - C38EF300255B6DBD007E1867 /* UIUtil.m */, - C38EF2EF255B6DBB007E1867 /* Weak.swift */, - C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */, - C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */, - C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */, - C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */, - C38EF2D0255B6DAE007E1867 /* ProfileFetcherJob.swift */, - C38EF25A255B6D6E007E1867 /* OWSSyncManager.h */, - C38EF25C255B6D6E007E1867 /* OWSSyncManager.m */, - C38EF259255B6D6E007E1867 /* SystemContactsFetcher.swift */, - C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */, - C38EF23C255B6D66007E1867 /* UIColor+OWS.h */, - C38EF242255B6D67007E1867 /* UIColor+OWS.m */, - C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */, C38EF2BF255B6DA6007E1867 /* OWSContactOffersInteraction.h */, C38EF2C0255B6DA6007E1867 /* OWSContactOffersInteraction.m */, C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, - C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */, - C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */, - C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */, - C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */, - C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */, - C38EF239255B6D66007E1867 /* UIFont+OWS.h */, - C38EF238255B6D66007E1867 /* UIFont+OWS.m */, C38EF284255B6D84007E1867 /* AppSetup.h */, C38EF287255B6D85007E1867 /* AppSetup.m */, C38EF289255B6D85007E1867 /* NoopCallMessageHandler.swift */, C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */, - C38EF281255B6D84007E1867 /* OWSAudioSession.swift */, C38EF288255B6D85007E1867 /* OWSSounds.h */, C38EF28B255B6D86007E1867 /* OWSSounds.m */, C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, C38EF283255B6D84007E1867 /* VersionMigrations.h */, C38EF286255B6D85007E1867 /* VersionMigrations.m */, - C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, - C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, - C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */, - C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */, - C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */, - C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */, - C38EF23D255B6D66007E1867 /* UIView+OWS.h */, - C38EF23E255B6D66007E1867 /* UIView+OWS.m */, - C38EF240255B6D67007E1867 /* UIView+OWS.swift */, - C38EF236255B6D65007E1867 /* UIViewController+OWS.h */, - C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */, - C38EF224255B6D5D007E1867 /* SignalAttachment.swift */, - C38EF214255B6D3A007E1867 /* Theme.m */, C33FDA8B255A57FD00E217F9 /* AppVersion.m */, - C33FDA6E255A57FA00E217F9 /* Array+Description.swift */, - C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */, - C33FDC03255A581D00E217F9 /* ByteParser.h */, - C33FDAE0255A580400E217F9 /* ByteParser.m */, - C33FDB0C255A580700E217F9 /* CDSQuote.h */, - C33FDAD0255A580300E217F9 /* CDSQuote.m */, - C33FDBE3255A581A00E217F9 /* CDSSigningCertificate.h */, - C33FDACB255A580200E217F9 /* CDSSigningCertificate.m */, - C33FDBED255A581B00E217F9 /* ClosedGroupParser.swift */, C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */, - C33FDBEE255A581B00E217F9 /* ClosedGroupUpdateMessage.swift */, - C33FDB76255A581000E217F9 /* ClosedGroupUtilities.swift */, - C33FDAD2255A580300E217F9 /* Contact.h */, - C33FDA77255A57FB00E217F9 /* Contact.m */, - C33FDB66255A580F00E217F9 /* ContactDiscoveryService.h */, - C33FDBDC255A581900E217F9 /* ContactDiscoveryService.m */, - C33FDB5E255A580E00E217F9 /* ContactParser.swift */, C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */, - C33FDAF0255A580500E217F9 /* ContactsUpdater.h */, - C33FDA84255A57FC00E217F9 /* ContactsUpdater.m */, C33FDB68255A580F00E217F9 /* ContentProxy.swift */, C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */, - C33FDBAC255A581500E217F9 /* Data+SecureRandom.swift */, C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */, C33FDB54255A580D00E217F9 /* DataSource.h */, C33FDBB6255A581600E217F9 /* DataSource.m */, - C33FDA7C255A57FB00E217F9 /* Debugging.swift */, - C33FDC04255A581D00E217F9 /* DecryptionUtilities.swift */, - C33FDBD1255A581800E217F9 /* DeviceLink.swift */, - C33FDB72255A581000E217F9 /* DeviceLinkIndex.swift */, - C33FDB0F255A580800E217F9 /* DeviceLinkingSession.swift */, - C33FDB8D255A581200E217F9 /* DeviceLinkingSessionDelegate.swift */, - C33FDB1F255A580900E217F9 /* DeviceLinkingUtilities.swift */, - C33FDB98255A581300E217F9 /* DeviceNames.swift */, C33FDBDA255A581900E217F9 /* Dictionary+Description.swift */, C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, - C33FDAD4255A580300E217F9 /* EncryptionUtilities.swift */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, - C33FDB89255A581200E217F9 /* FileServerAPI+Deprecated.swift */, C33FDAC6255A580200E217F9 /* Fingerprint.pb.swift */, C33FDB26255A580A00E217F9 /* FingerprintProto.swift */, C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, @@ -3572,115 +2939,44 @@ C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, C33FDB19255A580900E217F9 /* GroupUtilities.swift */, C33FDB87255A581100E217F9 /* JobQueue.swift */, - C33FDC0F255A581E00E217F9 /* LKDeviceLinkMessage.h */, - C33FDAFA255A580600E217F9 /* LKDeviceLinkMessage.m */, C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, - C33FDA91255A57FD00E217F9 /* LKSyncOpenGroupsMessage.h */, - C33FDBDF255A581A00E217F9 /* LKSyncOpenGroupsMessage.m */, - C33FDB61255A580E00E217F9 /* LKUnlinkDeviceMessage.h */, - C33FDB13255A580800E217F9 /* LKUnlinkDeviceMessage.m */, C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */, - C33FDACA255A580200E217F9 /* LokiMessage.swift */, C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */, - C33FDC1F255A581F00E217F9 /* LokiSessionResetImplementation.swift */, - C33FDAFD255A580600E217F9 /* LRUCache.swift */, + C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */, C33FDA7E255A57FB00E217F9 /* Mention.swift */, C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, - C33FDB82255A581100E217F9 /* MessageWrapper.swift */, - C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */, - C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */, - C33FDAA9255A580000E217F9 /* Mnemonic.swift */, - C33FDA9F255A57FF00E217F9 /* NetworkManager.swift */, C33FDB80255A581100E217F9 /* Notification+Loki.swift */, C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */, - C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */, - C33FDAB8255A580100E217F9 /* NSArray+Functional.m */, - C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */, - C33FDB0D255A580800E217F9 /* NSArray+OWS.m */, - C33FDB29255A580A00E217F9 /* NSData+Image.h */, - C33FDAEF255A580500E217F9 /* NSData+Image.m */, C33FDB0E255A580800E217F9 /* NSError+MessageSending.h */, C33FDB09255A580700E217F9 /* NSError+MessageSending.m */, C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */, C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */, - C33FDADC255A580400E217F9 /* NSObject+Casting.h */, - C33FDAAA255A580000E217F9 /* NSObject+Casting.m */, - C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */, - C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */, - C33FDAC1255A580100E217F9 /* NSSet+Functional.m */, - C33FDB12255A580800E217F9 /* NSString+SSK.h */, - C33FDB45255A580C00E217F9 /* NSString+SSK.m */, - C33FDBE7255A581A00E217F9 /* NSTimer+OWS.h */, - C33FDA8F255A57FD00E217F9 /* NSTimer+OWS.m */, - C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */, - C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */, - C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */, - C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */, - C33FDBD0255A581800E217F9 /* OnionRequestAPI+Encryption.swift */, C33FDA99255A57FE00E217F9 /* OutageDetection.swift */, - C33FDB21255A580900E217F9 /* OWS2FAManager.h */, - C33FDB9A255A581300E217F9 /* OWS2FAManager.m */, - C33FDAA3255A57FF00E217F9 /* OWSAddToContactsOfferMessage.h */, - C33FDAA2255A57FF00E217F9 /* OWSAddToContactsOfferMessage.m */, - C33FDBBD255A581600E217F9 /* OWSAddToProfileWhitelistOfferMessage.h */, - C33FDAE5255A580400E217F9 /* OWSAddToProfileWhitelistOfferMessage.m */, - C33FDAD6255A580300E217F9 /* OWSAnalytics.h */, - C33FDA89255A57FD00E217F9 /* OWSAnalytics.m */, - C33FDAF5255A580600E217F9 /* OWSAnalyticsEvents.h */, - C33FDBAF255A581500E217F9 /* OWSAnalyticsEvents.m */, C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */, C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */, C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */, C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */, C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */, C33FDB07255A580700E217F9 /* OWSBackupFragment.m */, - C33FDBD4255A581900E217F9 /* OWSBatchMessageProcessor.h */, - C33FDB10255A580800E217F9 /* OWSBatchMessageProcessor.m */, - C33FDBF3255A581B00E217F9 /* OWSBlockedPhoneNumbersMessage.h */, - C33FDBE0255A581A00E217F9 /* OWSBlockedPhoneNumbersMessage.m */, C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */, - C33FDAC8255A580200E217F9 /* OWSCensorshipConfiguration.h */, - C33FDA7D255A57FB00E217F9 /* OWSCensorshipConfiguration.m */, C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */, C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */, - C33FDAC9255A580200E217F9 /* OWSContact.h */, - C33FDC0A255A581D00E217F9 /* OWSContact.m */, - C33FDB8E255A581200E217F9 /* OWSContact+Private.h */, - C33FDB35255A580B00E217F9 /* OWSContactDiscoveryOperation.swift */, C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */, C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */, - C33FDB42255A580C00E217F9 /* OWSCountryMetadata.h */, - C33FDAC5255A580200E217F9 /* OWSCountryMetadata.m */, - C33FDB2D255A580A00E217F9 /* OWSDevice.h */, - C33FDB30255A580A00E217F9 /* OWSDevice.m */, - C33FDAAD255A580000E217F9 /* OWSDeviceProvisioner.h */, - C33FDAD7255A580300E217F9 /* OWSDeviceProvisioner.m */, - C33FDB1B255A580900E217F9 /* OWSDeviceProvisioningCodeService.h */, - C33FDAEB255A580500E217F9 /* OWSDeviceProvisioningCodeService.m */, - C33FDBF5255A581B00E217F9 /* OWSDeviceProvisioningService.h */, - C33FDB92255A581200E217F9 /* OWSDeviceProvisioningService.m */, - C33FDBDB255A581900E217F9 /* OWSDevicesService.h */, - C33FDBE5255A581A00E217F9 /* OWSDevicesService.m */, C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, - C33FDB16255A580800E217F9 /* OWSDisappearingMessagesConfigurationMessage.h */, - C33FDB97255A581300E217F9 /* OWSDisappearingMessagesConfigurationMessage.m */, C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */, C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */, C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */, C33FDA96255A57FE00E217F9 /* OWSDispatch.h */, C33FDAC3255A580200E217F9 /* OWSDispatch.m */, - C33FDB63255A580E00E217F9 /* OWSDynamicOutgoingMessage.h */, - C33FDAD1255A580300E217F9 /* OWSDynamicOutgoingMessage.m */, - C33FDB2E255A580A00E217F9 /* OWSEndSessionMessage.h */, - C33FDB27255A580A00E217F9 /* OWSEndSessionMessage.m */, C33FDBF9255A581C00E217F9 /* OWSError.h */, C33FDC0B255A581D00E217F9 /* OWSError.m */, C33FDA72255A57FA00E217F9 /* OWSFailedAttachmentDownloadsJob.h */, @@ -3689,10 +2985,6 @@ C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */, C33FDBAB255A581500E217F9 /* OWSFileSystem.h */, C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */, - C33FDBC8255A581700E217F9 /* OWSFingerprint.h */, - C33FDB05255A580700E217F9 /* OWSFingerprint.m */, - C33FDBCF255A581800E217F9 /* OWSFingerprintBuilder.h */, - C33FDAEE255A580500E217F9 /* OWSFingerprintBuilder.m */, C33FDABB255A580100E217F9 /* OWSGroupsOutputStream.h */, C33FDAD8255A580300E217F9 /* OWSGroupsOutputStream.m */, C33FDB52255A580D00E217F9 /* OWSHTTPSecurityPolicy.h */, @@ -3701,125 +2993,48 @@ C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */, C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, - C33FDAF6255A580600E217F9 /* OWSIncomingSentMessageTranscript.h */, - C33FDB84255A581100E217F9 /* OWSIncomingSentMessageTranscript.m */, C33FDB2A255A580A00E217F9 /* OWSIncompleteCallsJob.h */, C33FDBF7255A581C00E217F9 /* OWSIncompleteCallsJob.m */, - C33FDAA6255A57FF00E217F9 /* OWSLinkedDeviceReadReceipt.h */, - C33FDA9A255A57FE00E217F9 /* OWSLinkedDeviceReadReceipt.m */, C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, - C33FDB14255A580800E217F9 /* OWSMath.h */, C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */, C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */, - C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */, C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */, C33FDB70255A580F00E217F9 /* OWSMessageServiceParams.m */, C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */, C33FDBA1255A581400E217F9 /* OWSOperation.h */, C33FDB78255A581000E217F9 /* OWSOperation.m */, - C33FDA66255A57F900E217F9 /* OWSOutgoingCallMessage.h */, - C33FDB28255A580A00E217F9 /* OWSOutgoingCallMessage.m */, - C33FDBB3255A581500E217F9 /* OWSOutgoingNullMessage.h */, - C33FDBE6255A581A00E217F9 /* OWSOutgoingNullMessage.m */, C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */, C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */, - C33FDB24255A580900E217F9 /* OWSOutgoingSentMessageTranscript.h */, - C33FDBD5255A581900E217F9 /* OWSOutgoingSentMessageTranscript.m */, - C33FDBE4255A581A00E217F9 /* OWSOutgoingSyncMessage.h */, - C33FDBFF255A581C00E217F9 /* OWSOutgoingSyncMessage.m */, - C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, - C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, - C33FDB1A255A580900E217F9 /* OWSPrimaryStorage+Calling.h */, - C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */, - C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */, - C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */, - C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */, - C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */, - C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */, - C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */, - C33FDB50255A580D00E217F9 /* OWSPrimaryStorage+PreKeyStore.m */, - C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */, - C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */, - C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */, - C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */, - C33FDB08255A580700E217F9 /* OWSProfileKeyMessage.h */, - C33FDB3D255A580B00E217F9 /* OWSProfileKeyMessage.m */, C33FDB62255A580E00E217F9 /* OWSProvisioningCipher.h */, C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */, - C33FDC0D255A581E00E217F9 /* OWSProvisioningMessage.h */, - C33FDA9B255A57FE00E217F9 /* OWSProvisioningMessage.m */, C33FDC19255A581F00E217F9 /* OWSQueues.h */, C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */, C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */, - C33FDAE2255A580400E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.h */, - C33FDB96255A581300E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.m */, C33FDAE1255A580400E217F9 /* OWSReadTracking.h */, - C33FDA8D255A57FD00E217F9 /* OWSReceiptsForSenderMessage.h */, - C33FDAAE255A580000E217F9 /* OWSReceiptsForSenderMessage.m */, C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */, C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */, C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */, C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */, - C38EEFD5255B5BA2007E1867 /* OldSnodeAPI.swift */, - C33FDB06255A580700E217F9 /* OWSRequestBuilder.h */, - C33FDB00255A580600E217F9 /* OWSRequestBuilder.m */, - C33FDBC0255A581700E217F9 /* OWSRequestFactory.h */, - C33FDB86255A581100E217F9 /* OWSRequestFactory.m */, - C33FDAA5255A57FF00E217F9 /* OWSRequestMaker.swift */, C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */, - C33FDAC7255A580200E217F9 /* OWSSignalService.h */, - C33FDB18255A580800E217F9 /* OWSSignalService.m */, - C33FDAFE255A580600E217F9 /* OWSStorage.h */, - C33FDAB1255A580000E217F9 /* OWSStorage.m */, C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, - C33FDB65255A580F00E217F9 /* OWSSyncConfigurationMessage.h */, - C33FDC1D255A581F00E217F9 /* OWSSyncConfigurationMessage.m */, - C33FDB57255A580D00E217F9 /* OWSSyncContactsMessage.h */, - C33FDA9C255A57FE00E217F9 /* OWSSyncContactsMessage.m */, - C33FDBB5255A581600E217F9 /* OWSSyncGroupsMessage.h */, - C33FDC00255A581C00E217F9 /* OWSSyncGroupsMessage.m */, - C33FDAF8255A580600E217F9 /* OWSSyncGroupsRequestMessage.h */, - C33FDA76255A57FB00E217F9 /* OWSSyncGroupsRequestMessage.m */, C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */, C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */, C33FDB5A255A580E00E217F9 /* OWSUDManager.swift */, - C33FDBD2255A581800E217F9 /* OWSUnknownContactBlockOfferMessage.h */, - C33FDBE2255A581A00E217F9 /* OWSUnknownContactBlockOfferMessage.m */, C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */, C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */, - C33FDB7C255A581000E217F9 /* OWSVerificationStateChangeMessage.h */, - C33FDB0B255A580700E217F9 /* OWSVerificationStateChangeMessage.m */, - C33FDBD9255A581900E217F9 /* OWSVerificationStateSyncMessage.h */, - C33FDACE255A580300E217F9 /* OWSVerificationStateSyncMessage.m */, - C33FDABA255A580100E217F9 /* OWSWebSocket.h */, - C33FDAAB255A580000E217F9 /* OWSWebSocket.m */, C33FDB8F255A581200E217F9 /* ParamParser.swift */, - C33FDBA2255A581400E217F9 /* PhoneNumber.h */, - C33FDA8A255A57FD00E217F9 /* PhoneNumber.m */, - C33FDBFA255A581C00E217F9 /* PhoneNumberUtil.h */, - C33FDB79255A581000E217F9 /* PhoneNumberUtil.m */, C33FDB3A255A580B00E217F9 /* Poller.swift */, C33FDB53255A580D00E217F9 /* PreKeyBundle+jsonDict.h */, C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */, C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */, - C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, - C33FDA83255A57FC00E217F9 /* Promise+retainUntilComplete.swift */, - C33FDC10255A581E00E217F9 /* ProofOfWork.swift */, - C33FDB91255A581200E217F9 /* ProtoUtils.h */, - C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, C33FDB33255A580B00E217F9 /* Provisioning.pb.swift */, C33FDAB0255A580000E217F9 /* ProvisioningProto.swift */, C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */, C33FDADF255A580400E217F9 /* PublicChatManager.swift */, C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */, C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */, - C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */, C33FDA98255A57FE00E217F9 /* RotateSignedKeyOperation.swift */, - C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */, - C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */, - C33FDBEA255A581A00E217F9 /* SessionRequestMessage.swift */, - C33FDC17255A581F00E217F9 /* SharedSenderKeysImplementation.swift */, C33FDBAE255A581500E217F9 /* SignalAccount.h */, C33FDC06255A581D00E217F9 /* SignalAccount.m */, C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */, @@ -3828,102 +3043,36 @@ C33FDAEC255A580500E217F9 /* SignalRecipient.h */, C33FDBB7255A581600E217F9 /* SignalRecipient.m */, C33FDC08255A581D00E217F9 /* SignalService.pb.swift */, - C33FDB4A255A580C00E217F9 /* SignalServiceClient.swift */, C33FDBA5255A581400E217F9 /* SignalServiceProfile.swift */, - C33FDBC2255A581700E217F9 /* SSKAsserts.h */, C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */, C33FDACD255A580200E217F9 /* SSKJobRecord.m */, - C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */, C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */, C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, C33FDAA4255A57FF00E217F9 /* SSKProto.swift */, - C33FDB6E255A580F00E217F9 /* SSKProtoPrekeyBundleMessage+Loki.swift */, - C33FDA78255A57FB00E217F9 /* SSKWebSocket.swift */, - C33FDB36255A580B00E217F9 /* Storage.swift */, - C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */, - C33FDB95255A581300E217F9 /* Storage+Collections.swift */, - C33FDBE8255A581A00E217F9 /* Storage+OnionRequests.swift */, - C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */, - C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, - C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */, - C33FDB3F255A580C00E217F9 /* String+SSK.swift */, - C33FDAAF255A580000E217F9 /* String+Trimming.swift */, C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, - C33FDAB6255A580100E217F9 /* SyncMessagesProtocol.swift */, C33FDB94255A581300E217F9 /* TSAccountManager.h */, C33FDB88255A581200E217F9 /* TSAccountManager.m */, - C33FDC15255A581E00E217F9 /* TSAttachment.h */, - C33FDAC2255A580200E217F9 /* TSAttachment.m */, - C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */, - C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */, - C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */, - C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */, C33FDB02255A580700E217F9 /* TSCall.h */, C33FDC1C255A581F00E217F9 /* TSCall.m */, C33FDC12255A581E00E217F9 /* TSConstants.h */, C33FDABE255A580100E217F9 /* TSConstants.m */, - C33FDAB3255A580000E217F9 /* TSContactThread.h */, - C33FDAF9255A580600E217F9 /* TSContactThread.m */, C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */, C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */, C33FDB46255A580C00E217F9 /* TSDatabaseView.m */, - C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, - C33FDBB0255A581500E217F9 /* TSErrorMessage.h */, - C33FDAE7255A580500E217F9 /* TSErrorMessage.m */, - C33FDB0A255A580700E217F9 /* TSGroupModel.h */, - C33FDB73255A581000E217F9 /* TSGroupModel.m */, - C33FDA79255A57FB00E217F9 /* TSGroupThread.h */, - C33FDC01255A581C00E217F9 /* TSGroupThread.m */, - C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */, - C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */, - C33FDADD255A580400E217F9 /* TSInfoMessage.h */, - C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */, - C33FDAE6255A580400E217F9 /* TSInteraction.h */, - C33FDBE9255A581A00E217F9 /* TSInteraction.m */, - C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */, - C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */, - C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */, - C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */, - C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */, - C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */, - C33FDA70255A57FA00E217F9 /* TSMessage.h */, - C33FDB60255A580E00E217F9 /* TSMessage.m */, - C33FDAB5255A580000E217F9 /* TSNetworkManager.h */, - C33FDAB2255A580000E217F9 /* TSNetworkManager.m */, - C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */, - C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */, C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */, C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */, - C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */, - C33FDB83255A581100E217F9 /* TSQuotedMessage.m */, - C33FDBB1255A581500E217F9 /* TSSocketManager.h */, - C33FDC11255A581E00E217F9 /* TSSocketManager.m */, C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, - C33FDAD3255A580300E217F9 /* TSThread.h */, - C33FDBB8255A581600E217F9 /* TSThread.m */, - C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */, - C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */, - C33FDB9F255A581400E217F9 /* TTLUtilities.swift */, - C33FDBC4255A581700E217F9 /* TypingIndicatorMessage.swift */, C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */, - C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, - C33FDB81255A581100E217F9 /* UIImage+OWS.m */, - C33FDB49255A580C00E217F9 /* WeakTimer.swift */, C37F53E8255BA9BB002AEA92 /* Environment.h */, C37F5402255BA9ED002AEA92 /* Environment.m */, - C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, - C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, - C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, - C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */, - C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */, - C38EEF09255B49A8007E1867 /* SSKProtoEnvelope+Conversion.swift */, - C33FD9B7255A54A300E217F9 /* Meta */, + B8C2B33B2563770800551B4D /* ThreadUtil.h */, + B8C2B331256376F000551B4D /* ThreadUtil.m */, ); path = SignalUtilitiesKit; sourceTree = ""; @@ -3962,6 +3111,230 @@ path = CSV; sourceTree = ""; }; + C3851CD225624B060061EEB0 /* UI */ = { + isa = PBXGroup; + children = ( + B8C2B2C72563685C00551B4D /* CircleView.swift */, + C38EF23D255B6D66007E1867 /* UIView+OWS.h */, + C38EF23E255B6D66007E1867 /* UIView+OWS.m */, + C38EF240255B6D67007E1867 /* UIView+OWS.swift */, + C38EF236255B6D65007E1867 /* UIViewController+OWS.h */, + C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */, + C38EF23C255B6D66007E1867 /* UIColor+OWS.h */, + C38EF242255B6D67007E1867 /* UIColor+OWS.m */, + C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */, + C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */, + C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */, + C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */, + C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */, + C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */, + C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */, + C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */, + C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */, + C38EF358255B6DCC007E1867 /* MediaMessageView.swift */, + C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */, + C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */, + C38EF343255B6DC5007E1867 /* OWSNavigationController.h */, + C38EF356255B6DCB007E1867 /* OWSNavigationController.m */, + C38EF34D255B6DC8007E1867 /* OWSTableViewController.h */, + C38EF34B255B6DC8007E1867 /* OWSTableViewController.m */, + C38EF344255B6DC5007E1867 /* OWSViewController.h */, + C38EF355255B6DCB007E1867 /* OWSViewController.m */, + C38EF34C255B6DC8007E1867 /* ScreenLockViewController.h */, + C38EF351255B6DC9007E1867 /* ScreenLockViewController.m */, + C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */, + C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */, + C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */, + C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */, + C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */, + C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */, + C38EF33F255B6DC5007E1867 /* SheetViewController.swift */, + C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */, + C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */, + C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */, + C38EF3E7255B6DF5007E1867 /* OWSButton.swift */, + C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */, + C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */, + C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */, + C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */, + C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */, + C38EF3D7255B6DF0007E1867 /* OWSTextField.h */, + C38EF3E0255B6DF3007E1867 /* OWSTextField.m */, + C38EF3D8255B6DF0007E1867 /* OWSTextView.h */, + C38EF3DF255B6DF2007E1867 /* OWSTextView.m */, + C38EF3E9255B6DF6007E1867 /* Toast.swift */, + C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */, + C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */, + C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */, + C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */, + C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */, + C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */, + C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */, + C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */, + C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */, + C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */, + C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */, + C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */, + C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */, + C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */, + C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */, + C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */, + C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */, + C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */, + C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */, + C38EF2ED255B6DBB007E1867 /* DisplayableText.swift */, + C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */, + C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */, + C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */, + C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */, + C38EF212255B6D3A007E1867 /* Theme.h */, + C38EF214255B6D3A007E1867 /* Theme.m */, + C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */, + C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */, + C38EF30A255B6DBE007E1867 /* UIUtil.h */, + C38EF300255B6DBD007E1867 /* UIUtil.m */, + C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */, + C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */, + C38EF3E2255B6DF3007E1867 /* GalleryRailView.swift */, + C38EF3EE255B6DF6007E1867 /* GradientView.swift */, + C38EF3E3255B6DF4007E1867 /* VideoPlayerView.swift */, + C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */, + C38EF3E1255B6DF3007E1867 /* TappableView.swift */, + C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */, + C38EF306255B6DBE007E1867 /* OWSWindowManager.m */, + C38EF239255B6D66007E1867 /* UIFont+OWS.h */, + C38EF238255B6D66007E1867 /* UIFont+OWS.m */, + ); + path = UI; + sourceTree = ""; + }; + C3851CE3256250FA0061EEB0 /* Remove Later */ = { + isa = PBXGroup; + children = ( + C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, + C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */, + C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */, + C38EF3E5255B6DF4007E1867 /* ContactCellView.h */, + C38EF3D6255B6DEF007E1867 /* ContactCellView.m */, + C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */, + C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */, + C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */, + C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */, + C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */, + C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */, + ); + path = "Remove Later"; + sourceTree = ""; + }; + C38BBA0B255E31EC0041B9A3 /* Attachments */ = { + isa = PBXGroup; + children = ( + C38EF224255B6D5D007E1867 /* SignalAttachment.swift */, + C33FDC15255A581E00E217F9 /* TSAttachment.h */, + C33FDAC2255A580200E217F9 /* TSAttachment.m */, + C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */, + C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */, + C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */, + C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */, + ); + path = Attachments; + sourceTree = ""; + }; + C38BBA0C255E32020041B9A3 /* Threads */ = { + isa = PBXGroup; + children = ( + C33FDAB3255A580000E217F9 /* TSContactThread.h */, + C33FDAF9255A580600E217F9 /* TSContactThread.m */, + C33FDB0A255A580700E217F9 /* TSGroupModel.h */, + C33FDB73255A581000E217F9 /* TSGroupModel.m */, + C33FDA79255A57FB00E217F9 /* TSGroupThread.h */, + C33FDC01255A581C00E217F9 /* TSGroupThread.m */, + C33FDAD3255A580300E217F9 /* TSThread.h */, + C33FDBB8255A581600E217F9 /* TSThread.m */, + ); + path = Threads; + sourceTree = ""; + }; + C38BBA0D255E321C0041B9A3 /* Messages */ = { + isa = PBXGroup; + children = ( + C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, + C33FDBB0255A581500E217F9 /* TSErrorMessage.h */, + C33FDAE7255A580500E217F9 /* TSErrorMessage.m */, + C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */, + C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */, + C33FDADD255A580400E217F9 /* TSInfoMessage.h */, + C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */, + C33FDAE6255A580400E217F9 /* TSInteraction.h */, + C33FDBE9255A581A00E217F9 /* TSInteraction.m */, + C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */, + C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */, + C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */, + C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */, + C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */, + C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */, + C33FDA70255A57FA00E217F9 /* TSMessage.h */, + C33FDB60255A580E00E217F9 /* TSMessage.m */, + C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */, + C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */, + C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */, + C33FDB83255A581100E217F9 /* TSQuotedMessage.m */, + ); + path = Messages; + sourceTree = ""; + }; + C38BBA0E255E32440041B9A3 /* Database */ = { + isa = PBXGroup; + children = ( + C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, + C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, + C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, + C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */, + C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */, + C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */, + C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */, + C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, + C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, + C33FDB1A255A580900E217F9 /* OWSPrimaryStorage+Calling.h */, + C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */, + C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */, + C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */, + C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */, + C33FDB50255A580D00E217F9 /* OWSPrimaryStorage+PreKeyStore.m */, + C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */, + C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */, + C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */, + C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */, + C33FDAFE255A580600E217F9 /* OWSStorage.h */, + C33FDAB1255A580000E217F9 /* OWSStorage.m */, + C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */, + C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */, + C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, + C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, + C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, + C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */, + C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */, + ); + path = Database; + sourceTree = ""; + }; + C38BBA17255E327A0041B9A3 /* Move to main app */ = { + isa = PBXGroup; + children = ( + C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */, + C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */, + C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */, + C33FDB36255A580B00E217F9 /* Storage.swift */, + C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */, + C33FDB95255A581300E217F9 /* Storage+Collections.swift */, + C33FDBE8255A581A00E217F9 /* Storage+OnionRequests.swift */, + C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */, + C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, + C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */, + ); + path = "Move to main app"; + sourceTree = ""; + }; C396DAE72518407300FF6DC5 /* SwiftCSV */ = { isa = PBXGroup; children = ( @@ -4075,7 +3448,6 @@ C3C2A68B255388D500C340D1 /* Meta */, C3C2A5D72553860B00C340D1 /* AESGCM.swift */, C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */, - C3A7225D2558C38D0043A11F /* AnyPromise+Retaining.swift */, C3C2A5D12553860800C340D1 /* Array+Description.swift */, C3C2ABD12553C6C900C340D1 /* Data+SecureRandom.swift */, C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */, @@ -4089,6 +3461,7 @@ C352A3762557859C00338F3E /* NSTimer+Proxying.h */, C352A36C2557858D00338F3E /* NSTimer+Proxying.m */, C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */, + C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */, C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */, C3C2AC2D2553CBEB00C340D1 /* String+Trimming.swift */, C352A3A42557B5F000338F3E /* TSRequest.h */, @@ -4332,8 +3705,64 @@ C3CA3B11255CF17200F4C6D4 /* Utilities */ = { isa = PBXGroup; children = ( + C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, + C33FDB81255A581100E217F9 /* UIImage+OWS.m */, + C33FDB49255A580C00E217F9 /* WeakTimer.swift */, + C33FDB3F255A580C00E217F9 /* String+SSK.swift */, + C33FDAAF255A580000E217F9 /* String+Trimming.swift */, + C33FDBC2255A581700E217F9 /* SSKAsserts.h */, + C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */, + C33FDB91255A581200E217F9 /* ProtoUtils.h */, + C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, + C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */, + C33FDB14255A580800E217F9 /* OWSMath.h */, + C33FDADC255A580400E217F9 /* NSObject+Casting.h */, + C33FDAAA255A580000E217F9 /* NSObject+Casting.m */, + C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */, + C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */, + C33FDAC1255A580100E217F9 /* NSSet+Functional.m */, + C33FDB12255A580800E217F9 /* NSString+SSK.h */, + C33FDB45255A580C00E217F9 /* NSString+SSK.m */, + C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */, + C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */, + C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */, + C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */, + C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */, + C33FDAB8255A580100E217F9 /* NSArray+Functional.m */, + C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */, + C33FDB0D255A580800E217F9 /* NSArray+OWS.m */, + C33FDB29255A580A00E217F9 /* NSData+Image.h */, + C33FDAEF255A580500E217F9 /* NSData+Image.m */, + C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */, + C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */, + C33FDAFD255A580600E217F9 /* LRUCache.swift */, + C33FDA7C255A57FB00E217F9 /* Debugging.swift */, + C33FDC03255A581D00E217F9 /* ByteParser.h */, + C33FDAE0255A580400E217F9 /* ByteParser.m */, + C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */, + C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */, + C38EF225255B6D5D007E1867 /* AttachmentSharing.h */, + C38EF223255B6D5D007E1867 /* AttachmentSharing.m */, + C38EF241255B6D67007E1867 /* Collection+OWS.swift */, + C38EF2F8255B6DBC007E1867 /* DebugLogger.h */, + C38EF2E6255B6DBA007E1867 /* DebugLogger.m */, C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */, C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */, + C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */, + C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */, + C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */, + C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */, + C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */, + C38EF301255B6DBD007E1867 /* OWSFormat.h */, + C38EF305255B6DBE007E1867 /* OWSFormat.m */, + C38EF281255B6D84007E1867 /* OWSAudioSession.swift */, + C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */, + C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, + C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */, + C38EF2EF255B6DBB007E1867 /* Weak.swift */, + C38EF2FA255B6DBD007E1867 /* Bench.swift */, + C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */, + C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */, ); path = Utilities; sourceTree = ""; @@ -4480,35 +3909,27 @@ buildActionMask = 2147483647; files = ( C33FDD74255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.h in Headers */, - C33FDCDB255A582000E217F9 /* OWS2FAManager.h in Headers */, C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */, - C33FDD6B255A582000E217F9 /* TSSocketManager.h in Headers */, C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */, - C33FDC47255A581F00E217F9 /* OWSReceiptsForSenderMessage.h in Headers */, C33FDD46255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.h in Headers */, C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */, C33FDCE3255A582000E217F9 /* NSData+Image.h in Headers */, - C33FDC5D255A582000E217F9 /* OWSAddToContactsOfferMessage.h in Headers */, C38EF311255B6DBF007E1867 /* OWSScrubbingLogFormatter.h in Headers */, C33FDC77255A582000E217F9 /* OWSOutgoingReceiptManager.h in Headers */, + B8C2B3442563782400551B4D /* ThreadUtil.h in Headers */, C33FDCBB255A582000E217F9 /* AppReadiness.h in Headers */, C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */, - C33FDD82255A582000E217F9 /* OWSFingerprint.h in Headers */, C38EF32D255B6DBF007E1867 /* BlockListUIUtils.h in Headers */, C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */, C38EF291255B6D86007E1867 /* SignalKeyingStorage.h in Headers */, - C33FDD6F255A582000E217F9 /* OWSSyncGroupsMessage.h in Headers */, C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */, C33FDD73255A582000E217F9 /* ProfileManagerProtocol.h in Headers */, - C33FDD11255A582000E217F9 /* OWSSyncContactsMessage.h in Headers */, C38EF2D8255B6DAF007E1867 /* OWSUserProfile.h in Headers */, C33FDCB6255A582000E217F9 /* MIMETypeUtil.h in Headers */, - C33FDCAF255A582000E217F9 /* OWSAnalyticsEvents.h in Headers */, C33FDD17255A582000E217F9 /* TSErrorMessage_privateConstructor.h in Headers */, C33FDC93255A582000E217F9 /* OWSDisappearingMessagesConfiguration.h in Headers */, C38EF2C2255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h in Headers */, C33FDCCC255A582000E217F9 /* NSString+SSK.h in Headers */, - C33FDCB0255A582000E217F9 /* OWSIncomingSentMessageTranscript.h in Headers */, C38EF313255B6DBF007E1867 /* OWSUnreadIndicator.h in Headers */, C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, C33FDC9B255A582000E217F9 /* OWSReadTracking.h in Headers */, @@ -4516,29 +3937,20 @@ C33FDC97255A582000E217F9 /* TSInfoMessage.h in Headers */, C33FDD65255A582000E217F9 /* OWSFileSystem.h in Headers */, C33FDCD6255A582000E217F9 /* UIImage+OWS.h in Headers */, - C38EF219255B6D3B007E1867 /* OWSConversationColor.h in Headers */, - C38EF369255B6DCC007E1867 /* ViewControllerUtils.h in Headers */, C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */, - C33FDD7A255A582000E217F9 /* OWSRequestFactory.h in Headers */, C33FDC3A255A581F00E217F9 /* OWSDisappearingMessagesJob.h in Headers */, C33FDD6A255A582000E217F9 /* TSErrorMessage.h in Headers */, C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */, C33FDC7A255A582000E217F9 /* OWSIncomingMessageFinder.h in Headers */, C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */, - C33FDC8C255A582000E217F9 /* Contact.h in Headers */, C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */, C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */, C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */, C33FDD4E255A582000E217F9 /* TSAccountManager.h in Headers */, - C33FDD77255A582000E217F9 /* OWSAddToProfileWhitelistOfferMessage.h in Headers */, C33FDDAB255A582000E217F9 /* OWSIdentityManager.h in Headers */, - C33FDC82255A582000E217F9 /* OWSCensorshipConfiguration.h in Headers */, C33FDC2C255A581F00E217F9 /* OWSFailedAttachmentDownloadsJob.h in Headers */, - C33FDCD5255A582000E217F9 /* OWSDeviceProvisioningCodeService.h in Headers */, C38EF22A255B6D5D007E1867 /* AttachmentSharing.h in Headers */, - C33FDDB4255A582000E217F9 /* PhoneNumberUtil.h in Headers */, C33FDD67255A582000E217F9 /* OWSRecordTranscriptJob.h in Headers */, - C33FDCAA255A582000E217F9 /* ContactsUpdater.h in Headers */, C33FDDCF255A582000E217F9 /* TSAttachment.h in Headers */, C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */, C33FDC2F255A581F00E217F9 /* OWSSyncManagerProtocol.h in Headers */, @@ -4547,76 +3959,49 @@ C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */, C33FDCBC255A582000E217F9 /* TSCall.h in Headers */, C38EF2C3255B6DA6007E1867 /* OWSContactOffersInteraction.h in Headers */, - C33FDD95255A582000E217F9 /* OWSDevicesService.h in Headers */, C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */, C33FDCD4255A582000E217F9 /* OWSPrimaryStorage+Calling.h in Headers */, C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */, C33FDC5B255A582000E217F9 /* TSYapDatabaseObject.h in Headers */, - C33FDD8C255A582000E217F9 /* OWSUnknownContactBlockOfferMessage.h in Headers */, - C33FDD93255A582000E217F9 /* OWSVerificationStateSyncMessage.h in Headers */, C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */, C33FDD88255A582000E217F9 /* OWSMessageServiceParams.h in Headers */, C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */, C33FDCC4255A582000E217F9 /* TSGroupModel.h in Headers */, C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */, - C33FDC6F255A582000E217F9 /* TSNetworkManager.h in Headers */, C33FDD4B255A582000E217F9 /* ProtoUtils.h in Headers */, C33FDD19255A582000E217F9 /* YapDatabaseConnection+OWS.h in Headers */, - C33FDD1F255A582000E217F9 /* OWSSyncConfigurationMessage.h in Headers */, C38EF216255B6D3B007E1867 /* Theme.h in Headers */, C38EF31B255B6DBF007E1867 /* OWSPreferences.h in Headers */, C33FDD0C255A582000E217F9 /* OWSHTTPSecurityPolicy.h in Headers */, C33FDC57255A582000E217F9 /* OWSContactsOutputStream.h in Headers */, - C38EF314255B6DBF007E1867 /* OWSAvatarBuilder.h in Headers */, C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */, C33FDDD2255A582000E217F9 /* TSAttachmentPointer.h in Headers */, C38EF3F0255B6DF7007E1867 /* ThreadViewHelper.h in Headers */, - C33FDD1D255A582000E217F9 /* OWSDynamicOutgoingMessage.h in Headers */, C33FDCD7255A582000E217F9 /* OWSReadReceiptManager.h in Headers */, C33FDD21255A582000E217F9 /* OWSMediaGalleryFinder.h in Headers */, - C33FDCC6255A582000E217F9 /* CDSQuote.h in Headers */, C38EF274255B6D7A007E1867 /* OWSResaveCollectionDBMigration.h in Headers */, C33FDD02255A582000E217F9 /* TSOutgoingMessage.h in Headers */, C33FDC95255A582000E217F9 /* OWSFailedMessagesJob.h in Headers */, - C33FDD20255A582000E217F9 /* ContactDiscoveryService.h in Headers */, - C33FDD1B255A582000E217F9 /* LKUnlinkDeviceMessage.h in Headers */, C38EF3F1255B6DF7007E1867 /* OWSSearchBar.h in Headers */, C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */, - C33FDD8E255A582000E217F9 /* OWSBatchMessageProcessor.h in Headers */, C33FDC5A255A582000E217F9 /* OWSRecipientIdentity.h in Headers */, C33FDD1C255A582000E217F9 /* OWSProvisioningCipher.h in Headers */, C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */, - C33FDD48255A582000E217F9 /* OWSContact+Private.h in Headers */, C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */, - C33FDDA1255A582000E217F9 /* NSTimer+OWS.h in Headers */, C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */, C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */, C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */, - C33FDC74255A582000E217F9 /* OWSWebSocket.h in Headers */, C33FDC9E255A582000E217F9 /* TSAttachmentStream.h in Headers */, - C33FDC20255A581F00E217F9 /* OWSOutgoingCallMessage.h in Headers */, C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */, - C38EF3F8255B6DF7007E1867 /* ContactsViewHelper.h in Headers */, - C33FDC83255A582000E217F9 /* OWSContact.h in Headers */, - C33FDCB2255A582000E217F9 /* OWSSyncGroupsRequestMessage.h in Headers */, C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */, - C38EF262255B6D6F007E1867 /* OWSContactsManager.h in Headers */, - C33FDCC2255A582000E217F9 /* OWSProfileKeyMessage.h in Headers */, - C33FDCDE255A582000E217F9 /* OWSOutgoingSentMessageTranscript.h in Headers */, C33FDD84255A582000E217F9 /* LKGroupUtilities.h in Headers */, - C33FDDC7255A582000E217F9 /* OWSProvisioningMessage.h in Headers */, C33FDC8D255A582000E217F9 /* TSThread.h in Headers */, - C33FDC81255A582000E217F9 /* OWSSignalService.h in Headers */, - C33FDC4B255A582000E217F9 /* LKSyncOpenGroupsMessage.h in Headers */, C33FDDA5255A582000E217F9 /* OWSBlockingManager.h in Headers */, C38EF366255B6DCC007E1867 /* ScreenLockViewController.h in Headers */, - C33FDD9D255A582000E217F9 /* CDSSigningCertificate.h in Headers */, C33FDD16255A582000E217F9 /* NSArray+Functional.h in Headers */, C38EF35B255B6DCC007E1867 /* SelectThreadViewController.h in Headers */, C33FDCE9255A582000E217F9 /* ContactsManagerProtocol.h in Headers */, - C33FDCD0255A582000E217F9 /* OWSDisappearingMessagesConfigurationMessage.h in Headers */, C33FDCE4255A582000E217F9 /* OWSIncompleteCallsJob.h in Headers */, - C33FDCC0255A582000E217F9 /* OWSRequestBuilder.h in Headers */, C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */, C33FDC96255A582000E217F9 /* NSObject+Casting.h in Headers */, C33FDC75255A582000E217F9 /* OWSGroupsOutputStream.h in Headers */, @@ -4624,20 +4009,16 @@ C33FDD57255A582000E217F9 /* OWSCallMessageHandler.h in Headers */, C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */, C38EF403255B6DF7007E1867 /* ContactCellView.h in Headers */, - C33FDD6D255A582000E217F9 /* OWSOutgoingNullMessage.h in Headers */, C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */, C33FDD68255A582000E217F9 /* SignalAccount.h in Headers */, - C38EF315255B6DBF007E1867 /* OWSGroupAvatarBuilder.h in Headers */, C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */, C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */, - C33FDCE7255A582000E217F9 /* OWSDevice.h in Headers */, C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */, C33FDD0E255A582000E217F9 /* DataSource.h in Headers */, C38EF325255B6DBF007E1867 /* OWSWindowManager.h in Headers */, C33FDCF2255A582000E217F9 /* OWSBackgroundTask.h in Headers */, C38EF39C255B6DDA007E1867 /* OWSQuotedReplyModel.h in Headers */, C38EF404255B6DF7007E1867 /* ContactTableViewCell.h in Headers */, - C33FDD5C255A582000E217F9 /* PhoneNumber.h in Headers */, C38EF24A255B6D67007E1867 /* UIView+OWS.h in Headers */, C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */, C38EF322255B6DBF007E1867 /* DebugLogger.h in Headers */, @@ -4645,45 +4026,30 @@ C33FDD09255A582000E217F9 /* SSKJobRecord.h in Headers */, C33FDC94255A582000E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */, C38EF2D7255B6DAF007E1867 /* OWSProfileManager.h in Headers */, - C38EF364255B6DCC007E1867 /* NewNonContactConversationViewController.h in Headers */, C33FDC21255A581F00E217F9 /* OWSPrimaryStorage.h in Headers */, C38EF290255B6D86007E1867 /* AppSetup.h in Headers */, C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */, - C38EF328255B6DBF007E1867 /* OWSContactAvatarBuilder.h in Headers */, C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */, C38EF367255B6DCC007E1867 /* OWSTableViewController.h in Headers */, C33FDCEB255A582000E217F9 /* SSKEnvironment.h in Headers */, C38EF246255B6D67007E1867 /* UIFont+OWS.h in Headers */, C37F53A7255B96E0002AEA92 /* OWSAudioPlayer.h in Headers */, C33FDC35255A581F00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */, - C33FDDC9255A582000E217F9 /* LKDeviceLinkMessage.h in Headers */, - C33FDD89255A582000E217F9 /* OWSFingerprintBuilder.h in Headers */, C33FDD0D255A582000E217F9 /* PreKeyBundle+jsonDict.h in Headers */, C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */, C33FDCF5255A582000E217F9 /* NSNotificationCenter+OWS.h in Headers */, C33FDD34255A582000E217F9 /* NotificationsProtocol.h in Headers */, - C33FDC90255A582000E217F9 /* OWSAnalytics.h in Headers */, - C33FDD36255A582000E217F9 /* OWSVerificationStateChangeMessage.h in Headers */, C33FD9AF255A548A00E217F9 /* SignalUtilitiesKit.h in Headers */, - C33FDD9E255A582000E217F9 /* OWSOutgoingSyncMessage.h in Headers */, C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */, C33FDD06255A582000E217F9 /* AppVersion.h in Headers */, C33FDD90255A582000E217F9 /* OWSUploadOperation.h in Headers */, C33FDC8F255A582000E217F9 /* TSQuotedMessage.h in Headers */, C33FDC73255A582000E217F9 /* OWSStorage+Subclass.h in Headers */, C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */, - C33FDCFC255A582000E217F9 /* OWSCountryMetadata.h in Headers */, - C33FDC60255A582000E217F9 /* OWSLinkedDeviceReadReceipt.h in Headers */, C33FDD27255A582000E217F9 /* TSPreKeyManager.h in Headers */, - C33FDC67255A582000E217F9 /* OWSDeviceProvisioner.h in Headers */, - C33FDCE8255A582000E217F9 /* OWSEndSessionMessage.h in Headers */, - C38EF25F255B6D6F007E1867 /* OWSSyncManager.h in Headers */, - C33FDDAD255A582000E217F9 /* OWSBlockedPhoneNumbersMessage.h in Headers */, C33FDD0B255A582000E217F9 /* NSUserDefaults+OWS.h in Headers */, C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */, - C33FDC9C255A582000E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.h in Headers */, C37F53E9255BA9CE002AEA92 /* Environment.h in Headers */, - C33FDDAF255A582000E217F9 /* OWSDeviceProvisioningService.h in Headers */, C33FDCE6255A582000E217F9 /* TSDatabaseView.h in Headers */, C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */, C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */, @@ -5560,14 +4926,10 @@ buildActionMask = 2147483647; files = ( C38EF30D255B6DBF007E1867 /* OWSUnreadIndicator.m in Sources */, - C33FDD40255A582000E217F9 /* OWSRequestFactory.m in Sources */, - C33FDD96255A582000E217F9 /* ContactDiscoveryService.m in Sources */, C38EF3FD255B6DF7007E1867 /* OWSTextView.m in Sources */, C33FDCA9255A582000E217F9 /* NSData+Image.m in Sources */, C38EF3C6255B6DE7007E1867 /* ImageEditorModel.swift in Sources */, C38EF317255B6DBF007E1867 /* DisplayableText.swift in Sources */, - C33FDC8B255A582000E217F9 /* OWSDynamicOutgoingMessage.m in Sources */, - C38EEFD6255B5BA2007E1867 /* OldSnodeAPI.swift in Sources */, C38EF30F255B6DBF007E1867 /* AppPreferences.swift in Sources */, C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */, C33FDCA3255A582000E217F9 /* SSKMessageSenderJobRecord.m in Sources */, @@ -5579,28 +4941,21 @@ C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */, C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */, C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */, - C33FDDA7255A582000E217F9 /* ClosedGroupParser.swift in Sources */, C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */, C38EF35F255B6DCC007E1867 /* SelectRecipientViewController.m in Sources */, C38EF3C5255B6DE7007E1867 /* OWSViewController+ImageEditor.swift in Sources */, C33FDDCD255A582000E217F9 /* OWSAttachmentDownloads.m in Sources */, - C33FDC32255A581F00E217F9 /* SSKWebSocket.swift in Sources */, C33FDD97255A582000E217F9 /* OWSDisappearingMessagesJob.m in Sources */, C33FDD0F255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m in Sources */, C38EF320255B6DBF007E1867 /* OWSScrubbingLogFormatter.m in Sources */, - C33FDC44255A581F00E217F9 /* PhoneNumber.m in Sources */, C38EF39B255B6DDA007E1867 /* ThreadViewModel.swift in Sources */, C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */, C38EF330255B6DBF007E1867 /* OWSWindowManager.m in Sources */, C33FDD79255A582000E217F9 /* OWSHTTPSecurityPolicy.m in Sources */, C33FDDB7255A582000E217F9 /* OWSPrimaryStorage+Calling.m in Sources */, - C33FDD69255A582000E217F9 /* OWSAnalyticsEvents.m in Sources */, C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */, C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */, - C33FDCB4255A582000E217F9 /* LKDeviceLinkMessage.m in Sources */, - C33FDC70255A582000E217F9 /* SyncMessagesProtocol.swift in Sources */, C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */, - C33FDC5C255A582000E217F9 /* OWSAddToContactsOfferMessage.m in Sources */, C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */, C33FDCFB255A582000E217F9 /* MIMETypeUtil.m in Sources */, C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */, @@ -5608,27 +4963,18 @@ C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */, C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */, C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */, - C33FDD8A255A582000E217F9 /* OnionRequestAPI+Encryption.swift in Sources */, - C38EF36E255B6DCC007E1867 /* ContactFieldView.swift in Sources */, C38EF297255B6D86007E1867 /* OWSSounds.m in Sources */, - C38EF39D255B6DDA007E1867 /* ContactShareViewModel.swift in Sources */, - C33FDD3C255A582000E217F9 /* MessageWrapper.swift in Sources */, C33FDCF1255A582000E217F9 /* Storage+SnodeAPI.swift in Sources */, C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */, - C33FDDA8255A582000E217F9 /* ClosedGroupUpdateMessage.swift in Sources */, C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */, C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, - C38EF36A255B6DCC007E1867 /* NewNonContactConversationViewController.m in Sources */, C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */, C33FDD0A255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.m in Sources */, - C33FDDC3255A582000E217F9 /* AccountServiceClient.swift in Sources */, - C33FDC9F255A582000E217F9 /* OWSAddToProfileWhitelistOfferMessage.m in Sources */, C33FDC4E255A582000E217F9 /* Data+Streaming.swift in Sources */, C33FDCE5255A582000E217F9 /* OWSProvisioningCipher.m in Sources */, C33FDDD6255A582000E217F9 /* TSCall.m in Sources */, C33FDD1A255A582000E217F9 /* TSMessage.m in Sources */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, - C38EF360255B6DCC007E1867 /* ReturnToCallViewController.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */, C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */, @@ -5650,7 +4996,6 @@ C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */, C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */, C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */, - C33FDD51255A582000E217F9 /* OWSDisappearingMessagesConfigurationMessage.m in Sources */, C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */, C33FDD3F255A582000E217F9 /* AppContext.m in Sources */, C33FDCC7255A582000E217F9 /* NSArray+OWS.m in Sources */, @@ -5659,113 +5004,78 @@ C33FDD72255A582000E217F9 /* TSThread.m in Sources */, C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */, C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */, - C33FDD9C255A582000E217F9 /* OWSUnknownContactBlockOfferMessage.m in Sources */, C33FDC4A255A582000E217F9 /* TSYapDatabaseObject.m in Sources */, - C33FDC65255A582000E217F9 /* OWSWebSocket.m in Sources */, C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */, C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */, - C33FDCEF255A582000E217F9 /* OWSContactDiscoveryOperation.swift in Sources */, - C38EF217255B6D3B007E1867 /* OWSConversationColor.m in Sources */, C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */, - C33FDD59255A582000E217F9 /* TTLUtilities.swift in Sources */, C38EF2C5255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m in Sources */, - C33FDD7E255A582000E217F9 /* TypingIndicatorMessage.swift in Sources */, C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */, - C33FDC85255A582000E217F9 /* CDSSigningCertificate.m in Sources */, C38EF2C4255B6DA6007E1867 /* OWSContactOffersInteraction.m in Sources */, - C33FDC68255A582000E217F9 /* OWSReceiptsForSenderMessage.m in Sources */, C38EF388255B6DD2007E1867 /* AttachmentApprovalViewController.swift in Sources */, C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */, - C33FDD66255A582000E217F9 /* Data+SecureRandom.swift in Sources */, C33FDC72255A582000E217F9 /* NSArray+Functional.m in Sources */, C33FDD38255A582000E217F9 /* TSPreKeyManager.m in Sources */, - C33FDCCD255A582000E217F9 /* LKUnlinkDeviceMessage.m in Sources */, - C38EF261255B6D6F007E1867 /* OWSSyncManager.m in Sources */, C33FDD94255A582000E217F9 /* Dictionary+Description.swift in Sources */, C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */, C38EF22C255B6D5D007E1867 /* OWSVideoPlayer.swift in Sources */, - C33FDD18255A582000E217F9 /* ContactParser.swift in Sources */, - C33FDD2C255A582000E217F9 /* DeviceLinkIndex.swift in Sources */, C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */, C38EF407255B6DF7007E1867 /* Toast.swift in Sources */, C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */, C33FDDA2255A582000E217F9 /* Storage+OnionRequests.swift in Sources */, C38EF409255B6DF7007E1867 /* ContactTableViewCell.m in Sources */, - C33FDDBE255A582000E217F9 /* DecryptionUtilities.swift in Sources */, C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */, C33FDC3F255A581F00E217F9 /* OWSPrimaryStorage+Loki.swift in Sources */, - C33FDDB9255A582000E217F9 /* OWSOutgoingSyncMessage.m in Sources */, C38EF333255B6DBF007E1867 /* DeviceSleepManager.swift in Sources */, C33FDC52255A582000E217F9 /* RotateSignedKeyOperation.swift in Sources */, - C38EF481255B752E007E1867 /* SystemContactsFetcher.swift in Sources */, C33FDCDA255A582000E217F9 /* TSDatabaseSecondaryIndexes.m in Sources */, C38EF335255B6DBF007E1867 /* BlockListCache.swift in Sources */, C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */, C38EF316255B6DBF007E1867 /* ProximityMonitoringManager.swift in Sources */, - C33FDC6C255A582000E217F9 /* TSNetworkManager.m in Sources */, C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */, C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */, C33FDD58255A582000E217F9 /* TSAttachmentPointer.m in Sources */, C33FDD39255A582000E217F9 /* FullTextSearchFinder.swift in Sources */, - C33FDDA4255A582000E217F9 /* SessionRequestMessage.swift in Sources */, - C33FDC5F255A582000E217F9 /* OWSRequestMaker.swift in Sources */, - C38EEF0A255B49A8007E1867 /* SSKProtoEnvelope+Conversion.swift in Sources */, + C38EEF0A255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift in Sources */, C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */, C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */, C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, C33FDD2A255A582000E217F9 /* OWSMessageServiceParams.m in Sources */, - C33FDC7F255A582000E217F9 /* OWSCountryMetadata.m in Sources */, - C33FDC84255A582000E217F9 /* LokiMessage.swift in Sources */, C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */, C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */, - C38EF3F3255B6DF7007E1867 /* ContactsViewHelper.m in Sources */, C33FDC46255A581F00E217F9 /* PublicChatPoller.swift in Sources */, C38EF400255B6DF7007E1867 /* GalleryRailView.swift in Sources */, C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */, - C33FDCD9255A582000E217F9 /* DeviceLinkingUtilities.swift in Sources */, C33FDC34255A581F00E217F9 /* NSRegularExpression+SSK.swift in Sources */, - C33FDD7D255A582000E217F9 /* AnyPromise+Conversion.swift in Sources */, C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */, - C33FDD8B255A582000E217F9 /* DeviceLink.swift in Sources */, C38EF218255B6D3B007E1867 /* Theme.m in Sources */, C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */, C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */, C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */, C33FDD76255A582000E217F9 /* SSKKeychainStorage.swift in Sources */, - C33FDD33255A582000E217F9 /* PhoneNumberUtil.m in Sources */, C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */, C37F5403255BA9ED002AEA92 /* Environment.m in Sources */, C38EF2D4255B6DAF007E1867 /* OWSProfileManager.m in Sources */, C38EF248255B6D67007E1867 /* UIViewController+OWS.m in Sources */, C38EF272255B6D7A007E1867 /* OWSResaveCollectionDBMigration.m in Sources */, - C38EF35A255B6DCC007E1867 /* ViewControllerUtils.m in Sources */, C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */, C38EF276255B6D7A007E1867 /* OWSDatabaseMigration.m in Sources */, C38EF370255B6DCC007E1867 /* OWSNavigationController.m in Sources */, C38EF24E255B6D67007E1867 /* Collection+OWS.swift in Sources */, - C33FDD3E255A582000E217F9 /* OWSIncomingSentMessageTranscript.m in Sources */, C33FDD05255A582000E217F9 /* OWSChunkedOutputStream.m in Sources */, - C33FDCC5255A582000E217F9 /* OWSVerificationStateChangeMessage.m in Sources */, C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */, - C33FDCD2255A582000E217F9 /* OWSSignalService.m in Sources */, C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */, - C33FDC28255A581F00E217F9 /* Array+Description.swift in Sources */, C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */, C33FDCED255A582000E217F9 /* Provisioning.pb.swift in Sources */, C33FDCF0255A582000E217F9 /* Storage.swift in Sources */, C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */, - C33FDD50255A582000E217F9 /* OWSReadReceiptsForLinkedDevicesMessage.m in Sources */, C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */, C38EF229255B6D5D007E1867 /* SignalAttachment.swift in Sources */, C33FDDC2255A582000E217F9 /* SignalService.pb.swift in Sources */, - C38EF3FC255B6DF7007E1867 /* AvatarImageView.swift in Sources */, C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */, C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */, C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */, C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */, - C33FDC91255A582000E217F9 /* OWSDeviceProvisioner.m in Sources */, C33FDC6A255A582000E217F9 /* ProvisioningProto.swift in Sources */, - C33FDC37255A581F00E217F9 /* OWSCensorshipConfiguration.m in Sources */, C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */, C38EF24B255B6D67007E1867 /* UIView+OWS.m in Sources */, C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */, @@ -5787,42 +5097,23 @@ C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */, C38EF3C4255B6DE7007E1867 /* ImageEditorContents.swift in Sources */, C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */, - C33FDC49255A581F00E217F9 /* NSTimer+OWS.m in Sources */, - C38EF260255B6D6F007E1867 /* OWSContactsManager.m in Sources */, C33FDCFD255A582000E217F9 /* YapDatabaseConnection+OWS.m in Sources */, C38EF3BC255B6DE7007E1867 /* ImageEditorPanGestureRecognizer.swift in Sources */, C33FDC23255A581F00E217F9 /* SSKPreferences.swift in Sources */, C38EF372255B6DCC007E1867 /* MediaMessageView.swift in Sources */, - C33FDD4C255A582000E217F9 /* OWSDeviceProvisioningService.m in Sources */, - C33FDC31255A581F00E217F9 /* Contact.m in Sources */, - C38EF2D5255B6DAF007E1867 /* ProfileFetcherJob.swift in Sources */, C38EF387255B6DD2007E1867 /* AttachmentItemCollection.swift in Sources */, - C38EF318255B6DBF007E1867 /* OWSAvatarBuilder.m in Sources */, C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */, - C33FDC8A255A582000E217F9 /* CDSQuote.m in Sources */, - C33FDCA5255A582000E217F9 /* OWSDeviceProvisioningCodeService.m in Sources */, C33FDC38255A581F00E217F9 /* Mention.swift in Sources */, - C33FDD8F255A582000E217F9 /* OWSOutgoingSentMessageTranscript.m in Sources */, C33FDDC1255A582000E217F9 /* Storage+ClosedGroups.swift in Sources */, - C33FDC63255A582000E217F9 /* Mnemonic.swift in Sources */, - C38EF323255B6DBF007E1867 /* OWSContactAvatarBuilder.m in Sources */, C38EF3BF255B6DE7007E1867 /* ImageEditorView.swift in Sources */, C38EF365255B6DCC007E1867 /* OWSTableViewController.m in Sources */, C33FDC25255A581F00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */, - C33FDC59255A582000E217F9 /* NetworkManager.swift in Sources */, C38EF36B255B6DCC007E1867 /* ScreenLockViewController.m in Sources */, - C33FDDCB255A582000E217F9 /* TSSocketManager.m in Sources */, C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */, C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */, - C33FDCCA255A582000E217F9 /* OWSBatchMessageProcessor.m in Sources */, C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */, - C33FDDCA255A582000E217F9 /* ProofOfWork.swift in Sources */, C33FDCF4255A582000E217F9 /* Poller.swift in Sources */, C38EF332255B6DBF007E1867 /* OWSPreferences.m in Sources */, - C33FDDBA255A582000E217F9 /* OWSSyncGroupsMessage.m in Sources */, - C33FDDD7255A582000E217F9 /* OWSSyncConfigurationMessage.m in Sources */, - C33FDC43255A581F00E217F9 /* OWSAnalytics.m in Sources */, - C33FDD04255A582000E217F9 /* SignalServiceClient.swift in Sources */, C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */, C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */, C33FDC5E255A582000E217F9 /* SSKProto.swift in Sources */, @@ -5835,95 +5126,69 @@ C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */, C38EF28D255B6D86007E1867 /* OWSAudioSession.swift in Sources */, C33FDD7B255A582000E217F9 /* GeneralUtilities.swift in Sources */, - C33FDD47255A582000E217F9 /* DeviceLinkingSessionDelegate.swift in Sources */, C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */, C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */, C33FDD4F255A582000E217F9 /* Storage+Collections.swift in Sources */, C33FDD15255A582000E217F9 /* YapDatabaseTransaction+OWS.m in Sources */, C33FDD63255A582000E217F9 /* OWSIdentityManager.m in Sources */, - C33FDCC9255A582000E217F9 /* DeviceLinkingSession.swift in Sources */, C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */, C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */, C38EF30E255B6DBF007E1867 /* FullTextSearcher.swift in Sources */, - C33FDC54255A582000E217F9 /* OWSLinkedDeviceReadReceipt.m in Sources */, - C33FDDD9255A582000E217F9 /* LokiSessionResetImplementation.swift in Sources */, + C33FDDD9255A582000E217F9 /* LokiSessionRestorationImplementation.swift in Sources */, C33FDD31255A582000E217F9 /* NSUserDefaults+OWS.m in Sources */, C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */, C38EF3BB255B6DE7007E1867 /* ImageEditorStrokeItem.swift in Sources */, C33FDCA1255A582000E217F9 /* TSErrorMessage.m in Sources */, C38EF295255B6D86007E1867 /* NoopCallMessageHandler.swift in Sources */, - C33FDDD1255A582000E217F9 /* SharedSenderKeysImplementation.swift in Sources */, - C33FDCBF255A582000E217F9 /* OWSFingerprint.m in Sources */, C38EF3C0255B6DE7007E1867 /* ImageEditorCropViewController.swift in Sources */, C38EF401255B6DF7007E1867 /* VideoPlayerView.swift in Sources */, C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */, C38EF3FE255B6DF7007E1867 /* OWSTextField.m in Sources */, - C33FDCA8255A582000E217F9 /* OWSFingerprintBuilder.m in Sources */, C33FDC40255A581F00E217F9 /* OWSDisappearingMessagesFinder.m in Sources */, - C33FDD28255A582000E217F9 /* SSKProtoPrekeyBundleMessage+Loki.swift in Sources */, C33FDD24255A582000E217F9 /* SignalMessage.swift in Sources */, C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, - C38EF361255B6DCC007E1867 /* EditContactShareNameViewController.swift in Sources */, C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */, - C33FDC8E255A582000E217F9 /* EncryptionUtilities.swift in Sources */, C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */, C38EF293255B6D86007E1867 /* AppSetup.m in Sources */, - C33FDC55255A582000E217F9 /* OWSProvisioningMessage.m in Sources */, C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */, C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */, C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */, C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */, C33FDC78255A582000E217F9 /* TSConstants.m in Sources */, - C33FDD52255A582000E217F9 /* DeviceNames.swift in Sources */, C33FDCE0255A582000E217F9 /* FingerprintProto.swift in Sources */, - C33FDDA0255A582000E217F9 /* OWSOutgoingNullMessage.m in Sources */, C38EF324255B6DBF007E1867 /* Bench.swift in Sources */, C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */, C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */, C38EF3F2255B6DF7007E1867 /* DisappearingTimerConfigurationView.swift in Sources */, C33FDCD8255A582000E217F9 /* OWSIncomingMessageFinder.m in Sources */, - C33FDCE2255A582000E217F9 /* OWSOutgoingCallMessage.m in Sources */, C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, - C33FDD9A255A582000E217F9 /* OWSBlockedPhoneNumbersMessage.m in Sources */, - C33FDD99255A582000E217F9 /* LKSyncOpenGroupsMessage.m in Sources */, C33FDCAC255A582000E217F9 /* ProxiedContentDownloader.swift in Sources */, C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */, C33FDCDC255A582000E217F9 /* OWSMediaUtils.swift in Sources */, C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */, - C33FDC30255A581F00E217F9 /* OWSSyncGroupsRequestMessage.m in Sources */, - C33FDD9F255A582000E217F9 /* OWSDevicesService.m in Sources */, - C33FDD43255A582000E217F9 /* FileServerAPI+Deprecated.swift in Sources */, C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */, - C33FDD30255A582000E217F9 /* ClosedGroupUtilities.swift in Sources */, C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */, C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */, - C33FDC3E255A581F00E217F9 /* ContactsUpdater.m in Sources */, C33FDCFE255A582000E217F9 /* OWSContactsOutputStream.m in Sources */, - C33FDC88255A582000E217F9 /* OWSVerificationStateSyncMessage.m in Sources */, C33FDDBC255A582000E217F9 /* OWSPrimaryStorage.m in Sources */, - C33FDD54255A582000E217F9 /* OWS2FAManager.m in Sources */, C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */, C33FDDAA255A582000E217F9 /* LokiDatabaseUtilities.swift in Sources */, - C33FDCBA255A582000E217F9 /* OWSRequestBuilder.m in Sources */, C33FDC2B255A581F00E217F9 /* OWSReadReceiptManager.m in Sources */, C38EF326255B6DBF007E1867 /* ConversationStyle.swift in Sources */, - C38EF312255B6DBF007E1867 /* OWSGroupAvatarBuilder.m in Sources */, C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */, C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */, + B8C2B332256376F000551B4D /* ThreadUtil.m in Sources */, C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */, - C33FDCF7255A582000E217F9 /* OWSProfileKeyMessage.m in Sources */, C3CA3B1D255CF3C800F4C6D4 /* MessageSender+Utilities.swift in Sources */, C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */, C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */, - C38EF362255B6DCC007E1867 /* ContactShareApprovalViewController.swift in Sources */, C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */, C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */, C33FDC92255A582000E217F9 /* OWSGroupsOutputStream.m in Sources */, - C33FDC56255A582000E217F9 /* OWSSyncContactsMessage.m in Sources */, C38EF28E255B6D86007E1867 /* SignalKeyingStorage.m in Sources */, + B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */, C38EF406255B6DF7007E1867 /* OWSAlerts.swift in Sources */, - C33FDC3D255A581F00E217F9 /* Promise+retainUntilComplete.swift in Sources */, C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */, C33FDDA3255A582000E217F9 /* TSInteraction.m in Sources */, C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */, @@ -5935,10 +5200,7 @@ C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */, C38EF319255B6DBF007E1867 /* Weak.swift in Sources */, C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */, - C33FDDC4255A582000E217F9 /* OWSContact.m in Sources */, - C33FDCE1255A582000E217F9 /* OWSEndSessionMessage.m in Sources */, C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */, - C33FDCEA255A582000E217F9 /* OWSDevice.m in Sources */, C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */, C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */, C33FDD2B255A582000E217F9 /* OWSMediaGalleryFinder.m in Sources */, @@ -5975,7 +5237,7 @@ C352A36D2557858E00338F3E /* NSTimer+Proxying.m in Sources */, C3C2ABD22553C6C900C340D1 /* Data+SecureRandom.swift in Sources */, C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */, - C3A7225E2558C38D0043A11F /* AnyPromise+Retaining.swift in Sources */, + C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */, C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Description.swift in Sources */, C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */, C352A3A62557B60D00338F3E /* TSRequest.m in Sources */, @@ -6103,7 +5365,6 @@ files = ( C396DAF52518408B00FF6DC5 /* CSV.swift in Sources */, B8CCF63723961D6D0091D419 /* NewPrivateChatVC.swift in Sources */, - 4CC0B59C20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift in Sources */, 3461293E1FD1D72B00532771 /* ExperienceUpgradeFinder.swift in Sources */, C3F0A61A255C9902007BE2A3 /* Storage+SessionProtocolKit.swift in Sources */, 34C4E2582118957600BEA353 /* WebRTCProto.swift in Sources */, @@ -6118,9 +5379,7 @@ 34D1F0501F7D45A60066283D /* GifPickerCell.swift in Sources */, 3496957421A301A100DCFE74 /* OWSBackupAPI.swift in Sources */, C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */, - 34D99C931F2937CC00D284D6 /* OWSAnalytics.swift in Sources */, B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */, - B80C6B5B2384C7F900FDBC8B /* DeviceNameModalDelegate.swift in Sources */, C3550A03255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift in Sources */, 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */, B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */, @@ -6135,7 +5394,6 @@ 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */, 34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */, 4CFD151D22415AA400F2450F /* CallVideoHintView.swift in Sources */, - 34D1F0AB1F867BFC0066283D /* OWSContactOffersCell.m in Sources */, C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */, B82B408A2399EC0600A248E7 /* FakeChatView.swift in Sources */, 343A65981FC4CFE7000477A1 /* ConversationScrollButton.m in Sources */, @@ -6146,29 +5404,22 @@ 45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */, 4CEB78C92178EBAB00F315D2 /* OWSSessionResetJobRecord.m in Sources */, 45794E861E00620000066731 /* CallUIAdapter.swift in Sources */, - 340FC8BA204DAC8D007AEB0F /* FingerprintViewScanController.m in Sources */, C396DAF32518408B00FF6DC5 /* Description.swift in Sources */, - 4585C4681ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift in Sources */, 450D19131F85236600970622 /* RemoteVideoView.m in Sources */, 34129B8621EF877A005457A8 /* LinkPreviewView.swift in Sources */, 34386A54207D271D009F5D9C /* NeverClearView.swift in Sources */, - B885D5F4233491AB00EE0D8E /* DeviceLinkingModal.swift in Sources */, 45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */, 451166C01FD86B98000739BA /* AccountManager.swift in Sources */, B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */, 3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */, 4C2F454F214C00E1004871FF /* AvatarTableViewCell.swift in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, - B80C6B592384C4E700FDBC8B /* DeviceNameModal.swift in Sources */, 4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */, 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */, - 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, 34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */, B886B4A92398BA1500211ABE /* QRCode.swift in Sources */, 3496955D219B605E00DCFE74 /* PhotoCollectionPickerController.swift in Sources */, - 3403B95D20EA9527001A1F44 /* OWSContactShareButtonsView.m in Sources */, 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */, - B80C6B572384A56D00FDBC8B /* DeviceLinksVC.swift in Sources */, 34A8B3512190A40E00218A25 /* MediaAlbumCellView.swift in Sources */, 34D1F0AE1F867BFC0066283D /* OWSMessageCell.m in Sources */, C396DAF42518408B00FF6DC5 /* Parser.swift in Sources */, @@ -6185,11 +5436,8 @@ B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */, 34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */, 34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */, - 340FC8BC204DAC8D007AEB0F /* FingerprintViewController.m in Sources */, 450DF2051E0D74AC003D14BE /* Platform.swift in Sources */, 4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */, - 340FC8B2204DAC8D007AEB0F /* AdvancedSettingsTableViewController.m in Sources */, - 452B999020A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift in Sources */, B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */, 346129991FD1E4DA00532771 /* SignalApp.m in Sources */, 3496957121A301A100DCFE74 /* OWSBackupImportJob.m in Sources */, @@ -6199,7 +5447,6 @@ C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */, 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */, C3F0A62C255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift in Sources */, - 452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */, 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */, 34D1F0881F8678AA0066283D /* ConversationViewLayout.m in Sources */, B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */, @@ -6212,12 +5459,9 @@ 34D1F0B71F87F8850066283D /* OWSGenericAttachmentView.m in Sources */, 34D920E720E179C200D51158 /* OWSMessageFooterView.m in Sources */, 341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */, - 348BB25D20A0C5530047AEC2 /* ContactShareViewHelper.swift in Sources */, - 34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */, B85357C523A1F13800AAF6CD /* LinkDeviceVC.swift in Sources */, 4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */, C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */, - 4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */, 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */, 34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */, C3F0A608255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift in Sources */, @@ -6225,10 +5469,8 @@ 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */, 2400888E239F30A600305217 /* SessionRestorationView.swift in Sources */, B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */, - 4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */, 34EA69402194933900702471 /* MediaDownloadView.swift in Sources */, B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */, - 340FC8AB204DAC8D007AEB0F /* DomainFrontingCountryViewController.m in Sources */, 4C586926224FAB83003FD070 /* AVAudioSession+OWS.m in Sources */, 3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */, C3550A1D255DD73500194B6A /* Storage+SessionMessagingKit.swift in Sources */, @@ -6243,9 +5485,7 @@ 34ABC0E421DD20C500ED9469 /* ConversationMessageMapping.swift in Sources */, 34DBF003206BD5A500025978 /* OWSMessageTextView.m in Sources */, 34D1F0B41F86D31D0066283D /* ConversationCollectionView.m in Sources */, - 45D308AD2049A439000189E4 /* PinEntryView.m in Sources */, B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */, - 340FC8B1204DAC8D007AEB0F /* BlockListViewController.m in Sources */, 45B5360E206DD8BB00D61655 /* UIResponder+OWS.swift in Sources */, 4CFE6B6C21F92BA700006701 /* LegacyNotificationsAdaptee.swift in Sources */, B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */, @@ -6253,13 +5493,11 @@ 3441FD9F21A3604F00BB9542 /* BackupRestoreViewController.swift in Sources */, 45F659821E1BE77000444429 /* NonCallKitCallUIAdaptee.swift in Sources */, 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */, - 34B3F8771E8DF1700035BE1A /* ContactsPicker.swift in Sources */, 45C0DC1B1E68FE9000E04C47 /* UIApplication+OWS.swift in Sources */, 45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */, 4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */, 45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */, C396DAF22518408B00FF6DC5 /* NamedView.swift in Sources */, - 340FC8BB204DAC8D007AEB0F /* OWSAddToContactViewController.m in Sources */, 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */, 452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */, B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */, @@ -6273,7 +5511,6 @@ 45F659731E1BD99C00444429 /* CallKitCallUIAdaptee.swift in Sources */, 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */, 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */, - 45DDA6242090CEB500DE97F8 /* ConversationHeaderView.swift in Sources */, C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */, B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */, 3488F9362191CC4000E524CC /* ConversationMediaView.swift in Sources */, @@ -6289,7 +5526,6 @@ 4C21D5D6223A9DC500EF8A77 /* UIAlerts+iOS9.m in Sources */, 34DBF004206BD5A500025978 /* OWSBubbleView.m in Sources */, 3496957021A301A100DCFE74 /* OWSBackupIO.m in Sources */, - 34E88D262098C5AE00A608F4 /* ContactViewController.swift in Sources */, 34AC0A23211C829F00997B47 /* OWSLabel.m in Sources */, 34EA69422194DE8000702471 /* MediaUploadView.swift in Sources */, 76EB054018170B33006006FC /* AppDelegate.m in Sources */, @@ -6299,7 +5535,6 @@ C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */, 340FC8B5204DAC8D007AEB0F /* AboutTableViewController.m in Sources */, C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */, - 340FC8B9204DAC8D007AEB0F /* UpdateGroupViewController.m in Sources */, B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */, C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */, C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */, @@ -6313,7 +5548,6 @@ B85357C723A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift in Sources */, C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */, 340FC8AE204DAC8D007AEB0F /* OWSSoundSettingsViewController.m in Sources */, - 4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */, 340FC8B0204DAC8D007AEB0F /* AddToBlockListViewController.m in Sources */, 3496957321A301A100DCFE74 /* OWSBackupJob.m in Sources */, 34C4E2572118957600BEA353 /* OWSWebRTCDataProtos.pb.swift in Sources */, @@ -6322,17 +5556,13 @@ 45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */, 34D1F0B01F867BFC0066283D /* OWSSystemMessageCell.m in Sources */, 45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */, - B894D0712339D6F300B4D94D /* DeviceLinkingModalDelegate.swift in Sources */, - 34CA631B2097806F00E526A0 /* OWSContactShareView.m in Sources */, B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */, 34D1F0861F8678AA0066283D /* ConversationViewController.m in Sources */, 3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */, B90418E6183E9DD40038554A /* DateUtil.m in Sources */, - 340FC8BD204DAC8D007AEB0F /* ShowGroupMembersViewController.m in Sources */, C33100092558FF6D00070591 /* UserCell.swift in Sources */, C3645350252449260045C478 /* VoiceMessageView.swift in Sources */, 3496956F21A301A100DCFE74 /* OWSBackupLazyRestore.swift in Sources */, - 459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Signal.xcodeproj/xcshareddata/xcschemes/Signal-Internal.xcscheme b/Signal.xcodeproj/xcshareddata/xcschemes/Signal-Internal.xcscheme deleted file mode 100644 index e0d5ca92c..000000000 --- a/Signal.xcodeproj/xcshareddata/xcschemes/Signal-Internal.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Signal.xcodeproj/xcshareddata/xcschemes/SignalMessaging.xcscheme b/Signal.xcodeproj/xcshareddata/xcschemes/SignalMessaging.xcscheme deleted file mode 100644 index 8362675e7..000000000 --- a/Signal.xcodeproj/xcshareddata/xcschemes/SignalMessaging.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SignalUtilitiesKit/AccountServiceClient.swift b/SignalUtilitiesKit/AccountServiceClient.swift deleted file mode 100644 index da9c5ee06..000000000 --- a/SignalUtilitiesKit/AccountServiceClient.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - -// TODO define actual type, and validate length -public typealias IdentityKey = Data - -/// based on libsignal-service-java's AccountManager class -@objc(SSKAccountServiceClient) -public class AccountServiceClient: NSObject { - - static var shared = AccountServiceClient() - - private let serviceClient: SignalServiceClient - - override init() { - self.serviceClient = SignalServiceRestClient() - } - - public func getPreKeysCount() -> Promise { - return serviceClient.getAvailablePreKeys() - } - - public func setPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise { - return serviceClient.registerPreKeys(identityKey: identityKey, signedPreKeyRecord: signedPreKeyRecord, preKeyRecords: preKeyRecords) - } - - public func setSignedPreKey(_ signedPreKey: SignedPreKeyRecord) -> Promise { - return serviceClient.setCurrentSignedPreKey(signedPreKey) - } -} diff --git a/SignalUtilitiesKit/AnyPromise+Conversion.swift b/SignalUtilitiesKit/AnyPromise+Conversion.swift deleted file mode 100644 index 1c15fc554..000000000 --- a/SignalUtilitiesKit/AnyPromise+Conversion.swift +++ /dev/null @@ -1,10 +0,0 @@ -import PromiseKit - -public extension AnyPromise { - - public static func from(_ promise: Promise) -> AnyPromise { - let result = AnyPromise(promise) - result.retainUntilComplete() - return result - } -} diff --git a/SignalUtilitiesKit/AppContext.h b/SignalUtilitiesKit/AppContext.h index c1674864c..f9327db8a 100755 --- a/SignalUtilitiesKit/AppContext.h +++ b/SignalUtilitiesKit/AppContext.h @@ -39,8 +39,7 @@ NSString *NSStringForUIApplicationState(UIApplicationState value); @property (nonatomic, readonly) BOOL isMainApp; @property (nonatomic, readonly) BOOL isMainAppAndActive; -/// Whether the app was woken up by a silent push notification. This is important for -/// determining whether attachments should be downloaded or not. +/// Whether the app was woken up by a silent push notification. This is important for determining whether attachments should be downloaded or not. @property (nonatomic) BOOL wasWokenUpByPushNotification; // Whether the user is using a right-to-left language like Arabic. diff --git a/SignalUtilitiesKit/AppContext.m b/SignalUtilitiesKit/AppContext.m index ece6f2865..39423c3cc 100755 --- a/SignalUtilitiesKit/AppContext.m +++ b/SignalUtilitiesKit/AppContext.m @@ -3,7 +3,6 @@ // #import "AppContext.h" -#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/AppReadiness.m b/SignalUtilitiesKit/AppReadiness.m index 0153594ab..4424e177e 100755 --- a/SignalUtilitiesKit/AppReadiness.m +++ b/SignalUtilitiesKit/AppReadiness.m @@ -3,7 +3,6 @@ // #import "AppReadiness.h" -#import #import "AppContext.h" #import "SSKAsserts.h" diff --git a/SignalUtilitiesKit/AppSetup.m b/SignalUtilitiesKit/AppSetup.m index f50fa10c0..ee84e9235 100644 --- a/SignalUtilitiesKit/AppSetup.m +++ b/SignalUtilitiesKit/AppSetup.m @@ -8,25 +8,20 @@ #import #import #import -#import -#import + + #import #import -#import #import #import #import -#import -#import -#import #import #import #import #import #import -#import #import -#import + NS_ASSUME_NONNULL_BEGIN @@ -61,31 +56,17 @@ NS_ASSUME_NONNULL_BEGIN OWSPreferences *preferences = [OWSPreferences new]; - TSNetworkManager *networkManager = [[TSNetworkManager alloc] initDefault]; - OWSContactsManager *contactsManager = [[OWSContactsManager alloc] initWithPrimaryStorage:primaryStorage]; - ContactsUpdater *contactsUpdater = [ContactsUpdater new]; - OWSMessageSender *messageSender = [[OWSMessageSender alloc] initWithPrimaryStorage:primaryStorage]; - SSKMessageSenderJobQueue *messageSenderJobQueue = [SSKMessageSenderJobQueue new]; OWSProfileManager *profileManager = [[OWSProfileManager alloc] initWithPrimaryStorage:primaryStorage]; - OWSMessageManager *messageManager = [[OWSMessageManager alloc] initWithPrimaryStorage:primaryStorage]; OWSBlockingManager *blockingManager = [[OWSBlockingManager alloc] initWithPrimaryStorage:primaryStorage]; OWSIdentityManager *identityManager = [[OWSIdentityManager alloc] initWithPrimaryStorage:primaryStorage]; id udManager = [[OWSUDManagerImpl alloc] initWithPrimaryStorage:primaryStorage]; - OWSMessageDecrypter *messageDecrypter = [[OWSMessageDecrypter alloc] initWithPrimaryStorage:primaryStorage]; - OWSBatchMessageProcessor *batchMessageProcessor = - [[OWSBatchMessageProcessor alloc] initWithPrimaryStorage:primaryStorage]; - OWSMessageReceiver *messageReceiver = [[OWSMessageReceiver alloc] initWithPrimaryStorage:primaryStorage]; - TSSocketManager *socketManager = [[TSSocketManager alloc] init]; TSAccountManager *tsAccountManager = [[TSAccountManager alloc] initWithPrimaryStorage:primaryStorage]; - OWS2FAManager *ows2FAManager = [[OWS2FAManager alloc] initWithPrimaryStorage:primaryStorage]; OWSDisappearingMessagesJob *disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithPrimaryStorage:primaryStorage]; - ContactDiscoveryService *contactDiscoveryService = [[ContactDiscoveryService alloc] initDefault]; OWSReadReceiptManager *readReceiptManager = [[OWSReadReceiptManager alloc] initWithPrimaryStorage:primaryStorage]; OWSOutgoingReceiptManager *outgoingReceiptManager = [[OWSOutgoingReceiptManager alloc] initWithPrimaryStorage:primaryStorage]; - OWSSyncManager *syncManager = [[OWSSyncManager alloc] initDefault]; id reachabilityManager = [SSKReachabilityManagerImpl new]; id typingIndicators = [[OWSTypingIndicatorsImpl alloc] init]; OWSAttachmentDownloads *attachmentDownloads = [[OWSAttachmentDownloads alloc] init]; @@ -101,31 +82,18 @@ NS_ASSUME_NONNULL_BEGIN sounds:sounds windowManager:windowManager]]; - [SSKEnvironment setShared:[[SSKEnvironment alloc] initWithContactsManager:contactsManager - messageSender:messageSender - messageSenderJobQueue:messageSenderJobQueue - profileManager:profileManager - primaryStorage:primaryStorage - contactsUpdater:contactsUpdater - networkManager:networkManager - messageManager:messageManager - blockingManager:blockingManager - identityManager:identityManager - udManager:udManager - messageDecrypter:messageDecrypter - batchMessageProcessor:batchMessageProcessor - messageReceiver:messageReceiver - socketManager:socketManager - tsAccountManager:tsAccountManager - ows2FAManager:ows2FAManager - disappearingMessagesJob:disappearingMessagesJob - contactDiscoveryService:contactDiscoveryService - readReceiptManager:readReceiptManager - outgoingReceiptManager:outgoingReceiptManager - reachabilityManager:reachabilityManager - syncManager:syncManager - typingIndicators:typingIndicators - attachmentDownloads:attachmentDownloads]]; + [SSKEnvironment setShared:[[SSKEnvironment alloc] initWithProfileManager:profileManager + primaryStorage:primaryStorage + blockingManager:blockingManager + identityManager:identityManager + udManager:udManager + tsAccountManager:tsAccountManager + disappearingMessagesJob:disappearingMessagesJob + readReceiptManager:readReceiptManager + outgoingReceiptManager:outgoingReceiptManager + reachabilityManager:reachabilityManager + typingIndicators:typingIndicators + attachmentDownloads:attachmentDownloads]]; appSpecificSingletonBlock(); diff --git a/SignalUtilitiesKit/Array+Description.swift b/SignalUtilitiesKit/Array+Description.swift deleted file mode 100644 index 3d58476dc..000000000 --- a/SignalUtilitiesKit/Array+Description.swift +++ /dev/null @@ -1,7 +0,0 @@ - -public extension Array where Element : CustomStringConvertible { - - public var prettifiedDescription: String { - return "[ " + map { $0.description }.joined(separator: ", ") + " ]" - } -} diff --git a/SignalUtilitiesKit/SignalAttachment.swift b/SignalUtilitiesKit/Attachments/SignalAttachment.swift similarity index 98% rename from SignalUtilitiesKit/SignalAttachment.swift rename to SignalUtilitiesKit/Attachments/SignalAttachment.swift index 0a9aa7385..d5eadc9e4 100644 --- a/SignalUtilitiesKit/SignalAttachment.swift +++ b/SignalUtilitiesKit/Attachments/SignalAttachment.swift @@ -244,16 +244,6 @@ public class SignalAttachment: NSObject { return errorDescription } -// @objc -// public func buildOutgoingAttachmentInfo(message: TSMessage) -> OutgoingAttachmentInfo { -// assert(message.uniqueId != nil) -// return OutgoingAttachmentInfo(dataSource: dataSource, -// contentType: mimeType, -// sourceFilename: filenameOrDefault, -// caption: captionText, -// albumMessageId: message.uniqueId) -// } - @objc public func staticThumbnail() -> UIImage? { if isAnimatedImage { diff --git a/SignalUtilitiesKit/TSAttachment.h b/SignalUtilitiesKit/Attachments/TSAttachment.h similarity index 100% rename from SignalUtilitiesKit/TSAttachment.h rename to SignalUtilitiesKit/Attachments/TSAttachment.h diff --git a/SignalUtilitiesKit/TSAttachment.m b/SignalUtilitiesKit/Attachments/TSAttachment.m similarity index 100% rename from SignalUtilitiesKit/TSAttachment.m rename to SignalUtilitiesKit/Attachments/TSAttachment.m diff --git a/SignalUtilitiesKit/TSAttachmentPointer.h b/SignalUtilitiesKit/Attachments/TSAttachmentPointer.h similarity index 100% rename from SignalUtilitiesKit/TSAttachmentPointer.h rename to SignalUtilitiesKit/Attachments/TSAttachmentPointer.h diff --git a/SignalUtilitiesKit/TSAttachmentPointer.m b/SignalUtilitiesKit/Attachments/TSAttachmentPointer.m similarity index 99% rename from SignalUtilitiesKit/TSAttachmentPointer.m rename to SignalUtilitiesKit/Attachments/TSAttachmentPointer.m index 7cbcb181d..fe2b1fb4a 100644 --- a/SignalUtilitiesKit/TSAttachmentPointer.m +++ b/SignalUtilitiesKit/Attachments/TSAttachmentPointer.m @@ -5,7 +5,7 @@ #import "TSAttachmentPointer.h" #import "OWSBackupFragment.h" #import "TSAttachmentStream.h" -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/TSAttachmentStream.h b/SignalUtilitiesKit/Attachments/TSAttachmentStream.h similarity index 100% rename from SignalUtilitiesKit/TSAttachmentStream.h rename to SignalUtilitiesKit/Attachments/TSAttachmentStream.h diff --git a/SignalUtilitiesKit/TSAttachmentStream.m b/SignalUtilitiesKit/Attachments/TSAttachmentStream.m similarity index 100% rename from SignalUtilitiesKit/TSAttachmentStream.m rename to SignalUtilitiesKit/Attachments/TSAttachmentStream.m diff --git a/SignalUtilitiesKit/AvatarImageView.swift b/SignalUtilitiesKit/AvatarImageView.swift deleted file mode 100644 index b52a0d4af..000000000 --- a/SignalUtilitiesKit/AvatarImageView.swift +++ /dev/null @@ -1,264 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import UIKit - -@objc -public class AvatarImageView: UIImageView { - private let shadowLayer = CAShapeLayer() - @objc var contactID: String = "" - - public init() { - super.init(frame: .zero) - self.initialize() - } - - override init(frame: CGRect) { - super.init(frame: frame) - self.initialize() - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - self.initialize() - } - - override init(image: UIImage?) { - super.init(image: image) - self.initialize() - } - - func initialize() { - // Loki: Used to indicate a contact's online status - layer.borderWidth = 2 - - // Loki: Observe online status changes - NotificationCenter.default.addObserver(self, selector: #selector(handleContactOnlineStatusChangedNotification), name: .contactOnlineStatusChanged, object: nil) - - // Set up UI - self.autoPinToSquareAspectRatio() - - self.layer.minificationFilter = .trilinear - self.layer.magnificationFilter = .trilinear - self.layer.masksToBounds = true - - self.layer.addSublayer(self.shadowLayer) - - self.contentMode = .scaleToFill - } - - override public func layoutSubviews() { - self.layer.cornerRadius = self.frame.size.width / 2 - - // Loki: Update the online status indicator if needed - updateOnlineStatusIndicator() - - // Inner shadow. - // This should usually not be visible; it is used to distinguish - // profile pics from the background if they are similar. - self.shadowLayer.frame = self.bounds - self.shadowLayer.masksToBounds = true - let shadowBounds = self.bounds - let shadowPath = UIBezierPath(ovalIn: shadowBounds) - // This can be any value large enough to cast a sufficiently large shadow. - let shadowInset: CGFloat = -3 - shadowPath.append(UIBezierPath(rect: shadowBounds.insetBy(dx: shadowInset, dy: shadowInset))) - // This can be any color since the fill should be clipped. - self.shadowLayer.fillColor = UIColor.black.cgColor - self.shadowLayer.path = shadowPath.cgPath - self.shadowLayer.fillRule = .evenOdd - self.shadowLayer.shadowColor = (Theme.isDarkThemeEnabled ? UIColor.white : UIColor.black).cgColor - self.shadowLayer.shadowRadius = 0.5 - self.shadowLayer.shadowOpacity = 0.15 - self.shadowLayer.shadowOffset = .zero - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - @objc private func handleContactOnlineStatusChangedNotification(_ notification: Notification) { - let contactID = notification.object as! String - guard contactID == self.contactID else { return } - updateOnlineStatusIndicator() - } - - @objc func updateOnlineStatusIndicator() { - let color = UIColor.lokiGray() - let currentUserID = getUserHexEncodedPublicKey() - let isCurrentUser = (contactID == currentUserID) - layer.borderColor = isCurrentUser ? UIColor.clear.cgColor : color.cgColor - } -} - -/// Avatar View which updates itself as necessary when the profile, contact, or group picture changes. -@objc -public class ConversationAvatarImageView: AvatarImageView { - - let thread: TSThread - let diameter: UInt - let contactsManager: OWSContactsManager - - // nil if group avatar - let recipientId: String? - - // nil if contact avatar - let groupThreadId: String? - - required public init(thread: TSThread, diameter: UInt, contactsManager: OWSContactsManager) { - self.thread = thread - self.diameter = diameter - self.contactsManager = contactsManager - - switch thread { - case let contactThread as TSContactThread: - self.recipientId = contactThread.contactIdentifier() - self.groupThreadId = nil - case let groupThread as TSGroupThread: - self.recipientId = nil - self.groupThreadId = groupThread.uniqueId - default: - owsFailDebug("unexpected thread type: \(thread)") - self.recipientId = nil - self.groupThreadId = nil - } - - super.init(frame: .zero) - - if recipientId != nil { - self.contactID = recipientId! // Loki - NotificationCenter.default.addObserver(self, selector: #selector(handleOtherUsersProfileChanged(notification:)), name: NSNotification.Name(rawValue: kNSNotificationName_OtherUsersProfileDidChange), object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(handleSignalAccountsChanged(notification:)), name: NSNotification.Name.OWSContactsManagerSignalAccountsDidChange, object: nil) - } - - if groupThreadId != nil { - NotificationCenter.default.addObserver(self, selector: #selector(handleGroupAvatarChanged(notification:)), name: .TSGroupThreadAvatarChanged, object: nil) - } - - // TODO group avatar changed - self.updateImage() - } - - required public init?(coder aDecoder: NSCoder) { - notImplemented() - } - - @objc func handleSignalAccountsChanged(notification: Notification) { - Logger.debug("") - - // PERF: It would be nice if we could do this only if *this* user's SignalAccount changed, - // but currently this is only a course grained notification. - - self.updateImage() - } - - @objc func handleOtherUsersProfileChanged(notification: Notification) { - Logger.debug("") - - guard let changedRecipientId = notification.userInfo?[kNSNotificationKey_ProfileRecipientId] as? String else { - owsFailDebug("recipientId was unexpectedly nil") - return - } - - guard let recipientId = self.recipientId else { - // shouldn't call this for group threads - owsFailDebug("contactId was unexpectedly nil") - return - } - - guard recipientId == changedRecipientId else { - // not this avatar - return - } - - self.updateImage() - } - - @objc func handleGroupAvatarChanged(notification: Notification) { - Logger.debug("") - - guard let changedGroupThreadId = notification.userInfo?[TSGroupThread_NotificationKey_UniqueId] as? String else { - owsFailDebug("groupThreadId was unexpectedly nil") - return - } - - guard let groupThreadId = self.groupThreadId else { - // shouldn't call this for contact threads - owsFailDebug("groupThreadId was unexpectedly nil") - return - } - - guard groupThreadId == changedGroupThreadId else { - // not this avatar - return - } - - thread.reload() - - self.updateImage() - } - - public func updateImage() { - Logger.debug("updateImage") - - self.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: diameter) - } -} - -@objc -public class AvatarImageButton: UIButton { - private let shadowLayer = CAShapeLayer() - - // MARK: - Button Overrides - - override public func layoutSubviews() { - super.layoutSubviews() - - layer.cornerRadius = frame.size.width / 2 - - // Inner shadow. - // This should usually not be visible; it is used to distinguish - // profile pics from the background if they are similar. - shadowLayer.frame = bounds - shadowLayer.masksToBounds = true - let shadowBounds = bounds - let shadowPath = UIBezierPath(ovalIn: shadowBounds) - // This can be any value large enough to cast a sufficiently large shadow. - let shadowInset: CGFloat = -3 - shadowPath.append(UIBezierPath(rect: shadowBounds.insetBy(dx: shadowInset, dy: shadowInset))) - // This can be any color since the fill should be clipped. - shadowLayer.fillColor = UIColor.black.cgColor - shadowLayer.path = shadowPath.cgPath - shadowLayer.fillRule = .evenOdd - shadowLayer.shadowColor = (Theme.isDarkThemeEnabled ? UIColor.white : UIColor.black).cgColor - shadowLayer.shadowRadius = 0.5 - shadowLayer.shadowOpacity = 0.15 - shadowLayer.shadowOffset = .zero - } - - override public func setImage(_ image: UIImage?, for state: UIControl.State) { - ensureViewConfigured() - super.setImage(image, for: state) - } - - // MARK: Private - - var hasBeenConfigured = false - func ensureViewConfigured() { - guard !hasBeenConfigured else { - return - } - hasBeenConfigured = true - - autoPinToSquareAspectRatio() - - layer.minificationFilter = .trilinear - layer.magnificationFilter = .trilinear - layer.masksToBounds = true - layer.addSublayer(shadowLayer) - - contentMode = .scaleToFill - } -} diff --git a/SignalUtilitiesKit/CDSQuote.h b/SignalUtilitiesKit/CDSQuote.h deleted file mode 100644 index 7ba472c3b..000000000 --- a/SignalUtilitiesKit/CDSQuote.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface CDSQuote : NSObject - -@property (nonatomic, readonly) uint16_t version; -@property (nonatomic, readonly) uint16_t signType; -@property (nonatomic, readonly) BOOL isSigLinkable; -@property (nonatomic, readonly) uint32_t gid; -@property (nonatomic, readonly) uint16_t qeSvn; -@property (nonatomic, readonly) uint16_t pceSvn; -@property (nonatomic, readonly) NSData *basename; -@property (nonatomic, readonly) NSData *cpuSvn; -@property (nonatomic, readonly) uint64_t flags; -@property (nonatomic, readonly) uint64_t xfrm; -@property (nonatomic, readonly) NSData *mrenclave; -@property (nonatomic, readonly) NSData *mrsigner; -@property (nonatomic, readonly) uint16_t isvProdId; -@property (nonatomic, readonly) uint16_t isvSvn; -@property (nonatomic, readonly) NSData *reportData; -@property (nonatomic, readonly) NSData *signature; - -+ (nullable CDSQuote *)parseQuoteFromData:(NSData *)quoteData; - -- (BOOL)isDebugQuote; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/CDSQuote.m b/SignalUtilitiesKit/CDSQuote.m deleted file mode 100644 index 08d6d59e6..000000000 --- a/SignalUtilitiesKit/CDSQuote.m +++ /dev/null @@ -1,192 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "CDSQuote.h" -#import "ByteParser.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -static const long SGX_FLAGS_INITTED = 0x0000000000000001L; -static const long SGX_FLAGS_DEBUG = 0x0000000000000002L; -static const long SGX_FLAGS_MODE64BIT = 0x0000000000000004L; -static const long __unused SGX_FLAGS_PROVISION_KEY = 0x0000000000000004L; -static const long __unused SGX_FLAGS_EINITTOKEN_KEY = 0x0000000000000004L; -static const long SGX_FLAGS_RESERVED = 0xFFFFFFFFFFFFFFC8L; -static const long __unused SGX_XFRM_LEGACY = 0x0000000000000003L; -static const long __unused SGX_XFRM_AVX = 0x0000000000000006L; -static const long SGX_XFRM_RESERVED = 0xFFFFFFFFFFFFFFF8L; - -#pragma mark - - -@interface CDSQuote () - -@property (nonatomic) uint16_t version; -@property (nonatomic) uint16_t signType; -@property (nonatomic) BOOL isSigLinkable; -@property (nonatomic) uint32_t gid; -@property (nonatomic) uint16_t qeSvn; -@property (nonatomic) uint16_t pceSvn; -@property (nonatomic) NSData *basename; -@property (nonatomic) NSData *cpuSvn; -@property (nonatomic) uint64_t flags; -@property (nonatomic) uint64_t xfrm; -@property (nonatomic) NSData *mrenclave; -@property (nonatomic) NSData *mrsigner; -@property (nonatomic) uint16_t isvProdId; -@property (nonatomic) uint16_t isvSvn; -@property (nonatomic) NSData *reportData; -@property (nonatomic) NSData *signature; - -@end - -#pragma mark - - -@implementation CDSQuote - -+ (nullable CDSQuote *)parseQuoteFromData:(NSData *)quoteData -{ - ByteParser *_Nullable parser = [[ByteParser alloc] initWithData:quoteData littleEndian:YES]; - - // NOTE: This version is separate from and does _NOT_ match the signature body entity version. - uint16_t version = parser.nextShort; - if (version < 1 || version > 2) { - OWSFailDebug(@"unexpected quote version: %d", (int)version); - return nil; - } - - uint16_t signType = parser.nextShort; - if ((signType & ~1) != 0) { - OWSFailDebug(@"invalid signType: %d", (int)signType); - return nil; - } - - BOOL isSigLinkable = signType == 1; - uint32_t gid = parser.nextInt; - uint16_t qeSvn = parser.nextShort; - - uint16_t pceSvn = 0; - if (version > 1) { - pceSvn = parser.nextShort; - } else { - if (![parser readZero:2]) { - OWSFailDebug(@"non-zero pceSvn."); - return nil; - } - } - - if (![parser readZero:4]) { - OWSFailDebug(@"non-zero xeid."); - return nil; - } - - NSData *_Nullable basename = [parser readBytes:32]; - if (!basename) { - OWSFailDebug(@"couldn't read basename."); - return nil; - } - - // report_body - - NSData *_Nullable cpuSvn = [parser readBytes:16]; - if (!cpuSvn) { - OWSFailDebug(@"couldn't read cpuSvn."); - return nil; - } - if (![parser readZero:4]) { - OWSFailDebug(@"non-zero misc_select."); - return nil; - } - if (![parser readZero:28]) { - OWSFailDebug(@"non-zero reserved1."); - return nil; - } - - uint64_t flags = parser.nextLong; - if ((flags & SGX_FLAGS_RESERVED) != 0 || (flags & SGX_FLAGS_INITTED) == 0 || (flags & SGX_FLAGS_MODE64BIT) == 0) { - OWSFailDebug(@"invalid flags."); - return nil; - } - - uint64_t xfrm = parser.nextLong; - if ((xfrm & SGX_XFRM_RESERVED) != 0) { - OWSFailDebug(@"invalid xfrm."); - return nil; - } - - NSData *_Nullable mrenclave = [parser readBytes:32]; - if (!mrenclave) { - OWSFailDebug(@"couldn't read mrenclave."); - return nil; - } - if (![parser readZero:32]) { - OWSFailDebug(@"non-zero reserved2."); - return nil; - } - NSData *_Nullable mrsigner = [parser readBytes:32]; - if (!mrsigner) { - OWSFailDebug(@"couldn't read mrsigner."); - return nil; - } - if (![parser readZero:96]) { - OWSFailDebug(@"non-zero reserved3."); - return nil; - } - uint16_t isvProdId = parser.nextShort; - uint16_t isvSvn = parser.nextShort; - if (![parser readZero:60]) { - OWSFailDebug(@"non-zero reserved4."); - return nil; - } - NSData *_Nullable reportData = [parser readBytes:64]; - if (!reportData) { - OWSFailDebug(@"couldn't read reportData."); - return nil; - } - - // quote signature - uint32_t signatureLength = parser.nextInt; - if (signatureLength != quoteData.length - 436) { - OWSFailDebug(@"invalid signatureLength."); - return nil; - } - NSData *_Nullable signature = [parser readBytes:signatureLength]; - if (!signature) { - OWSFailDebug(@"couldn't read signature."); - return nil; - } - - if (parser.hasError) { - return nil; - } - - CDSQuote *quote = [CDSQuote new]; - quote.version = version; - quote.signType = signType; - quote.isSigLinkable = isSigLinkable; - quote.gid = gid; - quote.qeSvn = qeSvn; - quote.pceSvn = pceSvn; - quote.basename = basename; - quote.cpuSvn = cpuSvn; - quote.flags = flags; - quote.xfrm = xfrm; - quote.mrenclave = mrenclave; - quote.mrsigner = mrsigner; - quote.isvProdId = isvProdId; - quote.isvSvn = isvSvn; - quote.reportData = reportData; - quote.signature = signature; - - return quote; -} - -- (BOOL)isDebugQuote -{ - return (self.flags & SGX_FLAGS_DEBUG) != 0; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/CDSSigningCertificate.h b/SignalUtilitiesKit/CDSSigningCertificate.h deleted file mode 100644 index 3fd3ccf29..000000000 --- a/SignalUtilitiesKit/CDSSigningCertificate.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef NS_ENUM(NSUInteger, CDSSigningCertificateErrorCode) { - // AssertionError's indicate either developer or some serious system error that should never happen. - // - // Do not use this for an "expected" error, e.g. something that could be induced by user input which - // we specifically need to handle gracefull. - CDSSigningCertificateError_AssertionError = 1, - - CDSSigningCertificateError_InvalidPEMSupplied, - CDSSigningCertificateError_CouldNotExtractLeafCertificate, - CDSSigningCertificateError_InvalidDistinguishedName, - CDSSigningCertificateError_UntrustedCertificate -}; - -NSError *CDSSigningCertificateErrorMake(CDSSigningCertificateErrorCode code, NSString *localizedDescription); - -@interface CDSSigningCertificate : NSObject - -+ (nullable CDSSigningCertificate *)parseCertificateFromPem:(NSString *)certificatePem error:(NSError **)error; - -- (BOOL)verifySignatureOfBody:(NSString *)body signature:(NSData *)theirSignature; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/CDSSigningCertificate.m b/SignalUtilitiesKit/CDSSigningCertificate.m deleted file mode 100644 index edaa1e51b..000000000 --- a/SignalUtilitiesKit/CDSSigningCertificate.m +++ /dev/null @@ -1,391 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "CDSSigningCertificate.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSError *CDSSigningCertificateErrorMake(CDSSigningCertificateErrorCode code, NSString *localizedDescription) -{ - return [NSError errorWithDomain:@"CDSSigningCertificate" - code:code - userInfo:@{ NSLocalizedDescriptionKey : localizedDescription }]; -} - -@interface CDSSigningCertificate () - -@property (nonatomic) SecPolicyRef policy; -@property (nonatomic) SecTrustRef trust; -@property (nonatomic) SecKeyRef publicKey; - -@end - -#pragma mark - - -@implementation CDSSigningCertificate - -- (instancetype)init -{ - if (self = [super init]) { - _policy = NULL; - _trust = NULL; - _publicKey = NULL; - } - - return self; -} - -- (void)dealloc -{ - if (_policy) { - CFRelease(_policy); - _policy = NULL; - } - if (_trust) { - CFRelease(_trust); - _trust = NULL; - } - if (_publicKey) { - CFRelease(_publicKey); - _publicKey = NULL; - } -} - -+ (nullable CDSSigningCertificate *)parseCertificateFromPem:(NSString *)certificatePem error:(NSError **)error -{ - OWSAssertDebug(certificatePem); - *error = nil; - - CDSSigningCertificate *signingCertificate = [CDSSigningCertificate new]; - - NSArray *_Nullable anchorCertificates = [self anchorCertificates]; - if (anchorCertificates.count < 1) { - OWSFailDebug(@"Could not load anchor certificates."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"Could not load anchor certificates."); - return nil; - } - - NSArray *_Nullable certificateDerDatas = [self convertPemToDer:certificatePem]; - - if (certificateDerDatas.count < 1) { - OWSFailDebug(@"Could not parse PEM."); - *error = CDSSigningCertificateErrorMake(CDSSigningCertificateError_InvalidPEMSupplied, @"Could not parse PEM."); - return nil; - } - - // The leaf is always the first certificate. - NSData *_Nullable leafCertificateData = [certificateDerDatas firstObject]; - if (!leafCertificateData) { - OWSFailDebug(@"Could not extract leaf certificate data."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_CouldNotExtractLeafCertificate, @"Could not extract leaf certificate data."); - return nil; - } - if (![self verifyDistinguishedNameOfCertificate:leafCertificateData]) { - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_InvalidDistinguishedName, @"Could not extract leaf certificate data."); - return nil; - } - - NSMutableArray *certificates = [NSMutableArray new]; - for (NSData *certificateDerData in certificateDerDatas) { - SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certificateDerData)); - if (!certificate) { - OWSFailDebug(@"Could not create SecCertificate."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"Could not create SecCertificate."); - return nil; - } - [certificates addObject:(__bridge_transfer id)certificate]; - } - - SecPolicyRef policy = SecPolicyCreateBasicX509(); - signingCertificate.policy = policy; - if (!policy) { - OWSFailDebug(@"Could not create policy."); - *error = CDSSigningCertificateErrorMake(CDSSigningCertificateError_AssertionError, @"Could not create policy."); - return nil; - } - - SecTrustRef trust; - OSStatus status = SecTrustCreateWithCertificates((__bridge CFTypeRef)certificates, policy, &trust); - signingCertificate.trust = trust; - if (status != errSecSuccess) { - OWSFailDebug(@"Creating trust did not succeed."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"Creating trust did not succeed."); - return nil; - } - if (!trust) { - OWSFailDebug(@"Could not create trust."); - *error = CDSSigningCertificateErrorMake(CDSSigningCertificateError_AssertionError, @"Could not create trust."); - return nil; - } - - status = SecTrustSetNetworkFetchAllowed(trust, NO); - if (status != errSecSuccess) { - OWSFailDebug(@"trust fetch could not be configured."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"trust fetch could not be configured."); - return nil; - } - - status = SecTrustSetAnchorCertificatesOnly(trust, YES); - if (status != errSecSuccess) { - OWSFailDebug(@"trust anchor certs could not be configured."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"trust anchor certs could not be configured."); - return nil; - } - - NSMutableArray *pinnedCertificates = [NSMutableArray array]; - for (NSData *certificateData in anchorCertificates) { - SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certificateData)); - if (!certificate) { - OWSFailDebug(@"Could not create pinned SecCertificate."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"Could not create pinned SecCertificate."); - return nil; - } - - [pinnedCertificates addObject:(__bridge_transfer id)certificate]; - } - status = SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)pinnedCertificates); - if (status != errSecSuccess) { - OWSFailDebug(@"The anchor certificates couldn't be set."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"The anchor certificates couldn't be set."); - return nil; - } - - SecTrustResultType result; - status = SecTrustEvaluate(trust, &result); - if (status != errSecSuccess) { - OWSFailDebug(@"Could not evaluate certificates."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"Could not evaluate certificates."); - return nil; - } - - // `kSecTrustResultUnspecified` is confusingly named. It indicates success. - // See the comments in the header where it is defined. - BOOL isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); - if (!isValid) { - OWSFailDebug(@"Certificate was not trusted."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_UntrustedCertificate, @"Certificate was not trusted."); - return nil; - } - - SecKeyRef publicKey = SecTrustCopyPublicKey(trust); - signingCertificate.publicKey = publicKey; - if (!publicKey) { - OWSFailDebug(@"Could not extract public key."); - *error = CDSSigningCertificateErrorMake( - CDSSigningCertificateError_AssertionError, @"Could not extract public key."); - return nil; - } - - return signingCertificate; -} - -// PEM is just a series of blocks of base-64 encoded DER data. -// -// https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail -+ (nullable NSArray *)convertPemToDer:(NSString *)pemString -{ - NSMutableArray *certificateDatas = [NSMutableArray new]; - - NSError *error; - // We use ? for non-greedy matching. - NSRegularExpression *_Nullable regex = [NSRegularExpression - regularExpressionWithPattern:@"-----BEGIN.*?-----(.+?)-----END.*?-----" - options:NSRegularExpressionCaseInsensitive | NSRegularExpressionDotMatchesLineSeparators - error:&error]; - if (!regex || error) { - OWSFailDebug(@"could parse regex: %@.", error); - return nil; - } - - [regex enumerateMatchesInString:pemString - options:0 - range:NSMakeRange(0, pemString.length) - usingBlock:^(NSTextCheckingResult *_Nullable result, NSMatchingFlags flags, BOOL *stop) { - if (result.numberOfRanges != 2) { - OWSFailDebug(@"invalid PEM regex match."); - return; - } - NSString *_Nullable derString = [pemString substringWithRange:[result rangeAtIndex:1]]; - if (derString.length < 1) { - OWSFailDebug(@"empty PEM match."); - return; - } - // dataFromBase64String will ignore whitespace, which is - // necessary. - NSData *_Nullable derData = [NSData dataFromBase64String:derString]; - if (derData.length < 1) { - return; - } - [certificateDatas addObject:derData]; - }]; - - return certificateDatas; -} - -+ (nullable NSArray *)anchorCertificates -{ - static NSArray *anchorCertificates = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - // We need to use an Intel certificate as the anchor for IAS verification. - NSData *_Nullable anchorCertificate = [self certificateDataForService:@"ias-root"]; - if (!anchorCertificate) { - OWSFail(@"could not load anchor certificate."); - } else { - anchorCertificates = @[ anchorCertificate ]; - } - }); - return anchorCertificates; -} - -+ (nullable NSData *)certificateDataForService:(NSString *)service -{ - NSBundle *bundle = [NSBundle bundleForClass:self.class]; - NSString *path = [bundle pathForResource:service ofType:@"cer"]; - - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { - OWSFailDebug(@"could not locate certificate file."); - return nil; - } - - NSData *_Nullable certificateData = [NSData dataWithContentsOfFile:path]; - return certificateData; -} - -- (BOOL)verifySignatureOfBody:(NSString *)body signature:(NSData *)signature -{ - OWSAssertDebug(self.publicKey); - - NSData *bodyData = [body dataUsingEncoding:NSUTF8StringEncoding]; - - size_t signedHashBytesSize = SecKeyGetBlockSize(self.publicKey); - const void *signedHashBytes = [signature bytes]; - - NSData *_Nullable hashData = [Cryptography computeSHA256Digest:bodyData]; - if (hashData.length != CC_SHA256_DIGEST_LENGTH) { - OWSFailDebug(@"could not SHA256 for signature verification."); - return NO; - } - size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH; - const void *hashBytes = [hashData bytes]; - - OSStatus status = SecKeyRawVerify( - self.publicKey, kSecPaddingPKCS1SHA256, hashBytes, hashBytesSize, signedHashBytes, signedHashBytesSize); - - BOOL isValid = status == errSecSuccess; - if (!isValid) { - return NO; - } - return YES; -} - -+ (BOOL)verifyDistinguishedNameOfCertificate:(NSData *)certificateData -{ - OWSAssertDebug(certificateData); - - // The Security framework doesn't offer access to certificate properties - // with API available on iOS 9. We use OpenSSL to extract the name. - NSDictionary *_Nullable properties = [self propertiesForCertificate:certificateData]; - if (!properties) { - OWSFailDebug(@"Could not retrieve certificate properties."); - return NO; - } - // NSString *expectedDistinguishedName - // = @"CN=Intel SGX Attestation Report Signing,O=Intel Corporation,L=Santa Clara,ST=CA,C=US"; - NSDictionary *expectedProperties = @{ - @(SN_commonName) : // "CN" - @"Intel SGX Attestation Report Signing", - @(SN_organizationName) : // "O" - @"Intel Corporation", - @(SN_localityName) : // "L" - @"Santa Clara", - @(SN_stateOrProvinceName) : // "ST" - @"CA", - @(SN_countryName) : // "C" - @"US", - }; - - if (![properties isEqualToDictionary:expectedProperties]) { - return NO; - } - return YES; -} - -+ (nullable NSDictionary *)propertiesForCertificate:(NSData *)certificateData -{ - OWSAssertDebug(certificateData); - - if (certificateData.length >= UINT32_MAX) { - OWSFailDebug(@"certificate data is too long."); - return nil; - } - const unsigned char *certificateDataBytes = (const unsigned char *)[certificateData bytes]; - X509 *_Nullable certificateX509 = d2i_X509(NULL, &certificateDataBytes, [certificateData length]); - if (!certificateX509) { - OWSFailDebug(@"could not parse certificate."); - return nil; - } - - X509_NAME *_Nullable subjectName = X509_get_subject_name(certificateX509); - if (!subjectName) { - OWSFailDebug(@"could not extract subject name."); - return nil; - } - - NSMutableDictionary *certificateProperties = [NSMutableDictionary new]; - for (NSString *oid in @[ - @(SN_commonName), // "CN" - @(SN_organizationName), // "O" - @(SN_localityName), // "L" - @(SN_stateOrProvinceName), // "ST" - @(SN_countryName), // "C" - ]) { - int nid = OBJ_txt2nid(oid.UTF8String); - int index = X509_NAME_get_index_by_NID(subjectName, nid, -1); - - X509_NAME_ENTRY *_Nullable entry = X509_NAME_get_entry(subjectName, index); - if (!entry) { - OWSFailDebug(@"could not extract entry."); - return nil; - } - - ASN1_STRING *_Nullable entryData = X509_NAME_ENTRY_get_data(entry); - if (!entryData) { - OWSFailDebug(@"could not extract entry data."); - return nil; - } - - unsigned char *entryName = ASN1_STRING_data(entryData); - if (entryName == NULL) { - OWSFailDebug(@"could not extract entry string."); - return nil; - } - NSString *_Nullable entryString = [NSString stringWithUTF8String:(char *)entryName]; - if (!entryString) { - OWSFailDebug(@"could not parse entry name data."); - return nil; - } - certificateProperties[oid] = entryString; - } - return certificateProperties; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ClosedGroupParser.swift b/SignalUtilitiesKit/ClosedGroupParser.swift deleted file mode 100644 index 3118f569d..000000000 --- a/SignalUtilitiesKit/ClosedGroupParser.swift +++ /dev/null @@ -1,30 +0,0 @@ - -@objc public final class ClosedGroupParser : NSObject { - private let data: Data - - @objc public init(data: Data) { - self.data = data - } - - @objc public func parseGroupModels() -> [TSGroupModel] { - var index = 0 - var result: [TSGroupModel] = [] - while index < data.endIndex { - var uncheckedSize: UInt32? = try? data[index..<(index+4)].withUnsafeBytes { $0.pointee } - if let size = uncheckedSize, size >= data.count, let intermediate = try? data[index..<(index+4)].reversed() { - uncheckedSize = Data(intermediate).withUnsafeBytes { $0.pointee } - } - guard let size = uncheckedSize, size < data.count else { break } - let sizeAsInt = Int(size) - index += 4 - guard index + sizeAsInt <= data.count else { break } - let protoAsData = data[index..<(index+sizeAsInt)] - guard let proto = try? SSKProtoGroupDetails.parseData(protoAsData) else { break } - index += sizeAsInt - var groupModel = TSGroupModel(title: proto.name, memberIds: proto.members, image: nil, - groupId: proto.id, groupType: GroupType.closedGroup, adminIds: proto.admins) - result.append(groupModel) - } - return result - } -} diff --git a/SignalUtilitiesKit/ClosedGroupPoller.swift b/SignalUtilitiesKit/ClosedGroupPoller.swift index 0444b8656..01fb5f26a 100644 --- a/SignalUtilitiesKit/ClosedGroupPoller.swift +++ b/SignalUtilitiesKit/ClosedGroupPoller.swift @@ -61,7 +61,7 @@ public final class ClosedGroupPoller : NSObject { print("[Loki] Received \(messages.count) new message(s) in closed group with public key: \(publicKey).") } messages.forEach { json in - guard let envelope = SSKProtoEnvelope.from(json) else { return } + guard let envelope = SNProtoEnvelope.from(json) else { return } do { let data = try envelope.serializedData() let job = MessageReceiveJob(data: data) diff --git a/SignalUtilitiesKit/ClosedGroupUpdateMessage.swift b/SignalUtilitiesKit/ClosedGroupUpdateMessage.swift deleted file mode 100644 index 41006d707..000000000 --- a/SignalUtilitiesKit/ClosedGroupUpdateMessage.swift +++ /dev/null @@ -1,132 +0,0 @@ - -@objc(LKClosedGroupUpdateMessage) -internal final class ClosedGroupUpdateMessage : TSOutgoingMessage { - private let kind: Kind - - // MARK: Settings - @objc internal override var ttl: UInt32 { return UInt32(TTLUtilities.getTTL(for: .closedGroupUpdate)) } - - @objc internal override func shouldBeSaved() -> Bool { return false } - @objc internal override func shouldSyncTranscript() -> Bool { return false } - - // MARK: Kind - internal enum Kind { - case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) - case info(groupPublicKey: Data, name: String, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) - case senderKeyRequest(groupPublicKey: Data) - case senderKey(groupPublicKey: Data, senderKey: ClosedGroupSenderKey) - } - - // MARK: Initialization - internal init(thread: TSThread, kind: Kind) { - self.kind = kind - super.init(outgoingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageBody: "", - attachmentIds: NSMutableArray(), expiresInSeconds: 0, expireStartedAt: 0, isVoiceMessage: false, - groupMetaMessage: .unspecified, quotedMessage: nil, contactShare: nil, linkPreview: nil) - } - - required init(dictionary: [String:Any]) throws { - preconditionFailure("Use init(thread:kind:) instead.") - } - - // MARK: Coding - internal required init?(coder: NSCoder) { - guard let thread = coder.decodeObject(forKey: "thread") as? TSThread, - let timestamp = coder.decodeObject(forKey: "timestamp") as? UInt64, - let groupPublicKey = coder.decodeObject(forKey: "groupPublicKey") as? Data, - let rawKind = coder.decodeObject(forKey: "kind") as? String else { return nil } - switch rawKind { - case "new": - guard let name = coder.decodeObject(forKey: "name") as? String, - let groupPrivateKey = coder.decodeObject(forKey: "groupPrivateKey") as? Data, - let senderKeys = coder.decodeObject(forKey: "senderKeys") as? [ClosedGroupSenderKey], - let members = coder.decodeObject(forKey: "members") as? [Data], - let admins = coder.decodeObject(forKey: "admins") as? [Data] else { return nil } - self.kind = .new(groupPublicKey: groupPublicKey, name: name, groupPrivateKey: groupPrivateKey, senderKeys: senderKeys, members: members, admins: admins) - case "info": - guard let name = coder.decodeObject(forKey: "name") as? String, - let senderKeys = coder.decodeObject(forKey: "senderKeys") as? [ClosedGroupSenderKey], - let members = coder.decodeObject(forKey: "members") as? [Data], - let admins = coder.decodeObject(forKey: "admins") as? [Data] else { return nil } - self.kind = .info(groupPublicKey: groupPublicKey, name: name, senderKeys: senderKeys, members: members, admins: admins) - case "senderKeyRequest": - self.kind = .senderKeyRequest(groupPublicKey: groupPublicKey) - case "senderKey": - guard let senderKeys = coder.decodeObject(forKey: "senderKeys") as? [ClosedGroupSenderKey], - let senderKey = senderKeys.first else { return nil } - self.kind = .senderKey(groupPublicKey: groupPublicKey, senderKey: senderKey) - default: return nil - } - super.init(outgoingMessageWithTimestamp: timestamp, in: thread, messageBody: "", - attachmentIds: NSMutableArray(), expiresInSeconds: 0, expireStartedAt: 0, isVoiceMessage: false, - groupMetaMessage: .unspecified, quotedMessage: nil, contactShare: nil, linkPreview: nil) - } - - internal override func encode(with coder: NSCoder) { - coder.encode(thread, forKey: "thread") - coder.encode(timestamp, forKey: "timestamp") - switch kind { - case .new(let groupPublicKey, let name, let groupPrivateKey, let senderKeys, let members, let admins): - coder.encode("new", forKey: "kind") - coder.encode(groupPublicKey, forKey: "groupPublicKey") - coder.encode(name, forKey: "name") - coder.encode(groupPrivateKey, forKey: "groupPrivateKey") - coder.encode(senderKeys, forKey: "senderKeys") - coder.encode(members, forKey: "members") - coder.encode(admins, forKey: "admins") - case .info(let groupPublicKey, let name, let senderKeys, let members, let admins): - coder.encode("info", forKey: "kind") - coder.encode(groupPublicKey, forKey: "groupPublicKey") - coder.encode(name, forKey: "name") - coder.encode(senderKeys, forKey: "senderKeys") - coder.encode(members, forKey: "members") - coder.encode(admins, forKey: "admins") - case .senderKeyRequest(let groupPublicKey): - coder.encode(groupPublicKey, forKey: "groupPublicKey") - case .senderKey(let groupPublicKey, let senderKey): - coder.encode("senderKey", forKey: "kind") - coder.encode(groupPublicKey, forKey: "groupPublicKey") - coder.encode([ senderKey ], forKey: "senderKeys") - } - } - - // MARK: Building - @objc internal override func dataMessageBuilder() -> Any? { - guard let builder = super.dataMessageBuilder() as? SSKProtoDataMessage.SSKProtoDataMessageBuilder else { return nil } - do { - let closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate.SSKProtoDataMessageClosedGroupUpdateBuilder - switch kind { - case .new(let groupPublicKey, let name, let groupPrivateKey, let senderKeys, let members, let admins): - closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .new) - closedGroupUpdate.setName(name) - closedGroupUpdate.setGroupPrivateKey(groupPrivateKey) - closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() }) - closedGroupUpdate.setMembers(members) - closedGroupUpdate.setAdmins(admins) - case .info(let groupPublicKey, let name, let senderKeys, let members, let admins): - closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .info) - closedGroupUpdate.setName(name) - closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() }) - closedGroupUpdate.setMembers(members) - closedGroupUpdate.setAdmins(admins) - case .senderKeyRequest(let groupPublicKey): - closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKeyRequest) - case .senderKey(let groupPublicKey, let senderKey): - closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKey) - closedGroupUpdate.setSenderKeys([ try senderKey.toProto() ]) - } - builder.setClosedGroupUpdate(try closedGroupUpdate.build()) - } catch { - owsFailDebug("Failed to build closed group update due to error: \(error).") - return nil - } - return builder - } -} - -private extension ClosedGroupSenderKey { - - func toProto() throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { - return try SSKProtoDataMessageClosedGroupUpdateSenderKey.builder(chainKey: chainKey, keyIndex: UInt32(keyIndex), publicKey: publicKey).build() - } -} diff --git a/SignalUtilitiesKit/ClosedGroupUtilities.swift b/SignalUtilitiesKit/ClosedGroupUtilities.swift deleted file mode 100644 index 4521eb444..000000000 --- a/SignalUtilitiesKit/ClosedGroupUtilities.swift +++ /dev/null @@ -1,70 +0,0 @@ -import CryptoSwift - - -@objc(LKClosedGroupUtilities) -public final class ClosedGroupUtilities : NSObject { - - @objc(LKSSKDecryptionError) - public class SSKDecryptionError : NSError { // Not called `Error` for Obj-C interoperablity - - @objc public static let invalidGroupPublicKey = SSKDecryptionError(domain: "SSKErrorDomain", code: 1, userInfo: [ NSLocalizedDescriptionKey : "Invalid group public key." ]) - @objc public static let noData = SSKDecryptionError(domain: "SSKErrorDomain", code: 2, userInfo: [ NSLocalizedDescriptionKey : "Received an empty envelope." ]) - @objc public static let noGroupPrivateKey = SSKDecryptionError(domain: "SSKErrorDomain", code: 3, userInfo: [ NSLocalizedDescriptionKey : "Missing group private key." ]) - @objc public static let selfSend = SSKDecryptionError(domain: "SSKErrorDomain", code: 4, userInfo: [ NSLocalizedDescriptionKey : "Message addressed at self." ]) - } - - @objc(encryptData:usingGroupPublicKey:transaction:error:) - public static func encrypt(data: Data, groupPublicKey: String, transaction: YapDatabaseReadWriteTransaction) throws -> Data { - // 1. ) Encrypt the data with the user's sender key - guard let userPublicKey = OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey else { - throw SMKError.assertionError(description: "[Loki] Couldn't find user key pair.") - } - let ciphertextAndKeyIndex = try SharedSenderKeysImplementation.shared.encrypt(data, forGroupWithPublicKey: groupPublicKey, - senderPublicKey: userPublicKey, protocolContext: transaction) - let ivAndCiphertext = ciphertextAndKeyIndex[0] as! Data - let keyIndex = ciphertextAndKeyIndex[1] as! UInt - let encryptedMessage = ClosedGroupCiphertextMessage(_throws_withIVAndCiphertext: ivAndCiphertext, senderPublicKey: Data(hex: userPublicKey), keyIndex: UInt32(keyIndex)) - // 2. ) Encrypt the result for the group's public key to hide the sender public key and key index - let (ciphertext, _, ephemeralPublicKey) = try EncryptionUtilities.encrypt(encryptedMessage.serialized, using: groupPublicKey.removing05PrefixIfNeeded()) - // 3. ) Wrap the result - return try SSKProtoClosedGroupCiphertextMessageWrapper.builder(ciphertext: ciphertext, ephemeralPublicKey: ephemeralPublicKey).build().serializedData() - } - - @objc(decryptEnvelope:transaction:error:) - public static func decrypt(envelope: SSKProtoEnvelope, transaction: YapDatabaseReadWriteTransaction) throws -> [Any] { - let (plaintext, senderPublicKey) = try decrypt(envelope: envelope, transaction: transaction) - return [ plaintext, senderPublicKey ] - } - - public static func decrypt(envelope: SSKProtoEnvelope, transaction: YapDatabaseReadWriteTransaction) throws -> (plaintext: Data, senderPublicKey: String) { - // 1. ) Check preconditions - guard let groupPublicKey = envelope.source, SharedSenderKeysImplementation.shared.isClosedGroup(groupPublicKey) else { - throw SSKDecryptionError.invalidGroupPublicKey - } - guard let data = envelope.content else { - throw SSKDecryptionError.noData - } - guard let hexEncodedGroupPrivateKey = Storage.getClosedGroupPrivateKey(for: groupPublicKey) else { - throw SSKDecryptionError.noGroupPrivateKey - } - let groupPrivateKey = Data(hex: hexEncodedGroupPrivateKey) - // 2. ) Parse the wrapper - let wrapper = try SSKProtoClosedGroupCiphertextMessageWrapper.parseData(data) - let ivAndCiphertext = wrapper.ciphertext - let ephemeralPublicKey = wrapper.ephemeralPublicKey - // 3. ) Decrypt the data inside - let ephemeralSharedSecret = try Curve25519.generateSharedSecret(fromPublicKey: ephemeralPublicKey, privateKey: groupPrivateKey) - let salt = "LOKI" - let symmetricKey = try HMAC(key: salt.bytes, variant: .sha256).authenticate(ephemeralSharedSecret.bytes) - let closedGroupCiphertextMessageAsData = try DecryptionUtilities.decrypt(ivAndCiphertext, usingAESGCMWithSymmetricKey: Data(symmetricKey)) - // 4. ) Parse the closed group ciphertext message - let closedGroupCiphertextMessage = ClosedGroupCiphertextMessage(_throws_with: closedGroupCiphertextMessageAsData) - let senderPublicKey = closedGroupCiphertextMessage.senderPublicKey.toHexString() - guard senderPublicKey != getUserHexEncodedPublicKey() else { throw SSKDecryptionError.selfSend } - // 5. ) Use the info inside the closed group ciphertext message to decrypt the actual message content - let plaintext = try SharedSenderKeysImplementation.shared.decrypt(closedGroupCiphertextMessage.ivAndCiphertext, forGroupWithPublicKey: groupPublicKey, - senderPublicKey: senderPublicKey, keyIndex: UInt(closedGroupCiphertextMessage.keyIndex), protocolContext: transaction) - // 6. ) Return - return (plaintext, senderPublicKey) - } -} diff --git a/SignalUtilitiesKit/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/ClosedGroupsProtocol.swift index 067bdfed6..7a458ae86 100644 --- a/SignalUtilitiesKit/ClosedGroupsProtocol.swift +++ b/SignalUtilitiesKit/ClosedGroupsProtocol.swift @@ -41,34 +41,27 @@ public final class ClosedGroupsProtocol : NSObject { // Generate a key pair for the group let groupKeyPair = Curve25519.generateKeyPair() let groupPublicKey = groupKeyPair.hexEncodedPublicKey // Includes the "05" prefix - // Ensure the current user's master device is the one that's included in the member list - members.remove(userPublicKey) - members.insert(UserDefaults.standard[.masterHexEncodedPublicKey] ?? userPublicKey) + // Ensure the current user is included in the member list + members.insert(userPublicKey) let membersAsData = members.map { Data(hex: $0) } - // Create ratchets for all members (and their linked devices) - var membersAndLinkedDevices: Set = members - for member in members { - let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction) - membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.publicKey, $0.slave.publicKey ] }) - } - let senderKeys: [ClosedGroupSenderKey] = membersAndLinkedDevices.map { publicKey in - let ratchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + // Create ratchets for all members + let senderKeys: [ClosedGroupSenderKey] = members.map { publicKey in + let ratchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) } // Create the group - let admins = [ UserDefaults.standard[.masterHexEncodedPublicKey] ?? userPublicKey ] + let admins = [ userPublicKey ] let adminsAsData = admins.map { Data(hex: $0) } let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) let group = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) let thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction) thread.usesSharedSenderKeys = true thread.save(with: transaction) - SSKEnvironment.shared.profileManager.addThread(toProfileWhitelist: thread) // Establish sessions if needed - establishSessionsIfNeeded(with: [String](members), using: transaction) // Not `membersAndLinkedDevices` as this internally takes care of multi device already - // Send a closed group update message to all members (and their linked devices) using established channels + establishSessionsIfNeeded(with: [String](members), using: transaction) + // Send a closed group update message to all members using established channels var promises: [Promise] = [] - for member in members { // Not `membersAndLinkedDevices` as this internally takes care of multi device already + for member in members { guard member != userPublicKey else { continue } let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) @@ -158,7 +151,7 @@ public final class ClosedGroupsProtocol : NSObject { MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } // Send out the user's new ratchet to all members (minus the removed ones) using established channels - let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) for member in members { guard member != userPublicKey else { continue } @@ -176,7 +169,7 @@ public final class ClosedGroupsProtocol : NSObject { seal.fulfill(()) // Generate ratchets for any new members newSenderKeys = newMembers.map { publicKey in - let ratchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + let ratchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) } // Send a closed group update message to the existing members with the new members' ratchets (this message is aimed at the group) @@ -212,7 +205,7 @@ public final class ClosedGroupsProtocol : NSObject { let newGroupModel = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) thread.setGroupModel(newGroupModel, with: transaction) // Notify the user - let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel, contactsManager: SSKEnvironment.shared.contactsManager) + let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel) let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate, customMessage: updateInfo) infoMessage.save(with: transaction) // Return @@ -227,7 +220,7 @@ public final class ClosedGroupsProtocol : NSObject { /// The returned promise is fulfilled when the group update message has been sent. It doesn't wait for the user's new ratchet to be distributed. public static func leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise { - let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey() + let userPublicKey = getUserHexEncodedPublicKey() let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { print("[Loki] Can't leave nonexistent closed group.") @@ -288,7 +281,7 @@ public final class ClosedGroupsProtocol : NSObject { let admins = closedGroupUpdate.admins.map { $0.toHexString() } // Persist the ratchets senderKeys.forEach { senderKey in - guard members.contains(senderKey.publicKey.toHexString()) else { return } // TODO: This currently doesn't take into account multi device + guard members.contains(senderKey.publicKey.toHexString()) else { return } let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) } @@ -297,7 +290,7 @@ public final class ClosedGroupsProtocol : NSObject { let userPublicKey = getUserHexEncodedPublicKey() if missingSenderKeys.contains(userPublicKey) { establishSessionsIfNeeded(with: [String](members), using: transaction) - let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) for member in members { guard member != userPublicKey else { continue } @@ -324,7 +317,6 @@ public final class ClosedGroupsProtocol : NSObject { thread.usesSharedSenderKeys = true thread.save(with: transaction) } - SSKEnvironment.shared.profileManager.addThread(toProfileWhitelist: thread) // Add the group to the user's set of public keys to poll for Storage.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction) // Notify the PN server @@ -333,7 +325,7 @@ public final class ClosedGroupsProtocol : NSObject { let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) infoMessage.save(with: transaction) // Establish sessions if needed - establishSessionsIfNeeded(with: members, using: transaction) // This internally takes care of multi device + establishSessionsIfNeeded(with: members, using: transaction) } /// Invoked upon receiving a group update. A group update is sent out when a group's name is changed, when new users are added, when users leave or are @@ -353,12 +345,7 @@ public final class ClosedGroupsProtocol : NSObject { } let group = thread.groupModel // Check that the sender is a member of the group (before the update) - var membersAndLinkedDevices: Set = Set(group.groupMemberIds) - for member in group.groupMemberIds { - let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction) - membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.publicKey, $0.slave.publicKey ] }) - } - guard membersAndLinkedDevices.contains(senderPublicKey) else { + guard Set(group.groupMemberIds).contains(senderPublicKey) else { return print("[Loki] Ignoring closed group info message from non-member.") } // Store the ratchets for any new members (it's important that this happens before the code below) @@ -370,7 +357,7 @@ public final class ClosedGroupsProtocol : NSObject { // • Send out the user's new ratchet using established channels if other members of the group left or were removed // • Remove the group from the user's set of public keys to poll for if the current user was among the members that were removed let oldMembers = group.groupMemberIds - let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey() + let userPublicKey = getUserHexEncodedPublicKey() let wasUserRemoved = !members.contains(userPublicKey) if Set(members).intersection(oldMembers) != Set(oldMembers) { let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) @@ -384,8 +371,8 @@ public final class ClosedGroupsProtocol : NSObject { // Notify the PN server let _ = LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) } else { - establishSessionsIfNeeded(with: members, using: transaction) // This internally takes care of multi device - let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + establishSessionsIfNeeded(with: members, using: transaction) + let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) for member in members { guard member != userPublicKey else { continue } @@ -401,10 +388,10 @@ public final class ClosedGroupsProtocol : NSObject { // Update the group let newGroupModel = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) thread.setGroupModel(newGroupModel, with: transaction) - // Notify the user if needed (don't notify them if the message just contained linked device sender keys) + // Notify the user if needed if Set(members) != Set(oldMembers) || Set(admins) != Set(group.groupAdminIds) || name != group.groupName { let infoMessageType: TSInfoMessageType = wasUserRemoved ? .typeGroupQuit : .typeGroupUpdate - let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel, contactsManager: SSKEnvironment.shared.contactsManager) + let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel) let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: infoMessageType, customMessage: updateInfo) infoMessage.save(with: transaction) } @@ -420,19 +407,15 @@ public final class ClosedGroupsProtocol : NSObject { } let group = groupThread.groupModel // Check that the requesting user is a member of the group - var membersAndLinkedDevices: Set = Set(group.groupMemberIds) - for member in group.groupMemberIds { - let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction) - membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.publicKey, $0.slave.publicKey ] }) - } - guard membersAndLinkedDevices.contains(senderPublicKey) else { + let members = Set(group.groupMemberIds) + guard members.contains(senderPublicKey) else { return print("[Loki] Ignoring closed group sender key request from non-member.") } // Respond to the request print("[Loki] Responding to sender key request from: \(senderPublicKey).") - SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) // This internally takes care of multi device + SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) let userRatchet = Storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey) - ?? SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + ?? SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) thread.save(with: transaction) @@ -471,11 +454,7 @@ public final class ClosedGroupsProtocol : NSObject { public static func shouldIgnoreClosedGroupMessage(_ dataMessage: SSKProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SSKProtoEnvelope) -> Bool { guard thread.groupModel.groupType == .closedGroup else { return true } let publicKey = envelope.source! // Set during UD decryption - var result = false - Storage.read { transaction in - result = !thread.isUserMember(inGroup: publicKey, transaction: transaction) - } - return result + return !thread.isUserMember(inGroup: publicKey) } /// - Note: Deprecated. @@ -483,10 +462,6 @@ public final class ClosedGroupsProtocol : NSObject { public static func shouldIgnoreClosedGroupUpdateMessage(_ dataMessage: SSKProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SSKProtoEnvelope) -> Bool { guard thread.groupModel.groupType == .closedGroup else { return true } let publicKey = envelope.source! // Set during UD decryption - var result = false - Storage.read { transaction in - result = !thread.isUserAdmin(inGroup: publicKey, transaction: transaction) - } - return result + return !thread.isUserAdmin(inGroup: publicKey) } } diff --git a/SignalUtilitiesKit/Contact.h b/SignalUtilitiesKit/Contact.h deleted file mode 100644 index ff7455f8d..000000000 --- a/SignalUtilitiesKit/Contact.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * An adapter for the system contacts - */ - -@class CNContact; -@class PhoneNumber; -@class SignalRecipient; -@class UIImage; -@class YapDatabaseReadTransaction; - -@interface Contact : MTLModel - -@property (nullable, readonly, nonatomic) NSString *firstName; -@property (nullable, readonly, nonatomic) NSString *lastName; -@property (readonly, nonatomic) NSString *fullName; -@property (readonly, nonatomic) NSString *comparableNameFirstLast; -@property (readonly, nonatomic) NSString *comparableNameLastFirst; -@property (readonly, nonatomic) NSArray *parsedPhoneNumbers; -@property (readonly, nonatomic) NSArray *userTextPhoneNumbers; -@property (readonly, nonatomic) NSArray *emails; -@property (readonly, nonatomic) NSString *uniqueId; -@property (nonatomic, readonly) BOOL isSignalContact; -@property (nonatomic, readonly) NSString *cnContactId; - -- (NSArray *)signalRecipientsWithTransaction:(YapDatabaseReadTransaction *)transaction; -// TODO: Remove this method. -- (NSArray *)textSecureIdentifiers; - -#if TARGET_OS_IOS - -- (instancetype)initWithSystemContact:(CNContact *)cnContact NS_AVAILABLE_IOS(9_0); -+ (nullable Contact *)contactWithVCardData:(NSData *)data; -+ (nullable CNContact *)cnContactWithVCardData:(NSData *)data; - -- (NSString *)nameForPhoneNumber:(NSString *)recipientId; - -#endif // TARGET_OS_IOS - -+ (NSComparator)comparatorSortingNamesByFirstThenLast:(BOOL)firstNameOrdering; -+ (NSString *)formattedFullNameWithCNContact:(CNContact *)cnContact NS_SWIFT_NAME(formattedFullName(cnContact:)); -+ (nullable NSString *)localizedStringForCNLabel:(nullable NSString *)cnLabel; - -+ (CNContact *)mergeCNContact:(CNContact *)oldCNContact - newCNContact:(CNContact *)newCNContact NS_SWIFT_NAME(merge(cnContact:newCNContact:)); - -+ (nullable NSData *)avatarDataForCNContact:(nullable CNContact *)cnContact; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Contact.m b/SignalUtilitiesKit/Contact.m deleted file mode 100644 index c16a43c85..000000000 --- a/SignalUtilitiesKit/Contact.m +++ /dev/null @@ -1,434 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "Contact.h" -#import "OWSPrimaryStorage.h" -#import "PhoneNumber.h" -#import "SSKEnvironment.h" -#import "SignalRecipient.h" -#import "TSAccountManager.h" -#import -#import -#import - -@import Contacts; - -NS_ASSUME_NONNULL_BEGIN - -@interface Contact () - -@property (nonatomic, readonly) NSMutableDictionary *phoneNumberNameMap; -@property (nonatomic, readonly) NSUInteger imageHash; - -@end - -#pragma mark - - -@implementation Contact - -@synthesize comparableNameFirstLast = _comparableNameFirstLast; -@synthesize comparableNameLastFirst = _comparableNameLastFirst; - -#if TARGET_OS_IOS - -- (instancetype)initWithSystemContact:(CNContact *)cnContact -{ - self = [super init]; - if (!self) { - return self; - } - - _cnContactId = cnContact.identifier; - _firstName = cnContact.givenName.ows_stripped; - _lastName = cnContact.familyName.ows_stripped; - _fullName = [Contact formattedFullNameWithCNContact:cnContact]; - - NSMutableArray *phoneNumbers = [NSMutableArray new]; - NSMutableDictionary *phoneNumberNameMap = [NSMutableDictionary new]; - const NSUInteger kMaxPhoneNumbersConsidered = 50; - - NSArray *consideredPhoneNumbers; - if (cnContact.phoneNumbers.count <= kMaxPhoneNumbersConsidered) { - consideredPhoneNumbers = cnContact.phoneNumbers; - } else { - OWSLogInfo(@"For perf, only considering the first %lu phone numbers for contact with many numbers.", (unsigned long)kMaxPhoneNumbersConsidered); - consideredPhoneNumbers = [cnContact.phoneNumbers subarrayWithRange:NSMakeRange(0, kMaxPhoneNumbersConsidered)]; - } - for (CNLabeledValue *phoneNumberField in consideredPhoneNumbers) { - if ([phoneNumberField.value isKindOfClass:[CNPhoneNumber class]]) { - CNPhoneNumber *phoneNumber = (CNPhoneNumber *)phoneNumberField.value; - [phoneNumbers addObject:phoneNumber.stringValue]; - if ([phoneNumberField.label isEqualToString:CNLabelHome]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_HOME", @"Label for 'Home' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelWork]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_WORK", @"Label for 'Work' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberiPhone]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_IPHONE", @"Label for 'iPhone' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberMobile]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_MOBILE", @"Label for 'Mobile' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberMain]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_MAIN", @"Label for 'Main' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberHomeFax]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_HOME_FAX", @"Label for 'HomeFAX' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberWorkFax]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_WORK_FAX", @"Label for 'Work FAX' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberOtherFax]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_OTHER_FAX", @"Label for 'Other FAX' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberPager]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_PAGER", @"Label for 'Pager' phone numbers."); - } else if ([phoneNumberField.label isEqualToString:CNLabelOther]) { - phoneNumberNameMap[phoneNumber.stringValue] - = NSLocalizedString(@"PHONE_NUMBER_TYPE_OTHER", @"Label for 'Other' phone numbers."); - } else if (phoneNumberField.label.length > 0 && ![phoneNumberField.label hasPrefix:@"_$"]) { - // We'll reach this case for: - // - // * User-defined custom labels, which we want to display. - // * Labels like "_$!!$_", which I'm guessing are synced from other platforms. - // We don't want to display these labels. Even some of iOS' default labels (like Radio) show - // up this way. - phoneNumberNameMap[phoneNumber.stringValue] = phoneNumberField.label; - } - } - } - - _userTextPhoneNumbers = [phoneNumbers copy]; - _phoneNumberNameMap = [NSMutableDictionary new]; - _parsedPhoneNumbers = - [self parsedPhoneNumbersFromUserTextPhoneNumbers:phoneNumbers phoneNumberNameMap:phoneNumberNameMap]; - - NSMutableArray *emailAddresses = [NSMutableArray new]; - for (CNLabeledValue *emailField in cnContact.emailAddresses) { - if ([emailField.value isKindOfClass:[NSString class]]) { - [emailAddresses addObject:(NSString *)emailField.value]; - } - } - _emails = [emailAddresses copy]; - - NSData *_Nullable avatarData = [Contact avatarDataForCNContact:cnContact]; - if (avatarData) { - NSUInteger hashValue = 0; - NSData *_Nullable hashData = [Cryptography computeSHA256Digest:avatarData truncatedToBytes:sizeof(hashValue)]; - if (!hashData) { - OWSFailDebug(@"could not compute hash for avatar."); - } - [hashData getBytes:&hashValue length:sizeof(hashValue)]; - _imageHash = hashValue; - } else { - _imageHash = 0; - } - - return self; -} - -- (NSString *)uniqueId -{ - return self.cnContactId; -} - -+ (nullable Contact *)contactWithVCardData:(NSData *)data -{ - CNContact *_Nullable cnContact = [self cnContactWithVCardData:data]; - - if (!cnContact) { - OWSLogError(@"Could not parse vcard data."); - return nil; - } - - return [[self alloc] initWithSystemContact:cnContact]; -} - -#endif // TARGET_OS_IOS - -- (NSArray *)parsedPhoneNumbersFromUserTextPhoneNumbers:(NSArray *)userTextPhoneNumbers - phoneNumberNameMap:(nullable NSDictionary *) - phoneNumberNameMap -{ - OWSAssertDebug(self.phoneNumberNameMap); - - NSMutableDictionary *parsedPhoneNumberMap = [NSMutableDictionary new]; - NSMutableArray *parsedPhoneNumbers = [NSMutableArray new]; - for (NSString *phoneNumberString in userTextPhoneNumbers) { - for (PhoneNumber *phoneNumber in - [PhoneNumber tryParsePhoneNumbersFromsUserSpecifiedText:phoneNumberString - clientPhoneNumber:[TSAccountManager localNumber]]) { - [parsedPhoneNumbers addObject:phoneNumber]; - parsedPhoneNumberMap[phoneNumber.toE164] = phoneNumber; - NSString *phoneNumberName = phoneNumberNameMap[phoneNumberString]; - if (phoneNumberName) { - self.phoneNumberNameMap[phoneNumber.toE164] = phoneNumberName; - } - } - } - return [parsedPhoneNumbers sortedArrayUsingSelector:@selector(compare:)]; -} - -- (NSString *)comparableNameFirstLast { - if (_comparableNameFirstLast == nil) { - // Combine the two names with a tab separator, which has a lower ascii code than space, so that first names - // that contain a space ("Mary Jo\tCatlett") will sort after those that do not ("Mary\tOliver") - _comparableNameFirstLast = [self combineLeftName:_firstName withRightName:_lastName usingSeparator:@"\t"]; - } - - return _comparableNameFirstLast; -} - -- (NSString *)comparableNameLastFirst { - if (_comparableNameLastFirst == nil) { - // Combine the two names with a tab separator, which has a lower ascii code than space, so that last names - // that contain a space ("Van Der Beek\tJames") will sort after those that do not ("Van\tJames") - _comparableNameLastFirst = [self combineLeftName:_lastName withRightName:_firstName usingSeparator:@"\t"]; - } - - return _comparableNameLastFirst; -} - -- (NSString *)combineLeftName:(NSString *)leftName withRightName:(NSString *)rightName usingSeparator:(NSString *)separator { - const BOOL leftNameNonEmpty = (leftName.length > 0); - const BOOL rightNameNonEmpty = (rightName.length > 0); - - if (leftNameNonEmpty && rightNameNonEmpty) { - return [NSString stringWithFormat:@"%@%@%@", leftName, separator, rightName]; - } else if (leftNameNonEmpty) { - return [leftName copy]; - } else if (rightNameNonEmpty) { - return [rightName copy]; - } else { - return @""; - } -} - -- (NSString *)description { - return [NSString stringWithFormat:@"%@: %@", self.fullName, self.userTextPhoneNumbers]; -} - -- (BOOL)isSignalContact { - NSArray *identifiers = [self textSecureIdentifiers]; - - return [identifiers count] > 0; -} - -- (NSArray *)signalRecipientsWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - __block NSMutableArray *result = [NSMutableArray array]; - - for (PhoneNumber *number in [self.parsedPhoneNumbers sortedArrayUsingSelector:@selector(compare:)]) { - SignalRecipient *_Nullable signalRecipient = [SignalRecipient registeredRecipientForRecipientId:number.toE164 - mustHaveDevices:YES - transaction:transaction]; - if (signalRecipient) { - [result addObject:signalRecipient]; - } - } - - return [result copy]; -} - -- (NSArray *)textSecureIdentifiers { - __block NSMutableArray *identifiers = [NSMutableArray array]; - - [OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - for (PhoneNumber *number in self.parsedPhoneNumbers) { - if ([SignalRecipient isRegisteredRecipient:number.toE164 transaction:transaction]) { - [identifiers addObject:number.toE164]; - } - } - }]; - return [identifiers copy]; -} - -+ (NSComparator)comparatorSortingNamesByFirstThenLast:(BOOL)firstNameOrdering { - return ^NSComparisonResult(id obj1, id obj2) { - Contact *contact1 = (Contact *)obj1; - Contact *contact2 = (Contact *)obj2; - - if (firstNameOrdering) { - return [contact1.comparableNameFirstLast caseInsensitiveCompare:contact2.comparableNameFirstLast]; - } else { - return [contact1.comparableNameLastFirst caseInsensitiveCompare:contact2.comparableNameLastFirst]; - } - }; -} - -+ (NSString *)formattedFullNameWithCNContact:(CNContact *)cnContact -{ - return [CNContactFormatter stringFromContact:cnContact style:CNContactFormatterStyleFullName].ows_stripped; -} - -- (NSString *)nameForPhoneNumber:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug([self.textSecureIdentifiers containsObject:recipientId]); - - NSString *value = self.phoneNumberNameMap[recipientId]; - OWSAssertDebug(value); - if (!value) { - return NSLocalizedString(@"PHONE_NUMBER_TYPE_UNKNOWN", - @"Label used when we don't what kind of phone number it is (e.g. mobile/work/home)."); - } - return value; -} - -+ (nullable NSData *)avatarDataForCNContact:(nullable CNContact *)cnContact -{ - if (cnContact.thumbnailImageData) { - return cnContact.thumbnailImageData.copy; - } else if (cnContact.imageData) { - // This only occurs when sharing a contact via the share extension - return cnContact.imageData.copy; - } else { - return nil; - } -} - -// This method is used to de-bounce system contact fetch notifications -// by checking for changes in the contact data. -- (NSUInteger)hash -{ - // base hash is some arbitrary number - NSUInteger hash = 1825038313; - - hash = hash ^ self.fullName.hash; - - hash = hash ^ self.imageHash; - - for (PhoneNumber *phoneNumber in self.parsedPhoneNumbers) { - hash = hash ^ phoneNumber.toE164.hash; - } - - for (NSString *email in self.emails) { - hash = hash ^ email.hash; - } - - return hash; -} - -#pragma mark - CNContactConverters - -+ (nullable CNContact *)cnContactWithVCardData:(NSData *)data -{ - OWSAssertDebug(data); - - NSError *error; - NSArray *_Nullable contacts = [CNContactVCardSerialization contactsWithData:data error:&error]; - if (!contacts || error) { - OWSFailDebug(@"could not parse vcard: %@", error); - return nil; - } - if (contacts.count < 1) { - OWSFailDebug(@"empty vcard: %@", error); - return nil; - } - if (contacts.count > 1) { - OWSFailDebug(@"more than one contact in vcard: %@", error); - } - return contacts.firstObject; -} - -+ (CNContact *)mergeCNContact:(CNContact *)oldCNContact newCNContact:(CNContact *)newCNContact -{ - OWSAssertDebug(oldCNContact); - OWSAssertDebug(newCNContact); - - Contact *oldContact = [[Contact alloc] initWithSystemContact:oldCNContact]; - - CNMutableContact *_Nullable mergedCNContact = [oldCNContact mutableCopy]; - if (!mergedCNContact) { - OWSFailDebug(@"mergedCNContact was unexpectedly nil"); - return [CNContact new]; - } - - // Name - NSString *formattedFullName = [self.class formattedFullNameWithCNContact:mergedCNContact]; - - // merged all or nothing - do not try to piece-meal merge. - if (formattedFullName.length == 0) { - mergedCNContact.namePrefix = newCNContact.namePrefix.ows_stripped; - mergedCNContact.givenName = newCNContact.givenName.ows_stripped; - mergedCNContact.middleName = newCNContact.middleName.ows_stripped; - mergedCNContact.familyName = newCNContact.familyName.ows_stripped; - mergedCNContact.nameSuffix = newCNContact.nameSuffix.ows_stripped; - } - - if (mergedCNContact.organizationName.ows_stripped.length < 1) { - mergedCNContact.organizationName = newCNContact.organizationName.ows_stripped; - } - - // Phone Numbers - NSSet *existingParsedPhoneNumberSet = [NSSet setWithArray:oldContact.parsedPhoneNumbers]; - NSSet *existingUnparsedPhoneNumberSet = [NSSet setWithArray:oldContact.userTextPhoneNumbers]; - - NSMutableArray *> *mergedPhoneNumbers = [mergedCNContact.phoneNumbers mutableCopy]; - for (CNLabeledValue *labeledPhoneNumber in newCNContact.phoneNumbers) { - NSString *_Nullable unparsedPhoneNumber = labeledPhoneNumber.value.stringValue; - if ([existingUnparsedPhoneNumberSet containsObject:unparsedPhoneNumber]) { - // Skip phone number if "unparsed" form is a duplicate. - continue; - } - PhoneNumber *_Nullable parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:labeledPhoneNumber.value.stringValue]; - if (parsedPhoneNumber && [existingParsedPhoneNumberSet containsObject:parsedPhoneNumber]) { - // Skip phone number if "parsed" form is a duplicate. - continue; - } - [mergedPhoneNumbers addObject:labeledPhoneNumber]; - } - mergedCNContact.phoneNumbers = mergedPhoneNumbers; - - // Emails - NSSet *existingEmailSet = [NSSet setWithArray:oldContact.emails]; - NSMutableArray *> *mergedEmailAddresses = [mergedCNContact.emailAddresses mutableCopy]; - for (CNLabeledValue *labeledEmail in newCNContact.emailAddresses) { - NSString *normalizedValue = labeledEmail.value.ows_stripped; - if (![existingEmailSet containsObject:normalizedValue]) { - [mergedEmailAddresses addObject:labeledEmail]; - } - } - mergedCNContact.emailAddresses = mergedEmailAddresses; - - // Address - // merged all or nothing - do not try to piece-meal merge. - if (mergedCNContact.postalAddresses.count == 0) { - mergedCNContact.postalAddresses = newCNContact.postalAddresses; - } - - // Avatar - if (!mergedCNContact.imageData) { - mergedCNContact.imageData = newCNContact.imageData; - } - - return [mergedCNContact copy]; -} - -+ (nullable NSString *)localizedStringForCNLabel:(nullable NSString *)cnLabel -{ - if (cnLabel.length == 0) { - return nil; - } - - NSString *_Nullable localizedLabel = [CNLabeledValue localizedStringForLabel:cnLabel]; - - // Docs for localizedStringForLabel say it returns: - // > The localized string if a Contacts framework defined label, otherwise just returns the label. - // But in practice, at least on iOS11, if the label is not one of CNContacts known labels (like CNLabelHome) - // kUnlocalizedStringLabel is returned, rather than the unadultered label. - NSString *const kUnlocalizedStringLabel = @"__ABUNLOCALIZEDSTRING"; - - if ([localizedLabel isEqual:kUnlocalizedStringLabel]) { - return cnLabel; - } - - return localizedLabel; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ContactDiscoveryService.h b/SignalUtilitiesKit/ContactDiscoveryService.h deleted file mode 100644 index da414fbfd..000000000 --- a/SignalUtilitiesKit/ContactDiscoveryService.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern NSErrorUserInfoKey const ContactDiscoveryServiceErrorKey_Reason; -extern NSErrorDomain const ContactDiscoveryServiceErrorDomain; -typedef NS_ERROR_ENUM(ContactDiscoveryServiceErrorDomain, ContactDiscoveryServiceError){ - ContactDiscoveryServiceErrorAttestationFailed = 100, ContactDiscoveryServiceErrorAssertionError = 101 -}; - -@class ECKeyPair; -@class OWSAES256Key; - -@interface RemoteAttestationAuth : NSObject - -@property (nonatomic, readonly) NSString *username; -@property (nonatomic, readonly) NSString *password; - -@end - -#pragma mark - - -@interface RemoteAttestationKeys : NSObject - -@property (nonatomic, readonly) ECKeyPair *keyPair; -@property (nonatomic, readonly) NSData *serverEphemeralPublic; -@property (nonatomic, readonly) NSData *serverStaticPublic; - -@property (nonatomic, readonly) OWSAES256Key *clientKey; -@property (nonatomic, readonly) OWSAES256Key *serverKey; - -@end - -#pragma mark - - -@interface RemoteAttestation : NSObject - -@property (nonatomic, readonly) RemoteAttestationKeys *keys; -@property (nonatomic, readonly) NSArray *cookies; -@property (nonatomic, readonly) NSData *requestId; -@property (nonatomic, readonly) NSString *enclaveId; -@property (nonatomic, readonly) RemoteAttestationAuth *auth; - -@end - -#pragma mark - - -@interface ContactDiscoveryService : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initDefault NS_DESIGNATED_INITIALIZER; - -+ (instancetype)shared; - -- (void)testService; -- (void)performRemoteAttestationWithSuccess:(void (^)(RemoteAttestation *_Nonnull remoteAttestation))successHandler - failure:(void (^)(NSError *_Nonnull error))failureHandler; -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ContactDiscoveryService.m b/SignalUtilitiesKit/ContactDiscoveryService.m deleted file mode 100644 index 4b51a5980..000000000 --- a/SignalUtilitiesKit/ContactDiscoveryService.m +++ /dev/null @@ -1,774 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "ContactDiscoveryService.h" -#import "CDSQuote.h" -#import "CDSSigningCertificate.h" -#import "NSError+MessageSending.h" -#import "OWSError.h" -#import "OWSRequestFactory.h" -#import "SSKEnvironment.h" -#import "TSNetworkManager.h" -#import -#import -#import "SSKAsserts.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -NSErrorUserInfoKey const ContactDiscoveryServiceErrorKey_Reason = @"ContactDiscoveryServiceErrorKey_Reason"; -NSErrorDomain const ContactDiscoveryServiceErrorDomain = @"SignalServiceKit.ContactDiscoveryService"; - -NSError *ContactDiscoveryServiceErrorMakeWithReason(NSInteger code, NSString *reason) -{ - OWSCFailDebug(@"Error: %@", reason); - - return [NSError errorWithDomain:ContactDiscoveryServiceErrorDomain - code:code - userInfo:@{ ContactDiscoveryServiceErrorKey_Reason : reason }]; -} - -@interface RemoteAttestationAuth () - -@property (nonatomic) NSString *username; -@property (nonatomic) NSString *password; - -@end - -#pragma mark - - -@implementation RemoteAttestationAuth - -@end - -#pragma mark - - -@interface RemoteAttestationKeys () - -@property (nonatomic) ECKeyPair *keyPair; -@property (nonatomic) NSData *serverEphemeralPublic; -@property (nonatomic) NSData *serverStaticPublic; - -@property (nonatomic) OWSAES256Key *clientKey; -@property (nonatomic) OWSAES256Key *serverKey; - -@end - -#pragma mark - - -@implementation RemoteAttestationKeys - -+ (nullable RemoteAttestationKeys *)keysForKeyPair:(ECKeyPair *)keyPair - serverEphemeralPublic:(NSData *)serverEphemeralPublic - serverStaticPublic:(NSData *)serverStaticPublic - error:(NSError **)error -{ - if (!keyPair) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"Missing keyPair"); - return nil; - } - if (serverEphemeralPublic.length < 1) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"Invalid serverEphemeralPublic"); - return nil; - } - if (serverStaticPublic.length < 1) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"Invalid serverStaticPublic"); - return nil; - } - RemoteAttestationKeys *keys = [RemoteAttestationKeys new]; - keys.keyPair = keyPair; - keys.serverEphemeralPublic = serverEphemeralPublic; - keys.serverStaticPublic = serverStaticPublic; - if (![keys deriveKeys]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"failed to derive keys"); - return nil; - } - return keys; -} - -// Returns YES on success. -- (BOOL)deriveKeys -{ - NSData *ephemeralToEphemeral; - NSData *ephemeralToStatic; - @try { - ephemeralToEphemeral = - [Curve25519 throws_generateSharedSecretFromPublicKey:self.serverEphemeralPublic privateKey:self.keyPair.privateKey]; - ephemeralToStatic = - [Curve25519 throws_generateSharedSecretFromPublicKey:self.serverStaticPublic privateKey:self.keyPair.privateKey]; - } @catch (NSException *exception) { - OWSFailDebug(@"could not generate shared secrets: %@", exception); - return NO; - } - - NSData *masterSecret = [ephemeralToEphemeral dataByAppendingData:ephemeralToStatic]; - NSData *publicKeys = [NSData join:@[ - self.keyPair.publicKey, - self.serverEphemeralPublic, - self.serverStaticPublic, - ]]; - - NSData *_Nullable derivedMaterial; - @try { - derivedMaterial = - [HKDFKit deriveKey:masterSecret info:nil salt:publicKeys outputSize:(int)kAES256_KeyByteLength * 2]; - } @catch (NSException *exception) { - OWSFailDebug(@"could not derive service key: %@", exception); - return NO; - } - - if (!derivedMaterial) { - OWSFailDebug(@"missing derived service key."); - return NO; - } - if (derivedMaterial.length != kAES256_KeyByteLength * 2) { - OWSFailDebug(@"derived service key has unexpected length."); - return NO; - } - - NSData *_Nullable clientKeyData = - [derivedMaterial subdataWithRange:NSMakeRange(kAES256_KeyByteLength * 0, kAES256_KeyByteLength)]; - OWSAES256Key *_Nullable clientKey = [OWSAES256Key keyWithData:clientKeyData]; - if (!clientKey) { - OWSFailDebug(@"clientKey has unexpected length."); - return NO; - } - - NSData *_Nullable serverKeyData = - [derivedMaterial subdataWithRange:NSMakeRange(kAES256_KeyByteLength * 1, kAES256_KeyByteLength)]; - OWSAES256Key *_Nullable serverKey = [OWSAES256Key keyWithData:serverKeyData]; - if (!serverKey) { - OWSFailDebug(@"serverKey has unexpected length."); - return NO; - } - - self.clientKey = clientKey; - self.serverKey = serverKey; - - return YES; -} - -@end - -#pragma mark - - -@interface RemoteAttestation () - -@property (nonatomic) RemoteAttestationKeys *keys; -@property (nonatomic) NSArray *cookies; -@property (nonatomic) NSData *requestId; -@property (nonatomic) NSString *enclaveId; -@property (nonatomic) RemoteAttestationAuth *auth; - -@end - -#pragma mark - - -@implementation RemoteAttestation - -@end - -#pragma mark - - -@interface SignatureBodyEntity : NSObject - -@property (nonatomic) NSData *isvEnclaveQuoteBody; -@property (nonatomic) NSString *isvEnclaveQuoteStatus; -@property (nonatomic) NSString *timestamp; -@property (nonatomic) NSNumber *version; - -@end - -#pragma mark - - -@implementation SignatureBodyEntity - -@end - -#pragma mark - - -@interface NSDictionary (CDS) - -@end - -#pragma mark - - -@implementation NSDictionary (CDS) - -- (nullable NSString *)stringForKey:(NSString *)key -{ - NSString *_Nullable valueString = self[key]; - if (![valueString isKindOfClass:[NSString class]]) { - OWSFailDebug(@"couldn't parse string for key: %@", key); - return nil; - } - return valueString; -} - -- (nullable NSNumber *)numberForKey:(NSString *)key -{ - NSNumber *_Nullable value = self[key]; - if (![value isKindOfClass:[NSNumber class]]) { - OWSFailDebug(@"couldn't parse number for key: %@", key); - return nil; - } - return value; -} - -- (nullable NSData *)base64DataForKey:(NSString *)key -{ - NSString *_Nullable valueString = self[key]; - if (![valueString isKindOfClass:[NSString class]]) { - OWSFailDebug(@"couldn't parse base 64 value for key: %@", key); - return nil; - } - NSData *_Nullable valueData = [[NSData alloc] initWithBase64EncodedString:valueString options:0]; - if (!valueData) { - OWSFailDebug(@"couldn't decode base 64 value for key: %@", key); - return nil; - } - return valueData; -} - -- (nullable NSData *)base64DataForKey:(NSString *)key expectedLength:(NSUInteger)expectedLength -{ - NSData *_Nullable valueData = [self base64DataForKey:key]; - if (valueData && valueData.length != expectedLength) { - OWSLogDebug(@"decoded base 64 value for key: %@, has unexpected length: %lu != %lu", - key, - (unsigned long)valueData.length, - (unsigned long)expectedLength); - OWSFailDebug(@"decoded base 64 value for key has unexpected length: %lu != %lu", - (unsigned long)valueData.length, - (unsigned long)expectedLength); - return nil; - } - return valueData; -} - -@end - -#pragma mark - - -@implementation ContactDiscoveryService - -+ (instancetype)shared -{ - OWSAssertDebug(SSKEnvironment.shared.contactDiscoveryService); - - return SSKEnvironment.shared.contactDiscoveryService; -} - -- (instancetype)initDefault -{ - self = [super init]; - if (!self) { - return self; - } - - OWSSingletonAssert(); - - return self; -} - -- (void)testService -{ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self - performRemoteAttestationWithSuccess:^(RemoteAttestation *remoteAttestation) { - OWSLogDebug(@"succeeded"); - } - failure:^(NSError *error) { - OWSLogDebug(@"failed with error: %@", error); - }]; - }); -} - -- (void)performRemoteAttestationWithSuccess:(void (^)(RemoteAttestation *remoteAttestation))successHandler - failure:(void (^)(NSError *error))failureHandler -{ - [self - getRemoteAttestationAuthWithSuccess:^(RemoteAttestationAuth *auth) { - [self performRemoteAttestationWithAuth:auth success:successHandler failure:failureHandler]; - } - failure:failureHandler]; -} - -- (void)getRemoteAttestationAuthWithSuccess:(void (^)(RemoteAttestationAuth *))successHandler - failure:(void (^)(NSError *error))failureHandler -{ - TSRequest *request = [OWSRequestFactory remoteAttestationAuthRequest]; - [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseDict) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - RemoteAttestationAuth *_Nullable auth = [self parseAuthParams:responseDict]; - if (!auth) { - OWSLogError(@"remote attestation auth could not be parsed: %@", responseDict); - NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); - failureHandler(error); - return; - } - - successHandler(auth); - }); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; - OWSLogVerbose(@"remote attestation auth failure: %lu", (unsigned long)response.statusCode); - failureHandler(error); - }]; -} - -- (nullable RemoteAttestationAuth *)parseAuthParams:(id)response -{ - if (![response isKindOfClass:[NSDictionary class]]) { - return nil; - } - - NSDictionary *responseDict = response; - NSString *_Nullable password = [responseDict stringForKey:@"password"]; - if (password.length < 1) { - OWSFailDebug(@"missing or empty password."); - return nil; - } - - NSString *_Nullable username = [responseDict stringForKey:@"username"]; - if (username.length < 1) { - OWSFailDebug(@"missing or empty username."); - return nil; - } - - RemoteAttestationAuth *result = [RemoteAttestationAuth new]; - result.username = username; - result.password = password; - return result; -} - -- (void)performRemoteAttestationWithAuth:(RemoteAttestationAuth *)auth - success:(void (^)(RemoteAttestation *remoteAttestation))successHandler - failure:(void (^)(NSError *error))failureHandler -{ - return; // Loki: Do nothing - - ECKeyPair *keyPair = [Curve25519 generateKeyPair]; - - NSString *enclaveId = @"cd6cfc342937b23b1bdd3bbf9721aa5615ac9ff50a75c5527d441cd3276826c9"; - - TSRequest *request = [OWSRequestFactory remoteAttestationRequest:keyPair - enclaveId:enclaveId - authUsername:auth.username - authPassword:auth.password]; - - [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseJson) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSError *_Nullable error; - RemoteAttestation *_Nullable attestation = [self parseAttestationResponseJson:responseJson - response:task.response - keyPair:keyPair - enclaveId:enclaveId - auth:auth - error:&error]; - - if (!attestation) { - if (!error) { - OWSFailDebug(@"error was unexpectedly nil"); - error = ContactDiscoveryServiceErrorMakeWithReason(ContactDiscoveryServiceErrorAssertionError, - @"failure when parsing attestation - no reason given"); - } else { - OWSFailDebug(@"error with attestation: %@", error); - } - error.isRetryable = NO; - failureHandler(error); - return; - } - - successHandler(attestation); - }); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - failureHandler(error); - }]; -} - -- (nullable RemoteAttestation *)parseAttestationResponseJson:(id)responseJson - response:(NSURLResponse *)response - keyPair:(ECKeyPair *)keyPair - enclaveId:(NSString *)enclaveId - auth:(RemoteAttestationAuth *)auth - error:(NSError **)error -{ - OWSAssertDebug(responseJson); - OWSAssertDebug(response); - OWSAssertDebug(keyPair); - OWSAssertDebug(enclaveId.length > 0); - - if (![response isKindOfClass:[NSHTTPURLResponse class]]) { - *error = ContactDiscoveryServiceErrorMakeWithReason(ContactDiscoveryServiceErrorAssertionError, @"unexpected response type."); - return nil; - } - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - NSArray *cookies = - [NSHTTPCookie cookiesWithResponseHeaderFields:httpResponse.allHeaderFields forURL:httpResponse.URL]; - if (cookies.count < 1) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse cookie."); - return nil; - } - - if (![responseJson isKindOfClass:[NSDictionary class]]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"invalid json response"); - return nil; - } - NSDictionary *responseDict = responseJson; - NSData *_Nullable serverEphemeralPublic = - [responseDict base64DataForKey:@"serverEphemeralPublic" expectedLength:32]; - if (!serverEphemeralPublic) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse serverEphemeralPublic."); - return nil; - } - NSData *_Nullable serverStaticPublic = [responseDict base64DataForKey:@"serverStaticPublic" expectedLength:32]; - if (!serverStaticPublic) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse serverStaticPublic."); - return nil; - } - NSData *_Nullable encryptedRequestId = [responseDict base64DataForKey:@"ciphertext"]; - if (!encryptedRequestId) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse encryptedRequestId."); - return nil; - } - NSData *_Nullable encryptedRequestIv = [responseDict base64DataForKey:@"iv" expectedLength:12]; - if (!encryptedRequestIv) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse encryptedRequestIv."); - return nil; - } - NSData *_Nullable encryptedRequestTag = [responseDict base64DataForKey:@"tag" expectedLength:16]; - if (!encryptedRequestTag) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse encryptedRequestTag."); - return nil; - } - NSData *_Nullable quoteData = [responseDict base64DataForKey:@"quote"]; - if (!quoteData) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse quote data."); - return nil; - } - NSString *_Nullable signatureBody = [responseDict stringForKey:@"signatureBody"]; - if (![signatureBody isKindOfClass:[NSString class]]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse signatureBody."); - return nil; - } - NSData *_Nullable signature = [responseDict base64DataForKey:@"signature"]; - if (!signature) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse signature."); - return nil; - } - NSString *_Nullable encodedCertificates = [responseDict stringForKey:@"certificates"]; - if (![encodedCertificates isKindOfClass:[NSString class]]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse encodedCertificates."); - return nil; - } - NSString *_Nullable certificates = [encodedCertificates stringByRemovingPercentEncoding]; - if (!certificates) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't parse certificates."); - return nil; - } - - RemoteAttestationKeys *_Nullable keys = [RemoteAttestationKeys keysForKeyPair:keyPair - serverEphemeralPublic:serverEphemeralPublic - serverStaticPublic:serverStaticPublic - error:error]; - if (!keys || *error != nil) { - if (*error == nil) { - OWSFailDebug(@"missing error specifics"); - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"Couldn't derive keys. No reason given"); - } - return nil; - } - - CDSQuote *_Nullable quote = [CDSQuote parseQuoteFromData:quoteData]; - if (!quote) { - OWSFailDebug(@"couldn't parse quote."); - return nil; - } - NSData *_Nullable requestId = [self decryptRequestId:encryptedRequestId - encryptedRequestIv:encryptedRequestIv - encryptedRequestTag:encryptedRequestTag - keys:keys]; - if (!requestId) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"couldn't decrypt request id."); - return nil; - } - - if (![self verifyServerQuote:quote keys:keys enclaveId:enclaveId]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAttestationFailed, @"couldn't verify quote."); - return nil; - } - - if (![self verifyIasSignatureWithCertificates:certificates - signatureBody:signatureBody - signature:signature - quoteData:quoteData - error:error]) { - - if (*error == nil) { - OWSFailDebug(@"missing error specifics"); - *error = ContactDiscoveryServiceErrorMakeWithReason(ContactDiscoveryServiceErrorAssertionError, - @"verifyIasSignatureWithCertificates failed. No reason given"); - } - return nil; - } - - RemoteAttestation *result = [RemoteAttestation new]; - result.cookies = cookies; - result.keys = keys; - result.requestId = requestId; - result.enclaveId = enclaveId; - result.auth = auth; - - OWSLogVerbose(@"remote attestation complete."); - - return result; -} - -- (BOOL)verifyIasSignatureWithCertificates:(NSString *)certificates - signatureBody:(NSString *)signatureBody - signature:(NSData *)signature - quoteData:(NSData *)quoteData - error:(NSError **)error -{ - OWSAssertDebug(certificates.length > 0); - OWSAssertDebug(signatureBody.length > 0); - OWSAssertDebug(signature.length > 0); - OWSAssertDebug(quoteData); - - NSError *signingError; - CDSSigningCertificate *_Nullable certificate = - [CDSSigningCertificate parseCertificateFromPem:certificates error:&signingError]; - if (signingError) { - *error = signingError; - return NO; - } - - if (!certificate) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"could not parse signing certificate."); - return NO; - } - if (![certificate verifySignatureOfBody:signatureBody signature:signature]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAttestationFailed, @"could not verify signature."); - return NO; - } - - SignatureBodyEntity *_Nullable signatureBodyEntity = [self parseSignatureBodyEntity:signatureBody]; - if (!signatureBodyEntity) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"could not parse signature body."); - return NO; - } - - // Compare the first N bytes of the quote data with the signed quote body. - const NSUInteger kQuoteBodyComparisonLength = 432; - if (signatureBodyEntity.isvEnclaveQuoteBody.length < kQuoteBodyComparisonLength) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"isvEnclaveQuoteBody has unexpected length."); - return NO; - } - // NOTE: This version is separate from and does _NOT_ match the CDS quote version. - const NSUInteger kSignatureBodyVersion = 3; - if (![signatureBodyEntity.version isEqual:@(kSignatureBodyVersion)]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"signatureBodyEntity has unexpected version."); - return NO; - } - if (quoteData.length < kQuoteBodyComparisonLength) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"quoteData has unexpected length."); - return NO; - } - NSData *isvEnclaveQuoteBodyForComparison = - [signatureBodyEntity.isvEnclaveQuoteBody subdataWithRange:NSMakeRange(0, kQuoteBodyComparisonLength)]; - NSData *quoteDataForComparison = [quoteData subdataWithRange:NSMakeRange(0, kQuoteBodyComparisonLength)]; - if (![isvEnclaveQuoteBodyForComparison ows_constantTimeIsEqualToData:quoteDataForComparison]) { - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAttestationFailed, @"isvEnclaveQuoteBody and quoteData do not match."); - return NO; - } - - if (![@"OK" isEqualToString:signatureBodyEntity.isvEnclaveQuoteStatus]) { - NSString *reason = - [NSString stringWithFormat:@"invalid isvEnclaveQuoteStatus: %@", signatureBodyEntity.isvEnclaveQuoteStatus]; - *error = ContactDiscoveryServiceErrorMakeWithReason(ContactDiscoveryServiceErrorAttestationFailed, reason); - return NO; - } - - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; - [dateFormatter setTimeZone:timeZone]; - [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSSSS"]; - - // Specify parsing locale - // from: https://developer.apple.com/library/archive/qa/qa1480/_index.html - // Q: I'm using NSDateFormatter to parse an Internet-style date, but this fails for some users in some regions. - // I've set a specific date format string; shouldn't that force NSDateFormatter to work independently of the user's - // region settings? A: No. While setting a date format string will appear to work for most users, it's not the right - // solution to this problem. There are many places where format strings behave in unexpected ways. [...] - NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; - [dateFormatter setLocale:enUSPOSIXLocale]; - NSDate *timestampDate = [dateFormatter dateFromString:signatureBodyEntity.timestamp]; - if (!timestampDate) { - OWSFailDebug(@"Could not parse signature body timestamp: %@", signatureBodyEntity.timestamp); - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAssertionError, @"could not parse signature body timestamp."); - return NO; - } - - // Only accept signatures from the last 24 hours. - NSDateComponents *dayComponent = [[NSDateComponents alloc] init]; - dayComponent.day = 1; - NSCalendar *calendar = [NSCalendar currentCalendar]; - NSDate *timestampDatePlus1Day = [calendar dateByAddingComponents:dayComponent toDate:timestampDate options:0]; - - NSDate *now = [NSDate new]; - BOOL isExpired = [now isAfterDate:timestampDatePlus1Day]; - - if (isExpired) { - OWSFailDebug(@"Signature is expired: %@", signatureBodyEntity.timestamp); - *error = ContactDiscoveryServiceErrorMakeWithReason( - ContactDiscoveryServiceErrorAttestationFailed, @"Signature is expired."); - return NO; - } - - return YES; -} - -- (nullable SignatureBodyEntity *)parseSignatureBodyEntity:(NSString *)signatureBody -{ - OWSAssertDebug(signatureBody.length > 0); - - NSError *error = nil; - NSDictionary *_Nullable jsonDict = - [NSJSONSerialization JSONObjectWithData:[signatureBody dataUsingEncoding:NSUTF8StringEncoding] - options:0 - error:&error]; - if (error || ![jsonDict isKindOfClass:[NSDictionary class]]) { - OWSFailDebug(@"could not parse signature body JSON: %@.", error); - return nil; - } - NSString *_Nullable timestamp = [jsonDict stringForKey:@"timestamp"]; - if (timestamp.length < 1) { - OWSFailDebug(@"could not parse signature timestamp."); - return nil; - } - NSData *_Nullable isvEnclaveQuoteBody = [jsonDict base64DataForKey:@"isvEnclaveQuoteBody"]; - if (isvEnclaveQuoteBody.length < 1) { - OWSFailDebug(@"could not parse signature isvEnclaveQuoteBody."); - return nil; - } - NSString *_Nullable isvEnclaveQuoteStatus = [jsonDict stringForKey:@"isvEnclaveQuoteStatus"]; - if (isvEnclaveQuoteStatus.length < 1) { - OWSFailDebug(@"could not parse signature isvEnclaveQuoteStatus."); - return nil; - } - NSNumber *_Nullable version = [jsonDict numberForKey:@"version"]; - if (!version) { - OWSFailDebug(@"could not parse signature version."); - return nil; - } - - SignatureBodyEntity *result = [SignatureBodyEntity new]; - result.isvEnclaveQuoteBody = isvEnclaveQuoteBody; - result.isvEnclaveQuoteStatus = isvEnclaveQuoteStatus; - result.timestamp = timestamp; - result.version = version; - return result; -} - -- (BOOL)verifyServerQuote:(CDSQuote *)quote keys:(RemoteAttestationKeys *)keys enclaveId:(NSString *)enclaveId -{ - OWSAssertDebug(quote); - OWSAssertDebug(keys); - OWSAssertDebug(enclaveId.length > 0); - - if (quote.reportData.length < keys.serverStaticPublic.length) { - OWSFailDebug(@"reportData has unexpected length: %lu != %lu.", - (unsigned long)quote.reportData.length, - (unsigned long)keys.serverStaticPublic.length); - return NO; - } - - NSData *_Nullable theirServerPublicStatic = - [quote.reportData subdataWithRange:NSMakeRange(0, keys.serverStaticPublic.length)]; - if (theirServerPublicStatic.length != keys.serverStaticPublic.length) { - OWSFailDebug(@"could not extract server public static."); - return NO; - } - if (![keys.serverStaticPublic ows_constantTimeIsEqualToData:theirServerPublicStatic]) { - OWSFailDebug(@"server public statics do not match."); - return NO; - } - // It's easier to compare as hex data than parsing hexadecimal. - NSData *_Nullable ourEnclaveIdHexData = [enclaveId dataUsingEncoding:NSUTF8StringEncoding]; - NSData *_Nullable theirEnclaveIdHexData = - [quote.mrenclave.hexadecimalString dataUsingEncoding:NSUTF8StringEncoding]; - if (!ourEnclaveIdHexData || !theirEnclaveIdHexData - || ![ourEnclaveIdHexData ows_constantTimeIsEqualToData:theirEnclaveIdHexData]) { - OWSFailDebug(@"enclave ids do not match."); - return NO; - } - if (quote.isDebugQuote) { - OWSFailDebug(@"quote has invalid isDebugQuote value."); - return NO; - } - return YES; -} - -- (nullable NSData *)decryptRequestId:(NSData *)encryptedRequestId - encryptedRequestIv:(NSData *)encryptedRequestIv - encryptedRequestTag:(NSData *)encryptedRequestTag - keys:(RemoteAttestationKeys *)keys -{ - OWSAssertDebug(encryptedRequestId.length > 0); - OWSAssertDebug(encryptedRequestIv.length > 0); - OWSAssertDebug(encryptedRequestTag.length > 0); - OWSAssertDebug(keys); - - OWSAES256Key *_Nullable key = keys.serverKey; - if (!key) { - OWSFailDebug(@"invalid server key."); - return nil; - } - NSData *_Nullable decryptedData = [Cryptography decryptAESGCMWithInitializationVector:encryptedRequestIv - ciphertext:encryptedRequestId - additionalAuthenticatedData:nil - authTag:encryptedRequestTag - key:key]; - if (!decryptedData) { - OWSFailDebug(@"couldn't decrypt request id."); - return nil; - } - return decryptedData; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ContactFieldView.swift b/SignalUtilitiesKit/ContactFieldView.swift deleted file mode 100644 index 064565303..000000000 --- a/SignalUtilitiesKit/ContactFieldView.swift +++ /dev/null @@ -1,205 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -public class ContactFieldView: UIView { - - @available(*, unavailable, message: "use other constructor instead.") - public required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - public required init(rows: [UIView], hMargin: CGFloat) { - super.init(frame: CGRect.zero) - - self.layoutMargins = .zero - self.preservesSuperviewLayoutMargins = false - - addRows(rows: rows, hMargin: hMargin) - } - - private func addRows(rows: [UIView], hMargin: CGFloat) { - - var lastRow: UIView? - - let addSpacerRow = { - guard let prevRow = lastRow else { - owsFailDebug("missing last row") - return - } - let row = UIView() - row.backgroundColor = Theme.hairlineColor - self.addSubview(row) - row.autoSetDimension(.height, toSize: CGHairlineWidth()) - row.autoPinLeadingToSuperviewMargin(withInset: hMargin) - row.autoPinTrailingToSuperviewMargin() - row.autoPinEdge(.top, to: .bottom, of: prevRow, withOffset: 0) - lastRow = row - } - - let addRow: ((UIView) -> Void) = { (row) in - if lastRow != nil { - addSpacerRow() - } - self.addSubview(row) - row.autoPinLeadingToSuperviewMargin() - row.autoPinTrailingToSuperviewMargin() - if let lastRow = lastRow { - row.autoPinEdge(.top, to: .bottom, of: lastRow, withOffset: 0) - } else { - row.autoPinEdge(toSuperviewEdge: .top, withInset: 0) - } - lastRow = row - } - - for row in rows { - addRow(row) - } - - lastRow?.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0) - } - - public class func contactFieldView(forAvatarImage avatarImage: UIImage, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView { - var stackView: UIStackView - if let actionBlock = actionBlock { - stackView = TappableStackView(actionBlock: actionBlock) - } else { - stackView = UIStackView() - } - stackView.axis = .vertical - stackView.alignment = .leading - stackView.spacing = 3 - stackView.layoutMargins = layoutMargins - stackView.isLayoutMarginsRelativeArrangement = true - - let avatarView = AvatarImageView() - avatarView.image = avatarImage - let avatarSize = CGFloat(50) - avatarView.autoSetDimension(.width, toSize: avatarSize) - avatarView.autoSetDimension(.height, toSize: avatarSize) - avatarView.setCompressionResistanceHigh() - avatarView.setContentHuggingHigh() - stackView.addArrangedSubview(avatarView) - - return stackView - } - - public class func contactFieldView(forOrganizationName organizationName: String, layoutMargins: UIEdgeInsets) -> UIView { - return simpleFieldView(name: NSLocalizedString("CONTACT_FIELD_ORGANIZATION", - comment: "Label for the 'organization' field of a contact."), - value: organizationName, - layoutMargins: layoutMargins, actionBlock: nil) - } - - public class func contactFieldView(forPhoneNumber phoneNumber: OWSContactPhoneNumber, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView { - let formattedPhoneNumber = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber.phoneNumber) - return simpleFieldView(name: phoneNumber.localizedLabel(), value: formattedPhoneNumber, layoutMargins: layoutMargins, actionBlock: actionBlock) - } - - public class func contactFieldView(forEmail email: OWSContactEmail, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView { - return simpleFieldView(name: email.localizedLabel(), value: email.email, layoutMargins: layoutMargins, actionBlock: actionBlock) - } - - private class func simpleFieldView(name: String, value: String?, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView { - var stackView: UIStackView - if let actionBlock = actionBlock { - stackView = TappableStackView(actionBlock: actionBlock) - } else { - stackView = UIStackView() - } - stackView.axis = .vertical - stackView.alignment = .leading - stackView.spacing = 3 - stackView.layoutMargins = layoutMargins - stackView.isLayoutMarginsRelativeArrangement = true - - let nameLabel = UILabel() - nameLabel.text = name.lowercased() - nameLabel.font = UIFont.ows_dynamicTypeSubheadline - nameLabel.textColor = Theme.secondaryColor - nameLabel.lineBreakMode = .byTruncatingTail - stackView.addArrangedSubview(nameLabel) - - let valueLabel = UILabel() - valueLabel.text = value - valueLabel.font = UIFont.ows_dynamicTypeBody - valueLabel.textColor = Theme.primaryColor - valueLabel.lineBreakMode = .byTruncatingTail - stackView.addArrangedSubview(valueLabel) - - return stackView - } - - public class func contactFieldView(forAddress address: OWSContactAddress, layoutMargins: UIEdgeInsets, actionBlock : (() -> Void)?) -> UIView { - var stackView: UIStackView - if let actionBlock = actionBlock { - stackView = TappableStackView(actionBlock: actionBlock) - } else { - stackView = UIStackView() - } - stackView.axis = .vertical - stackView.alignment = .leading - stackView.spacing = 3 - stackView.layoutMargins = layoutMargins - stackView.isLayoutMarginsRelativeArrangement = true - - let nameLabel = UILabel() - nameLabel.text = address.localizedLabel() - nameLabel.font = UIFont.ows_dynamicTypeSubheadline - nameLabel.textColor = Theme.secondaryColor - nameLabel.lineBreakMode = .byTruncatingTail - stackView.addArrangedSubview(nameLabel) - - let tryToAddNameValue: ((String, String?) -> Void) = { (propertyName, propertyValue) in - guard let propertyValue = propertyValue else { - return - } - guard propertyValue.count > 0 else { - return - } - - let row = UIStackView() - row.axis = .horizontal - row.alignment = .leading - row.spacing = 10 - row.layoutMargins = .zero - - let nameLabel = UILabel() - nameLabel.text = propertyName - nameLabel.font = UIFont.ows_dynamicTypeBody - nameLabel.textColor = Theme.secondaryColor - nameLabel.lineBreakMode = .byTruncatingTail - row.addArrangedSubview(nameLabel) - nameLabel.setContentHuggingHigh() - nameLabel.setCompressionResistanceHigh() - - let valueLabel = UILabel() - valueLabel.text = propertyValue - valueLabel.font = UIFont.ows_dynamicTypeBody - valueLabel.textColor = Theme.primaryColor - valueLabel.lineBreakMode = .byTruncatingTail - row.addArrangedSubview(valueLabel) - - stackView.addArrangedSubview(row) - } - - tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_STREET", comment: "Label for the 'street' field of a contact's address."), - address.street) - tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POBOX", comment: "Label for the 'pobox' field of a contact's address."), - address.pobox) - tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_NEIGHBORHOOD", comment: "Label for the 'neighborhood' field of a contact's address."), - address.neighborhood) - tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_CITY", comment: "Label for the 'city' field of a contact's address."), - address.city) - tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_REGION", comment: "Label for the 'region' field of a contact's address."), - address.region) - tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_POSTCODE", comment: "Label for the 'postcode' field of a contact's address."), - address.postcode) - tryToAddNameValue(NSLocalizedString("CONTACT_FIELD_ADDRESS_COUNTRY", comment: "Label for the 'country' field of a contact's address."), - address.country) - - return stackView - } -} diff --git a/SignalUtilitiesKit/ContactParser.swift b/SignalUtilitiesKit/ContactParser.swift deleted file mode 100644 index 035bb580f..000000000 --- a/SignalUtilitiesKit/ContactParser.swift +++ /dev/null @@ -1,28 +0,0 @@ - -public final class ContactParser { - private let data: Data - - public init(data: Data) { - self.data = data - } - - public func parse() -> [(publicKey: String, isBlocked: Bool)] { - var index = 0 - var result: [(String, Bool)] = [] - while index < data.endIndex { - var uncheckedSize: UInt32? = try? data[index..<(index+4)].withUnsafeBytes { $0.pointee } - if let size = uncheckedSize, size >= data.count, let intermediate = try? data[index..<(index+4)].reversed() { - uncheckedSize = Data(intermediate).withUnsafeBytes { $0.pointee } - } - guard let size = uncheckedSize, size < data.count else { break } - let sizeAsInt = Int(size) - index += 4 - guard index + sizeAsInt <= data.count else { break } - let protoAsData = data[index..<(index+sizeAsInt)] - guard let proto = try? SSKProtoContactDetails.parseData(protoAsData) else { break } - index += sizeAsInt - result.append((publicKey: proto.number, isBlocked: proto.blocked)) - } - return result - } -} diff --git a/SignalUtilitiesKit/ContactShareApprovalViewController.swift b/SignalUtilitiesKit/ContactShareApprovalViewController.swift deleted file mode 100644 index 7b73f2ebc..000000000 --- a/SignalUtilitiesKit/ContactShareApprovalViewController.swift +++ /dev/null @@ -1,513 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation - - -@objc -public protocol ContactShareApprovalViewControllerDelegate: class { - func approveContactShare(_ approveContactShare: ContactShareApprovalViewController, - didApproveContactShare contactShare: ContactShareViewModel) - func approveContactShare(_ approveContactShare: ContactShareApprovalViewController, - didCancelContactShare contactShare: ContactShareViewModel) -} - -protocol ContactShareField: class { - - var isAvatar: Bool { get } - - func localizedLabel() -> String - - func isIncluded() -> Bool - - func setIsIncluded(_ isIncluded: Bool) - - func applyToContact(contact: ContactShareViewModel) -} - -// MARK: - - -class ContactShareFieldBase: NSObject, ContactShareField { - - let value: ContactFieldType - - private var isIncludedFlag = true - - var isAvatar: Bool { return false } - - required init(_ value: ContactFieldType) { - self.value = value - - super.init() - } - - func localizedLabel() -> String { - return value.localizedLabel() - } - - func isIncluded() -> Bool { - return isIncludedFlag - } - - func setIsIncluded(_ isIncluded: Bool) { - isIncludedFlag = isIncluded - } - - func applyToContact(contact: ContactShareViewModel) { - preconditionFailure("This method must be overridden") - } -} - -// MARK: - - -class ContactSharePhoneNumber: ContactShareFieldBase { - - override func applyToContact(contact: ContactShareViewModel) { - assert(isIncluded()) - - var values = [OWSContactPhoneNumber]() - values += contact.phoneNumbers - values.append(value) - contact.phoneNumbers = values - } -} - -// MARK: - - -class ContactShareEmail: ContactShareFieldBase { - - override func applyToContact(contact: ContactShareViewModel) { - assert(isIncluded()) - - var values = [OWSContactEmail]() - values += contact.emails - values.append(value) - contact.emails = values - } -} - -// MARK: - - -class ContactShareAddress: ContactShareFieldBase { - - override func applyToContact(contact: ContactShareViewModel) { - assert(isIncluded()) - - var values = [OWSContactAddress]() - values += contact.addresses - values.append(value) - contact.addresses = values - } -} - -// Stub class so that avatars conform to OWSContactField. -class OWSContactAvatar: NSObject, OWSContactField { - - public let avatarImage: UIImage - public let avatarData: Data - - required init(avatarImage: UIImage, avatarData: Data) { - self.avatarImage = avatarImage - self.avatarData = avatarData - - super.init() - } - - public func ows_isValid() -> Bool { - return true - } - - public func localizedLabel() -> String { - return "" - } - - override public var debugDescription: String { - return "Avatar" - } -} - -class ContactShareAvatarField: ContactShareFieldBase { - override var isAvatar: Bool { return true } - - override func applyToContact(contact: ContactShareViewModel) { - assert(isIncluded()) - - contact.avatarImageData = value.avatarData - } -} - -// MARK: - - -protocol ContactShareFieldViewDelegate: class { - func contactShareFieldViewDidChangeSelectedState() -} - -// MARK: - - -class ContactShareFieldView: UIStackView { - - weak var delegate: ContactShareFieldViewDelegate? - - let field: ContactShareField - - let previewViewBlock : (() -> UIView) - - private var checkbox: UIButton! - - // MARK: - Initializers - - @available(*, unavailable, message: "use init(call:) constructor instead.") - required init(coder aDecoder: NSCoder) { - notImplemented() - } - - required init(field: ContactShareField, previewViewBlock : @escaping (() -> UIView), delegate: ContactShareFieldViewDelegate) { - self.field = field - self.previewViewBlock = previewViewBlock - self.delegate = delegate - - super.init(frame: CGRect.zero) - - self.isUserInteractionEnabled = true - self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(wasTapped))) - - createContents() - } - - let hSpacing = CGFloat(10) - let hMargin = CGFloat(16) - - func createContents() { - self.axis = .horizontal - self.spacing = hSpacing - self.alignment = .center - self.layoutMargins = UIEdgeInsets(top: 0, left: hMargin, bottom: 0, right: hMargin) - self.isLayoutMarginsRelativeArrangement = true - - let checkbox = UIButton(type: .custom) - self.checkbox = checkbox - - let checkedIcon = #imageLiteral(resourceName: "contact_checkbox_checked") - let uncheckedIcon = #imageLiteral(resourceName: "contact_checkbox_unchecked") - checkbox.setImage(uncheckedIcon, for: .normal) - checkbox.setImage(checkedIcon, for: .selected) - checkbox.isSelected = field.isIncluded() - // Disable the checkbox; the entire row is hot. - checkbox.isUserInteractionEnabled = false - self.addArrangedSubview(checkbox) - checkbox.setCompressionResistanceHigh() - checkbox.setContentHuggingHigh() - - let previewView = previewViewBlock() - self.addArrangedSubview(previewView) - } - - @objc func wasTapped(sender: UIGestureRecognizer) { - Logger.info("") - - guard sender.state == .recognized else { - return - } - field.setIsIncluded(!field.isIncluded()) - checkbox.isSelected = field.isIncluded() - - delegate?.contactShareFieldViewDidChangeSelectedState() - } -} - -// MARK: - - -// TODO: Rename to ContactShareApprovalViewController -@objc -public class ContactShareApprovalViewController: OWSViewController, EditContactShareNameViewControllerDelegate, ContactShareFieldViewDelegate { - - weak var delegate: ContactShareApprovalViewControllerDelegate? - - let contactsManager: OWSContactsManager - - var contactShare: ContactShareViewModel - - var fieldViews = [ContactShareFieldView]() - - var nameLabel: UILabel! - - // MARK: Initializers - - @available(*, unavailable, message:"use other constructor instead.") - required public init?(coder aDecoder: NSCoder) { - notImplemented() - } - - @objc - required public init(contactShare: ContactShareViewModel, contactsManager: OWSContactsManager, delegate: ContactShareApprovalViewControllerDelegate) { - self.contactsManager = contactsManager - self.contactShare = contactShare - self.delegate = delegate - - super.init(nibName: nil, bundle: nil) - - buildFields() - } - - func buildFields() { - var fieldViews = [ContactShareFieldView]() - - let previewInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 0) - - if let avatarData = contactShare.avatarImageData { - if let avatarImage = contactShare.avatarImage { - let field = ContactShareAvatarField(OWSContactAvatar(avatarImage: avatarImage, avatarData: avatarData)) - let fieldView = ContactShareFieldView(field: field, previewViewBlock: { - return ContactFieldView.contactFieldView(forAvatarImage: avatarImage, layoutMargins: previewInsets, actionBlock: nil) - }, - delegate: self) - fieldViews.append(fieldView) - } else { - owsFailDebug("could not load avatar image.") - } - } - - for phoneNumber in contactShare.phoneNumbers { - let field = ContactSharePhoneNumber(phoneNumber) - let fieldView = ContactShareFieldView(field: field, previewViewBlock: { - return ContactFieldView.contactFieldView(forPhoneNumber: phoneNumber, layoutMargins: previewInsets, actionBlock: nil) - }, - delegate: self) - fieldViews.append(fieldView) - } - - for email in contactShare.emails { - let field = ContactShareEmail(email) - let fieldView = ContactShareFieldView(field: field, previewViewBlock: { - return ContactFieldView.contactFieldView(forEmail: email, layoutMargins: previewInsets, actionBlock: nil) - }, - delegate: self) - fieldViews.append(fieldView) - } - - for address in contactShare.addresses { - let field = ContactShareAddress(address) - let fieldView = ContactShareFieldView(field: field, previewViewBlock: { - return ContactFieldView.contactFieldView(forAddress: address, layoutMargins: previewInsets, actionBlock: nil) - }, - delegate: self) - fieldViews.append(fieldView) - } - - self.fieldViews = fieldViews - } - - // MARK: - View Lifecycle - - override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - updateNavigationBar() - } - - override public func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - } - - override public func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - } - - override public func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - } - - override public func loadView() { - super.loadView() - - self.navigationItem.title = NSLocalizedString("CONTACT_SHARE_APPROVAL_VIEW_TITLE", - comment: "Title for the 'Approve contact share' view.") - - self.view.backgroundColor = Theme.backgroundColor - - updateContent() - - updateNavigationBar() - } - - func isAtLeastOneFieldSelected() -> Bool { - for fieldView in fieldViews { - if fieldView.field.isIncluded(), !fieldView.field.isAvatar { - return true - } - } - return false - } - - func updateNavigationBar() { - self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, - target: self, - action: #selector(didPressCancel)) - - self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("ATTACHMENT_APPROVAL_SEND_BUTTON", - comment: "Label for 'send' button in the 'attachment approval' dialog."), - style: .plain, target: self, action: #selector(didPressSendButton)) - } - - private func updateContent() { - AssertIsOnMainThread() - - guard let rootView = self.view else { - owsFailDebug("missing root view.") - return - } - - for subview in rootView.subviews { - subview.removeFromSuperview() - } - - let scrollView = UIScrollView() - scrollView.preservesSuperviewLayoutMargins = false - self.view.addSubview(scrollView) - scrollView.layoutMargins = .zero - scrollView.autoPinEdge(toSuperviewSafeArea: .leading) - scrollView.autoPinEdge(toSuperviewSafeArea: .trailing) - scrollView.autoPinEdge(.top, to: .top, of: view) - scrollView.autoPinEdge(toSuperviewEdge: .bottom) - - let fieldsView = createFieldsView() - - scrollView.addSubview(fieldsView) - // Use layoutMarginsGuide for views inside UIScrollView - // that should have same width as scroll view. - fieldsView.autoPinLeadingToSuperviewMargin() - fieldsView.autoPinTrailingToSuperviewMargin() - fieldsView.autoPinEdge(toSuperviewEdge: .top) - fieldsView.autoPinEdge(toSuperviewEdge: .bottom) - fieldsView.setContentHuggingHorizontalLow() - } - - private func createFieldsView() -> UIView { - AssertIsOnMainThread() - - var rows = [UIView]() - - rows.append(createNameRow()) - - for fieldView in fieldViews { - rows.append(fieldView) - } - - return ContactFieldView(rows: rows, hMargin: hMargin) - } - - private let hMargin = CGFloat(16) - - func createNameRow() -> UIView { - let nameVMargin = CGFloat(16) - - let stackView = TappableStackView(actionBlock: { [weak self] in - guard let strongSelf = self else { return } - strongSelf.didPressEditName() - }) - - stackView.axis = .horizontal - stackView.alignment = .center - stackView.layoutMargins = UIEdgeInsets(top: nameVMargin, left: hMargin, bottom: nameVMargin, right: hMargin) - stackView.spacing = 10 - stackView.isLayoutMarginsRelativeArrangement = true - - let nameLabel = UILabel() - self.nameLabel = nameLabel - nameLabel.text = contactShare.name.displayName - nameLabel.font = UIFont.ows_dynamicTypeBody.ows_mediumWeight() - nameLabel.textColor = Theme.primaryColor - nameLabel.lineBreakMode = .byTruncatingTail - stackView.addArrangedSubview(nameLabel) - - let editNameLabel = UILabel() - editNameLabel.text = NSLocalizedString("CONTACT_EDIT_NAME_BUTTON", comment: "Label for the 'edit name' button in the contact share approval view.") - editNameLabel.font = UIFont.ows_dynamicTypeBody - editNameLabel.textColor = UIColor.ows_materialBlue - stackView.addArrangedSubview(editNameLabel) - editNameLabel.setContentHuggingHigh() - editNameLabel.setCompressionResistanceHigh() - - return stackView - } - - // MARK: - - - func filteredContactShare() -> ContactShareViewModel { - let result = self.contactShare.newContact(withName: self.contactShare.name) - - for fieldView in fieldViews { - if fieldView.field.isIncluded() { - fieldView.field.applyToContact(contact: result) - } - } - - return result - } - - // MARK: - - - @objc func didPressSendButton() { - AssertIsOnMainThread() - - guard isAtLeastOneFieldSelected() else { - OWSAlerts.showErrorAlert(message: NSLocalizedString("CONTACT_SHARE_NO_FIELDS_SELECTED", - comment: "Error indicating that at least one contact field must be selected before sharing a contact.")) - return - } - guard contactShare.ows_isValid else { - OWSAlerts.showErrorAlert(message: NSLocalizedString("CONTACT_SHARE_INVALID_CONTACT", - comment: "Error indicating that an invalid contact cannot be shared.")) - return - } - - Logger.info("") - - guard let delegate = self.delegate else { - owsFailDebug("missing delegate.") - return - } - - let filteredContactShare = self.filteredContactShare() - - assert(filteredContactShare.ows_isValid) - - delegate.approveContactShare(self, didApproveContactShare: filteredContactShare) - } - - @objc func didPressCancel() { - Logger.info("") - - guard let delegate = self.delegate else { - owsFailDebug("missing delegate.") - return - } - - delegate.approveContactShare(self, didCancelContactShare: contactShare) - } - - func didPressEditName() { - Logger.info("") - - let view = EditContactShareNameViewController(contactShare: contactShare, delegate: self) - self.navigationController?.pushViewController(view, animated: true) - } - - // MARK: - EditContactShareNameViewControllerDelegate - - public func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, - didEditContactShare contactShare: ContactShareViewModel) { - self.contactShare = contactShare - - nameLabel.text = contactShare.name.displayName - - self.updateNavigationBar() - } - - // MARK: - ContactShareFieldViewDelegate - - public func contactShareFieldViewDidChangeSelectedState() { - self.updateNavigationBar() - } -} diff --git a/SignalUtilitiesKit/ContactShareViewModel.swift b/SignalUtilitiesKit/ContactShareViewModel.swift deleted file mode 100644 index 4397f0045..000000000 --- a/SignalUtilitiesKit/ContactShareViewModel.swift +++ /dev/null @@ -1,168 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -public class ContactShareViewModel: NSObject { - - @objc - public let dbRecord: OWSContact - - @objc - public var avatarImageData: Data? { - didSet { - self.cachedAvatarImage = nil - } - } - - private var cachedAvatarImage: UIImage? - - @objc - public var avatarImage: UIImage? { - if self.cachedAvatarImage != nil { - return self.cachedAvatarImage - } - - guard let avatarImageData = self.avatarImageData else { - return nil - } - - self.cachedAvatarImage = UIImage(data: avatarImageData) - return cachedAvatarImage - } - - @objc - public required init(contactShareRecord: OWSContact, avatarImageData: Data?) { - self.dbRecord = contactShareRecord - self.avatarImageData = avatarImageData - } - - @objc - public convenience init(contactShareRecord: OWSContact, transaction: YapDatabaseReadTransaction) { - if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction) as? TSAttachmentStream { - self.init(contactShareRecord: contactShareRecord, avatarImageData: avatarAttachment.validStillImageData()) - } else { - self.init(contactShareRecord: contactShareRecord, avatarImageData: nil) - } - } - - @objc - public func getAvatarImage(diameter: CGFloat, contactsManager: OWSContactsManager) -> UIImage? { - if let avatarImage = avatarImage { - return avatarImage - } - - var colorSeed = name.displayName - let recipientIds = systemContactsWithSignalAccountPhoneNumbers(contactsManager) - if let firstRecipientId = recipientIds.first { - // Try to use the first signal id as the default - // avatar's color seed, so that it is as consistent - // as possible with the user's avatar in other views. - colorSeed = firstRecipientId - } - - let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: displayName, - colorSeed: colorSeed, - diameter: UInt(diameter)) - // Note: we use buildDefaultImage() and not build() so that contact - // share views always reflect the contents of the contact share. - // build() might return an avatar from a corresponding system - // contact or profile. This could mislead the user into thinking - // that an avatar they did not share was in fact included in the - // contact share. - return avatarBuilder.buildDefaultImage() - } - - // MARK: Delegated -> dbRecord - - @objc - public var name: OWSContactName { - get { - return dbRecord.name - } - set { - return dbRecord.name = newValue - } - } - - @objc - public var addresses: [OWSContactAddress] { - get { - return dbRecord.addresses - } - set { - return dbRecord.addresses = newValue - } - } - - @objc - public var emails: [OWSContactEmail] { - get { - return dbRecord.emails - } - set { - dbRecord.emails = newValue - } - } - - @objc - public var phoneNumbers: [OWSContactPhoneNumber] { - get { - return dbRecord.phoneNumbers - } - set { - dbRecord.phoneNumbers = newValue - } - } - - @objc - public func systemContactsWithSignalAccountPhoneNumbers(_ contactsManager: ContactsManagerProtocol) -> [String] { - return dbRecord.systemContactsWithSignalAccountPhoneNumbers(contactsManager) - } - - @objc - public func systemContactPhoneNumbers(_ contactsManager: ContactsManagerProtocol) -> [String] { - return dbRecord.systemContactPhoneNumbers(contactsManager) - } - - @objc - public func e164PhoneNumbers() -> [String] { - return dbRecord.e164PhoneNumbers() - } - - @objc - public var displayName: String { - return dbRecord.name.displayName - } - - @objc - public var ows_isValid: Bool { - return dbRecord.ows_isValid() - } - - @objc - public var isProfileAvatar: Bool { - return dbRecord.isProfileAvatar - } - - @objc - public func copy(withName name: OWSContactName) -> ContactShareViewModel { - - // TODO move the `copy` logic into the view model? - let newDbRecord = dbRecord.copy(with: name) - - return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: self.avatarImageData) - } - - @objc - public func newContact(withName name: OWSContactName) -> ContactShareViewModel { - - // TODO move the `newContact` logic into the view model? - let newDbRecord = dbRecord.newContact(with: name) - - // If we want to keep the avatar image, the caller will need to re-apply it. - return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: nil) - } -} diff --git a/SignalUtilitiesKit/ContactsUpdater.h b/SignalUtilitiesKit/ContactsUpdater.h deleted file mode 100644 index 7fc59f2bc..000000000 --- a/SignalUtilitiesKit/ContactsUpdater.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface ContactsUpdater : NSObject - -+ (instancetype)sharedUpdater; - -// This asynchronously tries to verify whether or not a group of possible -// contact ids correspond to service accounts. -// -// The failure callback is only invoked if the lookup fails. Otherwise, -// the success callback is invoked with the (possibly empty) set of contacts -// that were found. -- (void)lookupIdentifiers:(NSArray *)identifiers - success:(void (^)(NSArray *recipients))success - failure:(void (^)(NSError *error))failure; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ContactsUpdater.m b/SignalUtilitiesKit/ContactsUpdater.m deleted file mode 100644 index c033d07a1..000000000 --- a/SignalUtilitiesKit/ContactsUpdater.m +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "ContactsUpdater.h" -#import "OWSError.h" -#import "OWSPrimaryStorage.h" -#import "OWSRequestFactory.h" -#import "PhoneNumber.h" -#import "SSKEnvironment.h" -#import "TSNetworkManager.h" -#import -#import -#import -#import -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ContactsUpdater () - -@property (nonatomic, readonly) NSOperationQueue *contactIntersectionQueue; - -@end - -#pragma mark - - -@implementation ContactsUpdater - -+ (instancetype)sharedUpdater { - OWSAssertDebug(SSKEnvironment.shared.contactsUpdater); - - return SSKEnvironment.shared.contactsUpdater; -} - -- (instancetype)init -{ - self = [super init]; - if (!self) { - return self; - } - - _contactIntersectionQueue = [NSOperationQueue new]; - _contactIntersectionQueue.maxConcurrentOperationCount = 1; - _contactIntersectionQueue.name = self.logTag; - - OWSSingletonAssert(); - - return self; -} - -- (void)lookupIdentifiers:(NSArray *)identifiers - success:(void (^)(NSArray *recipients))success - failure:(void (^)(NSError *error))failure -{ - if (identifiers.count < 1) { - OWSFailDebug(@"Cannot lookup zero identifiers"); - DispatchMainThreadSafe(^{ - failure( - OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup zero identifiers")); - }); - return; - } - - [self contactIntersectionWithSet:[NSSet setWithArray:identifiers] - success:^(NSSet *recipients) { - if (recipients.count == 0) { - OWSLogInfo(@"no contacts are Signal users"); - } - DispatchMainThreadSafe(^{ - success(recipients.allObjects); - }); - } - failure:^(NSError *error) { - DispatchMainThreadSafe(^{ - failure(error); - }); - }]; -} - -- (void)contactIntersectionWithSet:(NSSet *)recipientIdsToLookup - success:(void (^)(NSSet *recipients))success - failure:(void (^)(NSError *error))failure -{ - OWSLegacyContactDiscoveryOperation *operation = - [[OWSLegacyContactDiscoveryOperation alloc] initWithRecipientIdsToLookup:recipientIdsToLookup.allObjects]; - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSArray *operationAndDependencies = [operation.dependencies arrayByAddingObject:operation]; - [self.contactIntersectionQueue addOperations:operationAndDependencies waitUntilFinished:YES]; - - if (operation.failingError != nil) { - failure(operation.failingError); - return; - } - - NSSet *registeredRecipientIds = operation.registeredRecipientIds; - - NSMutableSet *recipients = [NSMutableSet new]; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSString *recipientId in recipientIdsToLookup) { - if ([registeredRecipientIds containsObject:recipientId]) { - SignalRecipient *recipient = - [SignalRecipient markRecipientAsRegisteredAndGet:recipientId transaction:transaction]; - [recipients addObject:recipient]; - } else { - [SignalRecipient markRecipientAsUnregistered:recipientId transaction:transaction]; - } - } - }]; - - dispatch_async(dispatch_get_main_queue(), ^{ - success([recipients copy]); - }); - }); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ContactsViewHelper.h b/SignalUtilitiesKit/ContactsViewHelper.h deleted file mode 100644 index c4b73cb69..000000000 --- a/SignalUtilitiesKit/ContactsViewHelper.h +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class Contact; -@class ContactsViewHelper; -@class SignalAccount; -@class TSThread; - -@protocol CNContactViewControllerDelegate; - -@protocol ContactsViewHelperDelegate - -- (void)contactsViewHelperDidUpdateContacts; - -@optional - -- (BOOL)shouldHideLocalNumber; - -@end - -@protocol ContactEditingDelegate - -- (void)didFinishEditingContact; - -@end - -#pragma mark - - -@class CNContact; -@class OWSBlockingManager; -@class OWSContactsManager; - -@interface ContactsViewHelper : NSObject - -@property (nonatomic, readonly, weak) id delegate; - -@property (nonatomic, readonly) OWSContactsManager *contactsManager; -@property (nonatomic, readonly) OWSBlockingManager *blockingManager; - -@property (nonatomic, readonly) NSDictionary *signalAccountMap; -@property (nonatomic, readonly) NSArray *signalAccounts; - -// Useful to differentiate between having no signal accounts vs. haven't checked yet -@property (nonatomic, readonly) BOOL hasUpdatedContactsAtLeastOnce; - -// Suitable when the user tries to perform an action which is not possible due to the user having -// previously denied contact access. -- (void)presentMissingContactAccessAlertControllerFromViewController:(UIViewController *)viewController; - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithDelegate:(id)delegate; - -- (nullable SignalAccount *)fetchSignalAccountForRecipientId:(NSString *)recipientId; -- (SignalAccount *)fetchOrBuildSignalAccountForRecipientId:(NSString *)recipientId; - -// This method is faster than OWSBlockingManager but -// is only safe to be called on the main thread. -- (BOOL)isRecipientIdBlocked:(NSString *)recipientId; - -// This method is faster than OWSBlockingManager but -// is only safe to be called on the main thread. -- (BOOL)isThreadBlocked:(TSThread *)thread; - -// NOTE: This method uses a transaction. -- (NSString *)localNumber; - -- (NSArray *)signalAccountsMatchingSearchString:(NSString *)searchText; - -- (void)warmNonSignalContactsCacheAsync; -- (NSArray *)nonSignalContactsMatchingSearchString:(NSString *)searchText; - -- (void)presentContactViewControllerForRecipientId:(NSString *)recipientId - fromViewController:(UIViewController *)fromViewController - editImmediately:(BOOL)shouldEditImmediately; - -// This method can be used to edit existing contacts. -- (void)presentContactViewControllerForRecipientId:(NSString *)recipientId - fromViewController:(UIViewController *)fromViewController - editImmediately:(BOOL)shouldEditImmediately - addToExistingCnContact:(CNContact *_Nullable)cnContact; - -+ (void)presentMissingContactAccessAlertControllerFromViewController:(UIViewController *)viewController; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ContactsViewHelper.m b/SignalUtilitiesKit/ContactsViewHelper.m deleted file mode 100644 index 58ab0c5e5..000000000 --- a/SignalUtilitiesKit/ContactsViewHelper.m +++ /dev/null @@ -1,463 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "ContactsViewHelper.h" -#import "Environment.h" -#import "UIUtil.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import - -@import ContactsUI; - -NS_ASSUME_NONNULL_BEGIN - -@interface ContactsViewHelper () - -// This property is a cached value that is lazy-populated. -@property (nonatomic, nullable) NSArray *nonSignalContacts; - -@property (nonatomic) NSDictionary *signalAccountMap; -@property (nonatomic) NSArray *signalAccounts; - -@property (nonatomic, readonly) OWSBlockListCache *blockListCache; - -@property (nonatomic) BOOL shouldNotifyDelegateOfUpdatedContacts; -@property (nonatomic) BOOL hasUpdatedContactsAtLeastOnce; -@property (nonatomic) OWSProfileManager *profileManager; -@property (nonatomic, readonly) FullTextSearcher *fullTextSearcher; - -@end - -#pragma mark - - -@implementation ContactsViewHelper - -- (instancetype)initWithDelegate:(id)delegate -{ - self = [super init]; - if (!self) { - return self; - } - - OWSAssertDebug(delegate); - _delegate = delegate; - - _blockingManager = [OWSBlockingManager sharedManager]; - _blockListCache = [OWSBlockListCache new]; - [_blockListCache startObservingAndSyncStateWithDelegate:self]; - - _fullTextSearcher = FullTextSearcher.shared; - - _contactsManager = Environment.shared.contactsManager; - _profileManager = [OWSProfileManager sharedManager]; - - [self updateContacts]; - - [self observeNotifications]; - - return self; -} - -- (void)observeNotifications -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(signalAccountsDidChange:) - name:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)signalAccountsDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [self updateContacts]; -} - -#pragma mark - Contacts - -- (nullable SignalAccount *)fetchSignalAccountForRecipientId:(NSString *)recipientId -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(recipientId.length > 0); - - return self.signalAccountMap[recipientId]; -} - -- (SignalAccount *)fetchOrBuildSignalAccountForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId]; - return (signalAccount ?: [[SignalAccount alloc] initWithRecipientId:recipientId]); -} - -- (BOOL)isSignalAccountHidden:(SignalAccount *)signalAccount -{ - OWSAssertIsOnMainThread(); - - if ([self.delegate respondsToSelector:@selector(shouldHideLocalNumber)] && [self.delegate shouldHideLocalNumber] && - [self isCurrentUser:signalAccount]) { - - return YES; - } - - return NO; -} - -- (BOOL)isCurrentUser:(SignalAccount *)signalAccount -{ - OWSAssertIsOnMainThread(); - - NSString *localNumber = [TSAccountManager localNumber]; - if ([signalAccount.recipientId isEqualToString:localNumber]) { - return YES; - } - - for (PhoneNumber *phoneNumber in signalAccount.contact.parsedPhoneNumbers) { - if ([[phoneNumber toE164] isEqualToString:localNumber]) { - return YES; - } - } - - return NO; -} - -- (NSString *)localNumber -{ - return [TSAccountManager localNumber]; -} - -- (BOOL)isRecipientIdBlocked:(NSString *)recipientId -{ - OWSAssertIsOnMainThread(); - - return [self.blockListCache isRecipientIdBlocked:recipientId]; -} - -- (BOOL)isGroupIdBlocked:(NSData *)groupId -{ - OWSAssertIsOnMainThread(); - - return [self.blockListCache isGroupIdBlocked:groupId]; -} - -- (BOOL)isThreadBlocked:(TSThread *)thread -{ - if ([thread isKindOfClass:[TSContactThread class]]) { - TSContactThread *contactThread = (TSContactThread *)thread; - return [self isRecipientIdBlocked:contactThread.contactIdentifier]; - } else if ([thread isKindOfClass:[TSGroupThread class]]) { - TSGroupThread *groupThread = (TSGroupThread *)thread; - return [self isGroupIdBlocked:groupThread.groupModel.groupId]; - } else { - OWSFailDebug(@"%@ failure: unexpected thread: %@", self.logTag, thread.class); - return NO; - } -} - -- (void)updateContacts -{ - OWSAssertIsOnMainThread(); - - NSMutableDictionary *signalAccountMap = [NSMutableDictionary new]; - NSMutableArray *signalAccounts = [NSMutableArray new]; - for (SignalAccount *signalAccount in self.contactsManager.signalAccounts) { - if (![self isSignalAccountHidden:signalAccount]) { - signalAccountMap[signalAccount.recipientId] = signalAccount; - [signalAccounts addObject:signalAccount]; - } - } - self.signalAccountMap = [signalAccountMap copy]; - self.signalAccounts = [signalAccounts copy]; - self.nonSignalContacts = nil; - - // Don't fire delegate "change" events during initialization. - if (self.shouldNotifyDelegateOfUpdatedContacts) { - [self.delegate contactsViewHelperDidUpdateContacts]; - self.hasUpdatedContactsAtLeastOnce = YES; - } -} - -- (NSArray *)searchTermsForSearchString:(NSString *)searchText -{ - return [[[searchText ows_stripped] - componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] - filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *_Nullable searchTerm, - NSDictionary *_Nullable bindings) { - return searchTerm.length > 0; - }]]; -} - -- (NSArray *)signalAccountsMatchingSearchString:(NSString *)searchText -{ - // Check for matches against "Note to Self". - NSMutableArray *signalAccountsToSearch = [self.signalAccounts mutableCopy]; - SignalAccount *selfAccount = [[SignalAccount alloc] initWithRecipientId:self.localNumber]; - [signalAccountsToSearch addObject:selfAccount]; - return [self.fullTextSearcher filterSignalAccounts:signalAccountsToSearch withSearchText:searchText]; -} - -- (BOOL)doesContact:(Contact *)contact matchSearchTerm:(NSString *)searchTerm -{ - OWSAssertDebug(contact); - OWSAssertDebug(searchTerm.length > 0); - - if ([contact.fullName.lowercaseString containsString:searchTerm.lowercaseString]) { - return YES; - } - - NSString *asPhoneNumber = [PhoneNumber removeFormattingCharacters:searchTerm]; - if (asPhoneNumber.length > 0) { - for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { - if ([phoneNumber.toE164 containsString:asPhoneNumber]) { - return YES; - } - } - } - - return NO; -} - -- (BOOL)doesContact:(Contact *)contact matchSearchTerms:(NSArray *)searchTerms -{ - OWSAssertDebug(contact); - OWSAssertDebug(searchTerms.count > 0); - - for (NSString *searchTerm in searchTerms) { - if (![self doesContact:contact matchSearchTerm:searchTerm]) { - return NO; - } - } - - return YES; -} - -- (NSArray *)nonSignalContactsMatchingSearchString:(NSString *)searchText -{ - NSArray *searchTerms = [self searchTermsForSearchString:searchText]; - - if (searchTerms.count < 1) { - return [NSArray new]; - } - - return [self.nonSignalContacts filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(Contact *contact, - NSDictionary *_Nullable bindings) { - return [self doesContact:contact matchSearchTerms:searchTerms]; - }]]; -} - -- (void)warmNonSignalContactsCacheAsync -{ - OWSAssertIsOnMainThread(); - if (self.nonSignalContacts != nil) { - return; - } - - NSMutableSet *nonSignalContactSet = [NSMutableSet new]; - __block NSArray *nonSignalContacts; - - [OWSPrimaryStorage.dbReadConnection - asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { - for (Contact *contact in self.contactsManager.allContactsMap.allValues) { - NSArray *signalRecipients = [contact signalRecipientsWithTransaction:transaction]; - if (signalRecipients.count < 1) { - [nonSignalContactSet addObject:contact]; - } - } - nonSignalContacts = [nonSignalContactSet.allObjects - sortedArrayUsingComparator:^NSComparisonResult(Contact *_Nonnull left, Contact *_Nonnull right) { - return [left.fullName compare:right.fullName]; - }]; - } - completionBlock:^{ - self.nonSignalContacts = nonSignalContacts; - }]; -} - -- (nullable NSArray *)nonSignalContacts -{ - OWSAssertIsOnMainThread(); - if (!_nonSignalContacts) { - NSMutableSet *nonSignalContacts = [NSMutableSet new]; - [OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - for (Contact *contact in self.contactsManager.allContactsMap.allValues) { - NSArray *signalRecipients = [contact signalRecipientsWithTransaction:transaction]; - if (signalRecipients.count < 1) { - [nonSignalContacts addObject:contact]; - } - } - }]; - _nonSignalContacts = [nonSignalContacts.allObjects - sortedArrayUsingComparator:^NSComparisonResult(Contact *_Nonnull left, Contact *_Nonnull right) { - return [left.fullName compare:right.fullName]; - }]; - } - - return _nonSignalContacts; -} - -#pragma mark - Editing - -- (void)presentMissingContactAccessAlertControllerFromViewController:(UIViewController *)viewController -{ - [ContactsViewHelper presentMissingContactAccessAlertControllerFromViewController:viewController]; -} - -+ (void)presentMissingContactAccessAlertControllerFromViewController:(UIViewController *)viewController -{ - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_TITLE", comment - : @"Alert title for when the user has just tried to edit a " - @"contacts after declining to give Signal contacts " - @"permissions") - message:NSLocalizedString(@"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_BODY", comment - : @"Alert body for when the user has just tried to edit a " - @"contacts after declining to give Signal contacts " - @"permissions") - preferredStyle:UIAlertControllerStyleAlert]; - - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_ACTION_NOT_NOW", - @"Button text to dismiss missing contacts permission alert") - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"not_now") - style:UIAlertActionStyleCancel - handler:nil]]; - - UIAlertAction *_Nullable openSystemSettingsAction = CurrentAppContext().openSystemSettingsAction; - if (openSystemSettingsAction) { - [alert addAction:openSystemSettingsAction]; - } - - [viewController presentAlert:alert]; -} - -- (void)presentContactViewControllerForRecipientId:(NSString *)recipientId - fromViewController:(UIViewController *)fromViewController - editImmediately:(BOOL)shouldEditImmediately -{ - return; - /** - [self presentContactViewControllerForRecipientId:recipientId - fromViewController:fromViewController - editImmediately:shouldEditImmediately - addToExistingCnContact:nil]; - */ -} - -- (void)presentContactViewControllerForRecipientId:(NSString *)recipientId - fromViewController:(UIViewController *)fromViewController - editImmediately:(BOOL)shouldEditImmediately - addToExistingCnContact:(CNContact *_Nullable)existingContact -{ - SignalAccount *signalAccount = [self fetchSignalAccountForRecipientId:recipientId]; - - if (!self.contactsManager.supportsContactEditing) { - // Should not expose UI that lets the user get here. - OWSFailDebug(@"Contact editing not supported."); - return; - } - - if (!self.contactsManager.isSystemContactsAuthorized) { - [self presentMissingContactAccessAlertControllerFromViewController:fromViewController]; - return; - } - - CNContactViewController *_Nullable contactViewController; - CNContact *_Nullable cnContact = nil; - if (existingContact) { - CNMutableContact *updatedContact = [existingContact mutableCopy]; - NSMutableArray *phoneNumbers - = (updatedContact.phoneNumbers ? [updatedContact.phoneNumbers mutableCopy] : [NSMutableArray new]); - // Only add recipientId as a phone number for the existing contact - // if its not already present. - BOOL hasPhoneNumber = NO; - for (CNLabeledValue *existingPhoneNumber in phoneNumbers) { - CNPhoneNumber *phoneNumber = existingPhoneNumber.value; - if ([phoneNumber.stringValue isEqualToString:recipientId]) { - OWSFailDebug(@"We currently only should the 'add to existing contact' UI for phone numbers that don't " - @"correspond to an existing user."); - hasPhoneNumber = YES; - break; - } - } - if (!hasPhoneNumber) { - CNPhoneNumber *phoneNumber = [CNPhoneNumber phoneNumberWithStringValue:recipientId]; - CNLabeledValue *labeledPhoneNumber = - [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMain value:phoneNumber]; - [phoneNumbers addObject:labeledPhoneNumber]; - updatedContact.phoneNumbers = phoneNumbers; - - // When adding a phone number to an existing contact, immediately enter - // "edit" mode. - shouldEditImmediately = YES; - } - cnContact = updatedContact; - } - if (signalAccount && !cnContact) { - cnContact = [self.contactsManager cnContactWithId:signalAccount.contact.cnContactId]; - } - if (cnContact) { - if (shouldEditImmediately) { - // Not actually a "new" contact, but this brings up the edit form rather than the "Read" form - // saving our users a tap in some cases when we already know they want to edit. - contactViewController = [CNContactViewController viewControllerForNewContact:cnContact]; - - // Default title is "New Contact". We could give a more descriptive title, but anything - // seems redundant - the context is sufficiently clear. - contactViewController.title = @""; - } else { - contactViewController = [CNContactViewController viewControllerForContact:cnContact]; - } - } - - if (!contactViewController) { - CNMutableContact *newContact = [CNMutableContact new]; - CNPhoneNumber *phoneNumber = [CNPhoneNumber phoneNumberWithStringValue:recipientId]; - CNLabeledValue *labeledPhoneNumber = - [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMain value:phoneNumber]; - newContact.phoneNumbers = @[ labeledPhoneNumber ]; - - newContact.givenName = [self.profileManager profileNameForRecipientWithID:recipientId]; - - contactViewController = [CNContactViewController viewControllerForNewContact:newContact]; - } - - contactViewController.delegate = fromViewController; - contactViewController.allowsActions = NO; - contactViewController.allowsEditing = YES; - contactViewController.navigationItem.leftBarButtonItem = - [[UIBarButtonItem alloc] initWithTitle:CommonStrings.cancelButton - style:UIBarButtonItemStylePlain - target:fromViewController - action:@selector(didFinishEditingContact)]; - - OWSNavigationController *modal = [[OWSNavigationController alloc] initWithRootViewController:contactViewController]; - - // We want the presentation to imply a "replacement" in this case. - if (shouldEditImmediately) { - modal.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - } - [fromViewController presentViewController:modal animated:YES completion:nil]; -} - -- (void)blockListCacheDidUpdate:(OWSBlockListCache *)blocklistCache -{ - OWSAssertIsOnMainThread(); - [self updateContacts]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/CreatePreKeysOperation.swift b/SignalUtilitiesKit/CreatePreKeysOperation.swift index 5a8c75bcf..c74f96d13 100644 --- a/SignalUtilitiesKit/CreatePreKeysOperation.swift +++ b/SignalUtilitiesKit/CreatePreKeysOperation.swift @@ -8,10 +8,6 @@ import PromiseKit @objc(SSKCreatePreKeysOperation) public class CreatePreKeysOperation: OWSOperation { - private var accountServiceClient: AccountServiceClient { - return AccountServiceClient.shared - } - private var primaryStorage: OWSPrimaryStorage { return OWSPrimaryStorage.shared() } @@ -29,29 +25,5 @@ public class CreatePreKeysOperation: OWSOperation { SessionManagementProtocol.createPreKeys() reportSuccess() - - /* Loki: Original code - * ================ - let identityKey: Data = self.identityKeyManager.identityKeyPair()!.publicKey - let signedPreKeyRecord: SignedPreKeyRecord = self.primaryStorage.generateRandomSignedRecord() - let preKeyRecords: [PreKeyRecord] = self.primaryStorage.generatePreKeyRecords() - - self.primaryStorage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - self.primaryStorage.storePreKeyRecords(preKeyRecords) - - firstly { - self.accountServiceClient.setPreKeys(identityKey: identityKey, signedPreKeyRecord: signedPreKeyRecord, preKeyRecords: preKeyRecords) - }.done { - signedPreKeyRecord.markAsAcceptedByService() - self.primaryStorage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - self.primaryStorage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - - Logger.debug("done") - self.reportSuccess() - }.catch { error in - self.reportError(error) - }.retainUntilComplete() - * ================ - */ } } diff --git a/SignalUtilitiesKit/Data+SecureRandom.swift b/SignalUtilitiesKit/Data+SecureRandom.swift deleted file mode 100644 index e520e4553..000000000 --- a/SignalUtilitiesKit/Data+SecureRandom.swift +++ /dev/null @@ -1,12 +0,0 @@ - -public extension Data { - - /// Returns `size` bytes of random data generated using the default secure random number generator. See - /// [SecRandomCopyBytes](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) for more information. - public static func getSecureRandomData(ofSize size: UInt) -> Data? { - var data = Data(count: Int(size)) - let result = data.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, Int(size), $0.baseAddress!) } - guard result == errSecSuccess else { return nil } - return data - } -} diff --git a/SignalUtilitiesKit/OWSDatabaseMigration.h b/SignalUtilitiesKit/Database/OWSDatabaseMigration.h similarity index 100% rename from SignalUtilitiesKit/OWSDatabaseMigration.h rename to SignalUtilitiesKit/Database/OWSDatabaseMigration.h diff --git a/SignalUtilitiesKit/OWSDatabaseMigration.m b/SignalUtilitiesKit/Database/OWSDatabaseMigration.m similarity index 100% rename from SignalUtilitiesKit/OWSDatabaseMigration.m rename to SignalUtilitiesKit/Database/OWSDatabaseMigration.m diff --git a/SignalUtilitiesKit/OWSDatabaseMigrationRunner.h b/SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.h similarity index 100% rename from SignalUtilitiesKit/OWSDatabaseMigrationRunner.h rename to SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.h diff --git a/SignalUtilitiesKit/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.m similarity index 100% rename from SignalUtilitiesKit/OWSDatabaseMigrationRunner.m rename to SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.m diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+Calling.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.h similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+Calling.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.h diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+Calling.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.m similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+Calling.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.m diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+PreKeyStore.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.h similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+PreKeyStore.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.h diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+PreKeyStore.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.m similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+PreKeyStore.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.m diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+SessionStore.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+SessionStore.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+SessionStore.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.m similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+SessionStore.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.m diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+SignedPreKeyStore.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.h similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+SignedPreKeyStore.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.h diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+SignedPreKeyStore.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.m similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+SignedPreKeyStore.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.m diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+keyFromIntLong.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.h similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+keyFromIntLong.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.h diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+keyFromIntLong.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.m similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+keyFromIntLong.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.m diff --git a/SignalUtilitiesKit/OWSPrimaryStorage.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage.h similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage.h diff --git a/SignalUtilitiesKit/OWSPrimaryStorage.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage.m similarity index 97% rename from SignalUtilitiesKit/OWSPrimaryStorage.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage.m index a72fb259e..965eb093e 100644 --- a/SignalUtilitiesKit/OWSPrimaryStorage.m +++ b/SignalUtilitiesKit/Database/OWSPrimaryStorage.m @@ -4,8 +4,6 @@ #import "OWSPrimaryStorage.h" #import "AppContext.h" -#import "OWSAnalytics.h" -#import "OWSBatchMessageProcessor.h" #import "OWSDisappearingMessagesFinder.h" #import "OWSFailedAttachmentDownloadsJob.h" #import "OWSFailedMessagesJob.h" @@ -13,7 +11,6 @@ #import "OWSIncomingMessageFinder.h" #import "OWSIncompleteCallsJob.h" #import "OWSMediaGalleryFinder.h" -#import "OWSMessageReceiver.h" #import "OWSStorage+Subclass.h" #import "SSKEnvironment.h" #import "TSDatabaseSecondaryIndexes.h" @@ -198,16 +195,12 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) [self asyncRegisterExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:[TSDatabaseSecondaryIndexes registerTimeStampIndexExtensionName]]; - [OWSMessageReceiver asyncRegisterDatabaseExtension:self]; - [OWSBatchMessageProcessor asyncRegisterDatabaseExtension:self]; - [TSDatabaseView asyncRegisterUnseenDatabaseView:self]; [TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:self]; [TSDatabaseView asyncRegisterThreadSpecialMessagesDatabaseView:self]; [FullTextSearchFinder asyncRegisterDatabaseExtensionWithStorage:self]; [OWSIncomingMessageFinder asyncRegisterExtensionWithPrimaryStorage:self]; - [TSDatabaseView asyncRegisterSecondaryDevicesDatabaseView:self]; [OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self]; [OWSFailedMessagesJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; [OWSIncompleteCallsJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; @@ -216,9 +209,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self]; [SSKJobRecordFinder asyncRegisterDatabaseExtensionObjCWithStorage:self]; - // Loki - [LKDeviceLinkIndex asyncRegisterDatabaseExtensions:self]; - [self.database flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) completionBlock:^{ diff --git a/SignalUtilitiesKit/OWSResaveCollectionDBMigration.h b/SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.h similarity index 100% rename from SignalUtilitiesKit/OWSResaveCollectionDBMigration.h rename to SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.h diff --git a/SignalUtilitiesKit/OWSResaveCollectionDBMigration.m b/SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.m similarity index 100% rename from SignalUtilitiesKit/OWSResaveCollectionDBMigration.m rename to SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.m diff --git a/SignalUtilitiesKit/OWSStorage.h b/SignalUtilitiesKit/Database/OWSStorage.h similarity index 100% rename from SignalUtilitiesKit/OWSStorage.h rename to SignalUtilitiesKit/Database/OWSStorage.h diff --git a/SignalUtilitiesKit/OWSStorage.m b/SignalUtilitiesKit/Database/OWSStorage.m similarity index 100% rename from SignalUtilitiesKit/OWSStorage.m rename to SignalUtilitiesKit/Database/OWSStorage.m diff --git a/SignalUtilitiesKit/SSKKeychainStorage.swift b/SignalUtilitiesKit/Database/SSKKeychainStorage.swift similarity index 100% rename from SignalUtilitiesKit/SSKKeychainStorage.swift rename to SignalUtilitiesKit/Database/SSKKeychainStorage.swift diff --git a/SignalUtilitiesKit/TSYapDatabaseObject.h b/SignalUtilitiesKit/Database/TSYapDatabaseObject.h similarity index 100% rename from SignalUtilitiesKit/TSYapDatabaseObject.h rename to SignalUtilitiesKit/Database/TSYapDatabaseObject.h diff --git a/SignalUtilitiesKit/TSYapDatabaseObject.m b/SignalUtilitiesKit/Database/TSYapDatabaseObject.m similarity index 100% rename from SignalUtilitiesKit/TSYapDatabaseObject.m rename to SignalUtilitiesKit/Database/TSYapDatabaseObject.m diff --git a/SignalUtilitiesKit/YapDatabase+Promise.swift b/SignalUtilitiesKit/Database/YapDatabase+Promise.swift similarity index 100% rename from SignalUtilitiesKit/YapDatabase+Promise.swift rename to SignalUtilitiesKit/Database/YapDatabase+Promise.swift diff --git a/SignalUtilitiesKit/YapDatabaseConnection+OWS.h b/SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.h similarity index 100% rename from SignalUtilitiesKit/YapDatabaseConnection+OWS.h rename to SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.h diff --git a/SignalUtilitiesKit/YapDatabaseConnection+OWS.m b/SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.m similarity index 100% rename from SignalUtilitiesKit/YapDatabaseConnection+OWS.m rename to SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.m diff --git a/SignalUtilitiesKit/YapDatabaseTransaction+OWS.h b/SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.h similarity index 100% rename from SignalUtilitiesKit/YapDatabaseTransaction+OWS.h rename to SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.h diff --git a/SignalUtilitiesKit/YapDatabaseTransaction+OWS.m b/SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.m similarity index 98% rename from SignalUtilitiesKit/YapDatabaseTransaction+OWS.m rename to SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.m index 9596f2841..ef505701e 100644 --- a/SignalUtilitiesKit/YapDatabaseTransaction+OWS.m +++ b/SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.m @@ -70,6 +70,9 @@ NS_ASSUME_NONNULL_BEGIN - (nullable PreKeyBundle *)preKeyBundleForKey:(NSString *)key inCollection:(NSString *)collection { + OWSAssertDebug(key.length > 0); + OWSAssertDebug(collection.length > 0); + return [self objectForKey:key inCollection:collection ofExpectedType:PreKeyBundle.class]; } diff --git a/SignalUtilitiesKit/DecryptionUtilities.swift b/SignalUtilitiesKit/DecryptionUtilities.swift deleted file mode 100644 index 974451235..000000000 --- a/SignalUtilitiesKit/DecryptionUtilities.swift +++ /dev/null @@ -1,18 +0,0 @@ -import CryptoSwift - -enum DecryptionUtilities { - - /// - Note: Sync. Don't call from the main thread. - internal static func decrypt(_ ivAndCiphertext: Data, usingAESGCMWithSymmetricKey symmetricKey: Data) throws -> Data { - if Thread.isMainThread { - #if DEBUG - preconditionFailure("It's illegal to call decrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.") - #endif - } - let iv = ivAndCiphertext[0.. Bool { - guard let other = other as? Device else { return false } - return publicKey == other.publicKey && signature == other.signature - } - - @objc override public var hash: Int { // Override NSObject.hash and not Hashable.hashValue or Hashable.hash(into:) - var result = publicKey.hashValue - if let signature = signature { result = result ^ signature.hashValue } - return result - } - - @objc override public var description: String { return publicKey } - } - - // MARK: Lifecycle - @objc public init(between master: Device, and slave: Device) { - self.master = master - self.slave = slave - } - - // MARK: Coding - @objc public init?(coder: NSCoder) { - master = coder.decodeObject(forKey: "master") as! Device - slave = coder.decodeObject(forKey: "slave") as! Device - super.init() - } - - @objc public func encode(with coder: NSCoder) { - coder.encode(master, forKey: "master") - coder.encode(slave, forKey: "slave") - } - - // MARK: JSON - public func toJSON() -> JSON { - var result = [ "primaryDevicePubKey" : master.publicKey, "secondaryDevicePubKey" : slave.publicKey ] - if let masterSignature = master.signature { result["grantSignature"] = masterSignature.base64EncodedString() } - if let slaveSignature = slave.signature { result["requestSignature"] = slaveSignature.base64EncodedString() } - return result - } - - // MARK: Equality - @objc override public func isEqual(_ other: Any?) -> Bool { - guard let other = other as? DeviceLink else { return false } - return master == other.master && slave == other.slave - } - - // MARK: Hashing - @objc override public var hash: Int { // Override NSObject.hash and not Hashable.hashValue or Hashable.hash(into:) - return master.hash ^ slave.hash - } - - // MARK: Description - @objc override public var description: String { return "\(master) - \(slave)" } -} diff --git a/SignalUtilitiesKit/DeviceLinkIndex.swift b/SignalUtilitiesKit/DeviceLinkIndex.swift deleted file mode 100644 index 15c3fd0ec..000000000 --- a/SignalUtilitiesKit/DeviceLinkIndex.swift +++ /dev/null @@ -1,43 +0,0 @@ - -@objc(LKDeviceLinkIndex) -public final class DeviceLinkIndex : NSObject { - - private static let name = "loki_device_link_index" - - @objc public static let masterPublicKey = "master_hex_encoded_public_key" - @objc public static let slavePublicKey = "slave_hex_encoded_public_key" - @objc public static let isAuthorized = "is_authorized" - - @objc public static let indexDatabaseExtension: YapDatabaseSecondaryIndex = { - let setup = YapDatabaseSecondaryIndexSetup() - setup.addColumn(masterPublicKey, with: .text) - setup.addColumn(slavePublicKey, with: .text) - setup.addColumn(isAuthorized, with: .integer) - let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock { _, map, _, _, object in - guard let deviceLink = object as? DeviceLink else { return } - map[masterPublicKey] = deviceLink.master.publicKey - map[slavePublicKey] = deviceLink.slave.publicKey - map[isAuthorized] = deviceLink.isAuthorized - } - return YapDatabaseSecondaryIndex(setup: setup, handler: handler) - }() - - @objc public static let databaseExtensionName: String = name - - @objc public static func asyncRegisterDatabaseExtensions(_ storage: OWSStorage) { - storage.asyncRegister(indexDatabaseExtension, withName: name) - } - - @objc public static func getDeviceLinks(for query: YapDatabaseQuery, in transaction: YapDatabaseReadTransaction) -> [DeviceLink] { - guard let ext = transaction.ext(DeviceLinkIndex.name) as? YapDatabaseSecondaryIndexTransaction else { - print("[Loki] Couldn't get device link index database extension.") - return [] - } - var result: [DeviceLink] = [] - ext.enumerateKeysAndObjects(matching: query) { _, _, object, _ in - guard let deviceLink = object as? DeviceLink else { return } - result.append(deviceLink) - } - return result - } -} diff --git a/SignalUtilitiesKit/DeviceLinkingSession.swift b/SignalUtilitiesKit/DeviceLinkingSession.swift deleted file mode 100644 index b3b0bd1e1..000000000 --- a/SignalUtilitiesKit/DeviceLinkingSession.swift +++ /dev/null @@ -1,69 +0,0 @@ -import Curve25519Kit -import PromiseKit - -@objc (LKDeviceLinkingSession) -public final class DeviceLinkingSession : NSObject { - private let delegate: DeviceLinkingSessionDelegate - @objc public var isListeningForLinkingRequests = false - @objc public var isProcessingLinkingRequest = false - @objc public var isListeningForLinkingAuthorization = false - - // MARK: Lifecycle - @objc public static var current: DeviceLinkingSession? - - private init(delegate: DeviceLinkingSessionDelegate) { - self.delegate = delegate - } - - // MARK: Public API - public static func startListeningForLinkingRequests(with delegate: DeviceLinkingSessionDelegate) -> DeviceLinkingSession { - let session = DeviceLinkingSession(delegate: delegate) - session.isListeningForLinkingRequests = true - DeviceLinkingSession.current = session - return session - } - - public static func startListeningForLinkingAuthorization(with delegate: DeviceLinkingSessionDelegate) -> DeviceLinkingSession { - let session = DeviceLinkingSession(delegate: delegate) - session.isListeningForLinkingAuthorization = true - DeviceLinkingSession.current = session - return session - } - - @objc public func processLinkingRequest(from slavePublicKey: String, to masterPublicKey: String, with slaveSignature: Data) { - guard isListeningForLinkingRequests, !isProcessingLinkingRequest, masterPublicKey == getUserHexEncodedPublicKey() else { return } - let master = DeviceLink.Device(publicKey: masterPublicKey) - let slave = DeviceLink.Device(publicKey: slavePublicKey, signature: slaveSignature) - let deviceLink = DeviceLink(between: master, and: slave) - guard DeviceLinkingUtilities.hasValidSlaveSignature(deviceLink) else { return } - isProcessingLinkingRequest = true - DispatchQueue.main.async { - self.delegate.requestUserAuthorization(for: deviceLink) - } - } - - @objc public func processLinkingAuthorization(from masterPublicKey: String, for slavePublicKey: String, masterSignature: Data, slaveSignature: Data) { - guard isListeningForLinkingAuthorization, slavePublicKey == getUserHexEncodedPublicKey() else { return } - let master = DeviceLink.Device(publicKey: masterPublicKey, signature: masterSignature) - let slave = DeviceLink.Device(publicKey: slavePublicKey, signature: slaveSignature) - let deviceLink = DeviceLink(between: master, and: slave) - guard DeviceLinkingUtilities.hasValidSlaveSignature(deviceLink) && DeviceLinkingUtilities.hasValidMasterSignature(deviceLink) else { return } - DispatchQueue.main.async { - self.delegate.handleDeviceLinkAuthorized(deviceLink) - } - } - - public func stopListeningForLinkingRequests() { - DeviceLinkingSession.current = nil - isListeningForLinkingRequests = false - } - - public func stopListeningForLinkingAuthorization() { - DeviceLinkingSession.current = nil - isListeningForLinkingAuthorization = false - } - - public func markLinkingRequestAsProcessed() { - isProcessingLinkingRequest = false - } -} diff --git a/SignalUtilitiesKit/DeviceLinkingSessionDelegate.swift b/SignalUtilitiesKit/DeviceLinkingSessionDelegate.swift deleted file mode 100644 index ab806251c..000000000 --- a/SignalUtilitiesKit/DeviceLinkingSessionDelegate.swift +++ /dev/null @@ -1,6 +0,0 @@ - -public protocol DeviceLinkingSessionDelegate { - - func requestUserAuthorization(for deviceLink: DeviceLink) - func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) -} diff --git a/SignalUtilitiesKit/DeviceLinkingUtilities.swift b/SignalUtilitiesKit/DeviceLinkingUtilities.swift deleted file mode 100644 index 8893a1106..000000000 --- a/SignalUtilitiesKit/DeviceLinkingUtilities.swift +++ /dev/null @@ -1,57 +0,0 @@ - -@objc(LKDeviceLinkingUtilities) -public final class DeviceLinkingUtilities : NSObject { - private static var lastUnexpectedDeviceLinkRequestDate: Date? = nil - - private override init() { } - - @objc public static var shouldShowUnexpectedDeviceLinkRequestReceivedAlert: Bool { - let now = Date() - if let lastUnexpectedDeviceLinkRequestDate = lastUnexpectedDeviceLinkRequestDate { - if now.timeIntervalSince(lastUnexpectedDeviceLinkRequestDate) < 30 { return false } - } - lastUnexpectedDeviceLinkRequestDate = now - return true - } - - // When requesting a device link, the slave device signs the master device's public key. When authorizing - // a device link, the master device signs the slave device's public key. - - public static func getLinkingRequestMessage(for masterPublicKey: String) -> DeviceLinkMessage { - let slaveKeyPair = OWSIdentityManager.shared().identityKeyPair()! - let slavePublicKey = slaveKeyPair.hexEncodedPublicKey - var kind = UInt8(LKDeviceLinkMessageKind.request.rawValue) - let data = Data(hex: masterPublicKey) + Data(bytes: &kind, count: MemoryLayout.size(ofValue: kind)) - let slaveSignature = try! Ed25519.sign(data, with: slaveKeyPair) - let thread = TSContactThread.getOrCreateThread(contactId: masterPublicKey) - return DeviceLinkMessage(in: thread, masterPublicKey: masterPublicKey, slavePublicKey: slavePublicKey, masterSignature: nil, slaveSignature: slaveSignature) - } - - public static func getLinkingAuthorizationMessage(for deviceLink: DeviceLink) -> DeviceLinkMessage { - let masterKeyPair = OWSIdentityManager.shared().identityKeyPair()! - let masterPublicKey = masterKeyPair.hexEncodedPublicKey - let slavePublicKey = deviceLink.slave.publicKey - var kind = UInt8(LKDeviceLinkMessageKind.authorization.rawValue) - let data = Data(hex: slavePublicKey) + Data(bytes: &kind, count: MemoryLayout.size(ofValue: kind)) - let masterSignature = try! Ed25519.sign(data, with: masterKeyPair) - let slaveSignature = deviceLink.slave.signature! - let thread = TSContactThread.getOrCreateThread(contactId: slavePublicKey) - return DeviceLinkMessage(in: thread, masterPublicKey: masterPublicKey, slavePublicKey: slavePublicKey, masterSignature: masterSignature, slaveSignature: slaveSignature) - } - - public static func hasValidSlaveSignature(_ deviceLink: DeviceLink) -> Bool { - guard let slaveSignature = deviceLink.slave.signature else { return false } - let slavePublicKey = Data(hex: deviceLink.slave.publicKey.removing05PrefixIfNeeded()) - var kind = UInt8(LKDeviceLinkMessageKind.request.rawValue) - let data = Data(hex: deviceLink.master.publicKey) + Data(bytes: &kind, count: MemoryLayout.size(ofValue: kind)) - return (try? Ed25519.verifySignature(slaveSignature, publicKey: slavePublicKey, data: data)) ?? false - } - - public static func hasValidMasterSignature(_ deviceLink: DeviceLink) -> Bool { - guard let masterSignature = deviceLink.master.signature else { return false } - let masterPublicKey = Data(hex: deviceLink.master.publicKey.removing05PrefixIfNeeded()) - var kind = UInt8(LKDeviceLinkMessageKind.authorization.rawValue) - let data = Data(hex: deviceLink.slave.publicKey) + Data(bytes: &kind, count: MemoryLayout.size(ofValue: kind)) - return (try? Ed25519.verifySignature(masterSignature, publicKey: masterPublicKey, data: data)) ?? false - } -} diff --git a/SignalUtilitiesKit/DeviceNames.swift b/SignalUtilitiesKit/DeviceNames.swift deleted file mode 100644 index e349a56f4..000000000 --- a/SignalUtilitiesKit/DeviceNames.swift +++ /dev/null @@ -1,218 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import Curve25519Kit -import SignalCoreKit - -@objc -public enum DeviceNameError: Int, Error { - case assertionFailure - case invalidInput -} - -@objc -public class DeviceNames: NSObject { - // Never instantiate this class. - private override init() {} - - private static let syntheticIVLength: UInt = 16 - - @objc - public class func encryptDeviceName(plaintext: String, - identityKeyPair: ECKeyPair) throws -> Data { - - guard let plaintextData = plaintext.data(using: .utf8) else { - owsFailDebug("Could not convert text to UTF-8.") - throw DeviceNameError.invalidInput - } - - let ephemeralKeyPair = Curve25519.generateKeyPair() - - // master_secret = ECDH(ephemeral_private, identity_public). - let masterSecret: Data - do { - masterSecret = try Curve25519.generateSharedSecret(fromPublicKey: identityKeyPair.publicKey, privateKey: ephemeralKeyPair.privateKey) - } catch { - Logger.error("Could not generate shared secret: \(error)") - throw error - } - - // synthetic_iv = HmacSHA256(key=HmacSHA256(key=master_secret, input=“auth”), input=plaintext)[0:16] - let syntheticIV = try computeSyntheticIV(masterSecret: masterSecret, - plaintextData: plaintextData) - - // cipher_key = HmacSHA256(key=HmacSHA256(key=master_secret, “cipher”), input=synthetic_iv) - let cipherKey = try computeCipherKey(masterSecret: masterSecret, syntheticIV: syntheticIV) - - // cipher_text = AES-CTR(key=cipher_key, input=plaintext, counter=0) - // - // An all-zeros IV corresponds to an AES CTR counter of zero. - let ciphertextIV = Data(count: Int(kAES256CTR_IVLength)) - guard let ciphertextKey = OWSAES256Key(data: cipherKey) else { - owsFailDebug("Invalid cipher key.") - throw DeviceNameError.assertionFailure - } - guard let ciphertext: AES256CTREncryptionResult = Cryptography.encryptAESCTR(plaintextData: plaintextData, initializationVector: ciphertextIV, key: ciphertextKey) else { - owsFailDebug("Could not encrypt cipher text.") - throw DeviceNameError.assertionFailure - } - - guard let keyData = (ephemeralKeyPair.publicKey as NSData).prependKeyType() else { - owsFailDebug("Could not prepend key type.") - throw DeviceNameError.assertionFailure - } - let protoBuilder = SignalIOSProtoDeviceName.builder(ephemeralPublic: keyData as Data, - syntheticIv: syntheticIV, - ciphertext: ciphertext.ciphertext) - let protoData = try protoBuilder.buildSerializedData() - - // NOTE: This uses Data's foundation method rather than the NSData's SSK method. - let protoDataBase64 = protoData.base64EncodedData() - - return protoDataBase64 - } - - private class func computeSyntheticIV(masterSecret: Data, - plaintextData: Data) throws -> Data { - // synthetic_iv = HmacSHA256(key=HmacSHA256(key=master_secret, input=“auth”), input=plaintext)[0:16] - guard let syntheticIVInput = "auth".data(using: .utf8) else { - owsFailDebug("Could not convert text to UTF-8.") - throw DeviceNameError.assertionFailure - } - guard let syntheticIVKey = Cryptography.computeSHA256HMAC(syntheticIVInput, withHMACKey: masterSecret) else { - owsFailDebug("Could not compute synthetic IV key.") - throw DeviceNameError.assertionFailure - } - guard let syntheticIV = Cryptography.truncatedSHA256HMAC(plaintextData, withHMACKey: syntheticIVKey, truncation: syntheticIVLength) else { - owsFailDebug("Could not compute synthetic IV.") - throw DeviceNameError.assertionFailure - } - return syntheticIV - } - - private class func computeCipherKey(masterSecret: Data, - syntheticIV: Data) throws -> Data { - // cipher_key = HmacSHA256(key=HmacSHA256(key=master_secret, “cipher”), input=synthetic_iv) - guard let cipherKeyInput = "cipher".data(using: .utf8) else { - owsFailDebug("Could not convert text to UTF-8.") - throw DeviceNameError.assertionFailure - } - guard let cipherKeyKey = Cryptography.computeSHA256HMAC(cipherKeyInput, withHMACKey: masterSecret) else { - owsFailDebug("Could not compute cipher key key.") - throw DeviceNameError.assertionFailure - } - guard let cipherKey = Cryptography.computeSHA256HMAC(syntheticIV, withHMACKey: cipherKeyKey) else { - owsFailDebug("Could not compute cipher key.") - throw DeviceNameError.assertionFailure - } - return cipherKey - } - - @objc - public class func decryptDeviceName(base64String: String, - identityKeyPair: ECKeyPair) throws -> String { - - guard let protoData = Data(base64Encoded: base64String) else { - // Not necessarily an error; might be a legacy device name. - throw DeviceNameError.invalidInput - } - - return try decryptDeviceName(protoData: protoData, - identityKeyPair: identityKeyPair) - } - - @objc - public class func decryptDeviceName(base64Data: Data, - identityKeyPair: ECKeyPair) throws -> String { - - guard let protoData = Data(base64Encoded: base64Data) else { - // Not necessarily an error; might be a legacy device name. - throw DeviceNameError.invalidInput - } - - return try decryptDeviceName(protoData: protoData, - identityKeyPair: identityKeyPair) - } - - @objc - public class func decryptDeviceName(protoData: Data, - identityKeyPair: ECKeyPair) throws -> String { - - let proto: SignalIOSProtoDeviceName - do { - proto = try SignalIOSProtoDeviceName.parseData(protoData) - } catch { - // Not necessarily an error; might be a legacy device name. - Logger.error("failed to parse proto") - throw DeviceNameError.invalidInput - } - - let ephemeralPublicData = proto.ephemeralPublic - let receivedSyntheticIV = proto.syntheticIv - let ciphertext = proto.ciphertext - - let ephemeralPublic: Data - do { - ephemeralPublic = try (ephemeralPublicData as NSData).removeKeyType() as Data - } catch { - owsFailDebug("failed to remove key type") - throw DeviceNameError.invalidInput - } - - guard ephemeralPublic.count > 0 else { - owsFailDebug("Invalid ephemeral public.") - throw DeviceNameError.assertionFailure - } - guard receivedSyntheticIV.count == syntheticIVLength else { - owsFailDebug("Invalid synthetic IV.") - throw DeviceNameError.assertionFailure - } - guard ciphertext.count > 0 else { - owsFailDebug("Invalid cipher text.") - throw DeviceNameError.assertionFailure - } - - // master_secret = ECDH(identity_private, ephemeral_public) - let masterSecret: Data - do { - masterSecret = try Curve25519.generateSharedSecret(fromPublicKey: ephemeralPublic, privateKey: identityKeyPair.privateKey) - } catch { - Logger.error("Could not generate shared secret: \(error)") - throw error - } - - // cipher_key = HmacSHA256(key=HmacSHA256(key=master_secret, input=“cipher”), input=synthetic_iv) - let cipherKey = try computeCipherKey(masterSecret: masterSecret, syntheticIV: receivedSyntheticIV) - - // plaintext = AES-CTR(key=cipher_key, input=ciphertext, counter=0) - // - // An all-zeros IV corresponds to an AES CTR counter of zero. - let ciphertextIV = Data(count: Int(kAES256CTR_IVLength)) - guard let ciphertextKey = OWSAES256Key(data: cipherKey) else { - owsFailDebug("Invalid cipher key.") - throw DeviceNameError.assertionFailure - } - guard let plaintextData = Cryptography.decryptAESCTR(cipherText: ciphertext, initializationVector: ciphertextIV, key: ciphertextKey) else { - owsFailDebug("Could not decrypt cipher text.") - throw DeviceNameError.assertionFailure - } - - // Verify the synthetic IV was correct. - // constant_time_compare(HmacSHA256(key=HmacSHA256(key=master_secret, input=”auth”), input=plaintext)[0:16], synthetic_iv) == true - let computedSyntheticIV = try computeSyntheticIV(masterSecret: masterSecret, - plaintextData: plaintextData) - guard receivedSyntheticIV.ows_constantTimeIsEqual(to: computedSyntheticIV) else { - owsFailDebug("Synthetic IV did not match.") - throw DeviceNameError.assertionFailure - } - - guard let plaintext = String(bytes: plaintextData, encoding: .utf8) else { - owsFailDebug("Invalid plaintext.") - throw DeviceNameError.invalidInput - } - - return plaintext - } -} diff --git a/SignalUtilitiesKit/EditContactShareNameViewController.swift b/SignalUtilitiesKit/EditContactShareNameViewController.swift deleted file mode 100644 index 9cd8b4fb3..000000000 --- a/SignalUtilitiesKit/EditContactShareNameViewController.swift +++ /dev/null @@ -1,332 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -public protocol ContactNameFieldViewDelegate: class { - func nameFieldDidChange() -} - -// MARK: - - -class ContactNameFieldView: UIView { - weak var delegate: ContactNameFieldViewDelegate? - - let name: String - let initialValue: String? - - var valueView: UITextField! - - var hasUnsavedChanges = false - - // MARK: - Initializers - - @available(*, unavailable, message: "use other constructor instead.") - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - required init(name: String, value: String?, delegate: ContactNameFieldViewDelegate) { - self.name = name - self.initialValue = value - self.delegate = delegate - - super.init(frame: CGRect.zero) - - self.isUserInteractionEnabled = true - self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(wasTapped))) - - createContents() - } - - private let hMargin = CGFloat(16) - private let vMargin = CGFloat(10) - - func createContents() { - self.layoutMargins = UIEdgeInsets(top: vMargin, left: hMargin, bottom: vMargin, right: hMargin) - - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.alignment = .center - stackView.layoutMargins = .zero - stackView.spacing = 10 - self.addSubview(stackView) - stackView.autoPinEdgesToSuperviewMargins() - - let nameLabel = UILabel() - nameLabel.text = name - nameLabel.font = UIFont.ows_dynamicTypeBody - nameLabel.textColor = UIColor.ows_materialBlue - nameLabel.lineBreakMode = .byTruncatingTail - stackView.addArrangedSubview(nameLabel) - nameLabel.setContentHuggingHigh() - nameLabel.setCompressionResistanceHigh() - - valueView = UITextField() - if let initialValue = initialValue { - valueView.text = initialValue - } - valueView.font = UIFont.ows_dynamicTypeBody - valueView.textColor = Theme.primaryColor - stackView.addArrangedSubview(valueView) - - valueView.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged) - } - - @objc func wasTapped(sender: UIGestureRecognizer) { - Logger.info("") - - guard sender.state == .recognized else { - return - } - - valueView.becomeFirstResponder() - } - - @objc func textFieldDidChange(sender: UITextField) { - Logger.info("") - - hasUnsavedChanges = true - - guard let delegate = self.delegate else { - owsFailDebug("missing delegate.") - return - } - - delegate.nameFieldDidChange() - } - - public func value() -> String { - guard let value = valueView.text else { - return "" - } - return value - } -} - -// MARK: - - -@objc -public protocol EditContactShareNameViewControllerDelegate: class { - func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, - didEditContactShare contactShare: ContactShareViewModel) -} - -// MARK: - - -@objc -public class EditContactShareNameViewController: OWSViewController, ContactNameFieldViewDelegate { - weak var delegate: EditContactShareNameViewControllerDelegate? - - let contactShare: ContactShareViewModel - - var namePrefixView: ContactNameFieldView! - var givenNameView: ContactNameFieldView! - var middleNameView: ContactNameFieldView! - var familyNameView: ContactNameFieldView! - var nameSuffixView: ContactNameFieldView! - var organizationNameView: ContactNameFieldView! - - var fieldViews = [ContactNameFieldView]() - - // MARK: Initializers - - @available(*, unavailable, message:"use other constructor instead.") - required public init?(coder aDecoder: NSCoder) { - notImplemented() - } - - @objc - required public init(contactShare: ContactShareViewModel, delegate: EditContactShareNameViewControllerDelegate) { - self.contactShare = contactShare - self.delegate = delegate - - super.init(nibName: nil, bundle: nil) - - buildFields() - } - - func buildFields() { - namePrefixView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_NAME_PREFIX", - comment: "Label for the 'name prefix' field of a contact."), - value: contactShare.name.namePrefix, delegate: self) - givenNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_GIVEN_NAME", - comment: "Label for the 'given name' field of a contact."), - value: contactShare.name.givenName, delegate: self) - middleNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_MIDDLE_NAME", - comment: "Label for the 'middle name' field of a contact."), - value: contactShare.name.middleName, delegate: self) - familyNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_FAMILY_NAME", - comment: "Label for the 'family name' field of a contact."), - value: contactShare.name.familyName, delegate: self) - nameSuffixView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_NAME_SUFFIX", - comment: "Label for the 'name suffix' field of a contact."), - value: contactShare.name.nameSuffix, delegate: self) - organizationNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_ORGANIZATION", - comment: "Label for the 'organization' field of a contact."), - value: contactShare.name.organizationName, delegate: self) - fieldViews = [ - namePrefixView , - givenNameView , - middleNameView , - familyNameView , - nameSuffixView, - organizationNameView - ] - } - - override public var canBecomeFirstResponder: Bool { - return true - } - - // MARK: - View Lifecycle - - override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - updateNavigationBar() - } - - override public func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - } - - override public func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - } - - override public func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - } - - override public func loadView() { - super.loadView() - - self.navigationItem.title = NSLocalizedString("CONTACT_SHARE_EDIT_NAME_VIEW_TITLE", - comment: "Title for the 'edit contact share name' view.") - - self.view.preservesSuperviewLayoutMargins = false - self.view.backgroundColor = Theme.backgroundColor - - updateContent() - - updateNavigationBar() - } - - func hasUnsavedChanges() -> Bool { - for fieldView in fieldViews { - if fieldView.hasUnsavedChanges { - return true - } - } - return false - } - - func updateNavigationBar() { - self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, - target: self, - action: #selector(didPressCancel)) - - if hasUnsavedChanges() { - self.navigationItem.rightBarButtonItem = - UIBarButtonItem(barButtonSystemItem: .save, - target: self, - action: #selector(didPressSave)) - } else { - self.navigationItem.rightBarButtonItem = nil - } - } - - private func updateContent() { - AssertIsOnMainThread() - - guard let rootView = self.view else { - owsFailDebug("missing root view.") - return - } - - for subview in rootView.subviews { - subview.removeFromSuperview() - } - - let scrollView = UIScrollView() - scrollView.preservesSuperviewLayoutMargins = false - self.view.addSubview(scrollView) - scrollView.layoutMargins = .zero - scrollView.autoPinWidthToSuperview() - scrollView.autoPinEdge(.top, to: .top, of: view) - scrollView.autoPinEdge(toSuperviewEdge: .bottom) - - let fieldsView = createFieldsView() - - scrollView.addSubview(fieldsView) - fieldsView.autoPinLeadingToSuperviewMargin() - fieldsView.autoPinTrailingToSuperviewMargin() - fieldsView.autoPinEdge(toSuperviewEdge: .top) - fieldsView.autoPinEdge(toSuperviewEdge: .bottom) - } - - private func createFieldsView() -> UIView { - AssertIsOnMainThread() - - var rows = [UIView]() - - for fieldView in fieldViews { - rows.append(fieldView) - } - - return ContactFieldView(rows: rows, hMargin: hMargin) - } - - private let hMargin = CGFloat(16) - - // MARK: - - - @objc func didPressSave() { - Logger.info("") - - guard let newName = OWSContactName() else { - owsFailDebug("could not create a new name.") - return - } - newName.namePrefix = namePrefixView.value().ows_stripped() - newName.givenName = givenNameView.value().ows_stripped() - newName.middleName = middleNameView.value().ows_stripped() - newName.familyName = familyNameView.value().ows_stripped() - newName.nameSuffix = nameSuffixView.value().ows_stripped() - newName.organizationName = organizationNameView.value().ows_stripped() - - let modifiedContactShare = contactShare.copy(withName: newName) - - guard let delegate = self.delegate else { - owsFailDebug("missing delegate.") - return - } - - delegate.editContactShareNameView(self, didEditContactShare: modifiedContactShare) - - guard let navigationController = self.navigationController else { - owsFailDebug("Missing navigationController.") - return - } - navigationController.popViewController(animated: true) - } - - @objc func didPressCancel() { - Logger.info("") - - guard let navigationController = self.navigationController else { - owsFailDebug("Missing navigationController.") - return - } - navigationController.popViewController(animated: true) - } - - // MARK: - ContactNameFieldViewDelegate - - public func nameFieldDidChange() { - updateNavigationBar() - } -} diff --git a/SignalUtilitiesKit/EncryptionUtilities.swift b/SignalUtilitiesKit/EncryptionUtilities.swift deleted file mode 100644 index cdb4db90f..000000000 --- a/SignalUtilitiesKit/EncryptionUtilities.swift +++ /dev/null @@ -1,38 +0,0 @@ -import CryptoSwift - -internal typealias EncryptionResult = (ciphertext: Data, symmetricKey: Data, ephemeralPublicKey: Data) - -enum EncryptionUtilities { - internal static let gcmTagSize: UInt = 16 - internal static let ivSize: UInt = 12 - - /// - Note: Sync. Don't call from the main thread. - internal static func encrypt(_ plaintext: Data, usingAESGCMWithSymmetricKey symmetricKey: Data) throws -> Data { - if Thread.isMainThread { - #if DEBUG - preconditionFailure("It's illegal to call encrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.") - #endif - } - let iv = Data.getSecureRandomData(ofSize: ivSize)! - let gcm = GCM(iv: iv.bytes, tagLength: Int(gcmTagSize), mode: .combined) - let aes = try AES(key: symmetricKey.bytes, blockMode: gcm, padding: .noPadding) - let ciphertext = try aes.encrypt(plaintext.bytes) - return iv + Data(ciphertext) - } - - /// - Note: Sync. Don't call from the main thread. - internal static func encrypt(_ plaintext: Data, using hexEncodedX25519PublicKey: String) throws -> EncryptionResult { - if Thread.isMainThread { - #if DEBUG - preconditionFailure("It's illegal to call encrypt(_:forSnode:) from the main thread.") - #endif - } - let x25519PublicKey = Data(hex: hexEncodedX25519PublicKey) - let ephemeralKeyPair = Curve25519.generateKeyPair() - let ephemeralSharedSecret = try! Curve25519.generateSharedSecret(fromPublicKey: x25519PublicKey, privateKey: ephemeralKeyPair.privateKey) - let salt = "LOKI" - let symmetricKey = try HMAC(key: salt.bytes, variant: .sha256).authenticate(ephemeralSharedSecret.bytes) - let ciphertext = try encrypt(plaintext, usingAESGCMWithSymmetricKey: Data(bytes: symmetricKey)) - return (ciphertext, Data(bytes: symmetricKey), ephemeralKeyPair.publicKey) - } -} diff --git a/SignalUtilitiesKit/Environment.h b/SignalUtilitiesKit/Environment.h index 10b08c09f..64d7ddc61 100644 --- a/SignalUtilitiesKit/Environment.h +++ b/SignalUtilitiesKit/Environment.h @@ -1,7 +1,6 @@ #import @class OWSAudioSession; -@class OWSContactsManager; @class OWSPreferences; @class OWSSounds; @class OWSWindowManager; @@ -26,7 +25,6 @@ windowManager:(OWSWindowManager *)windowManager; @property (nonatomic, readonly) OWSAudioSession *audioSession; -@property (nonatomic, readonly) OWSContactsManager *contactsManager; @property (nonatomic, readonly) id proximityMonitoringManager; @property (nonatomic, readonly) OWSPreferences *preferences; @property (nonatomic, readonly) OWSSounds *sounds; diff --git a/SignalUtilitiesKit/Environment.m b/SignalUtilitiesKit/Environment.m index 0e591e592..2f282d3cc 100644 --- a/SignalUtilitiesKit/Environment.m +++ b/SignalUtilitiesKit/Environment.m @@ -1,6 +1,6 @@ + #import #import "SSKAsserts.h" -#import "OWSContactsManager.h" #import "OWSWindowManager.h" #import #import "OWSPreferences.h" @@ -11,7 +11,6 @@ static Environment *sharedEnvironment = nil; @interface Environment () @property (nonatomic) OWSAudioSession *audioSession; -@property (nonatomic) OWSContactsManager *contactsManager; @property (nonatomic) OWSPreferences *preferences; @property (nonatomic) id proximityMonitoringManager; @property (nonatomic) OWSSounds *sounds; @@ -54,6 +53,7 @@ static Environment *sharedEnvironment = nil; windowManager:(OWSWindowManager *)windowManager { self = [super init]; + if (!self) { return self; } @@ -75,9 +75,4 @@ static Environment *sharedEnvironment = nil; return self; } -- (OWSContactsManager *)contactsManager -{ - return (OWSContactsManager *)SSKEnvironment.shared.contactsManager; -} - @end diff --git a/SignalUtilitiesKit/FileServerAPI+Deprecated.swift b/SignalUtilitiesKit/FileServerAPI+Deprecated.swift deleted file mode 100644 index 1fd608a6f..000000000 --- a/SignalUtilitiesKit/FileServerAPI+Deprecated.swift +++ /dev/null @@ -1,148 +0,0 @@ -import PromiseKit - -public extension FileServerAPI { - - /// Gets the device links associated with the given hex encoded public key from the - /// server and stores and returns the valid ones. - /// - /// - Note: Deprecated. - public static func getDeviceLinks(associatedWith hexEncodedPublicKey: String) -> Promise> { - return getDeviceLinks(associatedWith: [ hexEncodedPublicKey ]) - } - - /// Gets the device links associated with the given hex encoded public keys from the - /// server and stores and returns the valid ones. - /// - /// - Note: Deprecated. - public static func getDeviceLinks(associatedWith hexEncodedPublicKeys: Set) -> Promise> { - return Promise.value([]) - /* - let hexEncodedPublicKeysDescription = "[ \(hexEncodedPublicKeys.joined(separator: ", ")) ]" - print("[Loki] Getting device links for: \(hexEncodedPublicKeysDescription).") - return getAuthToken(for: server).then2 { token -> Promise> in - let queryParameters = "ids=\(hexEncodedPublicKeys.map { "@\($0)" }.joined(separator: ","))&include_user_annotations=1" - let url = URL(string: "\(server)/users?\(queryParameters)")! - let request = TSRequest(url: url) - return OnionRequestAPI.sendOnionRequest(request, to: server, using: fileServerPublicKey).map2 { rawResponse -> Set in - guard let data = rawResponse["data"] as? [JSON] else { - print("[Loki] Couldn't parse device links for users: \(hexEncodedPublicKeys) from: \(rawResponse).") - throw DotNetAPIError.parsingFailed - } - return Set(data.flatMap { data -> [DeviceLink] in - guard let annotations = data["annotations"] as? [JSON], !annotations.isEmpty else { return [] } - guard let annotation = annotations.first(where: { $0["type"] as? String == deviceLinkType }), - let value = annotation["value"] as? JSON, let rawDeviceLinks = value["authorisations"] as? [JSON], - let hexEncodedPublicKey = data["username"] as? String else { - print("[Loki] Couldn't parse device links from: \(rawResponse).") - return [] - } - return rawDeviceLinks.compactMap { rawDeviceLink in - guard let masterPublicKey = rawDeviceLink["primaryDevicePubKey"] as? String, let slavePublicKey = rawDeviceLink["secondaryDevicePubKey"] as? String, - let base64EncodedSlaveSignature = rawDeviceLink["requestSignature"] as? String else { - print("[Loki] Couldn't parse device link for user: \(hexEncodedPublicKey) from: \(rawResponse).") - return nil - } - let masterSignature: Data? - if let base64EncodedMasterSignature = rawDeviceLink["grantSignature"] as? String { - masterSignature = Data(base64Encoded: base64EncodedMasterSignature) - } else { - masterSignature = nil - } - let slaveSignature = Data(base64Encoded: base64EncodedSlaveSignature) - let master = DeviceLink.Device(publicKey: masterPublicKey, signature: masterSignature) - let slave = DeviceLink.Device(publicKey: slavePublicKey, signature: slaveSignature) - let deviceLink = DeviceLink(between: master, and: slave) - if let masterSignature = masterSignature { - guard DeviceLinkingUtilities.hasValidMasterSignature(deviceLink) else { - print("[Loki] Received a device link with an invalid master signature.") - return nil - } - } - guard DeviceLinkingUtilities.hasValidSlaveSignature(deviceLink) else { - print("[Loki] Received a device link with an invalid slave signature.") - return nil - } - return deviceLink - } - }) - }.map2 { deviceLinks in - storage.setDeviceLinks(deviceLinks) - return deviceLinks - } - }.handlingInvalidAuthTokenIfNeeded(for: server) - */ - } - - /// - Note: Deprecated. - public static func setDeviceLinks(_ deviceLinks: Set) -> Promise { - return Promise.value(()) - /* - print("[Loki] Updating device links.") - return getAuthToken(for: server).then2 { token -> Promise in - let isMaster = deviceLinks.contains { $0.master.publicKey == getUserHexEncodedPublicKey() } - let deviceLinksAsJSON = deviceLinks.map { $0.toJSON() } - let value = !deviceLinksAsJSON.isEmpty ? [ "isPrimary" : isMaster ? 1 : 0, "authorisations" : deviceLinksAsJSON ] : nil - let annotation: JSON = [ "type" : deviceLinkType, "value" : value ] - let parameters: JSON = [ "annotations" : [ annotation ] ] - let url = URL(string: "\(server)/users/me")! - let request = TSRequest(url: url, method: "PATCH", parameters: parameters) - request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ] - return attempt(maxRetryCount: 8, recoveringOn: SnodeAPI.workQueue) { - OnionRequestAPI.sendOnionRequest(request, to: server, using: fileServerPublicKey).map2 { _ in } - }.handlingInvalidAuthTokenIfNeeded(for: server).recover2 { error in - print("[Loki] Couldn't update device links due to error: \(error).") - throw error - } - } - */ - } - - /// Adds the given device link to the user's device mapping on the server. - /// - /// - Note: Deprecated. - public static func addDeviceLink(_ deviceLink: DeviceLink) -> Promise { - return Promise.value(()) - /* - var deviceLinks: Set = [] - storage.dbReadConnection.read { transaction in - deviceLinks = storage.getDeviceLinks(for: getUserHexEncodedPublicKey(), in: transaction) - } - deviceLinks.insert(deviceLink) - return setDeviceLinks(deviceLinks).map2 { _ in - storage.addDeviceLink(deviceLink) - } - */ - } - - /// Removes the given device link from the user's device mapping on the server. - /// - /// - Note: Deprecated. - public static func removeDeviceLink(_ deviceLink: DeviceLink) -> Promise { - return Promise.value(()) - /* - var deviceLinks: Set = [] - storage.dbReadConnection.read { transaction in - deviceLinks = storage.getDeviceLinks(for: getUserHexEncodedPublicKey(), in: transaction) - } - deviceLinks.remove(deviceLink) - return setDeviceLinks(deviceLinks).map2 { _ in - storage.removeDeviceLink(deviceLink) - } - */ - } -} - -@objc public extension FileServerAPI { - - /// - Note: Deprecated. - @objc(getDeviceLinksAssociatedWithHexEncodedPublicKey:) - public static func objc_getDeviceLinks(associatedWith hexEncodedPublicKey: String) -> AnyPromise { - return AnyPromise.from(getDeviceLinks(associatedWith: hexEncodedPublicKey)) - } - - /// - Note: Deprecated. - @objc(getDeviceLinksAssociatedWithHexEncodedPublicKeys:) - public static func objc_getDeviceLinks(associatedWith hexEncodedPublicKeys: Set) -> AnyPromise { - return AnyPromise.from(getDeviceLinks(associatedWith: hexEncodedPublicKeys)) - } -} diff --git a/SignalUtilitiesKit/FullTextSearchFinder.swift b/SignalUtilitiesKit/FullTextSearchFinder.swift index 1fcd44e96..d6a3913b1 100644 --- a/SignalUtilitiesKit/FullTextSearchFinder.swift +++ b/SignalUtilitiesKit/FullTextSearchFinder.swift @@ -155,10 +155,6 @@ public class FullTextSearchFinder: NSObject { // MARK: - Index Building - private class var contactsManager: ContactsManagerProtocol { - return SSKEnvironment.shared.contactsManager - } - private static let groupThreadIndexer: SearchIndexer = SearchIndexer { (groupThread: TSGroupThread, transaction: YapDatabaseReadTransaction) in let groupName = groupThread.groupModel.groupName ?? "" @@ -185,24 +181,9 @@ public class FullTextSearchFinder: NSObject { } private static let recipientIndexer: SearchIndexer = SearchIndexer { (recipientId: String, transaction: YapDatabaseReadTransaction) in - let displayName = contactsManager.displayName(forPhoneIdentifier: recipientId, transaction: transaction) + let displayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true) - let nationalNumber: String = { (recipientId: String) -> String in - - guard let phoneNumber = PhoneNumber(fromE164: recipientId) else { - owsFailDebug("unexpected unparseable recipientId: \(recipientId)") - return "" - } - - guard let digitScalars = phoneNumber.nationalNumber?.unicodeScalars.filter({ CharacterSet.decimalDigits.contains($0) }) else { - owsFailDebug("unexpected unparseable recipientId: \(recipientId)") - return "" - } - - return String(String.UnicodeScalarView(digitScalars)) - }(recipientId) - - return "\(recipientId) \(nationalNumber) \(displayName)" + return "\(recipientId) \(displayName)" } private static let messageIndexer: SearchIndexer = SearchIndexer { (message: TSMessage, transaction: YapDatabaseReadTransaction) in diff --git a/SignalUtilitiesKit/FullTextSearcher.swift b/SignalUtilitiesKit/FullTextSearcher.swift index 285b5c332..d711bd614 100644 --- a/SignalUtilitiesKit/FullTextSearcher.swift +++ b/SignalUtilitiesKit/FullTextSearcher.swift @@ -438,14 +438,9 @@ public class FullTextSearcher: NSObject { return result } - private var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - private func indexingString(recipientId: String) -> String { - let contactName = contactsManager.displayName(forPhoneIdentifier: recipientId) - let profileName = contactsManager.profileName(forRecipientId: recipientId) + let profileName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true) - return "\(recipientId) \(contactName) \(profileName ?? "")" + return "\(recipientId) \(profileName ?? "")" } } diff --git a/SignalUtilitiesKit/GroupUtilities.swift b/SignalUtilitiesKit/GroupUtilities.swift index 69b5f9ff1..51f6640a5 100644 --- a/SignalUtilitiesKit/GroupUtilities.swift +++ b/SignalUtilitiesKit/GroupUtilities.swift @@ -10,9 +10,7 @@ public enum GroupUtilities { } public static func getClosedGroupMembers(_ closedGroup: TSGroupThread, with transaction: YapDatabaseReadTransaction) -> [String] { - return closedGroup.groupModel.groupMemberIds.filter { member in - OWSPrimaryStorage.shared().getMasterHexEncodedPublicKey(for: member, in: transaction) == nil // Don't show slave devices - } + return closedGroup.groupModel.groupMemberIds } public static func getClosedGroupMemberCount(_ closedGroup: TSGroupThread) -> Int { diff --git a/SignalUtilitiesKit/LKDeviceLinkMessage.h b/SignalUtilitiesKit/LKDeviceLinkMessage.h deleted file mode 100644 index 783078a42..000000000 --- a/SignalUtilitiesKit/LKDeviceLinkMessage.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "TSOutgoingMessage.h" - -typedef NS_ENUM(NSUInteger, LKDeviceLinkMessageKind) { - LKDeviceLinkMessageKindRequest = 1, - LKDeviceLinkMessageKindAuthorization = 2, -}; - -NS_SWIFT_NAME(DeviceLinkMessage) -@interface LKDeviceLinkMessage : TSOutgoingMessage - -@property (nonatomic, readonly) NSString *masterPublicKey; -@property (nonatomic, readonly) NSString *slavePublicKey; -@property (nonatomic, readonly) NSData *masterSignature; // nil for device linking requests -@property (nonatomic, readonly) NSData *slaveSignature; -@property (nonatomic, readonly) LKDeviceLinkMessageKind kind; - -- (instancetype)initInThread:(TSThread *)thread masterPublicKey:(NSString *)masterHexEncodedPublicKey slavePublicKey:(NSString *)slaveHexEncodedPublicKey masterSignature:(NSData * _Nullable)masterSignature slaveSignature:(NSData *)slaveSignature; - -@end diff --git a/SignalUtilitiesKit/LKDeviceLinkMessage.m b/SignalUtilitiesKit/LKDeviceLinkMessage.m deleted file mode 100644 index e1836a1fd..000000000 --- a/SignalUtilitiesKit/LKDeviceLinkMessage.m +++ /dev/null @@ -1,89 +0,0 @@ -#import "LKDeviceLinkMessage.h" -#import "OWSIdentityManager.h" -#import "OWSPrimaryStorage+Loki.h" -#import "ProfileManagerProtocol.h" -#import "ProtoUtils.h" -#import "SSKEnvironment.h" -#import "SignalRecipient.h" -#import -#import -#import - -@implementation LKDeviceLinkMessage - -#pragma mark Convenience -- (LKDeviceLinkMessageKind)kind { - if (self.masterSignature != nil) { - return LKDeviceLinkMessageKindAuthorization; - } else { - return LKDeviceLinkMessageKindRequest; - } -} - -#pragma mark Initialization -- (instancetype)initInThread:(TSThread *)thread masterPublicKey:(NSString *)masterHexEncodedPublicKey slavePublicKey:(NSString *)slaveHexEncodedPublicKey masterSignature:(NSData * _Nullable)masterSignature slaveSignature:(NSData *)slaveSignature { - self = [self initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp inThread:thread messageBody:@"" attachmentIds:[NSMutableArray new] - expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil]; - if (self) { - _masterPublicKey = masterHexEncodedPublicKey; - _slavePublicKey = slaveHexEncodedPublicKey; - _masterSignature = masterSignature; - _slaveSignature = slaveSignature; - } - return self; -} - -#pragma mark Building -- (nullable id)prepareCustomContentBuilder:(SignalRecipient *)recipient { - SSKProtoContentBuilder *contentBuilder = [super prepareCustomContentBuilder:recipient]; - NSError *error; - if (self.kind == LKDeviceLinkMessageKindRequest) { - // The slave device attaches a pre key bundle with the request it sends so that a - // session can be established with the master device. - PreKeyBundle *preKeyBundle = [OWSPrimaryStorage.sharedManager generatePreKeyBundleForContact:recipient.recipientId]; - SSKProtoPrekeyBundleMessageBuilder *preKeyBundleMessageBuilder = [SSKProtoPrekeyBundleMessage builderFromPreKeyBundle:preKeyBundle]; - SSKProtoPrekeyBundleMessage *preKeyBundleMessage = [preKeyBundleMessageBuilder buildAndReturnError:&error]; - if (error || preKeyBundleMessage == nil) { - OWSFailDebug(@"Failed to build pre key bundle message for: %@ due to error: %@.", recipient.recipientId, error); - return nil; - } else { - [contentBuilder setPrekeyBundleMessage:preKeyBundleMessage]; - } - } else { - // The master device attaches its display name and profile picture URL to the device link - // authorization message so that the slave device is in sync with these things as soon - // as possible. - id profileManager = SSKEnvironment.shared.profileManager; - NSString *displayName = profileManager.localProfileName; - NSString *profilePictureURL = profileManager.profilePictureURL; - SSKProtoDataMessageLokiProfileBuilder *profileBuilder = [SSKProtoDataMessageLokiProfile builder]; - [profileBuilder setDisplayName:displayName]; - [profileBuilder setProfilePicture:profilePictureURL ?: @""]; - SSKProtoDataMessageBuilder *messageBuilder = [SSKProtoDataMessage builder]; - [messageBuilder setProfile:[profileBuilder buildAndReturnError:nil]]; - [ProtoUtils addLocalProfileKeyToDataMessageBuilder:messageBuilder]; - [contentBuilder setDataMessage:[messageBuilder buildIgnoringErrors]]; - } - // Build the device link message - SSKProtoLokiDeviceLinkMessageBuilder *deviceLinkMessageBuilder = [SSKProtoLokiDeviceLinkMessage builder]; - [deviceLinkMessageBuilder setMasterPublicKey:self.masterPublicKey]; - [deviceLinkMessageBuilder setSlavePublicKey:self.slavePublicKey]; - if (self.masterSignature != nil) { [deviceLinkMessageBuilder setMasterSignature:self.masterSignature]; } - [deviceLinkMessageBuilder setSlaveSignature:self.slaveSignature]; - SSKProtoLokiDeviceLinkMessage *deviceLinkMessage = [deviceLinkMessageBuilder buildAndReturnError:&error]; - if (error || deviceLinkMessage == nil) { - OWSFailDebug(@"Failed to build device link message for: %@ due to error: %@.", recipient.recipientId, error); - return nil; - } else { - [contentBuilder setLokiDeviceLinkMessage:deviceLinkMessage]; - } - // Return - return contentBuilder; -} - -#pragma mark Settings -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeLinkDevice]; } -- (BOOL)shouldSyncTranscript { return NO; } -- (BOOL)shouldBeSaved { return NO; } - -@end diff --git a/SignalUtilitiesKit/LKGroupUtilities.h b/SignalUtilitiesKit/LKGroupUtilities.h index b613a37aa..ac74482f4 100644 --- a/SignalUtilitiesKit/LKGroupUtilities.h +++ b/SignalUtilitiesKit/LKGroupUtilities.h @@ -7,9 +7,6 @@ NS_ASSUME_NONNULL_BEGIN +(NSString *)getEncodedOpenGroupID:(NSString *)groupID; +(NSData *)getEncodedOpenGroupIDAsData:(NSString *)groupID; -+(NSString *)getEncodedRSSFeedID:(NSString *)groupID; -+(NSData *)getEncodedRSSFeedIDAsData:(NSString *)groupID; - +(NSString *)getEncodedClosedGroupID:(NSString *)groupID; +(NSData *)getEncodedClosedGroupIDAsData:(NSString *)groupID; diff --git a/SignalUtilitiesKit/LKGroupUtilities.m b/SignalUtilitiesKit/LKGroupUtilities.m index f0cd741ad..9cced30f0 100644 --- a/SignalUtilitiesKit/LKGroupUtilities.m +++ b/SignalUtilitiesKit/LKGroupUtilities.m @@ -3,10 +3,9 @@ @implementation LKGroupUtilities -#define ClosedGroupPrefix @"__textsecure_group__!" // a.k.a. private group chat +#define ClosedGroupPrefix @"__textsecure_group__!" #define MMSGroupPrefix @"__signal_mms_group__!" -#define OpenGroupPrefix @"__loki_public_chat_group__!" // a.k.a. public group chat -#define RSSFeedPrefix @"__loki_rss_feed_group__!" +#define OpenGroupPrefix @"__loki_public_chat_group__!" +(NSString *)getEncodedOpenGroupID:(NSString *)groupID { @@ -18,16 +17,6 @@ return [[OpenGroupPrefix stringByAppendingString:groupID] dataUsingEncoding:NSUTF8StringEncoding]; } -+(NSString *)getEncodedRSSFeedID:(NSString *)groupID -{ - return [RSSFeedPrefix stringByAppendingString:groupID]; -} - -+(NSData *)getEncodedRSSFeedIDAsData:(NSString *)groupID -{ - return [[RSSFeedPrefix stringByAppendingString:groupID] dataUsingEncoding:NSUTF8StringEncoding]; -} - +(NSString *)getEncodedClosedGroupID:(NSString *)groupID { return [ClosedGroupPrefix stringByAppendingString:groupID]; diff --git a/SignalUtilitiesKit/LKSyncOpenGroupsMessage.h b/SignalUtilitiesKit/LKSyncOpenGroupsMessage.h deleted file mode 100644 index 4c4969128..000000000 --- a/SignalUtilitiesKit/LKSyncOpenGroupsMessage.h +++ /dev/null @@ -1,14 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -NS_SWIFT_NAME(SyncOpenGroupsMessage) -@interface LKSyncOpenGroupsMessage : OWSOutgoingSyncMessage - -- (instancetype)init NS_DESIGNATED_INITIALIZER; - -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/LKSyncOpenGroupsMessage.m b/SignalUtilitiesKit/LKSyncOpenGroupsMessage.m deleted file mode 100644 index 8881ec3e1..000000000 --- a/SignalUtilitiesKit/LKSyncOpenGroupsMessage.m +++ /dev/null @@ -1,43 +0,0 @@ -#import "LKSyncOpenGroupsMessage.h" -#import "OWSPrimaryStorage.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation LKSyncOpenGroupsMessage - -- (instancetype)init -{ - return [super init]; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - NSError *error; - NSMutableArray *openGroupSyncMessages = @[].mutableCopy; - __block NSDictionary *openGroups; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - openGroups = [LKDatabaseUtilities getAllPublicChats:transaction]; - }]; - for (SNOpenGroup *openGroup in openGroups.allValues) { - SSKProtoSyncMessageOpenGroupDetailsBuilder *openGroupSyncMessageBuilder = [SSKProtoSyncMessageOpenGroupDetails builderWithUrl:openGroup.server channelID:openGroup.channel]; - SSKProtoSyncMessageOpenGroupDetails *_Nullable openGroupSyncMessage = [openGroupSyncMessageBuilder buildAndReturnError:&error]; - if (error || !openGroupSyncMessage) { - OWSFailDebug(@"Couldn't build protobuf due to error: %@.", error); - return nil; - } - [openGroupSyncMessages addObject:openGroupSyncMessage]; - } - SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder]; - [syncMessageBuilder setOpenGroups:openGroupSyncMessages]; - return syncMessageBuilder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/LKUnlinkDeviceMessage.h b/SignalUtilitiesKit/LKUnlinkDeviceMessage.h deleted file mode 100644 index 4999120e7..000000000 --- a/SignalUtilitiesKit/LKUnlinkDeviceMessage.h +++ /dev/null @@ -1,12 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -NS_SWIFT_NAME(UnlinkDeviceMessage) -@interface LKUnlinkDeviceMessage : TSOutgoingMessage - -- (instancetype)initWithThread:(TSThread *)thread; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/LKUnlinkDeviceMessage.m b/SignalUtilitiesKit/LKUnlinkDeviceMessage.m deleted file mode 100644 index d1a7594e6..000000000 --- a/SignalUtilitiesKit/LKUnlinkDeviceMessage.m +++ /dev/null @@ -1,27 +0,0 @@ -#import "LKUnlinkDeviceMessage.h" -#import -#import - -@implementation LKUnlinkDeviceMessage - -#pragma mark Initialization -- (instancetype)initWithThread:(TSThread *)thread { - return [self initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp inThread:thread messageBody:@"" attachmentIds:[NSMutableArray new] - expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil]; -} - -#pragma mark Building -- (nullable id)dataMessageBuilder -{ - SSKProtoDataMessageBuilder *builder = super.dataMessageBuilder; - if (builder == nil) { return nil; } - [builder setFlags:SSKProtoDataMessageFlagsUnlinkDevice]; - return builder; -} - -#pragma mark Settings -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeUnlinkDevice]; } -- (BOOL)shouldSyncTranscript { return NO; } -- (BOOL)shouldBeSaved { return NO; } - -@end diff --git a/SignalUtilitiesKit/LKUserDefaults.swift b/SignalUtilitiesKit/LKUserDefaults.swift index 0ce6bea81..077c7c2a9 100644 --- a/SignalUtilitiesKit/LKUserDefaults.swift +++ b/SignalUtilitiesKit/LKUserDefaults.swift @@ -7,8 +7,6 @@ public enum LKUserDefaults { case hasSeenGIFMetadataWarning case hasViewedSeed case isUsingFullAPNs - /// Whether the device was unlinked as a slave device (used to notify the user on the landing screen). - case wasUnlinked } public enum Date : Swift.String { @@ -16,7 +14,6 @@ public enum LKUserDefaults { } public enum Double : Swift.String { - /// - Note: Deprecated case lastDeviceTokenUpload = "lastDeviceTokenUploadTime" } @@ -24,50 +21,35 @@ public enum LKUserDefaults { case appMode } - public enum String { - case slaveDeviceName(Swift.String) + public enum String : Swift.String { case deviceToken - /// `nil` if this is a master device or if the user hasn't linked a device. - case masterHexEncodedPublicKey - - public var key: Swift.String { - switch self { - case .slaveDeviceName(let hexEncodedPublicKey): return "\(hexEncodedPublicKey)_display_name" - case .deviceToken: return "deviceToken" - case .masterHexEncodedPublicKey: return "masterDeviceHexEncodedPublicKey" - } - } } } public extension UserDefaults { - public subscript(bool: LKUserDefaults.Bool) -> Bool { + subscript(bool: LKUserDefaults.Bool) -> Bool { get { return self.bool(forKey: bool.rawValue) } set { set(newValue, forKey: bool.rawValue) } } - public subscript(date: LKUserDefaults.Date) -> Date? { + subscript(date: LKUserDefaults.Date) -> Date? { get { return self.object(forKey: date.rawValue) as? Date } set { set(newValue, forKey: date.rawValue) } } - public subscript(double: LKUserDefaults.Double) -> Double { + subscript(double: LKUserDefaults.Double) -> Double { get { return self.double(forKey: double.rawValue) } set { set(newValue, forKey: double.rawValue) } } - public subscript(int: LKUserDefaults.Int) -> Int { + subscript(int: LKUserDefaults.Int) -> Int { get { return self.integer(forKey: int.rawValue) } set { set(newValue, forKey: int.rawValue) } } - public subscript(string: LKUserDefaults.String) -> String? { - get { return self.string(forKey: string.key) } - set { set(newValue, forKey: string.key) } - } - - public var isMasterDevice: Bool { - return (self[.masterHexEncodedPublicKey] == nil) + subscript(string: LKUserDefaults.String) -> String? { + get { return self.string(forKey: string.rawValue) } + set { set(newValue, forKey: string.rawValue) } } } diff --git a/SignalUtilitiesKit/LokiDatabaseUtilities.swift b/SignalUtilitiesKit/LokiDatabaseUtilities.swift index 8655eb10c..42d51545f 100644 --- a/SignalUtilitiesKit/LokiDatabaseUtilities.swift +++ b/SignalUtilitiesKit/LokiDatabaseUtilities.swift @@ -23,51 +23,6 @@ public final class LokiDatabaseUtilities : NSObject { - // MARK: - Device Links - @objc(getLinkedDeviceHexEncodedPublicKeysFor:in:) - public static func getLinkedDeviceHexEncodedPublicKeys(for hexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> Set { - return [ hexEncodedPublicKey ] - /* - let storage = OWSPrimaryStorage.shared() - let masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: hexEncodedPublicKey, in: transaction) ?? hexEncodedPublicKey - var result = Set(storage.getDeviceLinks(for: masterHexEncodedPublicKey, in: transaction).flatMap { deviceLink in - return [ deviceLink.master.publicKey, deviceLink.slave.publicKey ] - }) - result.insert(hexEncodedPublicKey) - return result - */ - } - - @objc(getLinkedDeviceThreadsFor:in:) - public static func getLinkedDeviceThreads(for hexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> Set { - return Set([ TSContactThread.getWithContactId(hexEncodedPublicKey, transaction: transaction) ].compactMap { $0 }) -// return Set(getLinkedDeviceHexEncodedPublicKeys(for: hexEncodedPublicKey, in: transaction).compactMap { TSContactThread.getWithContactId($0, transaction: transaction) }) - } - - @objc(isUserLinkedDevice:in:) - public static func isUserLinkedDevice(_ hexEncodedPublicKey: String, transaction: YapDatabaseReadTransaction) -> Bool { - return hexEncodedPublicKey == getUserHexEncodedPublicKey() - /* - let userHexEncodedPublicKey = getUserHexEncodedPublicKey() - let userLinkedDeviceHexEncodedPublicKeys = getLinkedDeviceHexEncodedPublicKeys(for: userHexEncodedPublicKey, in: transaction) - return userLinkedDeviceHexEncodedPublicKeys.contains(hexEncodedPublicKey) - */ - } - - @objc(getMasterHexEncodedPublicKeyFor:in:) - public static func objc_getMasterHexEncodedPublicKey(for slaveHexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> String? { - return nil -// return OWSPrimaryStorage.shared().getMasterHexEncodedPublicKey(for: slaveHexEncodedPublicKey, in: transaction) - } - - @objc(getDeviceLinksFor:in:) - public static func objc_getDeviceLinks(for masterHexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> Set { - return [] -// return OWSPrimaryStorage.shared().getDeviceLinks(for: masterHexEncodedPublicKey, in: transaction) - } - - - // MARK: - Open Groups private static let publicChatCollection = "LokiPublicChatCollection" diff --git a/SignalUtilitiesKit/LokiMessage.swift b/SignalUtilitiesKit/LokiMessage.swift deleted file mode 100644 index c2048e763..000000000 --- a/SignalUtilitiesKit/LokiMessage.swift +++ /dev/null @@ -1,75 +0,0 @@ -import PromiseKit - -public struct LokiMessage { - /// The hex encoded public key of the recipient. - let recipientPublicKey: String - /// The content of the message. - let data: LosslessStringConvertible - /// The time to live for the message in milliseconds. - let ttl: UInt64 - /// Whether this message is a ping. - /// - /// - Note: The concept of pinging only applies to P2P messaging. - let isPing: Bool - /// When the proof of work was calculated, if applicable (P2P messages don't require proof of work). - /// - /// - Note: Expressed as milliseconds since 00:00:00 UTC on 1 January 1970. - private(set) var timestamp: UInt64? = nil - /// The base 64 encoded proof of work, if applicable (P2P messages don't require proof of work). - private(set) var nonce: String? = nil - - private init(destination: String, data: LosslessStringConvertible, ttl: UInt64, isPing: Bool) { - self.recipientPublicKey = destination - self.data = data - self.ttl = ttl - self.isPing = isPing - } - - /// Construct a `LokiMessage` from a `SignalMessage`. - /// - /// - Note: `timestamp` is the original message timestamp (i.e. `TSOutgoingMessage.timestamp`). - public static func from(signalMessage: SignalMessage) -> LokiMessage? { - // To match the desktop application, we have to wrap the data in an envelope and then wrap that in a websocket object - do { - let wrappedMessage = try MessageWrapper.wrap(message: signalMessage) - let data = wrappedMessage.base64EncodedString() - let destination = signalMessage.recipientPublicKey - var ttl = TTLUtilities.fallbackMessageTTL - if let messageTTL = signalMessage.ttl, messageTTL > 0 { ttl = UInt64(messageTTL) } - let isPing = signalMessage.isPing - return LokiMessage(destination: destination, data: data, ttl: ttl, isPing: isPing) - } catch let error { - print("[Loki] Failed to convert Signal message to Loki message: \(signalMessage).") - return nil - } - } - - /// Calculate the proof of work for this message. - /// - /// - Returns: The promise of a new message with its `timestamp` and `nonce` set. - public func calculatePoW() -> Promise { - return Promise { seal in - DispatchQueue.global(qos: .userInitiated).async { - let now = NSDate.ows_millisecondTimeStamp() - let dataAsString = self.data as! String // Safe because of how from(signalMessage:with:) is implemented - if let nonce = ProofOfWork.calculate(data: dataAsString, pubKey: self.recipientPublicKey, timestamp: now, ttl: self.ttl) { - var result = self - result.timestamp = now - result.nonce = nonce - seal.fulfill(result) - } else { - seal.reject(SessionMessagingKit.MessageSender.Error.proofOfWorkCalculationFailed) - } - } - } - } - - public func toJSON() -> JSON { - var result = [ "pubKey" : recipientPublicKey, "data" : data.description, "ttl" : String(ttl) ] - if let timestamp = timestamp, let nonce = nonce { - result["timestamp"] = String(timestamp) - result["nonce"] = nonce - } - return result - } -} diff --git a/SignalUtilitiesKit/LokiPushNotificationManager.swift b/SignalUtilitiesKit/LokiPushNotificationManager.swift index 1d1c47095..50b172d6f 100644 --- a/SignalUtilitiesKit/LokiPushNotificationManager.swift +++ b/SignalUtilitiesKit/LokiPushNotificationManager.swift @@ -100,7 +100,8 @@ public final class LokiPushNotificationManager : NSObject { public static func objc_register(with token: Data, publicKey: String, isForcedUpdate: Bool) -> AnyPromise { return AnyPromise.from(register(with: token, publicKey: publicKey, isForcedUpdate: isForcedUpdate)) } - + + @discardableResult static func performOperation(_ operation: ClosedGroupOperation, for closedGroupPublicKey: String, publicKey: String) -> Promise { let isUsingFullAPNs = UserDefaults.standard[.isUsingFullAPNs] guard isUsingFullAPNs else { return Promise { $0.fulfill(()) } } @@ -123,31 +124,4 @@ public final class LokiPushNotificationManager : NSObject { } return promise } - - static func notify(for signalMessage: SignalMessage) -> Promise { - let message = LokiMessage.from(signalMessage: signalMessage)! - let parameters = [ "data" : message.data.description, "send_to" : message.recipientPublicKey] - let url = URL(string: "\(server)/notify")! - let request = TSRequest(url: url, method: "POST", parameters: parameters) - request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] - let promise: Promise = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { - OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: pnServerPublicKey).map2 { response in - guard let json = response["body"] as? JSON else { - return print("[Loki] Couldn't notify PN server.") - } - guard json["code"] as? Int != 0 else { - return print("[Loki] Couldn't notify PN server due to error: \(json["message"] as? String ?? "nil").") - } - } - } - promise.catch2 { error in - print("[Loki] Couldn't notify PN server.") - } - return promise - } - - @objc(notifyForMessage:) - public static func objc_notify(for signalMessage: SignalMessage) -> AnyPromise { - return AnyPromise.from(notify(for: signalMessage)) - } } diff --git a/SignalUtilitiesKit/LokiSessionResetImplementation.swift b/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift similarity index 95% rename from SignalUtilitiesKit/LokiSessionResetImplementation.swift rename to SignalUtilitiesKit/LokiSessionRestorationImplementation.swift index 64569eb62..50271146c 100644 --- a/SignalUtilitiesKit/LokiSessionResetImplementation.swift +++ b/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift @@ -29,7 +29,7 @@ public final class SessionRestorationImplementation : NSObject, SessionRestorati Storage.read { transaction in thread = TSContactThread.getWithContactId(publicKey, transaction: transaction) } - return thread?.sessionResetStatus ?? .none + return thread?.sessionRestorationStatus ?? .none } public func handleNewSessionAdopted(for publicKey: String, using transaction: Any) { @@ -42,7 +42,7 @@ public final class SessionRestorationImplementation : NSObject, SessionRestorati let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetDone) infoMessage.save(with: transaction) // Update the session reset status - thread.sessionResetStatus = .none + thread.sessionRestorationStatus = .none thread.save(with: transaction) } } diff --git a/SignalUtilitiesKit/MentionsManager.swift b/SignalUtilitiesKit/MentionsManager.swift index bc1588e0c..969038463 100644 --- a/SignalUtilitiesKit/MentionsManager.swift +++ b/SignalUtilitiesKit/MentionsManager.swift @@ -35,7 +35,7 @@ public final class MentionsManager : NSObject { publicChat = LokiDatabaseUtilities.getPublicChat(for: threadID, in: transaction) } storage.dbReadConnection.read { transaction in - candidates = cache.flatMap { publicKey in + candidates = cache.compactMap { publicKey in let uncheckedDisplayName: String? if let publicChat = publicChat { uncheckedDisplayName = UserDisplayNameUtilities.getPublicChatDisplayName(for: publicKey, in: publicChat.channel, on: publicChat.server) diff --git a/SignalUtilitiesKit/MessageWrapper.swift b/SignalUtilitiesKit/MessageWrapper.swift deleted file mode 100644 index f19626906..000000000 --- a/SignalUtilitiesKit/MessageWrapper.swift +++ /dev/null @@ -1,72 +0,0 @@ - -public enum MessageWrapper { - - public enum Error : LocalizedError { - case failedToWrapData - case failedToWrapMessageInEnvelope - case failedToWrapEnvelopeInWebSocketMessage - case failedToUnwrapData - - public var errorDescription: String? { - switch self { - case .failedToWrapData: return "Failed to wrap data." - case .failedToWrapMessageInEnvelope: return "Failed to wrap message in envelope." - case .failedToWrapEnvelopeInWebSocketMessage: return "Failed to wrap envelope in web socket message." - case .failedToUnwrapData: return "Failed to unwrap data." - } - } - } - - /// Wraps `message` in an `SSKProtoEnvelope` and then a `WebSocketProtoWebSocketMessage` to match the desktop application. - public static func wrap(message: SignalMessage) throws -> Data { - do { - let envelope = try createEnvelope(around: message) - let webSocketMessage = try createWebSocketMessage(around: envelope) - return try webSocketMessage.serializedData() - } catch let error { - throw error as? Error ?? Error.failedToWrapData - } - } - - private static func createEnvelope(around message: SignalMessage) throws -> SSKProtoEnvelope { - do { - let builder = SSKProtoEnvelope.builder(type: message.type, timestamp: message.timestamp) - builder.setSource(message.senderPublicKey) - builder.setSourceDevice(message.senderDeviceID) - if let content = try Data(base64Encoded: message.content, options: .ignoreUnknownCharacters) { - builder.setContent(content) - } else { - throw Error.failedToWrapMessageInEnvelope - } - return try builder.build() - } catch let error { - print("[Loki] Failed to wrap message in envelope: \(error).") - throw Error.failedToWrapMessageInEnvelope - } - } - - private static func createWebSocketMessage(around envelope: SSKProtoEnvelope) throws -> WebSocketProtoWebSocketMessage { - do { - let requestBuilder = WebSocketProtoWebSocketRequestMessage.builder(verb: "PUT", path: "/api/v1/message", requestID: UInt64.random(in: 1.. SSKProtoEnvelope { - do { - let webSocketMessage = try WebSocketProtoWebSocketMessage.parseData(data) - let envelope = webSocketMessage.request!.body! - return try SSKProtoEnvelope.parseData(envelope) - } catch let error { - print("[Loki] Failed to unwrap data: \(error).") - throw Error.failedToUnwrapData - } - } -} diff --git a/SignalUtilitiesKit/TSErrorMessage.h b/SignalUtilitiesKit/Messages/TSErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/TSErrorMessage.h rename to SignalUtilitiesKit/Messages/TSErrorMessage.h diff --git a/SignalUtilitiesKit/TSErrorMessage.m b/SignalUtilitiesKit/Messages/TSErrorMessage.m similarity index 94% rename from SignalUtilitiesKit/TSErrorMessage.m rename to SignalUtilitiesKit/Messages/TSErrorMessage.m index 12b29e7b7..90f30198e 100644 --- a/SignalUtilitiesKit/TSErrorMessage.m +++ b/SignalUtilitiesKit/Messages/TSErrorMessage.m @@ -4,7 +4,6 @@ #import "TSErrorMessage.h" #import "ContactsManagerProtocol.h" -#import "OWSMessageManager.h" #import "SSKEnvironment.h" #import "TSContactThread.h" #import "TSErrorMessage_privateConstructor.h" @@ -89,7 +88,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1; withTransaction:(YapDatabaseReadWriteTransaction *)transaction failedMessageType:(TSErrorMessageType)errorMessageType { - NSString *source = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:envelope.source in:transaction] ?: envelope.source; + NSString *source = envelope.source; TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:source transaction:transaction]; @@ -123,9 +122,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1; NSString *messageFormat = NSLocalizedString(@"ERROR_MESSAGE_NON_BLOCKING_IDENTITY_CHANGE_FORMAT", @"Shown when signal users safety numbers changed, embeds the user's {{name or phone number}}"); - NSString *recipientDisplayName = - [SSKEnvironment.shared.contactsManager displayNameForPhoneIdentifier:self.recipientId - transaction:transaction]; + NSString *recipientDisplayName = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.recipientId avoidingWriteTransaction:YES]; return [NSString stringWithFormat:messageFormat, recipientDisplayName]; } else { // recipientId will be nil for legacy errors diff --git a/SignalUtilitiesKit/TSErrorMessage_privateConstructor.h b/SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h similarity index 100% rename from SignalUtilitiesKit/TSErrorMessage_privateConstructor.h rename to SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h diff --git a/SignalUtilitiesKit/TSIncomingMessage.h b/SignalUtilitiesKit/Messages/TSIncomingMessage.h similarity index 100% rename from SignalUtilitiesKit/TSIncomingMessage.h rename to SignalUtilitiesKit/Messages/TSIncomingMessage.h diff --git a/SignalUtilitiesKit/TSIncomingMessage.m b/SignalUtilitiesKit/Messages/TSIncomingMessage.m similarity index 100% rename from SignalUtilitiesKit/TSIncomingMessage.m rename to SignalUtilitiesKit/Messages/TSIncomingMessage.m diff --git a/SignalUtilitiesKit/TSInfoMessage.h b/SignalUtilitiesKit/Messages/TSInfoMessage.h similarity index 98% rename from SignalUtilitiesKit/TSInfoMessage.h rename to SignalUtilitiesKit/Messages/TSInfoMessage.h index d01fa2c9f..53e462619 100644 --- a/SignalUtilitiesKit/TSInfoMessage.h +++ b/SignalUtilitiesKit/Messages/TSInfoMessage.h @@ -18,7 +18,6 @@ typedef NS_ENUM(NSInteger, TSInfoMessageType) { TSInfoMessageTypeGroupQuit, TSInfoMessageTypeDisappearingMessagesUpdate, TSInfoMessageAddToContactsOffer, - TSInfoMessageVerificationStateChange, TSInfoMessageAddUserToProfileWhitelistOffer, TSInfoMessageAddGroupToProfileWhitelistOffer, TSInfoMessageTypeLokiSessionResetInProgress, diff --git a/SignalUtilitiesKit/TSInfoMessage.m b/SignalUtilitiesKit/Messages/TSInfoMessage.m similarity index 91% rename from SignalUtilitiesKit/TSInfoMessage.m rename to SignalUtilitiesKit/Messages/TSInfoMessage.m index 3a7d5be6e..fb9cd0dc7 100644 --- a/SignalUtilitiesKit/TSInfoMessage.m +++ b/SignalUtilitiesKit/Messages/TSInfoMessage.m @@ -127,9 +127,7 @@ NSUInteger TSInfoMessageSchemaVersion = 1; return NSLocalizedString(@"UNSUPPORTED_ATTACHMENT", nil); case TSInfoMessageUserNotRegistered: if (self.unregisteredRecipientId.length > 0) { - id contactsManager = SSKEnvironment.shared.contactsManager; - NSString *recipientName = [contactsManager displayNameForPhoneIdentifier:self.unregisteredRecipientId - transaction:transaction]; + NSString *recipientName = @""; return [NSString stringWithFormat:NSLocalizedString(@"ERROR_UNREGISTERED_USER_FORMAT", @"Format string for 'unregistered user' error. Embeds {{the " @"unregistered user's name or signal id}}."), @@ -144,9 +142,6 @@ NSUInteger TSInfoMessageSchemaVersion = 1; case TSInfoMessageAddToContactsOffer: return NSLocalizedString(@"ADD_TO_CONTACTS_OFFER", @"Message shown in conversation view that offers to add an unknown user to your phone's contacts."); - case TSInfoMessageVerificationStateChange: - return NSLocalizedString(@"VERIFICATION_STATE_CHANGE_GENERIC", - @"Generic message indicating that verification state changed for a given user."); case TSInfoMessageAddUserToProfileWhitelistOffer: return NSLocalizedString(@"ADD_USER_TO_PROFILE_WHITELIST_OFFER", @"Message shown in conversation view that offers to share your profile with a user."); diff --git a/SignalUtilitiesKit/TSInteraction.h b/SignalUtilitiesKit/Messages/TSInteraction.h similarity index 100% rename from SignalUtilitiesKit/TSInteraction.h rename to SignalUtilitiesKit/Messages/TSInteraction.h diff --git a/SignalUtilitiesKit/TSInteraction.m b/SignalUtilitiesKit/Messages/TSInteraction.m similarity index 99% rename from SignalUtilitiesKit/TSInteraction.m rename to SignalUtilitiesKit/Messages/TSInteraction.m index 1a94cdba6..6bc729a9e 100644 --- a/SignalUtilitiesKit/TSInteraction.m +++ b/SignalUtilitiesKit/Messages/TSInteraction.m @@ -214,7 +214,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) // effectively the same as sorting by server timestamp. if (self.thread.isGroupThread) { TSGroupThread *thread = (TSGroupThread *)self.thread; - if (thread.isPublicChat) { + if (thread.isOpenGroup) { sortId1 = self.sortId; sortId2 = other.sortId; } diff --git a/SignalUtilitiesKit/TSInvalidIdentityKeyErrorMessage.h b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/TSInvalidIdentityKeyErrorMessage.h rename to SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.h diff --git a/SignalUtilitiesKit/TSInvalidIdentityKeyErrorMessage.m b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/TSInvalidIdentityKeyErrorMessage.m rename to SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.m diff --git a/SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.h b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.h rename to SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h diff --git a/SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.m b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m similarity index 99% rename from SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.m rename to SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m index 034853307..8b745f029 100644 --- a/SignalUtilitiesKit/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -3,7 +3,6 @@ // #import "TSInvalidIdentityKeyReceivingErrorMessage.h" -#import "OWSFingerprint.h" #import "OWSIdentityManager.h" #import "OWSPrimaryStorage+SessionStore.h" #import "OWSPrimaryStorage.h" diff --git a/SignalUtilitiesKit/TSInvalidIdentityKeySendingErrorMessage.h b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/TSInvalidIdentityKeySendingErrorMessage.h rename to SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.h diff --git a/SignalUtilitiesKit/TSInvalidIdentityKeySendingErrorMessage.m b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.m similarity index 98% rename from SignalUtilitiesKit/TSInvalidIdentityKeySendingErrorMessage.m rename to SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.m index 78379f6d2..b3649a09d 100644 --- a/SignalUtilitiesKit/TSInvalidIdentityKeySendingErrorMessage.m +++ b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.m @@ -3,7 +3,6 @@ // #import "TSInvalidIdentityKeySendingErrorMessage.h" -#import "OWSFingerprint.h" #import "OWSIdentityManager.h" #import "OWSPrimaryStorage+SessionStore.h" #import "OWSPrimaryStorage.h" diff --git a/SignalUtilitiesKit/TSMessage.h b/SignalUtilitiesKit/Messages/TSMessage.h similarity index 93% rename from SignalUtilitiesKit/TSMessage.h rename to SignalUtilitiesKit/Messages/TSMessage.h index bef830cad..7702f8655 100644 --- a/SignalUtilitiesKit/TSMessage.h +++ b/SignalUtilitiesKit/Messages/TSMessage.h @@ -29,13 +29,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly, nullable) OWSContact *contactShare; @property (nonatomic, nullable) OWSLinkPreview *linkPreview; @property BOOL skipSave; -// P2P -@property (nonatomic) BOOL isP2P; // Open groups @property (nonatomic) uint64_t openGroupServerMessageID; @property (nonatomic, readonly) BOOL isOpenGroupMessage; // Push notifications -@property (nonatomic) BOOL hasAttachmentsInNSE; +@property (nonatomic) BOOL hasUnfetchedAttachmentsFromPN; - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; @@ -77,10 +75,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateWithLinkPreview:(OWSLinkPreview *)linkPreview transaction:(YapDatabaseReadWriteTransaction *)transaction; -#pragma mark - Open Groups - -- (void)saveOpenGroupServerMessageID:(uint64_t)serverMessageID in:(YapDatabaseReadWriteTransaction *_Nullable)transaction; - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSMessage.m b/SignalUtilitiesKit/Messages/TSMessage.m similarity index 94% rename from SignalUtilitiesKit/TSMessage.m rename to SignalUtilitiesKit/Messages/TSMessage.m index e582b2080..0003614aa 100644 --- a/SignalUtilitiesKit/TSMessage.m +++ b/SignalUtilitiesKit/Messages/TSMessage.m @@ -6,7 +6,7 @@ #import "AppContext.h" #import "MIMETypeUtil.h" #import "NSString+SSK.h" -#import "OWSContact.h" + #import "OWSDisappearingMessagesConfiguration.h" #import "TSAttachment.h" #import "TSAttachmentStream.h" @@ -196,10 +196,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4; [result addObjectsFromArray:self.quotedMessage.thumbnailAttachmentStreamIds]; } - if (self.contactShare.avatarAttachmentId) { - [result addObject:self.contactShare.avatarAttachmentId]; - } - if (self.linkPreview.imageAttachmentId) { [result addObject:self.linkPreview.imageAttachmentId]; } @@ -359,12 +355,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4; return bodyDescription; } else if (attachmentDescription.length > 0) { return attachmentDescription; - } else if (self.contactShare) { - if (CurrentAppContext().isRTL) { - return [self.contactShare.name.displayName stringByAppendingString:@" 👤"]; - } else { - return [@"👤 " stringByAppendingString:self.contactShare.name.displayName]; - } } else { // TODO: We should do better here. return @""; @@ -450,17 +440,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4; return self.openGroupServerMessageID > 0; } -- (void)saveOpenGroupServerMessageID:(uint64_t)serverMessageID in:(YapDatabaseReadWriteTransaction *_Nullable)transaction { - self.openGroupServerMessageID = serverMessageID; - if (transaction == nil) { - [self save]; - [self.dbReadWriteConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{}]; - } else { - [self saveWithTransaction:transaction]; - [transaction.connection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{}]; - } -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSOutgoingMessage.h b/SignalUtilitiesKit/Messages/TSOutgoingMessage.h similarity index 97% rename from SignalUtilitiesKit/TSOutgoingMessage.h rename to SignalUtilitiesKit/Messages/TSOutgoingMessage.h index 7a734f521..0d33b756a 100644 --- a/SignalUtilitiesKit/TSOutgoingMessage.h +++ b/SignalUtilitiesKit/Messages/TSOutgoingMessage.h @@ -142,9 +142,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { @property (nonatomic, readonly) BOOL isOnline; -/// Loki: Whether proof of work is being calculated for this message. -@property (atomic, readonly) BOOL isCalculatingPoW; - /// Loki: Time to live for the message in milliseconds. @property (nonatomic, readonly) uint ttl; @@ -197,9 +194,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { #pragma mark - Update With... Methods -// When sending a message, when proof of work calculation is started, we should mark it as such -- (void)saveIsCalculatingProofOfWork:(BOOL)isCalculatingPoW withTransaction:(YapDatabaseReadWriteTransaction *)transaction; - // This method is used to record a successful send to one recipient. - (void)updateWithSentRecipient:(NSString *)recipientId wasSentByUD:(BOOL)wasSentByUD diff --git a/SignalUtilitiesKit/TSOutgoingMessage.m b/SignalUtilitiesKit/Messages/TSOutgoingMessage.m similarity index 96% rename from SignalUtilitiesKit/TSOutgoingMessage.m rename to SignalUtilitiesKit/Messages/TSOutgoingMessage.m index f681ccb6b..cff531a5b 100644 --- a/SignalUtilitiesKit/TSOutgoingMessage.m +++ b/SignalUtilitiesKit/Messages/TSOutgoingMessage.m @@ -6,8 +6,7 @@ #import "TSOutgoingMessage.h" #import "NSString+SSK.h" -#import "OWSContact.h" -#import "OWSOutgoingSyncMessage.h" + #import "OWSPrimaryStorage.h" #import "ProfileManagerProtocol.h" #import "ProtoUtils.h" @@ -93,8 +92,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt @property (atomic, nullable) NSDictionary *recipientStateMap; -@property (atomic) BOOL isCalculatingPoW; - @end #pragma mark - @@ -327,7 +324,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } _hasSyncedTranscript = NO; - _isCalculatingPoW = NO; if ([thread isKindOfClass:TSGroupThread.class]) { // Unless specified, we assume group messages are "Delivery" i.e. normal messages. @@ -350,15 +346,15 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt // recipient list from current thread state. NSMutableDictionary *recipientStateMap = [NSMutableDictionary new]; NSArray *recipientIds; - if ([self isKindOfClass:[OWSOutgoingSyncMessage class]]) { - NSString *_Nullable localNumber = [TSAccountManager localNumber]; - OWSAssertDebug(localNumber); - recipientIds = @[ - localNumber, - ]; - } else { - recipientIds = [thread recipientIdentifiers]; - } +// if ([self isKindOfClass:[OWSOutgoingSyncMessage class]]) { +// NSString *_Nullable localNumber = [TSAccountManager localNumber]; +// OWSAssertDebug(localNumber); +// recipientIds = @[ +// localNumber, +// ]; +// } else { +// recipientIds = [thread recipientIdentifiers]; +// } for (NSString *recipientId in recipientIds) { TSOutgoingMessageRecipientState *recipientState = [TSOutgoingMessageRecipientState new]; recipientState.state = OWSOutgoingMessageRecipientStateSending; @@ -612,7 +608,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } } [message setMostRecentFailureText:error.localizedDescription]; - [message setIsCalculatingPoW:NO]; }]; } @@ -629,7 +624,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt recipientState.state = OWSOutgoingMessageRecipientStateFailed; } } - [message setIsCalculatingPoW:NO]; }]; } @@ -676,14 +670,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt }]; } -- (void)saveIsCalculatingProofOfWork:(BOOL)isCalculatingPoW withTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { - [message setIsCalculatingPoW:isCalculatingPoW]; - }]; -} - - (void)updateWithSentRecipient:(NSString *)recipientId wasSentByUD:(BOOL)wasSentByUD transaction:(YapDatabaseReadWriteTransaction *)transaction { @@ -697,7 +683,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt if (!recipientState) { return; } recipientState.state = OWSOutgoingMessageRecipientStateSent; recipientState.wasSentByUD = wasSentByUD; - [message setIsCalculatingPoW:NO]; }]; } @@ -712,7 +697,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt = message.recipientStateMap[recipientId]; if (!recipientState) { return; } recipientState.state = OWSOutgoingMessageRecipientStateSkipped; - [message setIsCalculatingPoW:NO]; }]; } @@ -741,7 +725,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } recipientState.state = OWSOutgoingMessageRecipientStateSent; recipientState.deliveryTimestamp = deliveryTimestamp; - [message setIsCalculatingPoW:NO]; }]; } @@ -761,7 +744,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } recipientState.state = OWSOutgoingMessageRecipientStateSent; recipientState.readTimestamp = @(readTimestamp); - [message setIsCalculatingPoW:NO]; }]; } @@ -831,8 +813,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } } - [message setIsCalculatingPoW:NO]; - if (!isSentUpdate) { [message setIsFromLinkedDevice:YES]; } @@ -992,17 +972,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt [builder setQuote:quoteProto]; } - // Contact Share - if (self.contactShare) { - SSKProtoDataMessageContact *_Nullable contactProto = - [OWSContacts protoForContact:self.contactShare]; - if (contactProto) { - [builder addContact:contactProto]; - } else { - OWSFailDebug(@"contactProto was unexpectedly nil"); - } - } - // Link Preview if (self.linkPreview) { SSKProtoDataMessagePreviewBuilder *previewBuilder = @@ -1164,7 +1133,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt return [result copy]; } -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeRegular]; } +- (uint)ttl { return 2 * 24 * 60 * 60 * 1000; } @end diff --git a/SignalUtilitiesKit/TSQuotedMessage.h b/SignalUtilitiesKit/Messages/TSQuotedMessage.h similarity index 100% rename from SignalUtilitiesKit/TSQuotedMessage.h rename to SignalUtilitiesKit/Messages/TSQuotedMessage.h diff --git a/SignalUtilitiesKit/TSQuotedMessage.m b/SignalUtilitiesKit/Messages/TSQuotedMessage.m similarity index 100% rename from SignalUtilitiesKit/TSQuotedMessage.m rename to SignalUtilitiesKit/Messages/TSQuotedMessage.m diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 18c71fc06..085cc69ad 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -13,16 +13,10 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import -#import -#import #import #import #import -#import #import -#import -#import #import #import #import @@ -31,12 +25,8 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import -#import -#import -#import #import #import #import @@ -44,31 +34,18 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import -#import -#import #import -#import -#import -#import #import -#import -#import #import #import -#import #import #import #import -#import #import #import -#import #import #import #import -#import -#import #import #import #import @@ -77,20 +54,15 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import #import -#import -#import #import #import #import -#import #import #import -#import #import #import #import @@ -102,6 +74,7 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import +#import #import #import #import @@ -112,13 +85,9 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import -#import -#import #import #import #import -#import #import #import #import @@ -126,6 +95,5 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import diff --git a/SignalUtilitiesKit/Mnemonic.swift b/SignalUtilitiesKit/Mnemonic.swift deleted file mode 100644 index 9cbaa1588..000000000 --- a/SignalUtilitiesKit/Mnemonic.swift +++ /dev/null @@ -1,161 +0,0 @@ -import CryptoSwift - -/// Based on [mnemonic.js](https://github.com/loki-project/loki-messenger/blob/development/libloki/modules/mnemonic.js) . -public enum Mnemonic { - - public struct Language : Hashable { - fileprivate let filename: String - fileprivate let prefixLength: UInt - - public static let english = Language(filename: "english", prefixLength: 3) - public static let japanese = Language(filename: "japanese", prefixLength: 3) - public static let portuguese = Language(filename: "portuguese", prefixLength: 4) - public static let spanish = Language(filename: "spanish", prefixLength: 4) - - private static var wordSetCache: [Language:[String]] = [:] - private static var truncatedWordSetCache: [Language:[String]] = [:] - - private init(filename: String, prefixLength: UInt) { - self.filename = filename - self.prefixLength = prefixLength - } - - fileprivate func loadWordSet() -> [String] { - if let cachedResult = Language.wordSetCache[self] { - return cachedResult - } else { - let url = Bundle.main.url(forResource: filename, withExtension: "txt")! - let contents = try! String(contentsOf: url) - let result = contents.split(separator: ",").map { String($0) } - Language.wordSetCache[self] = result - return result - } - } - - fileprivate func loadTruncatedWordSet() -> [String] { - if let cachedResult = Language.truncatedWordSetCache[self] { - return cachedResult - } else { - let result = loadWordSet().map { $0.prefix(length: prefixLength) } - Language.truncatedWordSetCache[self] = result - return result - } - } - } - - public enum DecodingError : LocalizedError { - case generic, inputTooShort, missingLastWord, invalidWord, verificationFailed - - public var errorDescription: String? { - switch self { - case .generic: return NSLocalizedString("Something went wrong. Please check your recovery phrase and try again.", comment: "") - case .inputTooShort: return NSLocalizedString("Looks like you didn't enter enough words. Please check your recovery phrase and try again.", comment: "") - case .missingLastWord: return NSLocalizedString("You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.", comment: "") - case .invalidWord: return NSLocalizedString("There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.", comment: "") - case .verificationFailed: return NSLocalizedString("Your recovery phrase couldn't be verified. Please check what you entered and try again.", comment: "") - } - } - } - - public static func hash(hexEncodedString string: String, language: Language = .english) -> String { - return encode(hexEncodedString: string).split(separator: " ")[0..<3].joined(separator: " ") - } - - public static func encode(hexEncodedString string: String, language: Language = .english) -> String { - var string = string - let wordSet = language.loadWordSet() - let prefixLength = language.prefixLength - var result: [String] = [] - let n = wordSet.count - let characterCount = string.indices.count // Safe for this particular case - for chunkStartIndexAsInt in stride(from: 0, to: characterCount, by: 8) { - let chunkStartIndex = string.index(string.startIndex, offsetBy: chunkStartIndexAsInt) - let chunkEndIndex = string.index(chunkStartIndex, offsetBy: 8) - let p1 = string[string.startIndex.. String { - var words = mnemonic.split(separator: " ").map { String($0) } - let truncatedWordSet = language.loadTruncatedWordSet() - let prefixLength = language.prefixLength - var result = "" - let n = truncatedWordSet.count - // Check preconditions - guard words.count >= 12 else { throw DecodingError.inputTooShort } - guard !words.count.isMultiple(of: 3) else { throw DecodingError.missingLastWord } - // Get checksum word - let checksumWord = words.popLast()! - // Decode - for chunkStartIndex in stride(from: 0, to: words.count, by: 3) { - guard let w1 = truncatedWordSet.firstIndex(of: words[chunkStartIndex].prefix(length: prefixLength)), - let w2 = truncatedWordSet.firstIndex(of: words[chunkStartIndex + 1].prefix(length: prefixLength)), - let w3 = truncatedWordSet.firstIndex(of: words[chunkStartIndex + 2].prefix(length: prefixLength)) else { throw DecodingError.invalidWord } - let x = w1 + n * ((n - w1 + w2) % n) + n * n * ((n - w2 + w3) % n) - guard x % n == w1 else { throw DecodingError.generic } - let string = "0000000" + String(x, radix: 16) - result += swap(String(string[string.index(string.endIndex, offsetBy: -8).. String { - func toStringIndex(_ indexAsInt: Int) -> String.Index { - return x.index(x.startIndex, offsetBy: indexAsInt) - } - let p1 = x[toStringIndex(6).. Int { - let checksum = Array(x.map { $0.prefix(length: prefixLength) }.joined().utf8).crc32() - return Int(checksum) % x.count - } -} - -private extension String { - - func prefix(length: UInt) -> String { - return String(self[startIndex.. String { - return Mnemonic.hash(hexEncodedString: string) - } - - @objc(encodeHexEncodedString:) - public static func encode(hexEncodedString string: String) -> String { - return Mnemonic.encode(hexEncodedString: string) - } -} diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+Loki.h b/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.h similarity index 100% rename from SignalUtilitiesKit/OWSPrimaryStorage+Loki.h rename to SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.h diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+Loki.m b/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.m similarity index 99% rename from SignalUtilitiesKit/OWSPrimaryStorage+Loki.m rename to SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.m index 68f65931f..ab8d0bc1a 100644 --- a/SignalUtilitiesKit/OWSPrimaryStorage+Loki.m +++ b/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.m @@ -2,7 +2,7 @@ #import "OWSPrimaryStorage+PreKeyStore.h" #import "OWSPrimaryStorage+SignedPreKeyStore.h" #import "OWSPrimaryStorage+keyFromIntLong.h" -#import "OWSDevice.h" + #import "OWSIdentityManager.h" #import "NSDate+OWS.h" #import "TSAccountManager.h" @@ -106,7 +106,7 @@ uint32_t registrationID = [self.accountManager getOrGenerateRegistrationId]; PreKeyBundle *bundle = [[PreKeyBundle alloc] initWithRegistrationId:registrationID - deviceId:OWSDevicePrimaryDeviceId + deviceId:(uint32_t)1 preKeyId:preKey.Id preKeyPublic:preKey.keyPair.publicKey.prependKeyType signedPreKeyPublic:signedPreKey.keyPair.publicKey.prependKeyType diff --git a/SignalUtilitiesKit/OWSPrimaryStorage+Loki.swift b/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.swift similarity index 85% rename from SignalUtilitiesKit/OWSPrimaryStorage+Loki.swift rename to SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.swift index d9fb7896f..c46360579 100644 --- a/SignalUtilitiesKit/OWSPrimaryStorage+Loki.swift +++ b/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.swift @@ -62,14 +62,6 @@ public extension OWSPrimaryStorage { transaction.date(forKey: publicKey, inCollection: Storage.sessionRequestTimestampCollection) } - // MARK: Multi Device - public func setDeviceLinks(_ deviceLinks: Set) { } - public func addDeviceLink(_ deviceLink: DeviceLink) { } - public func removeDeviceLink(_ deviceLink: DeviceLink) { } - public func getDeviceLinks(for masterHexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> Set { return [] } - public func getDeviceLink(for slaveHexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> DeviceLink? { return nil } - public func getMasterHexEncodedPublicKey(for slaveHexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> String? { return nil } - // MARK: Open Groups public func getUserCount(for publicChat: OpenGroup, in transaction: YapDatabaseReadTransaction) -> Int? { return transaction.object(forKey: publicChat.id, inCollection: Storage.openGroupUserCountCollection) as? Int diff --git a/SignalUtilitiesKit/Storage+ClosedGroups.swift b/SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift similarity index 100% rename from SignalUtilitiesKit/Storage+ClosedGroups.swift rename to SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift diff --git a/SignalUtilitiesKit/Storage+Collections.swift b/SignalUtilitiesKit/Move to main app/Storage+Collections.swift similarity index 100% rename from SignalUtilitiesKit/Storage+Collections.swift rename to SignalUtilitiesKit/Move to main app/Storage+Collections.swift diff --git a/SignalUtilitiesKit/Storage+OnionRequests.swift b/SignalUtilitiesKit/Move to main app/Storage+OnionRequests.swift similarity index 100% rename from SignalUtilitiesKit/Storage+OnionRequests.swift rename to SignalUtilitiesKit/Move to main app/Storage+OnionRequests.swift diff --git a/SignalUtilitiesKit/Storage+PublicChats.swift b/SignalUtilitiesKit/Move to main app/Storage+PublicChats.swift similarity index 100% rename from SignalUtilitiesKit/Storage+PublicChats.swift rename to SignalUtilitiesKit/Move to main app/Storage+PublicChats.swift diff --git a/SignalUtilitiesKit/Storage+SessionManagement.swift b/SignalUtilitiesKit/Move to main app/Storage+SessionManagement.swift similarity index 100% rename from SignalUtilitiesKit/Storage+SessionManagement.swift rename to SignalUtilitiesKit/Move to main app/Storage+SessionManagement.swift diff --git a/SignalUtilitiesKit/Storage+SnodeAPI.swift b/SignalUtilitiesKit/Move to main app/Storage+SnodeAPI.swift similarity index 100% rename from SignalUtilitiesKit/Storage+SnodeAPI.swift rename to SignalUtilitiesKit/Move to main app/Storage+SnodeAPI.swift diff --git a/SignalUtilitiesKit/Storage.swift b/SignalUtilitiesKit/Move to main app/Storage.swift similarity index 100% rename from SignalUtilitiesKit/Storage.swift rename to SignalUtilitiesKit/Move to main app/Storage.swift diff --git a/SignalUtilitiesKit/NSTimer+OWS.h b/SignalUtilitiesKit/NSTimer+OWS.h deleted file mode 100644 index b77332dc1..000000000 --- a/SignalUtilitiesKit/NSTimer+OWS.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface NSTimer (OWS) - -// This method avoids the classic NSTimer retain cycle bug -// by using a weak reference to the target. -+ (NSTimer *)weakScheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval - target:(id)target - selector:(SEL)selector - userInfo:(nullable id)userInfo - repeats:(BOOL)repeats; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/NSTimer+OWS.m b/SignalUtilitiesKit/NSTimer+OWS.m deleted file mode 100644 index 5af85fcb7..000000000 --- a/SignalUtilitiesKit/NSTimer+OWS.m +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "NSTimer+OWS.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface NSTimerProxy : NSObject - -@property (nonatomic, weak) id target; -@property (nonatomic) SEL selector; - -@end - -#pragma mark - - -@implementation NSTimerProxy - -- (void)timerFired:(NSDictionary *)userInfo -{ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - [self.target performSelector:self.selector withObject:userInfo]; -#pragma clang diagnostic pop -} - -@end - -#pragma mark - - -static void *kNSTimer_OWS_Proxy = &kNSTimer_OWS_Proxy; - -@implementation NSTimer (OWS) - -- (NSTimerProxy *)ows_proxy -{ - return objc_getAssociatedObject(self, kNSTimer_OWS_Proxy); -} - -- (void)ows_setProxy:(NSTimerProxy *)proxy -{ - OWSAssertDebug(proxy); - - objc_setAssociatedObject(self, kNSTimer_OWS_Proxy, proxy, OBJC_ASSOCIATION_RETAIN); -} - -+ (NSTimer *)weakScheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval - target:(id)target - selector:(SEL)selector - userInfo:(nullable id)userInfo - repeats:(BOOL)repeats -{ - NSTimerProxy *proxy = [NSTimerProxy new]; - proxy.target = target; - proxy.selector = selector; - NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:timeInterval - target:proxy - selector:@selector(timerFired:) - userInfo:userInfo - repeats:repeats]; - [timer ows_setProxy:proxy]; - return timer; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/NetworkManager.swift b/SignalUtilitiesKit/NetworkManager.swift deleted file mode 100644 index c1892b669..000000000 --- a/SignalUtilitiesKit/NetworkManager.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - -enum NetworkManagerError: Error { - /// Wraps TSNetworkManager failure callback params in a single throwable error - case taskError(task: URLSessionDataTask, underlyingError: Error) -} - -extension NetworkManagerError { - var isNetworkError: Bool { - switch self { - case .taskError(_, let underlyingError): - return IsNSErrorNetworkFailure(underlyingError) - } - } - - var statusCode: Int { - switch self { - case .taskError(let task, _): - return task.statusCode() - } - } -} - -extension TSNetworkManager { - public typealias NetworkManagerResult = (task: URLSessionDataTask, responseObject: Any?) - - public func perform(_ request: TSRequest, withCompletionQueue queue: DispatchQueue = DispatchQueue.main) -> Promise { - return makePromise(request: request, queue: queue) - } - - public func makePromise(request: TSRequest, queue: DispatchQueue = DispatchQueue.main) -> Promise { - let (promise, resolver) = Promise.pending() - - self.makeRequest(request, - completionQueue: queue, - success: { task, responseObject in - resolver.fulfill((task: task, responseObject: responseObject)) - }, - failure: { task, error in - let nmError = NetworkManagerError.taskError(task: task, underlyingError: error) - let nsError: NSError = nmError as NSError - nsError.isRetryable = (error as NSError).isRetryable - resolver.reject(nsError) - }) - - return promise - } -} diff --git a/SignalUtilitiesKit/NewNonContactConversationViewController.h b/SignalUtilitiesKit/NewNonContactConversationViewController.h deleted file mode 100644 index 58aaeff38..000000000 --- a/SignalUtilitiesKit/NewNonContactConversationViewController.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -@protocol NewNonContactConversationViewControllerDelegate - -- (void)recipientIdWasSelected:(NSString *)recipientId; - -@end - -#pragma mark - - -@interface NewNonContactConversationViewController : SelectRecipientViewController - -@property (nonatomic, weak) id nonContactConversationDelegate; - -@end diff --git a/SignalUtilitiesKit/NewNonContactConversationViewController.m b/SignalUtilitiesKit/NewNonContactConversationViewController.m deleted file mode 100644 index a69f007d5..000000000 --- a/SignalUtilitiesKit/NewNonContactConversationViewController.m +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "NewNonContactConversationViewController.h" -#import "BlockListUIUtils.h" -#import "ContactsViewHelper.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface NewNonContactConversationViewController () - -@end - -#pragma mark - - -@implementation NewNonContactConversationViewController - -- (void)loadView -{ - self.delegate = self; - - [super loadView]; - - self.title = NSLocalizedString( - @"NEW_NONCONTACT_CONVERSATION_VIEW_TITLE", @"Title for the 'new non-contact conversation' view."); -} - -- (NSString *)phoneNumberSectionTitle -{ - return nil; -} - -- (NSString *)phoneNumberButtonText -{ - return NSLocalizedString(@"NEW_NONCONTACT_CONVERSATION_VIEW_BUTTON", - @"A label for the 'add by phone number' button in the 'new non-contact conversation' view"); -} - -- (NSString *)contactsSectionTitle -{ - OWSFailDebug(@"Method should never be called."); - - return nil; -} - -- (void)phoneNumberWasSelected:(NSString *)phoneNumber -{ - OWSAssertDebug(phoneNumber.length > 0); - - [self selectRecipient:phoneNumber]; -} - -- (void)signalAccountWasSelected:(SignalAccount *)signalAccount -{ - OWSAssertDebug(signalAccount); - - [self selectRecipient:signalAccount.recipientId]; -} - -- (void)selectRecipient:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - [self.nonContactConversationDelegate recipientIdWasSelected:recipientId]; -} - -- (BOOL)shouldHideLocalNumber -{ - return NO; -} - -- (BOOL)shouldHideContacts -{ - return YES; -} - -- (BOOL)shouldValidatePhoneNumbers -{ - return YES; -} - -- (BOOL)canSignalAccountBeSelected:(SignalAccount *)signalAccount -{ - OWSFailDebug(@"Method should never be called."); - - return NO; -} - -- (nullable NSString *)accessoryMessageForSignalAccount:(SignalAccount *)signalAccount -{ - OWSFailDebug(@"Method should never be called."); - - return nil; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Notification+Loki.swift b/SignalUtilitiesKit/Notification+Loki.swift index da6894d6d..e696caf26 100644 --- a/SignalUtilitiesKit/Notification+Loki.swift +++ b/SignalUtilitiesKit/Notification+Loki.swift @@ -2,51 +2,27 @@ public extension Notification.Name { // State changes - public static let blockedContactsUpdated = Notification.Name("blockedContactsUpdated") - public static let contactOnlineStatusChanged = Notification.Name("contactOnlineStatusChanged") - public static let groupThreadUpdated = Notification.Name("groupThreadUpdated") - public static let threadDeleted = Notification.Name("threadDeleted") - public static let threadSessionRestoreDevicesChanged = Notification.Name("threadSessionRestoreDevicesChanged") - // Message status changes - public static let calculatingPoW = Notification.Name("calculatingPoW") - public static let routing = Notification.Name("routing") - public static let messageSending = Notification.Name("messageSending") - public static let messageSent = Notification.Name("messageSent") - public static let messageFailed = Notification.Name("messageFailed") + static let blockedContactsUpdated = Notification.Name("blockedContactsUpdated") + static let contactOnlineStatusChanged = Notification.Name("contactOnlineStatusChanged") + static let groupThreadUpdated = Notification.Name("groupThreadUpdated") + static let threadDeleted = Notification.Name("threadDeleted") + static let threadSessionRestoreDevicesChanged = Notification.Name("threadSessionRestoreDevicesChanged") // Onboarding - public static let seedViewed = Notification.Name("seedViewed") + static let seedViewed = Notification.Name("seedViewed") // Interaction - public static let dataNukeRequested = Notification.Name("dataNukeRequested") - // Device linking - public static let unexpectedDeviceLinkRequestReceived = Notification.Name("unexpectedDeviceLinkRequestReceived") - // Onion requests - public static let buildingPaths = Notification.Name("buildingPaths") - public static let pathsBuilt = Notification.Name("pathsBuilt") - public static let onionRequestPathCountriesLoaded = Notification.Name("onionRequestPathCountriesLoaded") + static let dataNukeRequested = Notification.Name("dataNukeRequested") } @objc public extension NSNotification { // State changes - @objc public static let blockedContactsUpdated = Notification.Name.blockedContactsUpdated.rawValue as NSString - @objc public static let contactOnlineStatusChanged = Notification.Name.contactOnlineStatusChanged.rawValue as NSString - @objc public static let groupThreadUpdated = Notification.Name.groupThreadUpdated.rawValue as NSString - @objc public static let threadDeleted = Notification.Name.threadDeleted.rawValue as NSString - @objc public static let threadSessionRestoreDevicesChanged = Notification.Name.threadSessionRestoreDevicesChanged.rawValue as NSString - // Message statuses - @objc public static let calculatingPoW = Notification.Name.calculatingPoW.rawValue as NSString - @objc public static let routing = Notification.Name.routing.rawValue as NSString - @objc public static let messageSending = Notification.Name.messageSending.rawValue as NSString - @objc public static let messageSent = Notification.Name.messageSent.rawValue as NSString - @objc public static let messageFailed = Notification.Name.messageFailed.rawValue as NSString + @objc static let blockedContactsUpdated = Notification.Name.blockedContactsUpdated.rawValue as NSString + @objc static let contactOnlineStatusChanged = Notification.Name.contactOnlineStatusChanged.rawValue as NSString + @objc static let groupThreadUpdated = Notification.Name.groupThreadUpdated.rawValue as NSString + @objc static let threadDeleted = Notification.Name.threadDeleted.rawValue as NSString + @objc static let threadSessionRestoreDevicesChanged = Notification.Name.threadSessionRestoreDevicesChanged.rawValue as NSString // Onboarding - @objc public static let seedViewed = Notification.Name.seedViewed.rawValue as NSString + @objc static let seedViewed = Notification.Name.seedViewed.rawValue as NSString // Interaction - @objc public static let dataNukeRequested = Notification.Name.dataNukeRequested.rawValue as NSString - // Device linking - @objc public static let unexpectedDeviceLinkRequestReceived = Notification.Name.unexpectedDeviceLinkRequestReceived.rawValue as NSString - // Onion requests - @objc public static let buildingPaths = Notification.Name.buildingPaths.rawValue as NSString - @objc public static let pathsBuilt = Notification.Name.pathsBuilt.rawValue as NSString - @objc public static let onionRequestPathCountriesLoaded = Notification.Name.onionRequestPathCountriesLoaded.rawValue as NSString + @objc static let dataNukeRequested = Notification.Name.dataNukeRequested.rawValue as NSString } diff --git a/SignalUtilitiesKit/OWS2FAManager.h b/SignalUtilitiesKit/OWS2FAManager.h deleted file mode 100644 index a41eb6ebc..000000000 --- a/SignalUtilitiesKit/OWS2FAManager.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const NSNotificationName_2FAStateDidChange; - -typedef void (^OWS2FASuccess)(void); -typedef void (^OWS2FAFailure)(NSError *error); - -@class OWSPrimaryStorage; - -// This class can be safely accessed and used from any thread. -@interface OWS2FAManager : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; - -+ (instancetype)sharedManager; - -@property (nullable, nonatomic, readonly) NSString *pinCode; - -- (BOOL)is2FAEnabled; -- (BOOL)isDueForReminder; - -// Request with service -- (void)requestEnable2FAWithPin:(NSString *)pin - success:(nullable OWS2FASuccess)success - failure:(nullable OWS2FAFailure)failure; - -// Sore local settings if, used during registration -- (void)mark2FAAsEnabledWithPin:(NSString *)pin; - -- (void)disable2FAWithSuccess:(nullable OWS2FASuccess)success failure:(nullable OWS2FAFailure)failure; - -- (void)updateRepetitionIntervalWithWasSuccessful:(BOOL)wasSuccessful; - -// used for testing -- (void)setDefaultRepetitionInterval; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWS2FAManager.m b/SignalUtilitiesKit/OWS2FAManager.m deleted file mode 100644 index 24b208b9e..000000000 --- a/SignalUtilitiesKit/OWS2FAManager.m +++ /dev/null @@ -1,271 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWS2FAManager.h" -#import "NSNotificationCenter+OWS.h" -#import "OWSPrimaryStorage.h" -#import "OWSRequestFactory.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "TSNetworkManager.h" -#import "YapDatabaseConnection+OWS.h" -#import "SSKAsserts.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const NSNotificationName_2FAStateDidChange = @"NSNotificationName_2FAStateDidChange"; - -NSString *const kOWS2FAManager_Collection = @"kOWS2FAManager_Collection"; -NSString *const kOWS2FAManager_LastSuccessfulReminderDateKey = @"kOWS2FAManager_LastSuccessfulReminderDateKey"; -NSString *const kOWS2FAManager_PinCode = @"kOWS2FAManager_PinCode"; -NSString *const kOWS2FAManager_RepetitionInterval = @"kOWS2FAManager_RepetitionInterval"; - -const NSUInteger kHourSecs = 60 * 60; -const NSUInteger kDaySecs = kHourSecs * 24; - -@interface OWS2FAManager () - -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@end - -#pragma mark - - -@implementation OWS2FAManager - -+ (instancetype)sharedManager -{ - OWSAssertDebug(SSKEnvironment.shared.ows2FAManager); - - return SSKEnvironment.shared.ows2FAManager; -} - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - self = [super init]; - - if (!self) { - return self; - } - - OWSAssertDebug(primaryStorage); - - _dbConnection = primaryStorage.newDatabaseConnection; - - OWSSingletonAssert(); - - return self; -} - -#pragma mark - Dependencies - -- (TSNetworkManager *)networkManager { - OWSAssertDebug(SSKEnvironment.shared.networkManager); - - return SSKEnvironment.shared.networkManager; -} - -- (TSAccountManager *)tsAccountManager { - return TSAccountManager.sharedInstance; -} - -#pragma mark - - -- (nullable NSString *)pinCode -{ - return [self.dbConnection objectForKey:kOWS2FAManager_PinCode inCollection:kOWS2FAManager_Collection]; -} - -- (BOOL)is2FAEnabled -{ - return self.pinCode != nil; -} - -- (void)set2FANotEnabled -{ - [self.dbConnection removeObjectForKey:kOWS2FAManager_PinCode inCollection:kOWS2FAManager_Collection]; - - [[NSNotificationCenter defaultCenter] postNotificationNameAsync:NSNotificationName_2FAStateDidChange - object:nil - userInfo:nil]; - - [[self.tsAccountManager updateAccountAttributes] retainUntilComplete]; -} - -- (void)mark2FAAsEnabledWithPin:(NSString *)pin -{ - OWSAssertDebug(pin.length > 0); - - [self.dbConnection setObject:pin forKey:kOWS2FAManager_PinCode inCollection:kOWS2FAManager_Collection]; - - // Schedule next reminder relative to now - self.lastSuccessfulReminderDate = [NSDate new]; - - [[NSNotificationCenter defaultCenter] postNotificationNameAsync:NSNotificationName_2FAStateDidChange - object:nil - userInfo:nil]; - - [[self.tsAccountManager updateAccountAttributes] retainUntilComplete]; -} - -- (void)requestEnable2FAWithPin:(NSString *)pin - success:(nullable OWS2FASuccess)success - failure:(nullable OWS2FAFailure)failure -{ - OWSAssertDebug(pin.length > 0); - OWSAssertDebug(success); - OWSAssertDebug(failure); - - TSRequest *request = [OWSRequestFactory enable2FARequestWithPin:pin]; - [self.networkManager makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSAssertIsOnMainThread(); - - [self mark2FAAsEnabledWithPin:pin]; - - if (success) { - success(); - } - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSAssertIsOnMainThread(); - - if (failure) { - failure(error); - } - }]; -} - -- (void)disable2FAWithSuccess:(nullable OWS2FASuccess)success failure:(nullable OWS2FAFailure)failure -{ - TSRequest *request = [OWSRequestFactory disable2FARequest]; - [self.networkManager makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSAssertIsOnMainThread(); - - [self set2FANotEnabled]; - - if (success) { - success(); - } - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSAssertIsOnMainThread(); - - if (failure) { - failure(error); - } - }]; -} - - -#pragma mark - Reminders - -- (nullable NSDate *)lastSuccessfulReminderDate -{ - return [self.dbConnection dateForKey:kOWS2FAManager_LastSuccessfulReminderDateKey - inCollection:kOWS2FAManager_Collection]; -} - -- (void)setLastSuccessfulReminderDate:(nullable NSDate *)date -{ - OWSLogDebug(@"Seting setLastSuccessfulReminderDate:%@", date); - [self.dbConnection setDate:date - forKey:kOWS2FAManager_LastSuccessfulReminderDateKey - inCollection:kOWS2FAManager_Collection]; -} - -- (BOOL)isDueForReminder -{ - if (!self.is2FAEnabled) { - return NO; - } - - return self.nextReminderDate.timeIntervalSinceNow < 0; -} - -- (NSDate *)nextReminderDate -{ - NSDate *lastSuccessfulReminderDate = self.lastSuccessfulReminderDate ?: [NSDate distantPast]; - - return [lastSuccessfulReminderDate dateByAddingTimeInterval:self.repetitionInterval]; -} - -- (NSArray *)allRepetitionIntervals -{ - // Keep sorted monotonically increasing. - return @[ - @(6 * kHourSecs), - @(12 * kHourSecs), - @(1 * kDaySecs), - @(3 * kDaySecs), - @(7 * kDaySecs), - ]; -} - -- (double)defaultRepetitionInterval -{ - return self.allRepetitionIntervals.firstObject.doubleValue; -} - -- (NSTimeInterval)repetitionInterval -{ - return [self.dbConnection doubleForKey:kOWS2FAManager_RepetitionInterval - inCollection:kOWS2FAManager_Collection - defaultValue:self.defaultRepetitionInterval]; -} - -- (void)updateRepetitionIntervalWithWasSuccessful:(BOOL)wasSuccessful -{ - if (wasSuccessful) { - self.lastSuccessfulReminderDate = [NSDate new]; - } - - NSTimeInterval oldInterval = self.repetitionInterval; - NSTimeInterval newInterval = [self adjustRepetitionInterval:oldInterval wasSuccessful:wasSuccessful]; - - OWSLogInfo(@"%@ guess. Updating repetition interval: %f -> %f", - (wasSuccessful ? @"successful" : @"failed"), - oldInterval, - newInterval); - [self.dbConnection setDouble:newInterval - forKey:kOWS2FAManager_RepetitionInterval - inCollection:kOWS2FAManager_Collection]; -} - -- (NSTimeInterval)adjustRepetitionInterval:(NSTimeInterval)oldInterval wasSuccessful:(BOOL)wasSuccessful -{ - NSArray *allIntervals = self.allRepetitionIntervals; - - NSUInteger oldIndex = - [allIntervals indexOfObjectPassingTest:^BOOL(NSNumber *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) { - return oldInterval <= (NSTimeInterval)obj.doubleValue; - }]; - - NSUInteger newIndex; - if (wasSuccessful) { - newIndex = oldIndex + 1; - } else { - // prevent overflow - newIndex = oldIndex <= 0 ? 0 : oldIndex - 1; - } - - // clamp to be valid - newIndex = MAX(0, MIN(allIntervals.count - 1, newIndex)); - - NSTimeInterval newInterval = allIntervals[newIndex].doubleValue; - return newInterval; -} - -- (void)setDefaultRepetitionInterval -{ - [self.dbConnection setDouble:self.defaultRepetitionInterval - forKey:kOWS2FAManager_RepetitionInterval - inCollection:kOWS2FAManager_Collection]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAddToContactsOfferMessage.h b/SignalUtilitiesKit/OWSAddToContactsOfferMessage.h deleted file mode 100644 index 8f5a4daa7..000000000 --- a/SignalUtilitiesKit/OWSAddToContactsOfferMessage.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors -// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject) -__attribute__((deprecated)) @interface OWSAddToContactsOfferMessage : TSInfoMessage - -+ (instancetype)addToContactsOfferMessageWithTimestamp:(uint64_t)timestamp - thread:(TSThread *)thread - contactId:(NSString *)contactId; - -@property (nonatomic, readonly) NSString *contactId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAddToContactsOfferMessage.m b/SignalUtilitiesKit/OWSAddToContactsOfferMessage.m deleted file mode 100644 index af1b648c8..000000000 --- a/SignalUtilitiesKit/OWSAddToContactsOfferMessage.m +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSAddToContactsOfferMessage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSAddToContactsOfferMessage () - -@property (nonatomic) NSString *contactId; - -@end - -#pragma mark - - -// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors -// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" -@implementation OWSAddToContactsOfferMessage -#pragma clang diagnostic pop - -+ (instancetype)addToContactsOfferMessageWithTimestamp:(uint64_t)timestamp - thread:(TSThread *)thread - contactId:(NSString *)contactId -{ - return [[OWSAddToContactsOfferMessage alloc] initWithTimestamp:timestamp thread:thread contactId:contactId]; -} - -- (instancetype)initWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread contactId:(NSString *)contactId -{ - self = [super initWithTimestamp:timestamp inThread:thread messageType:TSInfoMessageAddToContactsOffer]; - - if (self) { - _contactId = contactId; - } - - return self; -} - -- (BOOL)shouldUseReceiptDateForSorting -{ - // Use the timestamp, not the "received at" timestamp to sort, - // since we're creating these interactions after the fact and back-dating them. - return NO; -} - -- (BOOL)isDynamicInteraction -{ - return YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.h b/SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.h deleted file mode 100644 index 143ec7ba0..000000000 --- a/SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors -// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject) -__attribute__((deprecated)) @interface OWSAddToProfileWhitelistOfferMessage : TSInfoMessage - -+ (instancetype)addToProfileWhitelistOfferMessageWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread; - -@property (nonatomic, readonly) NSString *contactId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.m b/SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.m deleted file mode 100644 index 0ca611409..000000000 --- a/SignalUtilitiesKit/OWSAddToProfileWhitelistOfferMessage.m +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSAddToProfileWhitelistOfferMessage.h" -#import "TSThread.h" - -NS_ASSUME_NONNULL_BEGIN - -// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors -// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" -@implementation OWSAddToProfileWhitelistOfferMessage -#pragma clang diagnostic pop - -+ (instancetype)addToProfileWhitelistOfferMessageWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread -{ - return [[OWSAddToProfileWhitelistOfferMessage alloc] - initWithTimestamp:timestamp - inThread:thread - messageType:(thread.isGroupThread ? TSInfoMessageAddGroupToProfileWhitelistOffer - : TSInfoMessageAddUserToProfileWhitelistOffer)]; -} - -- (BOOL)shouldUseReceiptDateForSorting -{ - // Use the timestamp, not the "received at" timestamp to sort, - // since we're creating these interactions after the fact and back-dating them. - return NO; -} - -- (BOOL)isDynamicInteraction -{ - return YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAnalytics.h b/SignalUtilitiesKit/OWSAnalytics.h deleted file mode 100755 index 789bafa61..000000000 --- a/SignalUtilitiesKit/OWSAnalytics.h +++ /dev/null @@ -1,165 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -// TODO: We probably don't need all of these levels. -typedef NS_ENUM(NSUInteger, OWSAnalyticsSeverity) { - // Info events are routine. - // - // It's safe to discard a large fraction of these events. - OWSAnalyticsSeverityInfo = 1, - // Error events should never be discarded. - OWSAnalyticsSeverityError = 3, - // Critical events are special. They are submitted immediately - // and not persisted, since the database may not be working. - OWSAnalyticsSeverityCritical = 4 -}; - -// This is a placeholder. We don't yet serialize or transmit analytics events. -// -// If/when we take this on, we'll want to develop a solution that can be used -// report user activity - especially serious bugs - without compromising user -// privacy in any way. We must _never_ include any identifying information. -@interface OWSAnalytics : NSObject - -// description: A non-empty string without any leading whitespace. -// This should conform to our analytics event naming conventions. -// "category_event_name", e.g. "database_error_no_database_file_found". -// parameters: Optional. -// If non-nil, the keys should all be non-empty NSStrings. -// Values should be NSStrings or NSNumbers. -+ (void)logEvent:(NSString *)eventName - severity:(OWSAnalyticsSeverity)severity - parameters:(nullable NSDictionary *)parameters - location:(const char *)location - line:(int)line; - -+ (void)appLaunchDidBegin; - -+ (long)orderOfMagnitudeOf:(long)value; - -@end - -typedef NSDictionary *_Nonnull (^OWSProdAssertParametersBlock)(void); - -// These methods should be used to assert errors for which we want to fire analytics events. -// -// In production, returns __Value, the assert value, so that we can handle this case. -// In debug builds, asserts. -// -// parametersBlock is of type OWSProdAssertParametersBlock. -// The "C" variants (e.g. OWSProdAssert() vs. OWSProdCAssert() should be used in free functions, -// where there is no self. They can also be used in blocks to avoid capturing a reference to self. -#define OWSProdAssertWParamsTemplate(__value, __eventName, __parametersBlock, __assertMacro) \ - { \ - if (!(BOOL)(__value)) { \ - NSDictionary *__eventParameters = (__parametersBlock ? __parametersBlock() : nil); \ - [DDLog flushLog]; \ - [OWSAnalytics logEvent:__eventName \ - severity:OWSAnalyticsSeverityError \ - parameters:__eventParameters \ - location:__PRETTY_FUNCTION__ \ - line:__LINE__]; \ - } \ - __assertMacro(__value); \ - return (BOOL)(__value); \ - } - -#define OWSProdAssertWParams(__value, __eventName, __parametersBlock) \ - OWSProdAssertWParamsTemplate(__value, __eventName, __parametersBlock, OWSAssert) - -#define OWSProdCAssertWParams(__value, __eventName, __parametersBlock) \ - OWSProdAssertWParamsTemplate(__value, __eventName, __parametersBlock, OWSCAssert) - -#define OWSProdAssert(__value, __eventName) OWSProdAssertWParams(__value, __eventName, nil) - -#define OWSProdCAssert(__value, __eventName) OWSProdCAssertWParams(__value, __eventName, nil) - -#define OWSProdFailWParamsTemplate(__eventName, __parametersBlock, __failMacro) \ - { \ - NSDictionary *__eventParameters \ - = (__parametersBlock ? ((OWSProdAssertParametersBlock)__parametersBlock)() : nil); \ - [OWSAnalytics logEvent:__eventName \ - severity:OWSAnalyticsSeverityCritical \ - parameters:__eventParameters \ - location:__PRETTY_FUNCTION__ \ - line:__LINE__]; \ - __failMacro(__eventName); \ - } - -#define OWSProdFailWParams(__eventName, __parametersBlock) \ - OWSProdFailWParamsTemplate(__eventName, __parametersBlock, OWSFailNoFormat) -#define OWSProdCFailWParams(__eventName, __parametersBlock) \ - OWSProdFailWParamsTemplate(__eventName, __parametersBlock, OWSCFailNoFormat) - -#define OWSProdFail(__eventName) OWSProdFailWParams(__eventName, nil) - -#define OWSProdCFail(__eventName) OWSProdCFailWParams(__eventName, nil) - -#define OWSProdCFail(__eventName) OWSProdCFailWParams(__eventName, nil) - -#define OWSProdEventWParams(__severityLevel, __eventName, __parametersBlock) \ - { \ - NSDictionary *__eventParameters \ - = (__parametersBlock ? ((OWSProdAssertParametersBlock)__parametersBlock)() : nil); \ - [OWSAnalytics logEvent:__eventName \ - severity:__severityLevel \ - parameters:__eventParameters \ - location:__PRETTY_FUNCTION__ \ - line:__LINE__]; \ - } - -#pragma mark - Info Events - -#define OWSProdInfoWParams(__eventName, __parametersBlock) \ - OWSProdEventWParams(OWSAnalyticsSeverityInfo, __eventName, __parametersBlock) - -#define OWSProdInfo(__eventName) OWSProdEventWParams(OWSAnalyticsSeverityInfo, __eventName, nil) - -#pragma mark - Error Events - -#define OWSProdErrorWParams(__eventName, __parametersBlock) \ - OWSProdEventWParams(OWSAnalyticsSeverityError, __eventName, __parametersBlock) - -#define OWSProdError(__eventName) OWSProdEventWParams(OWSAnalyticsSeverityError, __eventName, nil) - -#pragma mark - Critical Events - -#define OWSProdCriticalWParams(__eventName, __parametersBlock) \ - OWSProdEventWParams(OWSAnalyticsSeverityCritical, __eventName, __parametersBlock) - -#define OWSProdCritical(__eventName) OWSProdEventWParams(OWSAnalyticsSeverityCritical, __eventName, nil) - -#pragma mark - OWSMessageManager macros -// Defined here rather than in OWSMessageManager so that our analytic event extraction script -// can properly detect the event names. -// -// The debug logs can be more verbose than the analytics events. -// -// In this case `descriptionForEnvelope` is valuable enough to -// log but too dangerous to include in the analytics event. -#define OWSProdErrorWEnvelope(__analyticsEventName, __envelope) \ - { \ - OWSLogError(@"%s:%d %@: %@", \ - __PRETTY_FUNCTION__, \ - __LINE__, \ - __analyticsEventName, \ - [self descriptionForEnvelope:__envelope]); \ - OWSProdError(__analyticsEventName) \ - } - -#define OWSProdInfoWEnvelope(__analyticsEventName, __envelope) \ - { \ - OWSLogInfo(@"%s:%d %@: %@", \ - __PRETTY_FUNCTION__, \ - __LINE__, \ - __analyticsEventName, \ - [self descriptionForEnvelope:__envelope]); \ - OWSProdInfo(__analyticsEventName) \ - } - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAnalytics.m b/SignalUtilitiesKit/OWSAnalytics.m deleted file mode 100755 index c5d896915..000000000 --- a/SignalUtilitiesKit/OWSAnalytics.m +++ /dev/null @@ -1,426 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSAnalytics.h" -#import "AppContext.h" -#import "OWSBackgroundTask.h" -#import "OWSPrimaryStorage.h" -#import "OWSQueues.h" -#import "SSKEnvironment.h" -#import "YapDatabaseConnection+OWS.h" -#import -#import -#import -#import -#import -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -#ifdef DEBUG - -#define NO_SIGNAL_ANALYTICS - -#endif - -NSString *const kOWSAnalytics_EventsCollection = @"kOWSAnalytics_EventsCollection"; - -// Percentage of analytics events to discard. 0 <= x <= 100. -const int kOWSAnalytics_DiscardFrequency = 0; - -NSString *NSStringForOWSAnalyticsSeverity(OWSAnalyticsSeverity severity) -{ - switch (severity) { - case OWSAnalyticsSeverityInfo: - return @"Info"; - case OWSAnalyticsSeverityError: - return @"Error"; - case OWSAnalyticsSeverityCritical: - return @"Critical"; - } -} - -@interface OWSAnalytics () - -@property (nonatomic, readonly) Reachability *reachability; -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@property (atomic) BOOL hasRequestInFlight; - -@end - -#pragma mark - - -@implementation OWSAnalytics - -+ (instancetype)sharedInstance -{ - static OWSAnalytics *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [[self alloc] initDefault]; - }); - return instance; -} - -// We lazy-create the analytics DB connection, so that we can handle -// errors that occur while initializing OWSPrimaryStorage. -+ (YapDatabaseConnection *)dbConnection -{ - return SSKEnvironment.shared.analyticsDBConnection; -} - -- (instancetype)initDefault -{ - self = [super init]; - - if (!self) { - return self; - } - - _reachability = [Reachability reachabilityForInternetConnection]; - - [self observeNotifications]; - - OWSSingletonAssert(); - - return self; -} - -- (void)observeNotifications -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(reachabilityChanged) - name:kReachabilityChangedNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidBecomeActive) - name:OWSApplicationDidBecomeActiveNotification - object:nil]; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)reachabilityChanged -{ - OWSAssertIsOnMainThread(); - - [self tryToSyncEvents]; -} - -- (void)applicationDidBecomeActive -{ - OWSAssertIsOnMainThread(); - - [self tryToSyncEvents]; -} - -- (void)tryToSyncEvents -{ - return; // Loki: Do nothing - dispatch_async(self.serialQueue, ^{ - // Don't try to sync if: - // - // * There's no network available. - // * There's already a sync request in flight. - if (!self.reachability.isReachable) { - OWSLogVerbose(@"Not reachable"); - return; - } - if (self.hasRequestInFlight) { - return; - } - - __block NSString *firstEventKey = nil; - __block NSDictionary *firstEventDictionary = nil; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - // Take any event. We don't need to deliver them in any particular order. - [transaction enumerateKeysInCollection:kOWSAnalytics_EventsCollection - usingBlock:^(NSString *key, BOOL *_Nonnull stop) { - firstEventKey = key; - *stop = YES; - }]; - if (!firstEventKey) { - return; - } - - firstEventDictionary = [transaction objectForKey:firstEventKey inCollection:kOWSAnalytics_EventsCollection]; - OWSAssertDebug(firstEventDictionary); - OWSAssertDebug([firstEventDictionary isKindOfClass:[NSDictionary class]]); - }]; - - if (firstEventDictionary) { - [self sendEvent:firstEventDictionary eventKey:firstEventKey isCritical:NO]; - } - }); -} - -- (void)sendEvent:(NSDictionary *)eventDictionary eventKey:(NSString *)eventKey isCritical:(BOOL)isCritical -{ - return; // Loki: Do nothing - OWSAssertDebug(eventDictionary); - OWSAssertDebug(eventKey); - AssertOnDispatchQueue(self.serialQueue); - - if (isCritical) { - [self submitEvent:eventDictionary - eventKey:eventKey - success:^{ - OWSLogDebug(@"sendEvent[critical] succeeded: %@", eventKey); - } - failure:^{ - OWSLogError(@"sendEvent[critical] failed: %@", eventKey); - }]; - } else { - self.hasRequestInFlight = YES; - __block BOOL isComplete = NO; - [self submitEvent:eventDictionary - eventKey:eventKey - success:^{ - if (isComplete) { - return; - } - isComplete = YES; - OWSLogDebug(@"sendEvent succeeded: %@", eventKey); - dispatch_async(self.serialQueue, ^{ - self.hasRequestInFlight = NO; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - // Remove from queue. - [transaction removeObjectForKey:eventKey inCollection:kOWSAnalytics_EventsCollection]; - }]; - - // Wait a second between network requests / retries. - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [self tryToSyncEvents]; - }); - }); - } - failure:^{ - if (isComplete) { - return; - } - isComplete = YES; - OWSLogError(@"sendEvent failed: %@", eventKey); - dispatch_async(self.serialQueue, ^{ - self.hasRequestInFlight = NO; - - // Wait a second between network requests / retries. - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [self tryToSyncEvents]; - }); - }); - }]; - } -} - -- (void)submitEvent:(NSDictionary *)eventDictionary - eventKey:(NSString *)eventKey - success:(void (^_Nonnull)(void))successBlock - failure:(void (^_Nonnull)(void))failureBlock -{ - return; // Loki: Do nothing - OWSAssertDebug(eventDictionary); - OWSAssertDebug(eventKey); - AssertOnDispatchQueue(self.serialQueue); - - OWSLogDebug(@"submitting: %@", eventKey); - - __block OWSBackgroundTask *backgroundTask = - [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__ - completionBlock:^(BackgroundTaskState backgroundTaskState) { - if (backgroundTaskState == BackgroundTaskState_Success) { - successBlock(); - } else { - failureBlock(); - } - }]; - - // Until we integrate with an analytics platform, behave as though all event delivery succeeds. - dispatch_async(self.serialQueue, ^{ - backgroundTask = nil; - }); -} - -- (dispatch_queue_t)serialQueue -{ - static dispatch_queue_t queue = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - queue = dispatch_queue_create("org.whispersystems.analytics.serial", DISPATCH_QUEUE_SERIAL); - }); - return queue; -} - -- (NSString *)operatingSystemVersionString -{ - static NSString *result = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSOperatingSystemVersion operatingSystemVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; - result = [NSString stringWithFormat:@"%lu.%lu.%lu", - (unsigned long)operatingSystemVersion.majorVersion, - (unsigned long)operatingSystemVersion.minorVersion, - (unsigned long)operatingSystemVersion.patchVersion]; - }); - return result; -} - -- (NSDictionary *)eventSuperProperties -{ - NSMutableDictionary *result = [NSMutableDictionary new]; - result[@"app_version"] = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; - result[@"platform"] = @"ios"; - result[@"ios_version"] = self.operatingSystemVersionString; - return result; -} - -- (long)orderOfMagnitudeOf:(long)value -{ - return [OWSAnalytics orderOfMagnitudeOf:value]; -} - -+ (long)orderOfMagnitudeOf:(long)value -{ - if (value <= 0) { - return 0; - } - return (long)round(pow(10, floor(log10(value)))); -} - -- (void)addEvent:(NSString *)eventName severity:(OWSAnalyticsSeverity)severity properties:(NSDictionary *)properties -{ - return; // Loki: Do nothing - OWSAssertDebug(eventName.length > 0); - OWSAssertDebug(properties); - -#ifndef NO_SIGNAL_ANALYTICS - BOOL isError = severity == OWSAnalyticsSeverityError; - BOOL isCritical = severity == OWSAnalyticsSeverityCritical; - - uint32_t discardValue = arc4random_uniform(101); - if (!isError && !isCritical && discardValue < kOWSAnalytics_DiscardFrequency) { - OWSLogVerbose(@"Discarding event: %@", eventName); - return; - } - - void (^addEvent)(void) = ^{ - // Add super properties. - NSMutableDictionary *eventProperties = (properties ? [properties mutableCopy] : [NSMutableDictionary new]); - [eventProperties addEntriesFromDictionary:self.eventSuperProperties]; - - NSDictionary *eventDictionary = [eventProperties copy]; - OWSAssertDebug(eventDictionary); - NSString *eventKey = [NSUUID UUID].UUIDString; - OWSLogDebug(@"enqueuing event: %@", eventKey); - - if (isCritical) { - // Critical events should not be serialized or enqueued - they should be submitted immediately. - [self sendEvent:eventDictionary eventKey:eventKey isCritical:YES]; - } else { - // Add to queue. - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - const int kMaxQueuedEvents = 5000; - if ([transaction numberOfKeysInCollection:kOWSAnalytics_EventsCollection] > kMaxQueuedEvents) { - OWSLogError(@"Event queue overflow."); - return; - } - - [transaction setObject:eventDictionary forKey:eventKey inCollection:kOWSAnalytics_EventsCollection]; - }]; - - [self tryToSyncEvents]; - } - }; - - if ([self shouldReportAsync:severity]) { - dispatch_async(self.serialQueue, addEvent); - } else { - dispatch_sync(self.serialQueue, addEvent); - } -#endif -} - -+ (void)logEvent:(NSString *)eventName - severity:(OWSAnalyticsSeverity)severity - parameters:(nullable NSDictionary *)parameters - location:(const char *)location - line:(int)line -{ - [[self sharedInstance] logEvent:eventName severity:severity parameters:parameters location:location line:line]; -} - -- (void)logEvent:(NSString *)eventName - severity:(OWSAnalyticsSeverity)severity - parameters:(nullable NSDictionary *)parameters - location:(const char *)location - line:(int)line -{ - return; // Loki: Do nothing - DDLogFlag logFlag; - switch (severity) { - case OWSAnalyticsSeverityInfo: - logFlag = DDLogFlagInfo; - break; - case OWSAnalyticsSeverityError: - logFlag = DDLogFlagError; - break; - case OWSAnalyticsSeverityCritical: - logFlag = DDLogFlagError; - break; - default: - OWSFailDebug(@"Unknown severity."); - logFlag = DDLogFlagDebug; - break; - } - - // Log the event. - NSString *logString = [NSString stringWithFormat:@"%s:%d %@", location, line, eventName]; - if (!parameters) { - LOG_MAYBE([self shouldReportAsync:severity], LOG_LEVEL_DEF, logFlag, 0, nil, location, @"%@", logString); - } else { - LOG_MAYBE([self shouldReportAsync:severity], - LOG_LEVEL_DEF, - logFlag, - 0, - nil, - location, - @"%@ %@", - logString, - parameters); - } - if (![self shouldReportAsync:severity]) { - [DDLog flushLog]; - } - - NSMutableDictionary *eventProperties = (parameters ? [parameters mutableCopy] : [NSMutableDictionary new]); - eventProperties[@"event_location"] = [NSString stringWithFormat:@"%s:%d", location, line]; - [self addEvent:eventName severity:severity properties:eventProperties]; -} - -- (BOOL)shouldReportAsync:(OWSAnalyticsSeverity)severity -{ - return severity != OWSAnalyticsSeverityCritical; -} - -#pragma mark - Logging - -+ (void)appLaunchDidBegin -{ - [self.sharedInstance appLaunchDidBegin]; -} - -- (void)appLaunchDidBegin -{ - OWSProdInfo([OWSAnalyticsEvents appLaunch]); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAnalyticsEvents.h b/SignalUtilitiesKit/OWSAnalyticsEvents.h deleted file mode 100755 index 3f7b33d59..000000000 --- a/SignalUtilitiesKit/OWSAnalyticsEvents.h +++ /dev/null @@ -1,239 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSAnalyticsEvents : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -// The code between these markers is code-generated by: -// SignalServiceKit/Utilities/extract_analytics_event_names.py -// To add an event, insert your logging event as a string e.g.: -// -// OWSProdFail(@"messageSenderErrorMissingNewPreKeyBundle"); -// -// Then run SignalServiceKit/Utilities/extract_analytics_event_names.py, which -// will extract the string into a named method in this class. -#pragma mark - Code Generation Marker - -+ (NSString *)accountsErrorRegisterPushTokensFailed; - -+ (NSString *)accountsErrorUnregisterAccountRequestFailed; - -+ (NSString *)accountsErrorVerificationCodeRequestFailed; - -+ (NSString *)accountsErrorVerifyAccountRequestFailed; - -+ (NSString *)appDelegateErrorFailedToRegisterForRemoteNotifications; - -+ (NSString *)appLaunch; - -+ (NSString *)appLaunchComplete; - -+ (NSString *)callServiceCallAlreadySet; - -+ (NSString *)callServiceCallIdMismatch; - -+ (NSString *)callServiceCallMismatch; - -+ (NSString *)callServiceCallMissing; - -+ (NSString *)callServiceCallUnexpectedlyIdle; - -+ (NSString *)callServiceCallViewCouldNotPresent; - -+ (NSString *)callServiceCouldNotCreatePeerConnectionClientPromise; - -+ (NSString *)callServiceCouldNotCreateReadyToSendIceUpdatesPromise; - -+ (NSString *)callServiceErrorHandleLocalAddedIceCandidate; - -+ (NSString *)callServiceErrorHandleLocalHungupCall; - -+ (NSString *)callServiceErrorHandleReceivedErrorExternal; - -+ (NSString *)callServiceErrorHandleReceivedErrorInternal; - -+ (NSString *)callServiceErrorHandleRemoteAddedIceCandidate; - -+ (NSString *)callServiceErrorIncomingConnectionFailedExternal; - -+ (NSString *)callServiceErrorIncomingConnectionFailedInternal; - -+ (NSString *)callServiceErrorOutgoingConnectionFailedExternal; - -+ (NSString *)callServiceErrorOutgoingConnectionFailedInternal; - -+ (NSString *)callServiceErrorTimeoutWhileConnectingIncoming; - -+ (NSString *)callServiceErrorTimeoutWhileConnectingOutgoing; - -+ (NSString *)callServiceMissingFulfillReadyToSendIceUpdatesPromise; - -+ (NSString *)callServicePeerConnectionAlreadySet; - -+ (NSString *)callServicePeerConnectionMissing; - -+ (NSString *)callServiceCallDataMissing; - -+ (NSString *)contactsErrorContactsIntersectionFailed; - -+ (NSString *)errorAttachmentRequestFailed; - -+ (NSString *)errorCouldNotPresentViewDueToCall; - -+ (NSString *)errorEnableVideoCallingRequestFailed; - -+ (NSString *)errorGetDevicesFailed; - -+ (NSString *)errorPrekeysAvailablePrekeysRequestFailed; - -+ (NSString *)errorPrekeysCurrentSignedPrekeyRequestFailed; - -+ (NSString *)errorPrekeysUpdateFailedJustSigned; - -+ (NSString *)errorPrekeysUpdateFailedSignedAndOnetime; - -+ (NSString *)errorProvisioningCodeRequestFailed; - -+ (NSString *)errorProvisioningRequestFailed; - -+ (NSString *)errorUnlinkDeviceFailed; - -+ (NSString *)errorUpdateAttributesRequestFailed; - -+ (NSString *)messageSenderErrorMissingNewPreKeyBundle; - -+ (NSString *)messageManagerErrorCallMessageNoActionablePayload; - -+ (NSString *)messageManagerErrorCorruptMessage; - -+ (NSString *)messageManagerErrorCouldNotHandlePrekeyBundle; - -+ (NSString *)messageManagerErrorCouldNotHandleUnidentifiedSenderMessage; - -+ (NSString *)messageManagerErrorCouldNotHandleSecureMessage; - -+ (NSString *)messageManagerErrorEnvelopeNoActionablePayload; - -+ (NSString *)messageManagerErrorEnvelopeTypeKeyExchange; - -+ (NSString *)messageManagerErrorEnvelopeTypeOther; - -+ (NSString *)messageManagerErrorEnvelopeTypeUnknown; - -+ (NSString *)messageManagerErrorInvalidKey; - -+ (NSString *)messageManagerErrorInvalidKeyId; - -+ (NSString *)messageManagerErrorInvalidMessageVersion; - -+ (NSString *)messageManagerErrorInvalidProtocolMessage; - -+ (NSString *)messageManagerErrorMessageEnvelopeHasNoContent; - -+ (NSString *)messageManagerErrorNoSession; - -+ (NSString *)messageManagerErrorOversizeMessage; - -+ (NSString *)messageManagerErrorSyncMessageFromUnknownSource; - -+ (NSString *)messageManagerErrorUntrustedIdentityKeyException; - -+ (NSString *)messageReceiverErrorLargeMessage; - -+ (NSString *)messageReceiverErrorOversizeMessage; - -+ (NSString *)messageSendErrorCouldNotSerializeMessageJson; - -+ (NSString *)messageSendErrorFailedDueToPrekeyUpdateFailures; - -+ (NSString *)messageSendErrorFailedDueToUntrustedKey; - -+ (NSString *)messageSenderErrorCouldNotFindContacts1; - -+ (NSString *)messageSenderErrorCouldNotFindContacts2; - -+ (NSString *)messageSenderErrorCouldNotFindContacts3; - -+ (NSString *)messageSenderErrorCouldNotLoadAttachment; - -+ (NSString *)messageSenderErrorCouldNotParseMismatchedDevicesJson; - -+ (NSString *)messageSenderErrorCouldNotWriteAttachment; - -+ (NSString *)messageSenderErrorGenericSendFailure; - -+ (NSString *)messageSenderErrorInvalidIdentityKeyLength; - -+ (NSString *)messageSenderErrorInvalidIdentityKeyType; - -+ (NSString *)messageSenderErrorNoMissingOrExtraDevices; - -+ (NSString *)messageSenderErrorRecipientPrekeyRequestFailed; - -+ (NSString *)messageSenderErrorSendOperationDidNotComplete; - -+ (NSString *)messageSenderErrorUnexpectedKeyBundle; - -+ (NSString *)peerConnectionClientErrorSendDataChannelMessageFailed; - -+ (NSString *)prekeysDeletedOldAcceptedSignedPrekey; - -+ (NSString *)prekeysDeletedOldSignedPrekey; - -+ (NSString *)prekeysDeletedOldUnacceptedSignedPrekey; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidAcl; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidAlgorithm; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidCredential; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidDate; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidKey; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidPolicy; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidResponse; - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidSignature; - -+ (NSString *)registrationBegan; - -+ (NSString *)registrationRegisteredPhoneNumber; - -+ (NSString *)registrationRegisteringCode; - -+ (NSString *)registrationRegisteringRequestedNewCodeBySms; - -+ (NSString *)registrationRegisteringRequestedNewCodeByVoice; - -+ (NSString *)registrationRegisteringSubmittedCode; - -+ (NSString *)registrationRegistrationFailed; - -+ (NSString *)registrationVerificationBack; - -+ (NSString *)storageErrorCouldNotDecodeClass; - -+ (NSString *)storageErrorCouldNotLoadDatabase; - -+ (NSString *)storageErrorCouldNotLoadDatabaseSecondAttempt; - -+ (NSString *)storageErrorCouldNotStoreKeychainValue; - -+ (NSString *)storageErrorDeserialization; - -+ (NSString *)storageErrorFileProtection; - -#pragma mark - Code Generation Marker - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAnalyticsEvents.m b/SignalUtilitiesKit/OWSAnalyticsEvents.m deleted file mode 100755 index 1a4b0cb0c..000000000 --- a/SignalUtilitiesKit/OWSAnalyticsEvents.m +++ /dev/null @@ -1,549 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSAnalyticsEvents.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSAnalyticsEvents - -// The code between these markers is code-generated by: -// SignalServiceKit/Utilities/extract_analytics_event_names.py -#pragma mark - Code Generation Marker - -+ (NSString *)accountsErrorRegisterPushTokensFailed -{ - return @"accounts_error_register_push_tokens_failed"; -} - -+ (NSString *)accountsErrorUnregisterAccountRequestFailed -{ - return @"accounts_error_unregister_account_request_failed"; -} - -+ (NSString *)accountsErrorVerificationCodeRequestFailed -{ - return @"accounts_error_verification_code_request_failed"; -} - -+ (NSString *)accountsErrorVerifyAccountRequestFailed -{ - return @"accounts_error_verify_account_request_failed"; -} - -+ (NSString *)appDelegateErrorFailedToRegisterForRemoteNotifications -{ - return @"app_delegate_error_failed_to_register_for_remote_notifications"; -} - -+ (NSString *)appLaunch -{ - return @"app_launch"; -} - -+ (NSString *)appLaunchComplete -{ - return @"app_launch_complete"; -} - -+ (NSString *)callServiceCallAlreadySet -{ - return @"call_service_call_already_set"; -} - -+ (NSString *)callServiceCallIdMismatch -{ - return @"call_service_call_id_mismatch"; -} - -+ (NSString *)callServiceCallMismatch -{ - return @"call_service_call_mismatch"; -} - -+ (NSString *)callServiceCallMissing -{ - return @"call_service_call_missing"; -} - -+ (NSString *)callServiceCallUnexpectedlyIdle -{ - return @"call_service_call_unexpectedly_idle"; -} - -+ (NSString *)callServiceCallViewCouldNotPresent -{ - return @"call_service_call_view_could_not_present"; -} - -+ (NSString *)callServiceCouldNotCreatePeerConnectionClientPromise -{ - return @"call_service_could_not_create_peer_connection_client_promise"; -} - -+ (NSString *)callServiceCouldNotCreateReadyToSendIceUpdatesPromise -{ - return @"call_service_could_not_create_ready_to_send_ice_updates_promise"; -} - -+ (NSString *)callServiceErrorHandleLocalAddedIceCandidate -{ - return @"call_service_error_handle_local_added_ice_candidate"; -} - -+ (NSString *)callServiceErrorHandleLocalHungupCall -{ - return @"call_service_error_handle_local_hungup_call"; -} - -+ (NSString *)callServiceErrorHandleReceivedErrorExternal -{ - return @"call_service_error_handle_received_error_external"; -} - -+ (NSString *)callServiceErrorHandleReceivedErrorInternal -{ - return @"call_service_error_handle_received_error_internal"; -} - -+ (NSString *)callServiceErrorHandleRemoteAddedIceCandidate -{ - return @"call_service_error_handle_remote_added_ice_candidate"; -} - -+ (NSString *)callServiceErrorIncomingConnectionFailedExternal -{ - return @"call_service_error_incoming_connection_failed_external"; -} - -+ (NSString *)callServiceErrorIncomingConnectionFailedInternal -{ - return @"call_service_error_incoming_connection_failed_internal"; -} - -+ (NSString *)callServiceErrorOutgoingConnectionFailedExternal -{ - return @"call_service_error_outgoing_connection_failed_external"; -} - -+ (NSString *)callServiceErrorOutgoingConnectionFailedInternal -{ - return @"call_service_error_outgoing_connection_failed_internal"; -} - -+ (NSString *)callServiceErrorTimeoutWhileConnectingIncoming -{ - return @"call_service_error_timeout_while_connecting_incoming"; -} - -+ (NSString *)callServiceErrorTimeoutWhileConnectingOutgoing -{ - return @"call_service_error_timeout_while_connecting_outgoing"; -} - -+ (NSString *)callServiceMissingFulfillReadyToSendIceUpdatesPromise -{ - return @"call_service_missing_fulfill_ready_to_send_ice_updates_promise"; -} - -+ (NSString *)callServicePeerConnectionAlreadySet -{ - return @"call_service_peer_connection_already_set"; -} - -+ (NSString *)callServicePeerConnectionMissing -{ - return @"call_service_peer_connection_missing"; -} - -+ (NSString *)callServiceCallDataMissing -{ - return @"call_service_call_data_missing"; -} - -+ (NSString *)contactsErrorContactsIntersectionFailed -{ - return @"contacts_error_contacts_intersection_failed"; -} - -+ (NSString *)errorAttachmentRequestFailed -{ - return @"error_attachment_request_failed"; -} - -+ (NSString *)errorCouldNotPresentViewDueToCall -{ - return @"error_could_not_present_view_due_to_call"; -} - -+ (NSString *)errorEnableVideoCallingRequestFailed -{ - return @"error_enable_video_calling_request_failed"; -} - -+ (NSString *)errorGetDevicesFailed -{ - return @"error_get_devices_failed"; -} - -+ (NSString *)errorPrekeysAvailablePrekeysRequestFailed -{ - return @"error_prekeys_available_prekeys_request_failed"; -} - -+ (NSString *)errorPrekeysCurrentSignedPrekeyRequestFailed -{ - return @"error_prekeys_current_signed_prekey_request_failed"; -} - -+ (NSString *)errorPrekeysUpdateFailedJustSigned -{ - return @"error_prekeys_update_failed_just_signed"; -} - -+ (NSString *)errorPrekeysUpdateFailedSignedAndOnetime -{ - return @"error_prekeys_update_failed_signed_and_onetime"; -} - -+ (NSString *)errorProvisioningCodeRequestFailed -{ - return @"error_provisioning_code_request_failed"; -} - -+ (NSString *)errorProvisioningRequestFailed -{ - return @"error_provisioning_request_failed"; -} - -+ (NSString *)errorUnlinkDeviceFailed -{ - return @"error_unlink_device_failed"; -} - -+ (NSString *)errorUpdateAttributesRequestFailed -{ - return @"error_update_attributes_request_failed"; -} - -+ (NSString *)messageSenderErrorMissingNewPreKeyBundle -{ - return @"messageSenderErrorMissingNewPreKeyBundle"; -} - -+ (NSString *)messageManagerErrorCallMessageNoActionablePayload -{ - return @"message_manager_error_call_message_no_actionable_payload"; -} - -+ (NSString *)messageManagerErrorCorruptMessage -{ - return @"message_manager_error_corrupt_message"; -} - -+ (NSString *)messageManagerErrorCouldNotHandlePrekeyBundle -{ - return @"message_manager_error_could_not_handle_prekey_bundle"; -} - -+ (NSString *)messageManagerErrorCouldNotHandleUnidentifiedSenderMessage -{ - return @"message_manager_error_could_not_handle_unidentified_sender_message"; -} - -+ (NSString *)messageManagerErrorCouldNotHandleSecureMessage -{ - return @"message_manager_error_could_not_handle_secure_message"; -} - -+ (NSString *)messageManagerErrorEnvelopeNoActionablePayload -{ - return @"message_manager_error_envelope_no_actionable_payload"; -} - -+ (NSString *)messageManagerErrorEnvelopeTypeKeyExchange -{ - return @"message_manager_error_envelope_type_key_exchange"; -} - -+ (NSString *)messageManagerErrorEnvelopeTypeOther -{ - return @"message_manager_error_envelope_type_other"; -} - -+ (NSString *)messageManagerErrorEnvelopeTypeUnknown -{ - return @"message_manager_error_envelope_type_unknown"; -} - -+ (NSString *)messageManagerErrorInvalidKey -{ - return @"message_manager_error_invalid_key"; -} - -+ (NSString *)messageManagerErrorInvalidKeyId -{ - return @"message_manager_error_invalid_key_id"; -} - -+ (NSString *)messageManagerErrorInvalidMessageVersion -{ - return @"message_manager_error_invalid_message_version"; -} - -+ (NSString *)messageManagerErrorInvalidProtocolMessage -{ - return @"message_manager_error_invalid_protocol_message"; -} - -+ (NSString *)messageManagerErrorMessageEnvelopeHasNoContent -{ - return @"message_manager_error_message_envelope_has_no_content"; -} - -+ (NSString *)messageManagerErrorNoSession -{ - return @"message_manager_error_no_session"; -} - -+ (NSString *)messageManagerErrorOversizeMessage -{ - return @"message_manager_error_oversize_message"; -} - -+ (NSString *)messageManagerErrorSyncMessageFromUnknownSource -{ - return @"message_manager_error_sync_message_from_unknown_source"; -} - -+ (NSString *)messageManagerErrorUntrustedIdentityKeyException -{ - return @"message_manager_error_untrusted_identity_key_exception"; -} - -+ (NSString *)messageReceiverErrorLargeMessage -{ - return @"message_receiver_error_large_message"; -} - -+ (NSString *)messageReceiverErrorOversizeMessage -{ - return @"message_receiver_error_oversize_message"; -} - -+ (NSString *)messageSendErrorCouldNotSerializeMessageJson -{ - return @"message_send_error_could_not_serialize_message_json"; -} - -+ (NSString *)messageSendErrorFailedDueToPrekeyUpdateFailures -{ - return @"message_send_error_failed_due_to_prekey_update_failures"; -} - -+ (NSString *)messageSendErrorFailedDueToUntrustedKey -{ - return @"message_send_error_failed_due_to_untrusted_key"; -} - -+ (NSString *)messageSenderErrorCouldNotFindContacts1 -{ - return @"message_sender_error_could_not_find_contacts_1"; -} - -+ (NSString *)messageSenderErrorCouldNotFindContacts2 -{ - return @"message_sender_error_could_not_find_contacts_2"; -} - -+ (NSString *)messageSenderErrorCouldNotFindContacts3 -{ - return @"message_sender_error_could_not_find_contacts_3"; -} - -+ (NSString *)messageSenderErrorCouldNotLoadAttachment -{ - return @"message_sender_error_could_not_load_attachment"; -} - -+ (NSString *)messageSenderErrorCouldNotParseMismatchedDevicesJson -{ - return @"message_sender_error_could_not_parse_mismatched_devices_json"; -} - -+ (NSString *)messageSenderErrorCouldNotWriteAttachment -{ - return @"message_sender_error_could_not_write_attachment"; -} - -+ (NSString *)messageSenderErrorGenericSendFailure -{ - return @"message_sender_error_generic_send_failure"; -} - -+ (NSString *)messageSenderErrorInvalidIdentityKeyLength -{ - return @"message_sender_error_invalid_identity_key_length"; -} - -+ (NSString *)messageSenderErrorInvalidIdentityKeyType -{ - return @"message_sender_error_invalid_identity_key_type"; -} - -+ (NSString *)messageSenderErrorNoMissingOrExtraDevices -{ - return @"message_sender_error_no_missing_or_extra_devices"; -} - -+ (NSString *)messageSenderErrorRecipientPrekeyRequestFailed -{ - return @"message_sender_error_recipient_prekey_request_failed"; -} - -+ (NSString *)messageSenderErrorSendOperationDidNotComplete -{ - return @"message_sender_error_send_operation_did_not_complete"; -} - -+ (NSString *)messageSenderErrorUnexpectedKeyBundle -{ - return @"message_sender_error_unexpected_key_bundle"; -} - -+ (NSString *)peerConnectionClientErrorSendDataChannelMessageFailed -{ - return @"peer_connection_client_error_send_data_channel_message_failed"; -} - -+ (NSString *)prekeysDeletedOldAcceptedSignedPrekey -{ - return @"prekeys_deleted_old_accepted_signed_prekey"; -} - -+ (NSString *)prekeysDeletedOldSignedPrekey -{ - return @"prekeys_deleted_old_signed_prekey"; -} - -+ (NSString *)prekeysDeletedOldUnacceptedSignedPrekey -{ - return @"prekeys_deleted_old_unaccepted_signed_prekey"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidAcl -{ - return @"profile_manager_error_avatar_upload_form_invalid_acl"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidAlgorithm -{ - return @"profile_manager_error_avatar_upload_form_invalid_algorithm"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidCredential -{ - return @"profile_manager_error_avatar_upload_form_invalid_credential"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidDate -{ - return @"profile_manager_error_avatar_upload_form_invalid_date"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidKey -{ - return @"profile_manager_error_avatar_upload_form_invalid_key"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidPolicy -{ - return @"profile_manager_error_avatar_upload_form_invalid_policy"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidResponse -{ - return @"profile_manager_error_avatar_upload_form_invalid_response"; -} - -+ (NSString *)profileManagerErrorAvatarUploadFormInvalidSignature -{ - return @"profile_manager_error_avatar_upload_form_invalid_signature"; -} - -+ (NSString *)registrationBegan -{ - return @"registration_began"; -} - -+ (NSString *)registrationRegisteredPhoneNumber -{ - return @"registration_registered_phone_number"; -} - -+ (NSString *)registrationRegisteringCode -{ - return @"registration_registering_code"; -} - -+ (NSString *)registrationRegisteringRequestedNewCodeBySms -{ - return @"registration_registering_requested_new_code_by_sms"; -} - -+ (NSString *)registrationRegisteringRequestedNewCodeByVoice -{ - return @"registration_registering_requested_new_code_by_voice"; -} - -+ (NSString *)registrationRegisteringSubmittedCode -{ - return @"registration_registering_submitted_code"; -} - -+ (NSString *)registrationRegistrationFailed -{ - return @"registration_registration_failed"; -} - -+ (NSString *)registrationVerificationBack -{ - return @"registration_verification_back"; -} - -+ (NSString *)storageErrorCouldNotDecodeClass -{ - return @"storage_error_could_not_decode_class"; -} - -+ (NSString *)storageErrorCouldNotLoadDatabase -{ - return @"storage_error_could_not_load_database"; -} - -+ (NSString *)storageErrorCouldNotLoadDatabaseSecondAttempt -{ - return @"storage_error_could_not_load_database_second_attempt"; -} - -+ (NSString *)storageErrorCouldNotStoreKeychainValue -{ - return @"storage_error_could_not_store_keychain_value"; -} - -+ (NSString *)storageErrorDeserialization -{ - return @"storage_error_deserialization"; -} - -+ (NSString *)storageErrorFileProtection -{ - return @"storage_error_file_protection"; -} - -#pragma mark - Code Generation Marker - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAttachmentDownloads.m b/SignalUtilitiesKit/OWSAttachmentDownloads.m index 908dba719..740a622aa 100644 --- a/SignalUtilitiesKit/OWSAttachmentDownloads.m +++ b/SignalUtilitiesKit/OWSAttachmentDownloads.m @@ -11,7 +11,7 @@ #import "OWSError.h" #import "OWSFileSystem.h" #import "OWSPrimaryStorage.h" -#import "OWSRequestFactory.h" + #import "SSKEnvironment.h" #import "TSAttachmentPointer.h" #import "TSAttachmentStream.h" @@ -19,7 +19,7 @@ #import "TSGroupThread.h" #import "TSInfoMessage.h" #import "TSMessage.h" -#import "TSNetworkManager.h" + #import "TSThread.h" #import #import @@ -95,12 +95,6 @@ typedef void (^AttachmentDownloadFailure)(NSError *error); return SSKEnvironment.shared.primaryStorage; } -- (TSNetworkManager *)networkManager -{ - return SSKEnvironment.shared.networkManager; -} - - #pragma mark - - (instancetype)init @@ -171,9 +165,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error); OWSAssertDebug(attachmentPointer); [self enqueueJobsForAttachmentStreams:@[] - attachmentPointers:@[ - attachmentPointer, - ] + attachmentPointers:@[ attachmentPointer ] message:nil success:success failure:failure]; @@ -290,11 +282,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error); [job.attachmentPointer saveWithTransaction:transaction]; if (job.message) { - if (!CurrentAppContext().isMainApp) { - job.message.hasAttachmentsInNSE = true; - } else { - job.message.hasAttachmentsInNSE = false; - } + job.message.hasUnfetchedAttachmentsFromPN = !CurrentAppContext().isMainApp; [job.message saveWithTransaction:transaction]; [job.message touchWithTransaction:transaction]; diff --git a/SignalUtilitiesKit/OWSAvatarBuilder.h b/SignalUtilitiesKit/OWSAvatarBuilder.h deleted file mode 100644 index 81e7bd785..000000000 --- a/SignalUtilitiesKit/OWSAvatarBuilder.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -extern const NSUInteger kStandardAvatarSize; -extern const NSUInteger kLargeAvatarSize; - -@class TSThread; -@class UIImage; - -@interface OWSAvatarBuilder : NSObject - -+ (nullable UIImage *)buildImageForThread:(TSThread *)thread - diameter:(NSUInteger)diameter NS_SWIFT_NAME(buildImage(thread:diameter:)); - -+ (nullable UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter; - -- (nullable UIImage *)buildSavedImage; -- (nullable UIImage *)buildDefaultImage; -- (nullable UIImage *)build; - -+ (nullable UIImage *)avatarImageWithInitials:(NSString *)initials - backgroundColor:(UIColor *)backgroundColor - diameter:(NSUInteger)diameter; - -+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon - iconSize:(CGSize)iconSize - backgroundColor:(UIColor *)backgroundColor - diameter:(NSUInteger)diameter; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSAvatarBuilder.m b/SignalUtilitiesKit/OWSAvatarBuilder.m deleted file mode 100644 index 65553c79e..000000000 --- a/SignalUtilitiesKit/OWSAvatarBuilder.m +++ /dev/null @@ -1,296 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSAvatarBuilder.h" -#import "OWSContactAvatarBuilder.h" -#import "OWSGroupAvatarBuilder.h" -#import "TSContactThread.h" -#import "TSGroupThread.h" -#import "Theme.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" - - -NS_ASSUME_NONNULL_BEGIN - -const NSUInteger kStandardAvatarSize = 48; -const NSUInteger kLargeAvatarSize = 68; - -typedef void (^OWSAvatarDrawBlock)(CGContextRef context); - -@implementation OWSAvatarBuilder - -+ (nullable UIImage *)buildImageForThread:(TSThread *)thread - diameter:(NSUInteger)diameter -{ - OWSAssertDebug(thread); - - OWSAvatarBuilder *avatarBuilder; - if ([thread isKindOfClass:[TSContactThread class]]) { - TSContactThread *contactThread = (TSContactThread *)thread; - avatarBuilder = [[OWSContactAvatarBuilder alloc] initWithSignalId:contactThread.contactIdentifier colorName:contactThread.conversationColorName diameter:diameter]; - } else if ([thread isKindOfClass:[TSGroupThread class]]) { - avatarBuilder = [[OWSGroupAvatarBuilder alloc] initWithThread:(TSGroupThread *)thread diameter:diameter]; - } else { - OWSLogError(@"called with unsupported thread: %@", thread); - } - return [avatarBuilder build]; -} - -+ (nullable UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter -{ - NSArray *eyes = @[ @":", @"=", @"8", @"B" ]; - NSArray *mouths = @[ @"3", @")", @"(", @"|", @"\\", @"P", @"D", @"o" ]; - // eyebrows are rare - NSArray *eyebrows = @[ @">", @"", @"", @"", @"" ]; - - NSString *randomEye = eyes[arc4random_uniform((uint32_t)eyes.count)]; - NSString *randomMouth = mouths[arc4random_uniform((uint32_t)mouths.count)]; - NSString *randomEyebrow = eyebrows[arc4random_uniform((uint32_t)eyebrows.count)]; - NSString *face = [NSString stringWithFormat:@"%@%@%@", randomEyebrow, randomEye, randomMouth]; - - UIColor *backgroundColor = [UIColor colorWithRGBHex:0xaca6633]; - - return [self avatarImageWithDiameter:diameter - backgroundColor:backgroundColor - drawBlock:^(CGContextRef context) { - CGContextTranslateCTM(context, diameter / 2, diameter / 2); - CGContextRotateCTM(context, (CGFloat)M_PI_2); - CGContextTranslateCTM(context, -diameter / 2, -diameter / 2); - - [self drawInitialsInAvatar:face - textColor:self.avatarForegroundColor - font:[self avatarTextFontForDiameter:diameter] - diameter:diameter]; - }]; -} - -+ (UIColor *)avatarForegroundColor -{ - return (Theme.isDarkThemeEnabled ? UIColor.ows_gray05Color : UIColor.ows_whiteColor); -} - -+ (UIFont *)avatarTextFontForDiameter:(NSUInteger)diameter -{ - // Adapt the font size to reflect the diameter. - CGFloat fontSize = 20.f * diameter / kStandardAvatarSize; - return [UIFont ows_mediumFontWithSize:fontSize]; -} - -+ (nullable UIImage *)avatarImageWithInitials:(NSString *)initials - backgroundColor:(UIColor *)backgroundColor - diameter:(NSUInteger)diameter -{ - return [self avatarImageWithInitials:initials - backgroundColor:backgroundColor - textColor:self.avatarForegroundColor - font:[self avatarTextFontForDiameter:diameter] - diameter:diameter]; -} - -+ (nullable UIImage *)avatarImageWithInitials:(NSString *)initials - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - font:(UIFont *)font - diameter:(NSUInteger)diameter -{ - OWSAssertDebug(initials); - OWSAssertDebug(textColor); - OWSAssertDebug(font); - - return [self avatarImageWithDiameter:diameter - backgroundColor:backgroundColor - drawBlock:^(CGContextRef context) { - [self drawInitialsInAvatar:initials textColor:textColor font:font diameter:diameter]; - }]; -} - -+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon - iconSize:(CGSize)iconSize - backgroundColor:(UIColor *)backgroundColor - diameter:(NSUInteger)diameter -{ - return [self avatarImageWithIcon:icon - iconSize:iconSize - iconColor:self.avatarForegroundColor - backgroundColor:backgroundColor - diameter:diameter]; -} - -+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon - iconSize:(CGSize)iconSize - iconColor:(UIColor *)iconColor - backgroundColor:(UIColor *)backgroundColor - diameter:(NSUInteger)diameter -{ - OWSAssertDebug(icon); - OWSAssertDebug(iconColor); - - return [self avatarImageWithDiameter:diameter - backgroundColor:backgroundColor - drawBlock:^(CGContextRef context) { - [self drawIconInAvatar:icon - iconSize:iconSize - iconColor:iconColor - diameter:diameter - context:context]; - }]; -} - -+ (nullable UIImage *)avatarImageWithDiameter:(NSUInteger)diameter - backgroundColor:(UIColor *)backgroundColor - drawBlock:(OWSAvatarDrawBlock)drawBlock -{ - OWSAssertDebug(drawBlock); - OWSAssertDebug(backgroundColor); - OWSAssertDebug(diameter > 0); - - CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter); - - UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale); - CGContextRef _Nullable context = UIGraphicsGetCurrentContext(); - if (!context) { - return nil; - } - - CGContextSetFillColorWithColor(context, backgroundColor.CGColor); - CGContextFillRect(context, frame); - - // Gradient - CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); - CGFloat gradientLocations[] = { 0.0, 1.0 }; - CGGradientRef _Nullable gradient = CGGradientCreateWithColors(colorspace, - (__bridge CFArrayRef) @[ - (id)[UIColor colorWithWhite:0.f alpha:0.f].CGColor, - (id)[UIColor colorWithWhite:0.f alpha:0.15f].CGColor, - ], - gradientLocations); - if (!gradient) { - return nil; - } - CGPoint startPoint = CGPointMake(diameter * 0.5f, 0); - CGPoint endPoint = CGPointMake(diameter * 0.5f, diameter); - CGContextDrawLinearGradient(context, - gradient, - startPoint, - endPoint, - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - CFRelease(gradient); - - CGContextSaveGState(context); - drawBlock(context); - CGContextRestoreGState(context); - - UIImage *_Nullable image = UIGraphicsGetImageFromCurrentImageContext(); - - UIGraphicsEndImageContext(); - - return image; -} - -+ (void)drawInitialsInAvatar:(NSString *)initials - textColor:(UIColor *)textColor - font:(UIFont *)font - diameter:(NSUInteger)diameter -{ - OWSAssertDebug(initials); - OWSAssertDebug(textColor); - OWSAssertDebug(font); - OWSAssertDebug(diameter > 0); - - CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter); - - NSDictionary *textAttributes = @{ - NSFontAttributeName : font, - NSForegroundColorAttributeName : textColor, - }; - CGSize textSize = - [initials boundingRectWithSize:frame.size - options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) - attributes:textAttributes - context:nil] - .size; - // Ensure that the text fits within the avatar bounds, with a margin. - if (textSize.width > 0 && textSize.height > 0) { - CGFloat textDiameter = (CGFloat)sqrt(textSize.width * textSize.width + textSize.height * textSize.height); - // Leave a 10% margin. - CGFloat maxTextDiameter = diameter * 0.9f; - if (textDiameter > maxTextDiameter) { - font = [font fontWithSize:font.pointSize * maxTextDiameter / textDiameter]; - textAttributes = @{ - NSFontAttributeName : font, - NSForegroundColorAttributeName : textColor, - }; - textSize = - [initials boundingRectWithSize:frame.size - options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) - attributes:textAttributes - context:nil] - .size; - } - } else { - OWSFailDebug(@"Text has invalid bounds."); - } - - CGPoint drawPoint = CGPointMake((diameter - textSize.width) * 0.5f, (diameter - textSize.height) * 0.5f); - - [initials drawAtPoint:drawPoint withAttributes:textAttributes]; -} - -+ (void)drawIconInAvatar:(UIImage *)icon - iconSize:(CGSize)iconSize - iconColor:(UIColor *)iconColor - diameter:(NSUInteger)diameter - context:(CGContextRef)context -{ - OWSAssertDebug(icon); - OWSAssertDebug(iconColor); - OWSAssertDebug(diameter > 0); - OWSAssertDebug(context); - - // UIKit uses an ULO coordinate system (upper-left-origin). - // Core Graphics uses an LLO coordinate system (lower-left-origin). - CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, diameter); - CGContextConcatCTM(context, flipVertical); - - CGRect imageRect = CGRectZero; - imageRect.size = CGSizeMake(diameter, diameter); - - // The programmatic equivalent of UIImageRenderingModeAlwaysTemplate/tintColor. - CGContextSetBlendMode(context, kCGBlendModeNormal); - CGRect maskRect = CGRectZero; - maskRect.origin = CGPointScale( - CGPointSubtract(CGPointMake(diameter, diameter), CGPointMake(iconSize.width, iconSize.height)), 0.5f); - maskRect.size = iconSize; - CGContextClipToMask(context, maskRect, icon.CGImage); - CGContextSetFillColor(context, CGColorGetComponents(iconColor.CGColor)); - CGContextFillRect(context, imageRect); -} - -- (nullable UIImage *)build -{ - UIImage *_Nullable savedImage = [self buildSavedImage]; - if (savedImage) { - return savedImage; - } else { - return [self buildDefaultImage]; - } -} - -- (nullable UIImage *)buildSavedImage -{ - OWSAbstractMethod(); - return nil; -} - -- (nullable UIImage *)buildDefaultImage -{ - OWSAbstractMethod(); - return nil; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSBackgroundTask.m b/SignalUtilitiesKit/OWSBackgroundTask.m index 7384c063c..b9d8b17cc 100644 --- a/SignalUtilitiesKit/OWSBackgroundTask.m +++ b/SignalUtilitiesKit/OWSBackgroundTask.m @@ -4,7 +4,6 @@ #import "OWSBackgroundTask.h" #import "AppContext.h" -#import "NSTimer+OWS.h" #import #import "SSKAsserts.h" diff --git a/SignalUtilitiesKit/OWSBatchMessageProcessor.h b/SignalUtilitiesKit/OWSBatchMessageProcessor.h deleted file mode 100644 index ae364752f..000000000 --- a/SignalUtilitiesKit/OWSBatchMessageProcessor.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSPrimaryStorage; -@class OWSStorage; -@class SSKProtoEnvelope; -@class YapDatabaseReadWriteTransaction; - -@interface OWSMessageContentQueue : NSObject - -- (dispatch_queue_t)serialQueue; - -@end - -// This class is used to write incoming (decrypted, unprocessed) -// messages to a durable queue and then process them in batches, -// in the order in which they were received. -@interface OWSBatchMessageProcessor : NSObject - -@property (nonatomic, readonly) OWSMessageContentQueue *processingQueue; - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; - -+ (NSString *)databaseExtensionName; -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage; - -- (void)enqueueEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSBatchMessageProcessor.m b/SignalUtilitiesKit/OWSBatchMessageProcessor.m deleted file mode 100644 index 7b26795eb..000000000 --- a/SignalUtilitiesKit/OWSBatchMessageProcessor.m +++ /dev/null @@ -1,546 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSBatchMessageProcessor.h" -#import "AppContext.h" -#import "AppReadiness.h" -#import "NSArray+OWS.h" -#import "NotificationsProtocol.h" -#import "OWSBackgroundTask.h" -#import "OWSMessageManager.h" -#import "OWSPrimaryStorage+SessionStore.h" -#import "OWSPrimaryStorage.h" -#import "OWSQueues.h" -#import "OWSStorage.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "TSDatabaseView.h" -#import "TSErrorMessage.h" -#import "TSYapDatabaseObject.h" -#import -#import -#import -#import -#import -#import -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Persisted data model - -@interface OWSMessageContentJob : TSYapDatabaseObject - -@property (nonatomic, readonly) NSDate *createdAt; -@property (nonatomic, readonly) NSData *envelopeData; -@property (nonatomic, readonly, nullable) NSData *plaintextData; -@property (nonatomic, readonly) BOOL wasReceivedByUD; - -- (instancetype)initWithEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithUniqueId:(NSString *_Nullable)uniqueId NS_UNAVAILABLE; - -@property (nonatomic, readonly, nullable) SSKProtoEnvelope *envelope; - -@end - -#pragma mark - - -@implementation OWSMessageContentJob - -+ (NSString *)collection -{ - return @"OWSBatchMessageProcessingJob"; -} - -- (instancetype)initWithEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD -{ - OWSAssertDebug(envelopeData); - - self = [super initWithUniqueId:[NSUUID new].UUIDString]; - - if (!self) { - return self; - } - - _envelopeData = envelopeData; - _plaintextData = plaintextData; - _wasReceivedByUD = wasReceivedByUD; - _createdAt = [NSDate new]; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoEnvelope *)envelope -{ - NSError *error; - SSKProtoEnvelope *_Nullable result = [SSKProtoEnvelope parseData:self.envelopeData error:&error]; - - if (error) { - OWSFailDebug(@"paring SSKProtoEnvelope failed with error: %@", error); - return nil; - } - - return result; -} - -@end - -#pragma mark - Finder - -NSString *const OWSMessageContentJobFinderExtensionName = @"OWSMessageContentJobFinderExtensionName2"; -NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJobFinderExtensionGroup2"; - -@interface OWSMessageContentJobFinder : NSObject - -@end - -#pragma mark - - -@interface OWSMessageContentJobFinder () - -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@end - -#pragma mark - - -@implementation OWSMessageContentJobFinder - -- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection -{ - OWSSingletonAssert(); - - self = [super init]; - if (!self) { - return self; - } - - _dbConnection = dbConnection; - - return self; -} - -- (NSArray *)nextJobsForBatchSize:(NSUInteger)maxBatchSize -{ - NSMutableArray *jobs = [NSMutableArray new]; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - YapDatabaseViewTransaction *viewTransaction = [transaction ext:OWSMessageContentJobFinderExtensionName]; - OWSAssertDebug(viewTransaction != nil); - [viewTransaction enumerateKeysAndObjectsInGroup:OWSMessageContentJobFinderExtensionGroup - usingBlock:^(NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object, - NSUInteger index, - BOOL *_Nonnull stop) { - OWSMessageContentJob *job = object; - [jobs addObject:job]; - if (jobs.count >= maxBatchSize) { - *stop = YES; - } - }]; - }]; - - return [jobs copy]; -} - -- (void)addJobWithEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(envelopeData); - OWSAssertDebug(transaction); - - OWSMessageContentJob *job = [[OWSMessageContentJob alloc] initWithEnvelopeData:envelopeData - plaintextData:plaintextData - wasReceivedByUD:wasReceivedByUD]; - [job saveWithTransaction:transaction]; -} - -- (void)removeJobsWithIds:(NSArray *)uniqueIds -{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [transaction removeObjectsForKeys:uniqueIds inCollection:[OWSMessageContentJob collection]]; - }]; -} - -+ (YapDatabaseView *)databaseExtension -{ - YapDatabaseViewSorting *sorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - - if (![object1 isKindOfClass:[OWSMessageContentJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - OWSMessageContentJob *job1 = (OWSMessageContentJob *)object1; - - if (![object2 isKindOfClass:[OWSMessageContentJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - OWSMessageContentJob *job2 = (OWSMessageContentJob *)object2; - - return [job1.createdAt compare:job2.createdAt]; - }]; - - YapDatabaseViewGrouping *grouping = - [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable(YapDatabaseReadTransaction *_Nonnull transaction, - NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object) { - if (![object isKindOfClass:[OWSMessageContentJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", object, collection); - return nil; - } - - // Arbitrary string - all in the same group. We're only using the view for sorting. - return OWSMessageContentJobFinderExtensionGroup; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageContentJob collection]]]; - - return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; -} - - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage -{ - YapDatabaseView *existingView = [storage registeredExtension:OWSMessageContentJobFinderExtensionName]; - if (existingView) { - OWSFailDebug(@"%@ was already initialized.", OWSMessageContentJobFinderExtensionName); - // already initialized - return; - } - [storage asyncRegisterExtension:[self databaseExtension] withName:OWSMessageContentJobFinderExtensionName]; -} - -@end - -#pragma mark - Queue Processing - -@interface OWSMessageContentQueue () - -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -@property (nonatomic, readonly) OWSMessageContentJobFinder *finder; -@property (nonatomic) BOOL isDrainingQueue; -@property (atomic) BOOL isAppInBackground; - -- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection - finder:(OWSMessageContentJobFinder *)finder NS_DESIGNATED_INITIALIZER; -- (instancetype)init NS_UNAVAILABLE; - -@end - -#pragma mark - - -@implementation OWSMessageContentQueue - -- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection finder:(OWSMessageContentJobFinder *)finder -{ - OWSSingletonAssert(); - - self = [super init]; - - if (!self) { - return self; - } - - _dbConnection = dbConnection; - _finder = finder; - _isDrainingQueue = NO; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationWillEnterForeground:) - name:OWSApplicationWillEnterForegroundNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidEnterBackground:) - name:OWSApplicationDidEnterBackgroundNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(registrationStateDidChange:) - name:RegistrationStateDidChangeNotification - object:nil]; - - // Start processing. - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - if (CurrentAppContext().isMainApp) { - [self drainQueue]; - } - }]; - - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -#pragma mark - Singletons - -- (OWSMessageManager *)messageManager -{ - OWSAssertDebug(SSKEnvironment.shared.messageManager); - - return SSKEnvironment.shared.messageManager; -} - -- (TSAccountManager *)tsAccountManager -{ - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - - return SSKEnvironment.shared.tsAccountManager; -} - -#pragma mark - Notifications - -- (void)applicationWillEnterForeground:(NSNotification *)notification -{ - self.isAppInBackground = NO; -} - -- (void)applicationDidEnterBackground:(NSNotification *)notification -{ - self.isAppInBackground = YES; -} - -- (void)registrationStateDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - if (CurrentAppContext().isMainApp) { - [self drainQueue]; - } - }]; -} - -#pragma mark - instance methods - -- (dispatch_queue_t)serialQueue -{ - static dispatch_queue_t queue = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - queue = dispatch_queue_create("org.whispersystems.message.process", DISPATCH_QUEUE_SERIAL); - }); - return queue; -} - -- (void)enqueueEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(envelopeData); - OWSAssertDebug(transaction); - - // We need to persist the decrypted envelope data ASAP to prevent data loss. - [self.finder addJobWithEnvelopeData:envelopeData - plaintextData:plaintextData - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; -} - -- (void)drainQueue -{ - OWSAssertDebug(AppReadiness.isAppReady); - - if (!CurrentAppContext().isMainApp) { return; } - if (!self.tsAccountManager.isRegisteredAndReady) { return; } - - dispatch_async(self.serialQueue, ^{ - if (self.isDrainingQueue) { return; } - self.isDrainingQueue = YES; - [self drainQueueWorkStep]; - }); -} - -- (void)drainQueueWorkStep -{ - AssertOnDispatchQueue(self.serialQueue); - - // We want a value that is just high enough to yield performance benefits - const NSUInteger kIncomingMessageBatchSize = 32; - - NSArray *batchJobs = [self.finder nextJobsForBatchSize:kIncomingMessageBatchSize]; - OWSAssertDebug(batchJobs); - if (batchJobs.count < 1) { - self.isDrainingQueue = NO; - OWSLogVerbose(@"Queue is drained"); - return; - } - - OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - - NSArray *processedJobs = [self processJobs:batchJobs]; - - [self.finder removeJobsWithIds:processedJobs.uniqueIds]; - - OWSAssertDebug(backgroundTask); - backgroundTask = nil; - - OWSLogVerbose(@"completed %lu/%lu jobs. %lu jobs left.", - (unsigned long)processedJobs.count, - (unsigned long)batchJobs.count, - (unsigned long)[OWSMessageContentJob numberOfKeysInCollection]); - - // Wait a bit in hopes of increasing the batch size. - // This delay won't affect the first message to arrive when this queue is idle, - // so by definition we're receiving more than one message and can benefit from - // batching. - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), self.serialQueue, ^{ - [self drainQueueWorkStep]; - }); -} - -- (NSArray *)processJobs:(NSArray *)jobs -{ - AssertOnDispatchQueue(self.serialQueue); - - NSMutableArray *processedJobs = [NSMutableArray new]; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (OWSMessageContentJob *job in jobs) { - - void (^reportFailure)(YapDatabaseReadWriteTransaction *transaction) = ^( - YapDatabaseReadWriteTransaction *transaction) { - TSErrorMessage *errorMessage = [TSErrorMessage corruptedMessageInUnknownThread]; - [SSKEnvironment.shared.notificationsManager notifyUserForThreadlessErrorMessage:errorMessage transaction:transaction]; - }; - - @try { - SSKProtoEnvelope *_Nullable envelope = job.envelope; - if (!envelope) { - reportFailure(transaction); - } else { - [self.messageManager throws_processEnvelope:envelope - plaintextData:job.plaintextData - wasReceivedByUD:job.wasReceivedByUD - transaction:transaction - serverID:0]; - } - } @catch (NSException *exception) { - reportFailure(transaction); - } - - [processedJobs addObject:job]; - - if (self.isAppInBackground) { - // If the app is in the background, stop processing this batch. - // - // Since this check is done after processing jobs, we'll continue - // to process jobs in batches of 1. This reduces the cost of - // being interrupted and rolled back if app is suspended. - break; - } - } - }]; - - return processedJobs; -} - -@end - -#pragma mark - OWSBatchMessageProcessor - -@interface OWSBatchMessageProcessor () - -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@end - -#pragma mark - - -@implementation OWSBatchMessageProcessor - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - OWSSingletonAssert(); - - self = [super init]; - if (!self) { - return self; - } - - // For coherency we use the same dbConnection to persist and read the unprocessed envelopes - YapDatabaseConnection *dbConnection = [primaryStorage newDatabaseConnection]; - OWSMessageContentJobFinder *finder = [[OWSMessageContentJobFinder alloc] initWithDBConnection:dbConnection]; - OWSMessageContentQueue *processingQueue = - [[OWSMessageContentQueue alloc] initWithDBConnection:dbConnection finder:finder]; - - _processingQueue = processingQueue; - - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - if (CurrentAppContext().isMainApp) { - [self.processingQueue drainQueue]; - } - }]; - - return self; -} - -#pragma mark - class methods - -+ (NSString *)databaseExtensionName -{ - return OWSMessageContentJobFinderExtensionName; -} - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage -{ - [OWSMessageContentJobFinder asyncRegisterDatabaseExtension:storage]; -} - -#pragma mark - instance methods - -- (void)enqueueEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (envelopeData.length < 1) { - OWSFailDebug(@"Received an empty envelope."); - return; - } - OWSAssert(transaction); - - // We need to persist the decrypted envelope data ASAP to prevent data loss. - [self.processingQueue enqueueEnvelopeData:envelopeData - plaintextData:plaintextData - wasReceivedByUD:wasReceivedByUD - transaction:transaction]; - - // The new envelope won't be visible to the finder until this transaction commits, - // so drainQueue in the transaction completion. - [transaction addCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) - completionBlock:^{ - [self.processingQueue drainQueue]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.h b/SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.h deleted file mode 100644 index 59cb02b07..000000000 --- a/SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSBlockedPhoneNumbersMessage : OWSOutgoingSyncMessage - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithPhoneNumbers:(NSArray *)phoneNumbers - groupIds:(NSArray *)groupIds NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.m b/SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.m deleted file mode 100644 index a089a9aab..000000000 --- a/SignalUtilitiesKit/OWSBlockedPhoneNumbersMessage.m +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSBlockedPhoneNumbersMessage () - -@property (nonatomic, readonly) NSArray *phoneNumbers; -@property (nonatomic, readonly) NSArray *groupIds; - -@end - -@implementation OWSBlockedPhoneNumbersMessage - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (instancetype)initWithPhoneNumbers:(NSArray *)phoneNumbers groupIds:(NSArray *)groupIds -{ - self = [super init]; - if (!self) { - return self; - } - - _phoneNumbers = [phoneNumbers copy]; - _groupIds = [groupIds copy]; - - return self; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - SSKProtoSyncMessageBlockedBuilder *blockedBuilder = [SSKProtoSyncMessageBlocked builder]; - [blockedBuilder setNumbers:_phoneNumbers]; - [blockedBuilder setGroupIds:_groupIds]; - - NSError *error; - SSKProtoSyncMessageBlocked *_Nullable blockedProto = [blockedBuilder buildAndReturnError:&error]; - if (error || !blockedProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - - SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder]; - [syncMessageBuilder setBlocked:blockedProto]; - return syncMessageBuilder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSBlockingManager.m b/SignalUtilitiesKit/OWSBlockingManager.m index 3bb675757..34a1767f4 100644 --- a/SignalUtilitiesKit/OWSBlockingManager.m +++ b/SignalUtilitiesKit/OWSBlockingManager.m @@ -6,8 +6,6 @@ #import "AppContext.h" #import "AppReadiness.h" #import "NSNotificationCenter+OWS.h" -#import "OWSBlockedPhoneNumbersMessage.h" -#import "OWSMessageSender.h" #import "OWSPrimaryStorage.h" #import "SSKEnvironment.h" #import "TSContactThread.h" @@ -83,13 +81,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan object:nil]; } -- (OWSMessageSender *)messageSender -{ - OWSAssertDebug(SSKEnvironment.shared.messageSender); - - return SSKEnvironment.shared.messageSender; -} - #pragma mark - - (BOOL)isThreadBlocked:(TSThread *)thread @@ -183,11 +174,7 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (BOOL)isRecipientIdBlocked:(NSString *)recipientId { - __block NSString *masterPublicKey; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { - masterPublicKey = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:recipientId in:transaction] ?: recipientId; - }]; - return [self.blockedPhoneNumbers containsObject:masterPublicKey]; + return [self.blockedPhoneNumbers containsObject:recipientId]; } #pragma mark - Group Blocking @@ -356,7 +343,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan // This method should only be called from within a synchronized block. - (void)syncBlockListIfNecessary { - /* OWSAssertDebug(_blockedPhoneNumberSet); // If we haven't yet successfully synced the current "block list" changes, @@ -383,12 +369,14 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan OWSLogInfo(@"retrying sync of block list"); [self sendBlockListSyncMessageWithPhoneNumbers:self.blockedPhoneNumbers groupIds:localBlockedGroupIds]; - */ } - (void)sendBlockListSyncMessageWithPhoneNumbers:(NSArray *)blockedPhoneNumbers groupIds:(NSArray *)blockedGroupIds { + // TODO TODO TODO + + /* OWSAssertDebug(blockedPhoneNumbers); OWSAssertDebug(blockedGroupIds); @@ -406,6 +394,7 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan failure:^(NSError *error) { OWSLogError(@"Failed to send blocked phone numbers sync message with error: %@", error); }]; + */ } /// Records the last block list which we successfully synced. diff --git a/SignalUtilitiesKit/OWSCensorshipConfiguration.h b/SignalUtilitiesKit/OWSCensorshipConfiguration.h deleted file mode 100644 index 4d1aac625..000000000 --- a/SignalUtilitiesKit/OWSCensorshipConfiguration.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class AFSecurityPolicy; - -extern NSString *const OWSFrontingHost_GoogleEgypt; -extern NSString *const OWSFrontingHost_GoogleUAE; -extern NSString *const OWSFrontingHost_GoogleOman; -extern NSString *const OWSFrontingHost_GoogleQatar; - -@interface OWSCensorshipConfiguration : NSObject - -// returns nil if phone number is not known to be censored -+ (nullable instancetype)censorshipConfigurationWithPhoneNumber:(NSString *)e164PhoneNumber; - -// returns best censorship configuration for country code. Will return a default if one hasn't -// been specifically configured. -+ (instancetype)censorshipConfigurationWithCountryCode:(NSString *)countryCode; -+ (instancetype)defaultConfiguration; - -+ (BOOL)isCensoredPhoneNumber:(NSString *)e164PhoneNumber; - -@property (nonatomic, readonly) NSString *signalServiceReflectorHost; -@property (nonatomic, readonly) NSString *CDNReflectorHost; -@property (nonatomic, readonly) NSURL *domainFrontBaseURL; -@property (nonatomic, readonly) AFSecurityPolicy *domainFrontSecurityPolicy; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSCensorshipConfiguration.m b/SignalUtilitiesKit/OWSCensorshipConfiguration.m deleted file mode 100644 index 6a59e715f..000000000 --- a/SignalUtilitiesKit/OWSCensorshipConfiguration.m +++ /dev/null @@ -1,247 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSCensorshipConfiguration.h" -#import "OWSCountryMetadata.h" -#import "OWSError.h" -#import "OWSPrimaryStorage.h" -#import "TSConstants.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const OWSFrontingHost_GoogleEgypt = @"www.google.com.eg"; -NSString *const OWSFrontingHost_GoogleUAE = @"www.google.ae"; -NSString *const OWSFrontingHost_GoogleOman = @"www.google.com.om"; -NSString *const OWSFrontingHost_GoogleQatar = @"www.google.com.qa"; -NSString *const OWSFrontingHost_Default = @"www.google.com"; - -@implementation OWSCensorshipConfiguration - -// returns nil if phone number is not known to be censored -+ (nullable instancetype)censorshipConfigurationWithPhoneNumber:(NSString *)e164PhoneNumber -{ - NSString *countryCode = [self censoredCountryCodeWithPhoneNumber:e164PhoneNumber]; - if (countryCode.length == 0) { - return nil; - } - - return [self censorshipConfigurationWithCountryCode:countryCode]; -} - -// returns best censorship configuration for country code. Will return a default if one hasn't -// been specifically configured. -+ (instancetype)censorshipConfigurationWithCountryCode:(NSString *)countryCode -{ - OWSCountryMetadata *countryMetadadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; - OWSAssertDebug(countryMetadadata); - - NSString *_Nullable specifiedDomain = countryMetadadata.frontingDomain; - if (specifiedDomain.length == 0) { - return self.defaultConfiguration; - } - - NSString *frontingURLString = [NSString stringWithFormat:@"https://%@", specifiedDomain]; - NSURL *_Nullable baseURL = [NSURL URLWithString:frontingURLString]; - if (baseURL == nil) { - OWSFailDebug(@"baseURL was unexpectedly nil with specifiedDomain: %@", specifiedDomain); - return self.defaultConfiguration; - } - AFSecurityPolicy *securityPolicy = [self securityPolicyForDomain:specifiedDomain]; - OWSAssertDebug(securityPolicy); - - return [[OWSCensorshipConfiguration alloc] initWithDomainFrontBaseURL:baseURL securityPolicy:securityPolicy]; -} - -+ (instancetype)defaultConfiguration -{ - NSString *frontingURLString = [NSString stringWithFormat:@"https://%@", OWSFrontingHost_Default]; - NSURL *baseURL = [NSURL URLWithString:frontingURLString]; - AFSecurityPolicy *securityPolicy = [self securityPolicyForDomain:OWSFrontingHost_Default]; - - return [[OWSCensorshipConfiguration alloc] initWithDomainFrontBaseURL:baseURL securityPolicy:securityPolicy]; -} - -- (instancetype)initWithDomainFrontBaseURL:(NSURL *)domainFrontBaseURL securityPolicy:(AFSecurityPolicy *)securityPolicy -{ - OWSAssertDebug(domainFrontBaseURL); - OWSAssertDebug(securityPolicy); - - self = [super init]; - if (!self) { - return self; - } - - _domainFrontBaseURL = domainFrontBaseURL; - _domainFrontSecurityPolicy = securityPolicy; - - return self; -} - -// MARK: Public Getters - -- (NSString *)signalServiceReflectorHost -{ - return textSecureServiceReflectorHost; -} - -- (NSString *)CDNReflectorHost -{ - return textSecureCDNReflectorHost; -} - -// MARK: Util - -+ (NSDictionary *)censoredCountryCodes -{ - // The set of countries for which domain fronting should be automatically enabled. - // - // If you want to use a domain front other than the default, specify the domain front - // in OWSCountryMetadata, and ensure we have a Security Policy for that domain in - // `securityPolicyForDomain:` - return @{ - // Egypt - @"+20" : @"EG", - // Oman - @"+968" : @"OM", - // Qatar - @"+974" : @"QA", - // UAE - @"+971" : @"AE", - }; -} - -+ (BOOL)isCensoredPhoneNumber:(NSString *)e164PhoneNumber; -{ - return [self censoredCountryCodeWithPhoneNumber:e164PhoneNumber].length > 0; -} - -// Returns nil if the phone number is not known to be censored -+ (nullable NSString *)censoredCountryCodeWithPhoneNumber:(NSString *)e164PhoneNumber -{ - NSDictionary *censoredCountryCodes = self.censoredCountryCodes; - - for (NSString *callingCode in censoredCountryCodes) { - if ([e164PhoneNumber hasPrefix:callingCode]) { - return censoredCountryCodes[callingCode]; - } - } - - return nil; -} - -#pragma mark - Reflector Pinning Policy - -// When using censorship circumvention, we pin to the fronted domain host. -// Adding a new domain front entails adding a corresponding AFSecurityPolicy -// and pinning to it's CA. -// If the security policy requires new certificates, include them in the SSK bundle -+ (AFSecurityPolicy *)securityPolicyForDomain:(NSString *)domain -{ - if ([domain isEqualToString:OWSFrontingHost_GoogleEgypt]) { - return self.googlePinningPolicy; - } else if ([domain isEqualToString:OWSFrontingHost_GoogleQatar]) { - return self.googlePinningPolicy; - } else if ([domain isEqualToString:OWSFrontingHost_GoogleOman]) { - return self.googlePinningPolicy; - } else if ([domain isEqualToString:OWSFrontingHost_GoogleUAE]) { - return self.googlePinningPolicy; - } else { - OWSFailDebug(@"unknown pinning domain."); - return self.googlePinningPolicy; - } -} - -+ (AFSecurityPolicy *)pinningPolicyWithCertNames:(NSArray *)certNames -{ - NSMutableSet *certificates = [NSMutableSet new]; - for (NSString *certName in certNames) { - NSError *error; - NSData *certData = [self certificateDataWithName:certName error:&error]; - if (error) { - OWSFail(@"reading data for certificate: %@ failed with error: %@", certName, error); - } - - if (!certData) { - OWSFail(@"reading data for certificate: %@ failed with error: %@", certName, error); - } - [certificates addObject:certData]; - } - - return [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:certificates]; -} - -+ (nullable NSData *)certificateDataWithName:(NSString *)name error:(NSError **)error -{ - if (!name.length) { - NSString *failureDescription = [NSString stringWithFormat:@"%@ expected name with length > 0", self.logTag]; - *error = OWSErrorMakeAssertionError(failureDescription); - return nil; - } - - NSBundle *bundle = [NSBundle bundleForClass:self.class]; - NSString *path = [bundle pathForResource:name ofType:@"crt"]; - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { - NSString *failureDescription = - [NSString stringWithFormat:@"%@ Missing certificate for name: %@", self.logTag, name]; - *error = OWSErrorMakeAssertionError(failureDescription); - return nil; - } - - NSData *_Nullable certData = [NSData dataWithContentsOfFile:path options:0 error:error]; - - if (*error != nil) { - OWSFailDebug(@"Failed to read cert file with path: %@", path); - return nil; - } - - if (certData.length == 0) { - OWSFailDebug(@"empty certData for name: %@", name); - return nil; - } - - OWSLogVerbose(@"read cert data with name: %@ length: %lu", name, (unsigned long)certData.length); - return certData; -} - -+ (AFSecurityPolicy *)yahooViewPinningPolicy_deprecated -{ - static AFSecurityPolicy *securityPolicy = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - // DigiCertGlobalRootG2 - view.yahoo.com - NSArray *certNames = @[ @"DigiCertSHA2HighAssuranceServerCA" ]; - securityPolicy = [self pinningPolicyWithCertNames:certNames]; - }); - return securityPolicy; -} - -+ (AFSecurityPolicy *)souqPinningPolicy_deprecated -{ - static AFSecurityPolicy *securityPolicy = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - // SFSRootCAG2 - cms.souqcdn.com - NSArray *certNames = @[ @"SFSRootCAG2" ]; - securityPolicy = [self pinningPolicyWithCertNames:certNames]; - }); - return securityPolicy; -} - -+ (AFSecurityPolicy *)googlePinningPolicy -{ - static AFSecurityPolicy *securityPolicy = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - // GIAG2 cert plus root certs from pki.goog - NSArray *certNames = @[ @"GIAG2", @"GSR2", @"GSR4", @"GTSR1", @"GTSR2", @"GTSR3", @"GTSR4" ]; - securityPolicy = [self pinningPolicyWithCertNames:certNames]; - }); - return securityPolicy; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContact+Private.h b/SignalUtilitiesKit/OWSContact+Private.h deleted file mode 100644 index 6f922e60b..000000000 --- a/SignalUtilitiesKit/OWSContact+Private.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -// These private interfaces expose setter accessors to facilitate -// construction of fake messages, etc. -@interface OWSContactPhoneNumber (Private) - -@property (nonatomic) OWSContactPhoneType phoneType; -@property (nonatomic, nullable) NSString *label; - -@property (nonatomic) NSString *phoneNumber; - -@end - -#pragma mark - - -@interface OWSContactEmail (Private) - -@property (nonatomic) OWSContactEmailType emailType; -@property (nonatomic, nullable) NSString *label; - -@property (nonatomic) NSString *email; - -@end - -#pragma mark - - -@interface OWSContactAddress (Private) - -@property (nonatomic) OWSContactAddressType addressType; -@property (nonatomic, nullable) NSString *label; - -@property (nonatomic, nullable) NSString *street; -@property (nonatomic, nullable) NSString *pobox; -@property (nonatomic, nullable) NSString *neighborhood; -@property (nonatomic, nullable) NSString *city; -@property (nonatomic, nullable) NSString *region; -@property (nonatomic, nullable) NSString *postcode; -@property (nonatomic, nullable) NSString *country; - -@end - -#pragma mark - - -@interface OWSContact (Private) - -@property (nonatomic) NSArray *phoneNumbers; -@property (nonatomic) NSArray *emails; -@property (nonatomic) NSArray *addresses; - -@property (nonatomic) BOOL isProfileAvatar; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContact.h b/SignalUtilitiesKit/OWSContact.h deleted file mode 100644 index ca76dd5ca..000000000 --- a/SignalUtilitiesKit/OWSContact.h +++ /dev/null @@ -1,183 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@class CNContact; -@class OWSAttachmentInfo; -@class SSKProtoDataMessage; -@class SSKProtoDataMessageContact; -@class TSAttachment; -@class TSAttachmentStream; -@class YapDatabaseReadTransaction; -@class YapDatabaseReadWriteTransaction; - -extern BOOL kIsSendingContactSharesEnabled; - -typedef NS_ENUM(NSUInteger, OWSContactPhoneType) { - OWSContactPhoneType_Home = 1, - OWSContactPhoneType_Mobile, - OWSContactPhoneType_Work, - OWSContactPhoneType_Custom, -}; - -NSString *NSStringForContactPhoneType(OWSContactPhoneType value); - -@protocol OWSContactField - -- (BOOL)ows_isValid; - -- (NSString *)localizedLabel; - -@end - -#pragma mark - - -@interface OWSContactPhoneNumber : MTLModel - -@property (nonatomic, readonly) OWSContactPhoneType phoneType; -// Applies in the OWSContactPhoneType_Custom case. -@property (nonatomic, readonly, nullable) NSString *label; - -@property (nonatomic, readonly) NSString *phoneNumber; - -- (nullable NSString *)tryToConvertToE164; - -@end - -#pragma mark - - -typedef NS_ENUM(NSUInteger, OWSContactEmailType) { - OWSContactEmailType_Home = 1, - OWSContactEmailType_Mobile, - OWSContactEmailType_Work, - OWSContactEmailType_Custom, -}; - -NSString *NSStringForContactEmailType(OWSContactEmailType value); - -@interface OWSContactEmail : MTLModel - -@property (nonatomic, readonly) OWSContactEmailType emailType; -// Applies in the OWSContactEmailType_Custom case. -@property (nonatomic, readonly, nullable) NSString *label; - -@property (nonatomic, readonly) NSString *email; - -@end - -#pragma mark - - -typedef NS_ENUM(NSUInteger, OWSContactAddressType) { - OWSContactAddressType_Home = 1, - OWSContactAddressType_Work, - OWSContactAddressType_Custom, -}; - -NSString *NSStringForContactAddressType(OWSContactAddressType value); - -@interface OWSContactAddress : MTLModel - -@property (nonatomic, readonly) OWSContactAddressType addressType; -// Applies in the OWSContactAddressType_Custom case. -@property (nonatomic, readonly, nullable) NSString *label; - -@property (nonatomic, readonly, nullable) NSString *street; -@property (nonatomic, readonly, nullable) NSString *pobox; -@property (nonatomic, readonly, nullable) NSString *neighborhood; -@property (nonatomic, readonly, nullable) NSString *city; -@property (nonatomic, readonly, nullable) NSString *region; -@property (nonatomic, readonly, nullable) NSString *postcode; -@property (nonatomic, readonly, nullable) NSString *country; - -@end - -#pragma mark - - -@interface OWSContactName : MTLModel - -// The "name parts". -@property (nonatomic, nullable) NSString *givenName; -@property (nonatomic, nullable) NSString *familyName; -@property (nonatomic, nullable) NSString *nameSuffix; -@property (nonatomic, nullable) NSString *namePrefix; -@property (nonatomic, nullable) NSString *middleName; - -@property (nonatomic, nullable) NSString *organizationName; - -@property (nonatomic) NSString *displayName; - -// Returns true if any of the name parts (which doesn't include -// organization name) is non-empty. -- (BOOL)hasAnyNamePart; - -@end - -#pragma mark - - -@interface OWSContact : MTLModel - -@property (nonatomic) OWSContactName *name; - -@property (nonatomic, readonly) NSArray *phoneNumbers; -@property (nonatomic, readonly) NSArray *emails; -@property (nonatomic, readonly) NSArray *addresses; - -@property (nonatomic, readonly, nullable) NSString *avatarAttachmentId; -- (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction; -- (void)removeAvatarAttachmentWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; - -- (void)saveAvatarImage:(UIImage *)image transaction:(YapDatabaseReadWriteTransaction *)transaction; -// "Profile" avatars should _not_ be saved to device contacts. -@property (nonatomic, readonly) BOOL isProfileAvatar; - -- (instancetype)init NS_UNAVAILABLE; - -- (void)normalize; - -- (BOOL)ows_isValid; - -- (NSString *)debugDescription; - -#pragma mark - Creation and Derivation - -- (OWSContact *)newContactWithName:(OWSContactName *)name; - -- (OWSContact *)copyContactWithName:(OWSContactName *)name; - -#pragma mark - Phone Numbers and Recipient IDs - -- (NSArray *)systemContactsWithSignalAccountPhoneNumbers:(id)contactsManager - NS_SWIFT_NAME(systemContactsWithSignalAccountPhoneNumbers(_:)); -- (NSArray *)systemContactPhoneNumbers:(id)contactsManager - NS_SWIFT_NAME(systemContactPhoneNumbers(_:)); -- (NSArray *)e164PhoneNumbers NS_SWIFT_NAME(e164PhoneNumbers()); - -@end - -#pragma mark - - -// TODO: Move to separate source file, rename to OWSContactConversion. -@interface OWSContacts : NSObject - -#pragma mark - System Contact Conversion - -// `contactForSystemContact` does *not* handle avatars. That must be delt with by the caller -+ (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact; - -+ (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData; - -#pragma mark - Proto Serialization - -+ (nullable SSKProtoDataMessageContact *)protoForContact:(OWSContact *)contact; - -+ (nullable OWSContact *)contactForDataMessage:(SSKProtoDataMessage *)dataMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContact.m b/SignalUtilitiesKit/OWSContact.m deleted file mode 100644 index 9c5f9479a..000000000 --- a/SignalUtilitiesKit/OWSContact.m +++ /dev/null @@ -1,1126 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSContact.h" -#import "Contact.h" -#import "MimeTypeUtil.h" -#import "NSString+SSK.h" -#import "OWSContact+Private.h" -#import "PhoneNumber.h" -#import "TSAttachment.h" -#import "TSAttachmentPointer.h" -#import "TSAttachmentStream.h" -#import -#import - -@import Contacts; - -NS_ASSUME_NONNULL_BEGIN - -// NOTE: When changing the value of this feature flag, you also need -// to update the filtering in the SAE's info.plist. -BOOL kIsSendingContactSharesEnabled = YES; - -NSString *NSStringForContactPhoneType(OWSContactPhoneType value) -{ - switch (value) { - case OWSContactPhoneType_Home: - return @"Home"; - case OWSContactPhoneType_Mobile: - return @"Mobile"; - case OWSContactPhoneType_Work: - return @"Work"; - case OWSContactPhoneType_Custom: - return @"Custom"; - } -} - -@interface OWSContactPhoneNumber () - -@property (nonatomic) OWSContactPhoneType phoneType; -@property (nonatomic, nullable) NSString *label; - -@property (nonatomic) NSString *phoneNumber; - -@end - -#pragma mark - - -@implementation OWSContactPhoneNumber - -- (BOOL)ows_isValid -{ - if (self.phoneNumber.ows_stripped.length < 1) { - OWSLogWarn(@"invalid phone number: %@.", self.phoneNumber); - return NO; - } - return YES; -} - -- (NSString *)localizedLabel -{ - switch (self.phoneType) { - case OWSContactPhoneType_Home: - return [CNLabeledValue localizedStringForLabel:CNLabelHome]; - case OWSContactPhoneType_Mobile: - return [CNLabeledValue localizedStringForLabel:CNLabelPhoneNumberMobile]; - case OWSContactPhoneType_Work: - return [CNLabeledValue localizedStringForLabel:CNLabelWork]; - default: - if (self.label.ows_stripped.length < 1) { - return NSLocalizedString(@"CONTACT_PHONE", @"Label for a contact's phone number."); - } - return self.label.ows_stripped; - } -} - -- (NSString *)debugDescription -{ - NSMutableString *result = [NSMutableString new]; - [result appendFormat:@"[Phone Number: %@, ", NSStringForContactPhoneType(self.phoneType)]; - - if (self.label.length > 0) { - [result appendFormat:@"label: %@, ", self.label]; - } - if (self.phoneNumber.length > 0) { - [result appendFormat:@"phoneNumber: %@, ", self.phoneNumber]; - } - - [result appendString:@"]"]; - return result; -} - -- (nullable NSString *)tryToConvertToE164 -{ - PhoneNumber *_Nullable parsedPhoneNumber; - parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromE164:self.phoneNumber]; - if (!parsedPhoneNumber) { - parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:self.phoneNumber]; - } - if (parsedPhoneNumber) { - return parsedPhoneNumber.toE164; - } - return nil; -} - -@end - -#pragma mark - - -NSString *NSStringForContactEmailType(OWSContactEmailType value) -{ - switch (value) { - case OWSContactEmailType_Home: - return @"Home"; - case OWSContactEmailType_Mobile: - return @"Mobile"; - case OWSContactEmailType_Work: - return @"Work"; - case OWSContactEmailType_Custom: - return @"Custom"; - } -} - -@interface OWSContactEmail () - -@property (nonatomic) OWSContactEmailType emailType; -@property (nonatomic, nullable) NSString *label; - -@property (nonatomic) NSString *email; - -@end - -#pragma mark - - -@implementation OWSContactEmail - -- (BOOL)ows_isValid -{ - if (self.email.ows_stripped.length < 1) { - OWSLogWarn(@"invalid email: %@.", self.email); - return NO; - } - return YES; -} - -- (NSString *)localizedLabel -{ - switch (self.emailType) { - case OWSContactEmailType_Home: - return [CNLabeledValue localizedStringForLabel:CNLabelHome]; - case OWSContactEmailType_Mobile: - return [CNLabeledValue localizedStringForLabel:CNLabelPhoneNumberMobile]; - case OWSContactEmailType_Work: - return [CNLabeledValue localizedStringForLabel:CNLabelWork]; - default: - if (self.label.ows_stripped.length < 1) { - return NSLocalizedString(@"CONTACT_EMAIL", @"Label for a contact's email address."); - } - return self.label.ows_stripped; - } -} - -- (NSString *)debugDescription -{ - NSMutableString *result = [NSMutableString new]; - [result appendFormat:@"[Email: %@, ", NSStringForContactEmailType(self.emailType)]; - - if (self.label.length > 0) { - [result appendFormat:@"label: %@, ", self.label]; - } - if (self.email.length > 0) { - [result appendFormat:@"email: %@, ", self.email]; - } - - [result appendString:@"]"]; - return result; -} - -@end - -#pragma mark - - -NSString *NSStringForContactAddressType(OWSContactAddressType value) -{ - switch (value) { - case OWSContactAddressType_Home: - return @"Home"; - case OWSContactAddressType_Work: - return @"Work"; - case OWSContactAddressType_Custom: - return @"Custom"; - } -} -@interface OWSContactAddress () - -@property (nonatomic) OWSContactAddressType addressType; -@property (nonatomic, nullable) NSString *label; - -@property (nonatomic, nullable) NSString *street; -@property (nonatomic, nullable) NSString *pobox; -@property (nonatomic, nullable) NSString *neighborhood; -@property (nonatomic, nullable) NSString *city; -@property (nonatomic, nullable) NSString *region; -@property (nonatomic, nullable) NSString *postcode; -@property (nonatomic, nullable) NSString *country; - -@end - -#pragma mark - - -@implementation OWSContactAddress - -- (BOOL)ows_isValid -{ - if (self.street.ows_stripped.length < 1 && self.pobox.ows_stripped.length < 1 - && self.neighborhood.ows_stripped.length < 1 && self.city.ows_stripped.length < 1 - && self.region.ows_stripped.length < 1 && self.postcode.ows_stripped.length < 1 - && self.country.ows_stripped.length < 1) { - OWSLogWarn(@"invalid address; empty."); - return NO; - } - return YES; -} - -- (NSString *)localizedLabel -{ - switch (self.addressType) { - case OWSContactAddressType_Home: - return [CNLabeledValue localizedStringForLabel:CNLabelHome]; - case OWSContactAddressType_Work: - return [CNLabeledValue localizedStringForLabel:CNLabelWork]; - default: - if (self.label.ows_stripped.length < 1) { - return NSLocalizedString(@"CONTACT_ADDRESS", @"Label for a contact's postal address."); - } - return self.label.ows_stripped; - } -} - -- (NSString *)debugDescription -{ - NSMutableString *result = [NSMutableString new]; - [result appendFormat:@"[Address: %@, ", NSStringForContactAddressType(self.addressType)]; - - if (self.label.length > 0) { - [result appendFormat:@"label: %@, ", self.label]; - } - if (self.street.length > 0) { - [result appendFormat:@"street: %@, ", self.street]; - } - if (self.pobox.length > 0) { - [result appendFormat:@"pobox: %@, ", self.pobox]; - } - if (self.neighborhood.length > 0) { - [result appendFormat:@"neighborhood: %@, ", self.neighborhood]; - } - if (self.city.length > 0) { - [result appendFormat:@"city: %@, ", self.city]; - } - if (self.region.length > 0) { - [result appendFormat:@"region: %@, ", self.region]; - } - if (self.postcode.length > 0) { - [result appendFormat:@"postcode: %@, ", self.postcode]; - } - if (self.country.length > 0) { - [result appendFormat:@"country: %@, ", self.country]; - } - - [result appendString:@"]"]; - return result; -} - -@end - -#pragma mark - - -@implementation OWSContactName - -- (NSString *)logDescription -{ - NSMutableString *result = [NSMutableString new]; - [result appendString:@"["]; - - if (self.givenName.length > 0) { - [result appendFormat:@"givenName: %@, ", self.givenName]; - } - if (self.familyName.length > 0) { - [result appendFormat:@"familyName: %@, ", self.familyName]; - } - if (self.middleName.length > 0) { - [result appendFormat:@"middleName: %@, ", self.middleName]; - } - if (self.namePrefix.length > 0) { - [result appendFormat:@"namePrefix: %@, ", self.namePrefix]; - } - if (self.nameSuffix.length > 0) { - [result appendFormat:@"nameSuffix: %@, ", self.nameSuffix]; - } - if (self.displayName.length > 0) { - [result appendFormat:@"displayName: %@, ", self.displayName]; - } - - [result appendString:@"]"]; - return result; -} - -- (NSString *)displayName -{ - [self ensureDisplayName]; - - if (_displayName.length < 1) { - OWSFailDebug(@"could not derive a valid display name."); - return NSLocalizedString(@"CONTACT_WITHOUT_NAME", @"Indicates that a contact has no name."); - } - return _displayName; -} - -- (void)ensureDisplayName -{ - if (_displayName.length < 1) { - CNContact *_Nullable cnContact = [self systemContactForName]; - _displayName = [CNContactFormatter stringFromContact:cnContact style:CNContactFormatterStyleFullName]; - } - if (_displayName.length < 1) { - // Fall back to using the organization name. - _displayName = self.organizationName; - } -} - -- (void)updateDisplayName -{ - _displayName = nil; - - [self ensureDisplayName]; -} - -- (nullable CNContact *)systemContactForName -{ - CNMutableContact *systemContact = [CNMutableContact new]; - systemContact.givenName = self.givenName.ows_stripped; - systemContact.middleName = self.middleName.ows_stripped; - systemContact.familyName = self.familyName.ows_stripped; - systemContact.namePrefix = self.namePrefix.ows_stripped; - systemContact.nameSuffix = self.nameSuffix.ows_stripped; - // We don't need to set display name, it's implicit for system contacts. - systemContact.organizationName = self.organizationName.ows_stripped; - return systemContact; -} - -- (BOOL)hasAnyNamePart -{ - return (self.givenName.ows_stripped.length > 0 || self.middleName.ows_stripped.length > 0 - || self.familyName.ows_stripped.length > 0 || self.namePrefix.ows_stripped.length > 0 - || self.nameSuffix.ows_stripped.length > 0); -} - -@end - -#pragma mark - - -@interface OWSContact () - -@property (nonatomic) NSArray *phoneNumbers; -@property (nonatomic) NSArray *emails; -@property (nonatomic) NSArray *addresses; - -@property (nonatomic, nullable) NSString *avatarAttachmentId; -@property (nonatomic) BOOL isProfileAvatar; - -@property (nonatomic, nullable) NSArray *e164PhoneNumbersCached; - -@end - -#pragma mark - - -@implementation OWSContact - -- (instancetype)init -{ - if (self = [super init]) { - _name = [OWSContactName new]; - _phoneNumbers = @[]; - _emails = @[]; - _addresses = @[]; - } - - return self; -} - -- (void)normalize -{ - self.phoneNumbers = [self.phoneNumbers - filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(OWSContactPhoneNumber *value, - NSDictionary *_Nullable bindings) { - return value.ows_isValid; - }]]; - self.emails = [self.emails filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(OWSContactEmail *value, - NSDictionary *_Nullable bindings) { - return value.ows_isValid; - }]]; - self.addresses = - [self.addresses filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(OWSContactAddress *value, - NSDictionary *_Nullable bindings) { - return value.ows_isValid; - }]]; -} - -- (BOOL)ows_isValid -{ - if (self.name.displayName.ows_stripped.length < 1) { - OWSLogWarn(@"invalid contact; no display name."); - return NO; - } - BOOL hasValue = NO; - for (OWSContactPhoneNumber *phoneNumber in self.phoneNumbers) { - if (!phoneNumber.ows_isValid) { - return NO; - } - hasValue = YES; - } - for (OWSContactEmail *email in self.emails) { - if (!email.ows_isValid) { - return NO; - } - hasValue = YES; - } - for (OWSContactAddress *address in self.addresses) { - if (!address.ows_isValid) { - return NO; - } - hasValue = YES; - } - return hasValue; -} - -- (NSString *)debugDescription -{ - NSMutableString *result = [NSMutableString new]; - [result appendString:@"["]; - - [result appendFormat:@"%@, ", self.name.logDescription]; - - for (OWSContactPhoneNumber *phoneNumber in self.phoneNumbers) { - [result appendFormat:@"%@, ", phoneNumber.debugDescription]; - } - for (OWSContactEmail *email in self.emails) { - [result appendFormat:@"%@, ", email.debugDescription]; - } - for (OWSContactAddress *address in self.addresses) { - [result appendFormat:@"%@, ", address.debugDescription]; - } - - [result appendString:@"]"]; - return result; -} - -- (OWSContact *)newContactWithName:(OWSContactName *)name -{ - OWSAssertDebug(name); - - OWSContact *newContact = [OWSContact new]; - - newContact.name = name; - - [name updateDisplayName]; - - return newContact; -} - -- (OWSContact *)copyContactWithName:(OWSContactName *)name -{ - OWSAssertDebug(name); - - OWSContact *contactCopy = [self copy]; - - contactCopy.name = name; - - [name updateDisplayName]; - - return contactCopy; -} - -#pragma mark - Avatar - -- (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - return [TSAttachment fetchObjectWithUniqueID:self.avatarAttachmentId transaction:transaction]; -} - -- (void)saveAvatarImage:(UIImage *)image transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - NSData *imageData = UIImageJPEGRepresentation(image, (CGFloat)0.9); - - TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:OWSMimeTypeImageJpeg - byteCount:(UInt32)imageData.length - sourceFilename:nil - caption:nil - albumMessageId:nil]; - - NSError *error; - BOOL success = [attachmentStream writeData:imageData error:&error]; - OWSAssertDebug(success && !error); - - [attachmentStream saveWithTransaction:transaction]; - self.avatarAttachmentId = attachmentStream.uniqueId; -} - -- (void)removeAvatarAttachmentWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - TSAttachment *_Nullable attachment = - [TSAttachment fetchObjectWithUniqueID:self.avatarAttachmentId transaction:transaction]; - [attachment removeWithTransaction:transaction]; -} - -#pragma mark - Phone Numbers and Recipient IDs - -- (NSArray *)systemContactsWithSignalAccountPhoneNumbers:(id)contactsManager -{ - OWSAssertDebug(contactsManager); - - return [self.e164PhoneNumbers - filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *_Nullable recipientId, - NSDictionary *_Nullable bindings) { - return [contactsManager isSystemContactWithSignalAccount:recipientId]; - }]]; -} - -- (NSArray *)systemContactPhoneNumbers:(id)contactsManager -{ - OWSAssertDebug(contactsManager); - - return [self.e164PhoneNumbers - filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *_Nullable recipientId, - NSDictionary *_Nullable bindings) { - return [contactsManager isSystemContact:recipientId]; - }]]; -} - -- (NSArray *)e164PhoneNumbers -{ - if (self.e164PhoneNumbersCached) { - return self.e164PhoneNumbersCached; - } - NSMutableArray *e164PhoneNumbers = [NSMutableArray new]; - for (OWSContactPhoneNumber *phoneNumber in self.phoneNumbers) { - PhoneNumber *_Nullable parsedPhoneNumber; - parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromE164:phoneNumber.phoneNumber]; - if (!parsedPhoneNumber) { - parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumber.phoneNumber]; - } - if (parsedPhoneNumber) { - [e164PhoneNumbers addObject:parsedPhoneNumber.toE164]; - } - } - self.e164PhoneNumbersCached = e164PhoneNumbers; - return e164PhoneNumbers; -} - -@end - -#pragma mark - - -@implementation OWSContacts - -#pragma mark - System Contact Conversion - -// `contactForSystemContact` does *not* handle avatars. That must be delt with by the caller -+ (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact -{ - if (!systemContact) { - OWSFailDebug(@"Missing contact."); - return nil; - } - - OWSContact *contact = [OWSContact new]; - - OWSContactName *contactName = [OWSContactName new]; - contactName.givenName = systemContact.givenName.ows_stripped; - contactName.middleName = systemContact.middleName.ows_stripped; - contactName.familyName = systemContact.familyName.ows_stripped; - contactName.namePrefix = systemContact.namePrefix.ows_stripped; - contactName.nameSuffix = systemContact.nameSuffix.ows_stripped; - contactName.organizationName = systemContact.organizationName.ows_stripped; - [contactName ensureDisplayName]; - contact.name = contactName; - - NSMutableArray *phoneNumbers = [NSMutableArray new]; - for (CNLabeledValue *phoneNumberField in systemContact.phoneNumbers) { - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - - // Make a best effort to parse the phone number to e164. - NSString *unparsedPhoneNumber = phoneNumberField.value.stringValue; - PhoneNumber *_Nullable parsedPhoneNumber; - parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromE164:unparsedPhoneNumber]; - if (!parsedPhoneNumber) { - parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:unparsedPhoneNumber]; - } - if (parsedPhoneNumber) { - phoneNumber.phoneNumber = parsedPhoneNumber.toE164; - } else { - phoneNumber.phoneNumber = unparsedPhoneNumber; - } - - if ([phoneNumberField.label isEqualToString:CNLabelHome]) { - phoneNumber.phoneType = OWSContactPhoneType_Home; - } else if ([phoneNumberField.label isEqualToString:CNLabelWork]) { - phoneNumber.phoneType = OWSContactPhoneType_Work; - } else if ([phoneNumberField.label isEqualToString:CNLabelPhoneNumberMobile]) { - phoneNumber.phoneType = OWSContactPhoneType_Mobile; - } else { - phoneNumber.phoneType = OWSContactPhoneType_Custom; - phoneNumber.label = [Contact localizedStringForCNLabel:phoneNumberField.label]; - } - [phoneNumbers addObject:phoneNumber]; - } - contact.phoneNumbers = phoneNumbers; - - NSMutableArray *emails = [NSMutableArray new]; - for (CNLabeledValue *emailField in systemContact.emailAddresses) { - OWSContactEmail *email = [OWSContactEmail new]; - email.email = emailField.value; - if ([emailField.label isEqualToString:CNLabelHome]) { - email.emailType = OWSContactEmailType_Home; - } else if ([emailField.label isEqualToString:CNLabelWork]) { - email.emailType = OWSContactEmailType_Work; - } else { - email.emailType = OWSContactEmailType_Custom; - email.label = [Contact localizedStringForCNLabel:emailField.label]; - } - [emails addObject:email]; - } - contact.emails = emails; - - NSMutableArray *addresses = [NSMutableArray new]; - for (CNLabeledValue *addressField in systemContact.postalAddresses) { - OWSContactAddress *address = [OWSContactAddress new]; - address.street = addressField.value.street; - // TODO: Is this the correct mapping? - // address.neighborhood = addressField.value.subLocality; - address.city = addressField.value.city; - // TODO: Is this the correct mapping? - // address.region = addressField.value.subAdministrativeArea; - address.region = addressField.value.state; - address.postcode = addressField.value.postalCode; - // TODO: Should we be using 2-letter codes, 3-letter codes or names? - address.country = addressField.value.ISOCountryCode; - - if ([addressField.label isEqualToString:CNLabelHome]) { - address.addressType = OWSContactAddressType_Home; - } else if ([addressField.label isEqualToString:CNLabelWork]) { - address.addressType = OWSContactAddressType_Work; - } else { - address.addressType = OWSContactAddressType_Custom; - address.label = [Contact localizedStringForCNLabel:addressField.label]; - } - [addresses addObject:address]; - } - contact.addresses = addresses; - - return contact; -} - -+ (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData -{ - if (!contact) { - OWSFailDebug(@"Missing contact."); - return nil; - } - - CNMutableContact *systemContact = [CNMutableContact new]; - - systemContact.givenName = contact.name.givenName; - systemContact.middleName = contact.name.middleName; - systemContact.familyName = contact.name.familyName; - systemContact.namePrefix = contact.name.namePrefix; - systemContact.nameSuffix = contact.name.nameSuffix; - // We don't need to set display name, it's implicit for system contacts. - systemContact.organizationName = contact.name.organizationName; - - NSMutableArray *> *systemPhoneNumbers = [NSMutableArray new]; - for (OWSContactPhoneNumber *phoneNumber in contact.phoneNumbers) { - switch (phoneNumber.phoneType) { - case OWSContactPhoneType_Home: - [systemPhoneNumbers - addObject:[CNLabeledValue - labeledValueWithLabel:CNLabelHome - value:[CNPhoneNumber - phoneNumberWithStringValue:phoneNumber.phoneNumber]]]; - break; - case OWSContactPhoneType_Mobile: - [systemPhoneNumbers - addObject:[CNLabeledValue - labeledValueWithLabel:CNLabelPhoneNumberMobile - value:[CNPhoneNumber - phoneNumberWithStringValue:phoneNumber.phoneNumber]]]; - break; - case OWSContactPhoneType_Work: - [systemPhoneNumbers - addObject:[CNLabeledValue - labeledValueWithLabel:CNLabelWork - value:[CNPhoneNumber - phoneNumberWithStringValue:phoneNumber.phoneNumber]]]; - break; - case OWSContactPhoneType_Custom: - [systemPhoneNumbers - addObject:[CNLabeledValue - labeledValueWithLabel:phoneNumber.label - value:[CNPhoneNumber - phoneNumberWithStringValue:phoneNumber.phoneNumber]]]; - break; - } - } - systemContact.phoneNumbers = systemPhoneNumbers; - - NSMutableArray *> *systemEmails = [NSMutableArray new]; - for (OWSContactEmail *email in contact.emails) { - switch (email.emailType) { - case OWSContactEmailType_Home: - [systemEmails addObject:[CNLabeledValue labeledValueWithLabel:CNLabelHome value:email.email]]; - break; - case OWSContactEmailType_Mobile: - [systemEmails addObject:[CNLabeledValue labeledValueWithLabel:@"Mobile" value:email.email]]; - break; - case OWSContactEmailType_Work: - [systemEmails addObject:[CNLabeledValue labeledValueWithLabel:CNLabelWork value:email.email]]; - break; - case OWSContactEmailType_Custom: - [systemEmails addObject:[CNLabeledValue labeledValueWithLabel:email.label value:email.email]]; - break; - } - } - systemContact.emailAddresses = systemEmails; - - NSMutableArray *> *systemAddresses = [NSMutableArray new]; - for (OWSContactAddress *address in contact.addresses) { - CNMutablePostalAddress *systemAddress = [CNMutablePostalAddress new]; - systemAddress.street = address.street; - // TODO: Is this the correct mapping? - // systemAddress.subLocality = address.neighborhood; - systemAddress.city = address.city; - // TODO: Is this the correct mapping? - // systemAddress.subAdministrativeArea = address.region; - systemAddress.state = address.region; - systemAddress.postalCode = address.postcode; - // TODO: Should we be using 2-letter codes, 3-letter codes or names? - systemAddress.ISOCountryCode = address.country; - - switch (address.addressType) { - case OWSContactAddressType_Home: - [systemAddresses addObject:[CNLabeledValue labeledValueWithLabel:CNLabelHome value:systemAddress]]; - break; - case OWSContactAddressType_Work: - [systemAddresses addObject:[CNLabeledValue labeledValueWithLabel:CNLabelWork value:systemAddress]]; - break; - case OWSContactAddressType_Custom: - [systemAddresses addObject:[CNLabeledValue labeledValueWithLabel:address.label value:systemAddress]]; - break; - } - } - systemContact.postalAddresses = systemAddresses; - systemContact.imageData = imageData; - - return systemContact; -} - -#pragma mark - Proto Serialization - -+ (nullable SSKProtoDataMessageContact *)protoForContact:(OWSContact *)contact -{ - OWSAssertDebug(contact); - - SSKProtoDataMessageContactBuilder *contactBuilder = [SSKProtoDataMessageContact builder]; - - SSKProtoDataMessageContactNameBuilder *nameBuilder = [SSKProtoDataMessageContactName builder]; - - OWSContactName *contactName = contact.name; - if (contactName.givenName.ows_stripped.length > 0) { - nameBuilder.givenName = contactName.givenName.ows_stripped; - } - if (contactName.familyName.ows_stripped.length > 0) { - nameBuilder.familyName = contactName.familyName.ows_stripped; - } - if (contactName.middleName.ows_stripped.length > 0) { - nameBuilder.middleName = contactName.middleName.ows_stripped; - } - if (contactName.namePrefix.ows_stripped.length > 0) { - nameBuilder.prefix = contactName.namePrefix.ows_stripped; - } - if (contactName.nameSuffix.ows_stripped.length > 0) { - nameBuilder.suffix = contactName.nameSuffix.ows_stripped; - } - if (contactName.organizationName.ows_stripped.length > 0) { - contactBuilder.organization = contactName.organizationName.ows_stripped; - } - nameBuilder.displayName = contactName.displayName; - - NSError *error; - SSKProtoDataMessageContactName *_Nullable nameProto = [nameBuilder buildAndReturnError:&error]; - if (error || !nameProto) { - OWSLogError(@"could not build protobuf: %@", error); - } else { - [contactBuilder setName:nameProto]; - } - - for (OWSContactPhoneNumber *phoneNumber in contact.phoneNumbers) { - SSKProtoDataMessageContactPhoneBuilder *phoneBuilder = [SSKProtoDataMessageContactPhone builder]; - phoneBuilder.value = phoneNumber.phoneNumber; - if (phoneNumber.label.ows_stripped.length > 0) { - phoneBuilder.label = phoneNumber.label.ows_stripped; - } - switch (phoneNumber.phoneType) { - case OWSContactPhoneType_Home: - phoneBuilder.type = SSKProtoDataMessageContactPhoneTypeHome; - break; - case OWSContactPhoneType_Mobile: - phoneBuilder.type = SSKProtoDataMessageContactPhoneTypeMobile; - break; - case OWSContactPhoneType_Work: - phoneBuilder.type = SSKProtoDataMessageContactPhoneTypeWork; - break; - case OWSContactPhoneType_Custom: - phoneBuilder.type = SSKProtoDataMessageContactPhoneTypeCustom; - break; - } - SSKProtoDataMessageContactPhone *_Nullable numberProto = [phoneBuilder buildAndReturnError:&error]; - if (error || !numberProto) { - OWSLogError(@"could not build protobuf: %@", error); - } else { - [contactBuilder addNumber:numberProto]; - } - } - - for (OWSContactEmail *email in contact.emails) { - SSKProtoDataMessageContactEmailBuilder *emailBuilder = [SSKProtoDataMessageContactEmail builder]; - emailBuilder.value = email.email; - if (email.label.ows_stripped.length > 0) { - emailBuilder.label = email.label.ows_stripped; - } - switch (email.emailType) { - case OWSContactEmailType_Home: - emailBuilder.type = SSKProtoDataMessageContactEmailTypeHome; - break; - case OWSContactEmailType_Mobile: - emailBuilder.type = SSKProtoDataMessageContactEmailTypeMobile; - break; - case OWSContactEmailType_Work: - emailBuilder.type = SSKProtoDataMessageContactEmailTypeWork; - break; - case OWSContactEmailType_Custom: - emailBuilder.type = SSKProtoDataMessageContactEmailTypeCustom; - break; - } - SSKProtoDataMessageContactEmail *_Nullable emailProto = [emailBuilder buildAndReturnError:&error]; - if (error || !emailProto) { - OWSLogError(@"could not build protobuf: %@", error); - } else { - [contactBuilder addEmail:emailProto]; - } - } - - for (OWSContactAddress *address in contact.addresses) { - SSKProtoDataMessageContactPostalAddressBuilder *addressBuilder = - [SSKProtoDataMessageContactPostalAddress builder]; - if (address.label.ows_stripped.length > 0) { - addressBuilder.label = address.label.ows_stripped; - } - if (address.street.ows_stripped.length > 0) { - addressBuilder.street = address.street.ows_stripped; - } - if (address.pobox.ows_stripped.length > 0) { - addressBuilder.pobox = address.pobox.ows_stripped; - } - if (address.neighborhood.ows_stripped.length > 0) { - addressBuilder.neighborhood = address.neighborhood.ows_stripped; - } - if (address.city.ows_stripped.length > 0) { - addressBuilder.city = address.city.ows_stripped; - } - if (address.region.ows_stripped.length > 0) { - addressBuilder.region = address.region.ows_stripped; - } - if (address.postcode.ows_stripped.length > 0) { - addressBuilder.postcode = address.postcode.ows_stripped; - } - if (address.country.ows_stripped.length > 0) { - addressBuilder.country = address.country.ows_stripped; - } - SSKProtoDataMessageContactPostalAddress *_Nullable addressProto = [addressBuilder buildAndReturnError:&error]; - if (error || !addressProto) { - OWSLogError(@"could not build protobuf: %@", error); - } else { - [contactBuilder addAddress:addressProto]; - } - } - - if (contact.avatarAttachmentId) { - SSKProtoAttachmentPointer *_Nullable attachmentProto = - [TSAttachmentStream buildProtoForAttachmentId:contact.avatarAttachmentId]; - if (!attachmentProto) { - OWSLogError(@"could not build protobuf: %@", error); - } else { - SSKProtoDataMessageContactAvatarBuilder *avatarBuilder = [SSKProtoDataMessageContactAvatar builder]; - avatarBuilder.avatar = attachmentProto; - SSKProtoDataMessageContactAvatar *_Nullable avatarProto = [avatarBuilder buildAndReturnError:&error]; - if (error || !avatarProto) { - OWSLogError(@"could not build protobuf: %@", error); - } else { - contactBuilder.avatar = avatarProto; - } - } - } - - SSKProtoDataMessageContact *_Nullable contactProto = [contactBuilder buildAndReturnError:&error]; - if (error || !contactProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - if (contactProto.number.count < 1 && contactProto.email.count < 1 && contactProto.address.count < 1) { - OWSFailDebug(@"contact has neither phone, email or address."); - return nil; - } - return contactProto; -} - -+ (nullable OWSContact *)contactForDataMessage:(SSKProtoDataMessage *)dataMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(dataMessage); - - if (dataMessage.contact.count < 1) { - return nil; - } - OWSAssertDebug(dataMessage.contact.count == 1); - SSKProtoDataMessageContact *contactProto = dataMessage.contact.firstObject; - - OWSContact *contact = [OWSContact new]; - - OWSContactName *contactName = [OWSContactName new]; - if (contactProto.name) { - SSKProtoDataMessageContactName *nameProto = contactProto.name; - - if (nameProto.givenName) { - contactName.givenName = nameProto.givenName.ows_stripped; - } - if (nameProto.familyName) { - contactName.familyName = nameProto.familyName.ows_stripped; - } - if (nameProto.prefix) { - contactName.namePrefix = nameProto.prefix.ows_stripped; - } - if (nameProto.suffix) { - contactName.nameSuffix = nameProto.suffix.ows_stripped; - } - if (nameProto.middleName) { - contactName.middleName = nameProto.middleName.ows_stripped; - } - if (nameProto.displayName) { - contactName.displayName = nameProto.displayName.ows_stripped; - } - } - if (contactProto.organization) { - contactName.organizationName = contactProto.organization.ows_stripped; - } - [contactName ensureDisplayName]; - contact.name = contactName; - - NSMutableArray *phoneNumbers = [NSMutableArray new]; - for (SSKProtoDataMessageContactPhone *phoneNumberProto in contactProto.number) { - OWSContactPhoneNumber *_Nullable phoneNumber = [self phoneNumberForProto:phoneNumberProto]; - if (phoneNumber) { - [phoneNumbers addObject:phoneNumber]; - } - } - contact.phoneNumbers = [phoneNumbers copy]; - - NSMutableArray *emails = [NSMutableArray new]; - for (SSKProtoDataMessageContactEmail *emailProto in contactProto.email) { - OWSContactEmail *_Nullable email = [self emailForProto:emailProto]; - if (email) { - [emails addObject:email]; - } - } - contact.emails = [emails copy]; - - NSMutableArray *addresses = [NSMutableArray new]; - for (SSKProtoDataMessageContactPostalAddress *addressProto in contactProto.address) { - OWSContactAddress *_Nullable address = [self addressForProto:addressProto]; - if (address) { - [addresses addObject:address]; - } - } - contact.addresses = [addresses copy]; - - if (contactProto.avatar) { - SSKProtoDataMessageContactAvatar *avatarInfo = contactProto.avatar; - - if (avatarInfo.avatar) { - SSKProtoAttachmentPointer *avatarAttachment = avatarInfo.avatar; - - TSAttachmentPointer *_Nullable attachmentPointer = - [TSAttachmentPointer attachmentPointerFromProto:avatarAttachment albumMessage:nil]; - if (attachmentPointer) { - [attachmentPointer saveWithTransaction:transaction]; - contact.avatarAttachmentId = attachmentPointer.uniqueId; - contact.isProfileAvatar = avatarInfo.isProfile; - } else { - OWSFailDebug(@"Invalid avatar attachment."); - } - } else { - OWSFailDebug(@"avatarInfo.hasAvatar was unexpectedly false"); - } - } - - - return contact; -} - -+ (nullable OWSContactPhoneNumber *)phoneNumberForProto: - (SSKProtoDataMessageContactPhone *)phoneNumberProto -{ - OWSContactPhoneNumber *result = [OWSContactPhoneNumber new]; - result.phoneType = OWSContactPhoneType_Custom; - if (phoneNumberProto.hasType) { - switch (phoneNumberProto.type) { - case SSKProtoDataMessageContactPhoneTypeHome: - result.phoneType = OWSContactPhoneType_Home; - break; - case SSKProtoDataMessageContactPhoneTypeMobile: - result.phoneType = OWSContactPhoneType_Mobile; - break; - case SSKProtoDataMessageContactPhoneTypeWork: - result.phoneType = OWSContactPhoneType_Work; - break; - default: - break; - } - } - if (phoneNumberProto.hasLabel) { - result.label = phoneNumberProto.label.ows_stripped; - } - if (phoneNumberProto.hasValue) { - result.phoneNumber = phoneNumberProto.value.ows_stripped; - } else { - return nil; - } - return result; -} - -+ (nullable OWSContactEmail *)emailForProto:(SSKProtoDataMessageContactEmail *)emailProto -{ - OWSContactEmail *result = [OWSContactEmail new]; - result.emailType = OWSContactEmailType_Custom; - if (emailProto.hasType) { - switch (emailProto.type) { - case SSKProtoDataMessageContactEmailTypeHome: - result.emailType = OWSContactEmailType_Home; - break; - case SSKProtoDataMessageContactEmailTypeMobile: - result.emailType = OWSContactEmailType_Mobile; - break; - case SSKProtoDataMessageContactEmailTypeWork: - result.emailType = OWSContactEmailType_Work; - break; - default: - break; - } - } - if (emailProto.hasLabel) { - result.label = emailProto.label.ows_stripped; - } - if (emailProto.hasValue) { - result.email = emailProto.value.ows_stripped; - } else { - return nil; - } - return result; -} - -+ (nullable OWSContactAddress *)addressForProto:(SSKProtoDataMessageContactPostalAddress *)addressProto -{ - OWSContactAddress *result = [OWSContactAddress new]; - result.addressType = OWSContactAddressType_Custom; - if (addressProto.hasType) { - switch (addressProto.type) { - case SSKProtoDataMessageContactPostalAddressTypeHome: - result.addressType = OWSContactAddressType_Home; - break; - case SSKProtoDataMessageContactPostalAddressTypeWork: - result.addressType = OWSContactAddressType_Work; - break; - default: - break; - } - } - if (addressProto.hasLabel) { - result.label = addressProto.label.ows_stripped; - } - if (addressProto.hasStreet) { - result.street = addressProto.street.ows_stripped; - } - if (addressProto.hasPobox) { - result.pobox = addressProto.pobox.ows_stripped; - } - if (addressProto.hasNeighborhood) { - result.neighborhood = addressProto.neighborhood.ows_stripped; - } - if (addressProto.hasCity) { - result.city = addressProto.city.ows_stripped; - } - if (addressProto.hasRegion) { - result.region = addressProto.region.ows_stripped; - } - if (addressProto.hasPostcode) { - result.postcode = addressProto.postcode.ows_stripped; - } - if (addressProto.hasCountry) { - result.country = addressProto.country.ows_stripped; - } - return result; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContactAvatarBuilder.h b/SignalUtilitiesKit/OWSContactAvatarBuilder.h deleted file mode 100644 index 4d2d14da1..000000000 --- a/SignalUtilitiesKit/OWSContactAvatarBuilder.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSContactThread; - -@interface OWSContactAvatarBuilder : OWSAvatarBuilder - -/** - * Build an avatar for a Signal recipient - */ -- (instancetype)initWithSignalId:(NSString *)signalId - colorName:(ConversationColorName)colorName - diameter:(NSUInteger)diameter; - -/** - * Build an avatar for a non-Signal recipient - */ -- (instancetype)initWithNonSignalName:(NSString *)nonSignalName - colorSeed:(NSString *)colorSeed - diameter:(NSUInteger)diameter; - -- (instancetype)initForLocalUserWithDiameter:(NSUInteger)diameter; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContactAvatarBuilder.m b/SignalUtilitiesKit/OWSContactAvatarBuilder.m deleted file mode 100644 index 1af9d9e47..000000000 --- a/SignalUtilitiesKit/OWSContactAvatarBuilder.m +++ /dev/null @@ -1,227 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSContactAvatarBuilder.h" -#import "OWSContactsManager.h" -#import "TSContactThread.h" -#import "TSGroupThread.h" -#import "TSThread.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSContactAvatarBuilder () - -@property (nonatomic, readonly) NSString *signalId; -@property (nonatomic, readonly) NSString *contactName; -@property (nonatomic, readonly) ConversationColorName colorName; -@property (nonatomic, readonly) NSUInteger diameter; - -@end - -@implementation OWSContactAvatarBuilder - -#pragma mark - Initializers - -- (instancetype)initWithContactId:(NSString *)contactId - name:(NSString *)name - colorName:(ConversationColorName)colorName - diameter:(NSUInteger)diameter -{ - self = [super init]; - if (!self) { - return self; - } - - OWSAssertDebug(colorName.length > 0); - - _signalId = contactId; - _contactName = name; - _colorName = colorName; - _diameter = diameter; - - return self; -} - -- (instancetype)initWithSignalId:(NSString *)signalId - colorName:(ConversationColorName)colorName - diameter:(NSUInteger)diameter -{ - // Name for avatar initials. - NSString *_Nullable name = [OWSContactAvatarBuilder.contactsManager nameFromSystemContactsForRecipientId:signalId]; - if (name.length == 0) { - name = [OWSContactAvatarBuilder.contactsManager profileNameForRecipientId:signalId]; - } - if (name.length == 0) { - name = signalId; - } - return [self initWithContactId:signalId name:name colorName:colorName diameter:diameter]; -} - -- (instancetype)initWithNonSignalName:(NSString *)nonSignalName - colorSeed:(NSString *)colorSeed - diameter:(NSUInteger)diameter -{ - ConversationColorName colorName = [TSThread stableColorNameForNewConversationWithString:colorSeed]; - return [self initWithContactId:colorSeed name:nonSignalName colorName:(NSString *)colorName diameter:diameter]; -} - -- (instancetype)initForLocalUserWithDiameter:(NSUInteger)diameter -{ - NSString *localNumber = [NSUserDefaults.standardUserDefaults stringForKey:@"masterDeviceHexEncodedPublicKey"]; - if (localNumber == nil) { - localNumber = [TSAccountManager localNumber]; - } - OWSAssertDebug(localNumber.length > 0); - OWSAssertDebug(diameter > 0); - - return [self initWithSignalId:localNumber colorName:kConversationColorName_Default diameter:diameter]; -} - -#pragma mark - Dependencies - -+ (OWSContactsManager *)contactsManager -{ - return (OWSContactsManager *)SSKEnvironment.shared.contactsManager; -} - -#pragma mark - Instance methods - -- (nullable UIImage *)buildSavedImage -{ - NSString *masterDeviceHexEncodedPublicKey = [NSUserDefaults.standardUserDefaults stringForKey:@"masterDeviceHexEncodedPublicKey"]; - if ([self.signalId isEqualToString:TSAccountManager.localNumber] || (masterDeviceHexEncodedPublicKey != nil && [self.signalId isEqualToString:masterDeviceHexEncodedPublicKey])) { - NSString *noteToSelfCacheKey = [NSString stringWithFormat:@"%@:note-to-self", self.cacheKey]; - UIImage *_Nullable cachedAvatar = - [OWSContactAvatarBuilder.contactsManager.avatarCache imageForKey:noteToSelfCacheKey - diameter:(CGFloat)self.diameter]; - if (cachedAvatar) { - return cachedAvatar; - } - - UIImage *image = [self noteToSelfImageWithConversationColorName:self.colorName]; - if (!image) { - OWSFailDebug(@"Could not generate avatar."); - return nil; - } - - [OWSContactAvatarBuilder.contactsManager.avatarCache setImage:image - forKey:noteToSelfCacheKey - diameter:self.diameter]; - return image; - } - - return [OWSContactAvatarBuilder.contactsManager imageForPhoneIdentifier:self.signalId]; -} - -- (id)cacheKey -{ - return [NSString stringWithFormat:@"%@-%d", self.signalId, Theme.isDarkThemeEnabled]; -} - -- (nullable UIImage *)buildDefaultImage -{ - UIImage *_Nullable cachedAvatar = - [OWSContactAvatarBuilder.contactsManager.avatarCache imageForKey:self.cacheKey diameter:(CGFloat)self.diameter]; - if (cachedAvatar) { - return cachedAvatar; - } - - /** - NSMutableString *initials = [NSMutableString string]; - - NSRange rangeOfLetters = [self.contactName rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]]; - if (rangeOfLetters.location != NSNotFound) { - // Contact name contains letters, so it's probably not just a phone number. - // Make an image from the contact's initials - NSCharacterSet *excludeAlphanumeric = [NSCharacterSet alphanumericCharacterSet].invertedSet; - NSArray *words = - [self.contactName componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - for (NSString *word in words) { - NSString *trimmedWord = [word stringByTrimmingCharactersInSet:excludeAlphanumeric]; - if (trimmedWord.length > 0) { - NSString *firstLetter = [trimmedWord substringToIndex:1]; - [initials appendString:firstLetter.localizedUppercaseString]; - } - } - - NSRange stringRange = { 0, MIN([initials length], (NSUInteger)3) }; // Rendering max 3 letters. - initials = [[initials substringWithRange:stringRange] mutableCopy]; - } - - UIColor *color = [OWSConversationColor conversationColorOrDefaultForColorName:self.colorName].themeColor; - OWSAssertDebug(color); - - UIImage *_Nullable image; - if (initials.length == 0) { - // We don't have a name for this contact, so we can't make an "initials" image. - - UIImage *icon; - if (self.diameter > kStandardAvatarSize) { - icon = [UIImage imageNamed:@"contact-avatar-1024"]; - } else { - icon = [UIImage imageNamed:@"contact-avatar-84"]; - } - CGFloat assetWidthPixels = CGImageGetWidth(icon.CGImage); - // The contact-avatar asset is designed to be 28pt if the avatar is kStandardAvatarSize. - // Adjust its size to reflect the actual output diameter. - // We use an oversize 1024px version of the asset to ensure quality results for larger avatars. - CGFloat scaling = (self.diameter / (CGFloat)kStandardAvatarSize) * (28 / assetWidthPixels); - - CGSize iconSize = CGSizeScale(icon.size, scaling); - image = - [OWSAvatarBuilder avatarImageWithIcon:icon iconSize:iconSize backgroundColor:color diameter:self.diameter]; - } else { - image = [OWSAvatarBuilder avatarImageWithInitials:initials backgroundColor:color diameter:self.diameter]; - } - - if (!image) { - OWSFailDebug(@"Could not generate avatar."); - return nil; - } - */ - - UIImage *image = [LKIdenticon generatePlaceholderIconWithSeed:self.signalId text:@"0" size:((CGFloat)self.diameter)]; - [OWSContactAvatarBuilder.contactsManager.avatarCache setImage:image forKey:self.cacheKey diameter:self.diameter]; - return image; -} - -- (nullable UIImage *)noteToSelfImageWithConversationColorName:(ConversationColorName)conversationColorName -{ - UIImage *baseImage = [[UIImage imageNamed:@"note-to-self-avatar"] asTintedImageWithColor:UIColor.whiteColor]; - UIColor *backgroundColor = [OWSConversationColor conversationColorOrDefaultForColorName:conversationColorName].themeColor; - - CGFloat paddingFactor = 1.6; - CGFloat paddedWidth = baseImage.size.width * paddingFactor; - CGFloat paddedheight = baseImage.size.height * paddingFactor; - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(paddedWidth, paddedheight), NO, 0.0); - CGContextRef _Nullable context = UIGraphicsGetCurrentContext(); - if (context == nil) { - OWSFailDebug(@"failure: context was unexpectedly nil"); - return nil; - } - [backgroundColor setFill]; - CGContextFillRect(context, CGRectMake(0, 0, paddedWidth, paddedheight)); - - CGPoint origin = CGPointMake((paddedWidth - baseImage.size.width) / 2.0f, - (paddedheight - baseImage.size.height) / 2.0f); - [baseImage drawAtPoint:origin]; - - UIImage *paddedImage = UIGraphicsGetImageFromCurrentImageContext(); - if (paddedImage == nil) { - OWSFailDebug(@"failure: paddedImage was unexpectedly nil"); - return nil; - } - UIGraphicsEndImageContext(); - - return paddedImage; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContactDiscoveryOperation.swift b/SignalUtilitiesKit/OWSContactDiscoveryOperation.swift deleted file mode 100644 index 8a71e43a7..000000000 --- a/SignalUtilitiesKit/OWSContactDiscoveryOperation.swift +++ /dev/null @@ -1,537 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalCoreKit - -@objc(OWSLegacyContactDiscoveryOperation) -public class LegacyContactDiscoveryBatchOperation: OWSOperation { - - @objc - public var registeredRecipientIds: Set - - private let recipientIdsToLookup: [String] - private var networkManager: TSNetworkManager { - return TSNetworkManager.shared() - } - - // MARK: Initializers - - @objc - public required init(recipientIdsToLookup: [String]) { - self.recipientIdsToLookup = recipientIdsToLookup - self.registeredRecipientIds = Set() - - super.init() - - Logger.debug("with recipientIdsToLookup: \(recipientIdsToLookup.count)") - } - - // MARK: OWSOperation Overrides - - // Called every retry, this is where the bulk of the operation's work should go. - override public func run() { - Logger.debug("") - - guard !isCancelled else { - Logger.info("no work to do, since we were canceled") - self.reportCancelled() - return - } - - var phoneNumbersByHashes: [String: String] = [:] - - for recipientId in recipientIdsToLookup { - guard let hash = Cryptography.truncatedSHA1Base64EncodedWithoutPadding(recipientId) else { - owsFailDebug("could not hash recipient id: \(recipientId)") - continue - } - assert(phoneNumbersByHashes[hash] == nil) - phoneNumbersByHashes[hash] = recipientId - } - - let hashes: [String] = Array(phoneNumbersByHashes.keys) - - let request = OWSRequestFactory.contactsIntersectionRequest(withHashesArray: hashes) - - self.networkManager.makeRequest(request, - success: { (task, responseDict) in - do { - self.registeredRecipientIds = try self.parse(response: responseDict, phoneNumbersByHashes: phoneNumbersByHashes) - self.reportSuccess() - } catch { - self.reportError(error) - } - }, - failure: { (task, error) in - guard let response = task.response as? HTTPURLResponse else { - let responseError: NSError = OWSErrorMakeUnableToProcessServerResponseError() as NSError - responseError.isRetryable = true - self.reportError(responseError) - return - } - - guard response.statusCode != 413 else { - let rateLimitError = OWSErrorWithCodeDescription(OWSErrorCode.contactsUpdaterRateLimit, "Contacts Intersection Rate Limit") - self.reportError(rateLimitError) - return - } - - self.reportError(error) - }) - } - - // Called at most one time. - override public func didSucceed() { - // Compare against new CDS service - let modernCDSOperation = CDSOperation(recipientIdsToLookup: self.recipientIdsToLookup) - let cdsFeedbackOperation = CDSFeedbackOperation(legacyRegisteredRecipientIds: self.registeredRecipientIds) - cdsFeedbackOperation.addDependency(modernCDSOperation) - - let operations = modernCDSOperation.dependencies + [modernCDSOperation, cdsFeedbackOperation] - CDSOperation.operationQueue.addOperations(operations, waitUntilFinished: false) - } - - // MARK: Private Helpers - - private func parse(response: Any?, phoneNumbersByHashes: [String: String]) throws -> Set { - - guard let responseDict = response as? [String: AnyObject] else { - let responseError: NSError = OWSErrorMakeUnableToProcessServerResponseError() as NSError - responseError.isRetryable = true - - throw responseError - } - - guard let contactDicts = responseDict["contacts"] as? [[String: AnyObject]] else { - let responseError: NSError = OWSErrorMakeUnableToProcessServerResponseError() as NSError - responseError.isRetryable = true - - throw responseError - } - - var registeredRecipientIds: Set = Set() - - for contactDict in contactDicts { - guard let hash = contactDict["token"] as? String, hash.count > 0 else { - owsFailDebug("hash was unexpectedly nil") - continue - } - - guard let recipientId = phoneNumbersByHashes[hash], recipientId.count > 0 else { - owsFailDebug("recipientId was unexpectedly nil") - continue - } - - guard recipientIdsToLookup.contains(recipientId) else { - owsFailDebug("unexpected recipientId") - continue - } - - registeredRecipientIds.insert(recipientId) - } - - return registeredRecipientIds - } - -} - -enum ContactDiscoveryError: Error { - case parseError(description: String) - case assertionError(description: String) - case clientError(underlyingError: Error) - case serverError(underlyingError: Error) -} - -@objc(OWSCDSOperation) -class CDSOperation: OWSOperation { - - let batchSize = 2048 - static let operationQueue: OperationQueue = { - let queue = OperationQueue() - queue.maxConcurrentOperationCount = 5 - queue.name = CDSOperation.logTag() - return queue - }() - - let recipientIdsToLookup: [String] - - @objc - var registeredRecipientIds: Set - - @objc - required init(recipientIdsToLookup: [String]) { - self.recipientIdsToLookup = recipientIdsToLookup - self.registeredRecipientIds = Set() - - super.init() - - Logger.debug("with recipientIdsToLookup: \(recipientIdsToLookup.count)") - for batchIds in recipientIdsToLookup.chunked(by: batchSize) { - let batchOperation = CDSBatchOperation(recipientIdsToLookup: batchIds) - self.addDependency(batchOperation) - } - } - - // MARK: Mandatory overrides - - // Called every retry, this is where the bulk of the operation's work should go. - override func run() { - Logger.debug("") - - for dependency in self.dependencies { - guard let batchOperation = dependency as? CDSBatchOperation else { - owsFailDebug("unexpected dependency: \(dependency)") - continue - } - - self.registeredRecipientIds.formUnion(batchOperation.registeredRecipientIds) - } - - self.reportSuccess() - } - -} - -public -class CDSBatchOperation: OWSOperation { - - private let recipientIdsToLookup: [String] - private(set) var registeredRecipientIds: Set - - private var networkManager: TSNetworkManager { - return TSNetworkManager.shared() - } - - private var contactDiscoveryService: ContactDiscoveryService { - return ContactDiscoveryService.shared() - } - - // MARK: Initializers - - public required init(recipientIdsToLookup: [String]) { - self.recipientIdsToLookup = Set(recipientIdsToLookup).map { $0 } - self.registeredRecipientIds = Set() - - super.init() - - Logger.debug("with recipientIdsToLookup: \(recipientIdsToLookup.count)") - } - - // MARK: OWSOperationOverrides - - // Called every retry, this is where the bulk of the operation's work should go. - override public func run() { - Logger.debug("") - - guard !isCancelled else { - Logger.info("no work to do, since we were canceled") - self.reportCancelled() - return - } - - contactDiscoveryService.performRemoteAttestation(success: { (remoteAttestation: RemoteAttestation) in - self.makeContactDiscoveryRequest(remoteAttestation: remoteAttestation) - }, - failure: self.reportError) - } - - private func makeContactDiscoveryRequest(remoteAttestation: RemoteAttestation) { - return // Loki: Do nothing - - guard !isCancelled else { - Logger.info("no work to do, since we were canceled") - self.reportCancelled() - return - } - - let encryptionResult: AES25GCMEncryptionResult - do { - encryptionResult = try encryptAddresses(recipientIds: recipientIdsToLookup, remoteAttestation: remoteAttestation) - } catch { - reportError(error) - return - } - - let request = OWSRequestFactory.enclaveContactDiscoveryRequest(withId: remoteAttestation.requestId, - addressCount: UInt(recipientIdsToLookup.count), - encryptedAddressData: encryptionResult.ciphertext, - cryptIv: encryptionResult.initializationVector, - cryptMac: encryptionResult.authTag, - enclaveId: remoteAttestation.enclaveId, - authUsername: remoteAttestation.auth.username, - authPassword: remoteAttestation.auth.password, - cookies: remoteAttestation.cookies) - - self.networkManager.makeRequest(request, - success: { (task, responseDict) in - do { - self.registeredRecipientIds = try self.handle(response: responseDict, remoteAttestation: remoteAttestation) - self.reportSuccess() - } catch { - self.reportError(error) - } - }, - failure: { (task, error) in - guard let response = task.response as? HTTPURLResponse else { - let responseError = OWSErrorMakeUnableToProcessServerResponseError() as NSError - responseError.isRetryable = true - self.reportError(responseError) - return - } - - guard response.statusCode != 413 else { - let rateLimitError: NSError = OWSErrorWithCodeDescription(OWSErrorCode.contactsUpdaterRateLimit, "Contacts Intersection Rate Limit") as NSError - - // TODO CDS ratelimiting, handle Retry-After header if available - rateLimitError.isRetryable = false - self.reportError(rateLimitError) - return - } - - guard response.statusCode / 100 != 4 else { - let clientError: NSError = ContactDiscoveryError.clientError(underlyingError: error) as NSError - clientError.isRetryable = (error as NSError).isRetryable - self.reportError(clientError) - return - } - - guard response.statusCode / 100 != 5 else { - let serverError = ContactDiscoveryError.serverError(underlyingError: error) as NSError - serverError.isRetryable = (error as NSError).isRetryable - - // TODO CDS ratelimiting, handle Retry-After header if available - self.reportError(serverError) - return - } - - self.reportError(error) - }) - } - - func encryptAddresses(recipientIds: [String], remoteAttestation: RemoteAttestation) throws -> AES25GCMEncryptionResult { - - let addressPlainTextData = try type(of: self).encodePhoneNumbers(recipientIds: recipientIds) - - guard let encryptionResult = Cryptography.encryptAESGCM(plainTextData: addressPlainTextData, - initializationVector: Cryptography.generateRandomBytes(kAESGCM256_DefaultIVLength), - additionalAuthenticatedData: remoteAttestation.requestId, - key: remoteAttestation.keys.clientKey) else { - - throw ContactDiscoveryError.assertionError(description: "Encryption failure") - } - - return encryptionResult - } - - class func encodePhoneNumbers(recipientIds: [String]) throws -> Data { - var output = Data() - - for recipientId in recipientIds { - guard recipientId.prefix(1) == "+" else { - throw ContactDiscoveryError.assertionError(description: "unexpected id format") - } - - let numericPortionIndex = recipientId.index(after: recipientId.startIndex) - let numericPortion = recipientId.suffix(from: numericPortionIndex) - - guard let numericIdentifier = UInt64(numericPortion), numericIdentifier > 99 else { - throw ContactDiscoveryError.assertionError(description: "unexpectedly short identifier") - } - - var bigEndian: UInt64 = CFSwapInt64HostToBig(numericIdentifier) - let buffer = UnsafeBufferPointer(start: &bigEndian, count: 1) - output.append(buffer) - } - - return output - } - - func handle(response: Any?, remoteAttestation: RemoteAttestation) throws -> Set { - let isIncludedData: Data = try parseAndDecrypt(response: response, remoteAttestation: remoteAttestation) - guard let isIncluded: [Bool] = type(of: self).boolArray(data: isIncludedData) else { - throw ContactDiscoveryError.assertionError(description: "isIncluded was unexpectedly nil") - } - - return try match(recipientIds: self.recipientIdsToLookup, isIncluded: isIncluded) - } - - class func boolArray(data: Data) -> [Bool]? { - var bools: [Bool]? - data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in - let buffer = UnsafeBufferPointer(start: bytes, count: data.count) - bools = Array(buffer) - } - - return bools - } - - func match(recipientIds: [String], isIncluded: [Bool]) throws -> Set { - guard recipientIds.count == isIncluded.count else { - throw ContactDiscoveryError.assertionError(description: "length mismatch for isIncluded/recipientIds") - } - - let includedRecipientIds: [String] = (0.. Data { - - guard let params = ParamParser(responseObject: response) else { - throw ContactDiscoveryError.parseError(description: "missing response dict") - } - - let cipherText = try params.requiredBase64EncodedData(key: "data") - let initializationVector = try params.requiredBase64EncodedData(key: "iv") - let authTag = try params.requiredBase64EncodedData(key: "mac") - - guard let plainText = Cryptography.decryptAESGCM(withInitializationVector: initializationVector, - ciphertext: cipherText, - additionalAuthenticatedData: nil, - authTag: authTag, - key: remoteAttestation.keys.serverKey) else { - throw ContactDiscoveryError.parseError(description: "decryption failed") - } - - return plainText - } -} - -class CDSFeedbackOperation: OWSOperation { - - enum FeedbackResult { - case ok - case mismatch - case attestationError(reason: String) - case unexpectedError(reason: String) - } - - private let legacyRegisteredRecipientIds: Set - - var networkManager: TSNetworkManager { - return TSNetworkManager.shared() - } - - // MARK: Initializers - - required init(legacyRegisteredRecipientIds: Set) { - self.legacyRegisteredRecipientIds = legacyRegisteredRecipientIds - - super.init() - - Logger.debug("") - } - - // MARK: OWSOperation Overrides - - override func checkForPreconditionError() -> Error? { - // override super with no-op - // In this rare case, we want to proceed even though our dependency might have an - // error so we can report the details of that error to the feedback service. - return nil - } - - // Called every retry, this is where the bulk of the operation's work should go. - override func run() { - - guard !isCancelled else { - Logger.info("no work to do, since we were canceled") - self.reportCancelled() - return - } - - guard let cdsOperation = dependencies.first as? CDSOperation else { - let error = OWSErrorMakeAssertionError("cdsOperation was unexpectedly nil") - self.reportError(error) - return - } - - if let error = cdsOperation.failingError { - switch error { - case TSNetworkManagerError.failedConnection: - // Don't submit feedback for connectivity errors - self.reportSuccess() - case ContactDiscoveryError.serverError, ContactDiscoveryError.clientError: - // Server already has this information, no need submit feedback - self.reportSuccess() - case let cdsError as ContactDiscoveryServiceError: - let reason = cdsError.reason - switch cdsError.code { - case .assertionError: - self.makeRequest(result: .unexpectedError(reason: "CDS assertionError: \(reason ?? "unknown")")) - case .attestationFailed: - self.makeRequest(result: .attestationError(reason: "CDS attestationFailed: \(reason ?? "unknown")")) - } - case ContactDiscoveryError.assertionError(let assertionDescription): - self.makeRequest(result: .unexpectedError(reason: "assertionError: \(assertionDescription)")) - case ContactDiscoveryError.parseError(description: let parseErrorDescription): - self.makeRequest(result: .unexpectedError(reason: "parseError: \(parseErrorDescription)")) - default: - let nsError = error as NSError - let reason = "unexpectedError code:\(nsError.code)" - self.makeRequest(result: .unexpectedError(reason: reason)) - } - - return - } - - if cdsOperation.registeredRecipientIds == legacyRegisteredRecipientIds { - self.makeRequest(result: .ok) - return - } else { - self.makeRequest(result: .mismatch) - return - } - } - - func makeRequest(result: FeedbackResult) { - let reason: String? - switch result { - case .ok: - reason = nil - case .mismatch: - reason = nil - case .attestationError(let attestationErrorReason): - reason = attestationErrorReason - case .unexpectedError(let unexpectedErrorReason): - reason = unexpectedErrorReason - } - let request = OWSRequestFactory.cdsFeedbackRequest(status: result.statusPath, reason: reason) - self.networkManager.makeRequest(request, - success: { _, _ in self.reportSuccess() }, - failure: { _, error in self.reportError(error) }) - } -} - -extension Array { -// func chunked(by chunkSize: Int) -> [[Element]] { -// return stride(from: 0, to: self.count, by: chunkSize).map { -// Array(self[$0.. -#import - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification; - -@class ImageCache; -@class OWSPrimaryStorage; -@class SignalAccount; -@class UIFont; - -/** - * Get latest Signal contacts, and be notified when they change. - */ -@interface OWSContactsManager : NSObject - -#pragma mark - Setup - -- (instancetype)init NS_UNAVAILABLE; - -- (id)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage; - -#pragma mark - Accessors - -@property (nonnull, readonly) ImageCache *avatarCache; - -@property (atomic, readonly) NSArray *allContacts; - -@property (atomic, readonly) NSDictionary *allContactsMap; - -// order of the signalAccounts array respects the systems contact sorting preference -@property (atomic, readonly) NSArray *signalAccounts; - -// This will return an instance of SignalAccount for _known_ signal accounts. -- (nullable SignalAccount *)fetchSignalAccountForRecipientId:(NSString *)recipientId; -// This will always return an instance of SignalAccount. -- (SignalAccount *)fetchOrBuildSignalAccountForRecipientId:(NSString *)recipientId; -- (BOOL)hasSignalAccountForRecipientId:(NSString *)recipientId; - -#pragma mark - System Contact Fetching - -// Must call `requestSystemContactsOnce` before accessing this method -@property (nonatomic, readonly) BOOL isSystemContactsAuthorized; -@property (nonatomic, readonly) BOOL isSystemContactsDenied; -@property (nonatomic, readonly) BOOL systemContactsHaveBeenRequestedAtLeastOnce; - -@property (nonatomic, readonly) BOOL supportsContactEditing; - -@property (atomic, readonly) BOOL isSetup; - -// Request systems contacts and start syncing changes. The user will see an alert -// if they haven't previously. -- (void)requestSystemContactsOnce; -- (void)requestSystemContactsOnceWithCompletion:(void (^_Nullable)(NSError *_Nullable error))completion; - -// Ensure's the app has the latest contacts, but won't prompt the user for contact -// access if they haven't granted it. -- (void)fetchSystemContactsOnceIfAlreadyAuthorized; - -// This variant will fetch system contacts if contact access has already been granted, -// but not prompt for contact access. Also, it will always notify delegates, even if -// contacts haven't changed, and will clear out any stale cached SignalAccounts -- (void)userRequestedSystemContactsRefreshWithCompletion:(void (^)(NSError *_Nullable error))completionHandler; - -#pragma mark - Util - -- (BOOL)isSystemContact:(NSString *)recipientId; -- (BOOL)isSystemContactWithSignalAccount:(NSString *)recipientId; -- (BOOL)hasNameInSystemContactsForRecipientId:(NSString *)recipientId; -- (NSString *)displayNameForSignalAccount:(SignalAccount *)signalAccount; - -/** - * Used for sorting, respects system contacts name sort order preference. - */ -- (NSString *)comparableNameForSignalAccount:(SignalAccount *)signalAccount; - -// Generally we prefer the formattedProfileName over the raw profileName so as to -// distinguish a profile name apart from a name pulled from the system's contacts. -// This helps clarify when the remote person chooses a potentially confusing profile name. -- (nullable NSString *)formattedProfileNameForRecipientId:(NSString *)recipientId; -- (nullable NSString *)profileNameForRecipientId:(NSString *)recipientId; -- (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId; -- (NSString *)stringForConversationTitleWithPhoneIdentifier:(NSString *)recipientId; - -- (nullable UIImage *)systemContactImageForPhoneIdentifier:(nullable NSString *)identifier; -- (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier; -- (nullable NSData *)profileImageDataForPhoneIdentifier:(nullable NSString *)identifier; - -- (nullable UIImage *)imageForPhoneIdentifier:(nullable NSString *)identifier; -- (NSAttributedString *)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *)font; -- (NSAttributedString *)formattedFullNameForRecipientId:(NSString *)recipientId font:(UIFont *)font; -- (NSString *)contactOrProfileNameForPhoneIdentifier:(NSString *)recipientId; -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId; -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId - primaryFont:(UIFont *)primaryFont - secondaryFont:(UIFont *)secondaryFont; -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId - primaryAttributes:(NSDictionary *)primaryAttributes - secondaryAttributes:(NSDictionary *)secondaryAttributes; -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContactsManager.m b/SignalUtilitiesKit/OWSContactsManager.m deleted file mode 100644 index e7c0024f9..000000000 --- a/SignalUtilitiesKit/OWSContactsManager.m +++ /dev/null @@ -1,1133 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSContactsManager.h" -#import "Environment.h" -#import "NSAttributedString+OWS.h" -#import "OWSFormat.h" -#import "OWSProfileManager.h" -#import "OWSUserProfile.h" -#import "ViewControllerUtils.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -@import Contacts; - -NS_ASSUME_NONNULL_BEGIN - -NSString *const OWSContactsManagerSignalAccountsDidChangeNotification - = @"OWSContactsManagerSignalAccountsDidChangeNotification"; - -NSString *const OWSContactsManagerCollection = @"OWSContactsManagerCollection"; -NSString *const OWSContactsManagerKeyLastKnownContactPhoneNumbers - = @"OWSContactsManagerKeyLastKnownContactPhoneNumbers"; -NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsManagerKeyNextFullIntersectionDate2"; - -@interface OWSContactsManager () - -@property (nonatomic) BOOL isContactsUpdateInFlight; -// This reflects the contents of the device phone book and includes -// contacts that do not correspond to any signal account. -@property (atomic) NSArray *allContacts; -@property (atomic) NSDictionary *allContactsMap; -@property (atomic) NSArray *signalAccounts; -@property (atomic) NSDictionary *signalAccountMap; -@property (nonatomic, readonly) SystemContactsFetcher *systemContactsFetcher; -@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection; -@property (nonatomic, readonly) YapDatabaseConnection *dbWriteConnection; -@property (nonatomic, readonly) NSCache *cnContactCache; -@property (nonatomic, readonly) NSCache *cnContactAvatarCache; -@property (atomic) BOOL isSetup; - -@end - -#pragma mark - - -@implementation OWSContactsManager - -- (id)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - self = [super init]; - if (!self) { - return self; - } - - // TODO: We need to configure the limits of this cache. - _avatarCache = [ImageCache new]; - - _dbReadConnection = primaryStorage.newDatabaseConnection; - _dbWriteConnection = primaryStorage.newDatabaseConnection; - - _allContacts = @[]; - _allContactsMap = @{}; - _signalAccountMap = @{}; - _signalAccounts = @[]; - _systemContactsFetcher = [SystemContactsFetcher new]; - _systemContactsFetcher.delegate = self; - _cnContactCache = [NSCache new]; - _cnContactCache.countLimit = 50; - _cnContactAvatarCache = [NSCache new]; - _cnContactAvatarCache.countLimit = 25; - - OWSSingletonAssert(); - - [AppReadiness runNowOrWhenAppWillBecomeReady:^{ - [self setup]; - - [self startObserving]; - }]; - - return self; -} - -- (void)setup { - __block NSMutableArray *signalAccounts; - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - NSUInteger signalAccountCount = [SignalAccount numberOfKeysInCollectionWithTransaction:transaction]; - OWSLogInfo(@"loading %lu signal accounts from cache.", (unsigned long)signalAccountCount); - - signalAccounts = [[NSMutableArray alloc] initWithCapacity:signalAccountCount]; - - [SignalAccount enumerateCollectionObjectsWithTransaction:transaction usingBlock:^(SignalAccount *signalAccount, BOOL * _Nonnull stop) { - [signalAccounts addObject:signalAccount]; - }]; - }]; - [signalAccounts sortUsingComparator:self.signalAccountComparator]; - - [self updateSignalAccounts:signalAccounts]; -} - -- (dispatch_queue_t)serialQueue -{ - static dispatch_queue_t _serialQueue; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _serialQueue = dispatch_queue_create("org.whispersystems.contacts.buildSignalAccount", DISPATCH_QUEUE_SERIAL); - }); - - return _serialQueue; -} - -#pragma mark - System Contact Fetching - -// Request contacts access if you haven't asked recently. -- (void)requestSystemContactsOnce -{ - [self requestSystemContactsOnceWithCompletion:nil]; -} - -- (void)requestSystemContactsOnceWithCompletion:(void (^_Nullable)(NSError *_Nullable error))completion -{ - [self.systemContactsFetcher requestOnceWithCompletion:completion]; -} - -- (void)fetchSystemContactsOnceIfAlreadyAuthorized -{ - [self.systemContactsFetcher fetchOnceIfAlreadyAuthorized]; -} - -- (void)userRequestedSystemContactsRefreshWithCompletion:(void (^)(NSError *_Nullable error))completionHandler -{ - [self.systemContactsFetcher userRequestedRefreshWithCompletion:completionHandler]; -} - -- (BOOL)isSystemContactsAuthorized -{ - return self.systemContactsFetcher.isAuthorized; -} - -- (BOOL)isSystemContactsDenied -{ - return self.systemContactsFetcher.isDenied; -} - -- (BOOL)systemContactsHaveBeenRequestedAtLeastOnce -{ - return self.systemContactsFetcher.systemContactsHaveBeenRequestedAtLeastOnce; -} - -- (BOOL)supportsContactEditing -{ - return self.systemContactsFetcher.supportsContactEditing; -} - -#pragma mark - CNContacts - -- (nullable CNContact *)cnContactWithId:(nullable NSString *)contactId -{ - OWSAssertDebug(self.cnContactCache); - - if (!contactId) { - return nil; - } - - CNContact *_Nullable cnContact; - @synchronized(self.cnContactCache) { - cnContact = [self.cnContactCache objectForKey:contactId]; - if (!cnContact) { - cnContact = [self.systemContactsFetcher fetchCNContactWithContactId:contactId]; - if (cnContact) { - [self.cnContactCache setObject:cnContact forKey:contactId]; - } - } - } - - return cnContact; -} - -- (nullable NSData *)avatarDataForCNContactId:(nullable NSString *)contactId -{ - // Don't bother to cache avatar data. - CNContact *_Nullable cnContact = [self cnContactWithId:contactId]; - return [Contact avatarDataForCNContact:cnContact]; -} - -- (nullable UIImage *)avatarImageForCNContactId:(nullable NSString *)contactId -{ - OWSAssertDebug(self.cnContactAvatarCache); - - if (!contactId) { - return nil; - } - - UIImage *_Nullable avatarImage; - @synchronized(self.cnContactAvatarCache) { - avatarImage = [self.cnContactAvatarCache objectForKey:contactId]; - if (!avatarImage) { - NSData *_Nullable avatarData = [self avatarDataForCNContactId:contactId]; - if (avatarData && [avatarData ows_isValidImage]) { - avatarImage = [UIImage imageWithData:avatarData]; - } - if (avatarImage) { - [self.cnContactAvatarCache setObject:avatarImage forKey:contactId]; - } - } - } - - return avatarImage; -} - -#pragma mark - SystemContactsFetcherDelegate - -- (void)systemContactsFetcher:(SystemContactsFetcher *)systemsContactsFetcher - updatedContacts:(NSArray *)contacts - isUserRequested:(BOOL)isUserRequested -{ - BOOL shouldClearStaleCache = YES; - [self updateWithContacts:contacts isUserRequested:isUserRequested shouldClearStaleCache:shouldClearStaleCache]; -} - -- (void)systemContactsFetcher:(SystemContactsFetcher *)systemContactsFetcher - hasAuthorizationStatus:(enum ContactStoreAuthorizationStatus)authorizationStatus -{ - if (authorizationStatus == ContactStoreAuthorizationStatusRestricted - || authorizationStatus == ContactStoreAuthorizationStatusDenied) { - // Clear the contacts cache if access to the system contacts is revoked. - [self updateWithContacts:@[] isUserRequested:NO shouldClearStaleCache:YES]; - } -} - -#pragma mark - Intersection - -- (NSSet *)recipientIdsForIntersectionWithContacts:(NSArray *)contacts -{ - OWSAssertDebug(contacts); - - NSMutableSet *recipientIds = [NSMutableSet set]; - - for (Contact *contact in contacts) { - for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { - [recipientIds addObject:phoneNumber.toE164]; - } - } - - return recipientIds; -} - -- (void)intersectContacts:(NSArray *)contacts - isUserRequested:(BOOL)isUserRequested - completion:(void (^)(NSError *_Nullable error))completion -{ - OWSAssertDebug(contacts); - OWSAssertDebug(completion); - - dispatch_async(self.serialQueue, ^{ - __block BOOL isFullIntersection = YES; - __block NSSet *allContactRecipientIds; - __block NSSet *recipientIdsForIntersection; - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - // Contact updates initiated by the user should always do a full intersection. - if (!isUserRequested) { - NSDate *_Nullable nextFullIntersectionDate = - [transaction dateForKey:OWSContactsManagerKeyNextFullIntersectionDate - inCollection:OWSContactsManagerCollection]; - if (nextFullIntersectionDate && [nextFullIntersectionDate isAfterNow]) { - isFullIntersection = NO; - } - } - - allContactRecipientIds = [self recipientIdsForIntersectionWithContacts:contacts]; - recipientIdsForIntersection = allContactRecipientIds; - - if (!isFullIntersection) { - // Do a "delta" intersection instead of a "full" intersection: - // only intersect new contacts which were not in the last successful - // "full" intersection. - NSSet *_Nullable lastKnownContactPhoneNumbers = - [transaction objectForKey:OWSContactsManagerKeyLastKnownContactPhoneNumbers - inCollection:OWSContactsManagerCollection]; - if (lastKnownContactPhoneNumbers) { - // Do a "delta" sync which only intersects recipient ids not included - // in the last full intersection. - NSMutableSet *newRecipientIds = [allContactRecipientIds mutableCopy]; - [newRecipientIds minusSet:lastKnownContactPhoneNumbers]; - recipientIdsForIntersection = newRecipientIds; - } else { - // Without a list of "last known" contact phone numbers, we'll have to do a full intersection. - isFullIntersection = YES; - } - } - }]; - OWSAssertDebug(recipientIdsForIntersection); - - if (recipientIdsForIntersection.count < 1) { - OWSLogInfo(@"Skipping intersection; no contacts to intersect."); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - completion(nil); - }); - return; - } else if (isFullIntersection) { - OWSLogInfo(@"Doing full intersection with %zu contacts.", recipientIdsForIntersection.count); - } else { - OWSLogInfo(@"Doing delta intersection with %zu contacts.", recipientIdsForIntersection.count); - } - - [self intersectContacts:recipientIdsForIntersection - retryDelaySeconds:1.0 - success:^(NSSet *registeredRecipients) { - [self markIntersectionAsComplete:allContactRecipientIds isFullIntersection:isFullIntersection]; - - completion(nil); - } - failure:^(NSError *error) { - completion(error); - }]; - }); -} - -- (void)markIntersectionAsComplete:(NSSet *)recipientIdsForIntersection - isFullIntersection:(BOOL)isFullIntersection -{ - OWSAssertDebug(recipientIdsForIntersection.count > 0); - - dispatch_async(self.serialQueue, ^{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction setObject:recipientIdsForIntersection - forKey:OWSContactsManagerKeyLastKnownContactPhoneNumbers - inCollection:OWSContactsManagerCollection]; - - if (isFullIntersection) { - // Don't do a full intersection more often than once every 6 hours. - const NSTimeInterval kMinFullIntersectionInterval = 6 * kHourInterval; - NSDate *nextFullIntersectionDate = [NSDate - dateWithTimeIntervalSince1970:[NSDate new].timeIntervalSince1970 + kMinFullIntersectionInterval]; - [transaction setDate:nextFullIntersectionDate - forKey:OWSContactsManagerKeyNextFullIntersectionDate - inCollection:OWSContactsManagerCollection]; - } - }]; - }); -} - -- (void)intersectContacts:(NSSet *)recipientIds - retryDelaySeconds:(double)retryDelaySeconds - success:(void (^)(NSSet *))successParameter - failure:(void (^)(NSError *))failureParameter -{ - OWSAssertDebug(recipientIds.count > 0); - OWSAssertDebug(retryDelaySeconds > 0); - OWSAssertDebug(successParameter); - OWSAssertDebug(failureParameter); - - void (^success)(NSArray *) = ^(NSArray *registeredRecipientIds) { - OWSLogInfo(@"Successfully intersected contacts."); - successParameter([NSSet setWithArray:registeredRecipientIds]); - }; - void (^failure)(NSError *) = ^(NSError *error) { - if ([error.domain isEqualToString:OWSSignalServiceKitErrorDomain] - && error.code == OWSErrorCodeContactsUpdaterRateLimit) { - OWSLogError(@"Contact intersection hit rate limit with error: %@", error); - failureParameter(error); - return; - } - - OWSLogWarn(@"Failed to intersect contacts with error: %@. Rescheduling", error); - - // Retry with exponential backoff. - // - // TODO: Abort if another contact intersection succeeds in the meantime. - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, (int64_t)(retryDelaySeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [self intersectContacts:recipientIds - retryDelaySeconds:retryDelaySeconds * 2.0 - success:successParameter - failure:failureParameter]; - }); - }; - [[ContactsUpdater sharedUpdater] lookupIdentifiers:recipientIds.allObjects success:success failure:failure]; -} - -- (void)startObserving -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(otherUsersProfileWillChange:) - name:kNSNotificationName_OtherUsersProfileWillChange - object:nil]; -} - -- (void)otherUsersProfileWillChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - NSString *recipientId = notification.userInfo[kNSNotificationKey_ProfileRecipientId]; - OWSAssertDebug(recipientId.length > 0); - - [self.avatarCache removeAllImagesForKey:recipientId]; - }]; -} - -- (void)updateWithContacts:(NSArray *)contacts - isUserRequested:(BOOL)isUserRequested - shouldClearStaleCache:(BOOL)shouldClearStaleCache -{ - dispatch_async(self.serialQueue, ^{ - NSMutableDictionary *allContactsMap = [NSMutableDictionary new]; - for (Contact *contact in contacts) { - for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { - NSString *phoneNumberE164 = phoneNumber.toE164; - if (phoneNumberE164.length > 0) { - allContactsMap[phoneNumberE164] = contact; - } - } - } - - dispatch_async(dispatch_get_main_queue(), ^{ - self.allContacts = contacts; - self.allContactsMap = [allContactsMap copy]; - [self.cnContactCache removeAllObjects]; - [self.cnContactAvatarCache removeAllObjects]; - - [self.avatarCache removeAllImages]; - - [self intersectContacts:contacts - isUserRequested:isUserRequested - completion:^(NSError *_Nullable error) { - // TODO: Should we do this on error? - [self buildSignalAccountsAndClearStaleCache:shouldClearStaleCache]; - }]; - }); - }); -} - -- (void)buildSignalAccountsAndClearStaleCache:(BOOL)shouldClearStaleCache -{ - dispatch_async(self.serialQueue, ^{ - NSMutableArray *signalAccounts = [NSMutableArray new]; - NSArray *contacts = self.allContacts; - - // We use a transaction only to load the SignalRecipients for each contact, - // in order to avoid database deadlock. - NSMutableDictionary *> *contactIdToSignalRecipientsMap = - [NSMutableDictionary new]; - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - for (Contact *contact in contacts) { - NSArray *signalRecipients = [contact signalRecipientsWithTransaction:transaction]; - contactIdToSignalRecipientsMap[contact.uniqueId] = signalRecipients; - } - }]; - - NSMutableSet *seenRecipientIds = [NSMutableSet new]; - for (Contact *contact in contacts) { - NSArray *signalRecipients = contactIdToSignalRecipientsMap[contact.uniqueId]; - for (SignalRecipient *signalRecipient in [signalRecipients sortedArrayUsingSelector:@selector((compare:))]) { - if ([seenRecipientIds containsObject:signalRecipient.recipientId]) { - OWSLogDebug(@"Ignoring duplicate contact: %@, %@", signalRecipient.recipientId, contact.fullName); - continue; - } - [seenRecipientIds addObject:signalRecipient.recipientId]; - - SignalAccount *signalAccount = [[SignalAccount alloc] initWithSignalRecipient:signalRecipient]; - signalAccount.contact = contact; - if (signalRecipients.count > 1) { - signalAccount.hasMultipleAccountContact = YES; - signalAccount.multipleAccountLabelText = - [[self class] accountLabelForContact:contact recipientId:signalRecipient.recipientId]; - } - [signalAccounts addObject:signalAccount]; - } - } - - NSMutableDictionary *oldSignalAccounts = [NSMutableDictionary new]; - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [SignalAccount - enumerateCollectionObjectsWithTransaction:transaction - usingBlock:^(id _Nonnull object, BOOL *_Nonnull stop) { - OWSAssertDebug([object isKindOfClass:[SignalAccount class]]); - SignalAccount *oldSignalAccount = (SignalAccount *)object; - - oldSignalAccounts[oldSignalAccount.uniqueId] = oldSignalAccount; - }]; - }]; - - NSMutableArray *accountsToSave = [NSMutableArray new]; - for (SignalAccount *signalAccount in signalAccounts) { - SignalAccount *_Nullable oldSignalAccount = oldSignalAccounts[signalAccount.uniqueId]; - - // keep track of which accounts are still relevant, so we can clean up orphans - [oldSignalAccounts removeObjectForKey:signalAccount.uniqueId]; - - if (oldSignalAccount == nil) { - // new Signal Account - [accountsToSave addObject:signalAccount]; - continue; - } - - if ([oldSignalAccount isEqual:signalAccount]) { - // Same value, no need to save. - continue; - } - - // value changed, save account - [accountsToSave addObject:signalAccount]; - } - - // Update cached SignalAccounts on disk - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - OWSLogInfo(@"Saving %lu SignalAccounts", (unsigned long)accountsToSave.count); - for (SignalAccount *signalAccount in accountsToSave) { - OWSLogVerbose(@"Saving SignalAccount: %@", signalAccount); - [signalAccount saveWithTransaction:transaction]; - } - - if (shouldClearStaleCache) { - OWSLogInfo(@"Removing %lu old SignalAccounts.", (unsigned long)oldSignalAccounts.count); - for (SignalAccount *signalAccount in oldSignalAccounts.allValues) { - OWSLogVerbose(@"Removing old SignalAccount: %@", signalAccount); - [signalAccount removeWithTransaction:transaction]; - } - } else { - // In theory we want to remove SignalAccounts if the user deletes the corresponding system contact. - // However, as of iOS11.2 CNContactStore occasionally gives us only a subset of the system contacts. - // Because of that, it's not safe to clear orphaned accounts. - // Because we still want to give users a way to clear their stale accounts, if they pull-to-refresh - // their contacts we'll clear the cached ones. - // RADAR: https://bugreport.apple.com/web/?problemID=36082946 - if (oldSignalAccounts.allValues.count > 0) { - OWSLogWarn(@"NOT Removing %lu old SignalAccounts.", (unsigned long)oldSignalAccounts.count); - for (SignalAccount *signalAccount in oldSignalAccounts.allValues) { - OWSLogVerbose(@"Ensuring old SignalAccount is not inadvertently lost: %@", signalAccount); - [signalAccounts addObject:signalAccount]; - } - - // re-sort signal accounts since we've appended some orphans - [signalAccounts sortUsingComparator:self.signalAccountComparator]; - } - } - }]; - - dispatch_async(dispatch_get_main_queue(), ^{ - [self updateSignalAccounts:signalAccounts]; - }); - }); -} - -- (void)updateSignalAccounts:(NSArray *)signalAccounts -{ - OWSAssertIsOnMainThread(); - - if ([signalAccounts isEqual:self.signalAccounts]) { - OWSLogDebug(@"SignalAccounts unchanged."); - return; - } - - NSMutableDictionary *signalAccountMap = [NSMutableDictionary new]; - for (SignalAccount *signalAccount in signalAccounts) { - signalAccountMap[signalAccount.recipientId] = signalAccount; - } - - self.signalAccountMap = [signalAccountMap copy]; - self.signalAccounts = [signalAccounts copy]; - [self.profileManager setContactRecipientIds:signalAccountMap.allKeys]; - - self.isSetup = YES; - - [[NSNotificationCenter defaultCenter] - postNotificationNameAsync:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; -} - -// TODO dependency inject, avoid circular dependencies. -- (OWSProfileManager *)profileManager -{ - return [OWSProfileManager sharedManager]; -} - -- (NSString *_Nullable)cachedContactNameForRecipientId:(NSString *)recipientId -{ - SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId]; - return [self cachedContactNameForRecipientId:recipientId signalAccount:signalAccount]; -} - -- (NSString *_Nullable)cachedContactNameForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - SignalAccount *_Nullable signalAccount = - [self fetchSignalAccountForRecipientId:recipientId transaction:transaction]; - return [self cachedContactNameForRecipientId:recipientId signalAccount:signalAccount]; -} - -- (NSString *_Nullable)cachedContactNameForRecipientId:(NSString *)recipientId - signalAccount:(nullable SignalAccount *)signalAccount -{ - OWSAssertDebug(recipientId.length > 0); - - if (!signalAccount) { - // search system contacts for no-longer-registered signal users, for which there will be no SignalAccount - Contact *_Nullable nonSignalContact = self.allContactsMap[recipientId]; - if (!nonSignalContact) { - return nil; - } - return nonSignalContact.fullName; - } - - NSString *fullName = signalAccount.contactFullName; - if (fullName.length == 0) { - return nil; - } - - NSString *multipleAccountLabelText = signalAccount.multipleAccountLabelText; - if (multipleAccountLabelText.length == 0) { - return fullName; - } - - return [NSString stringWithFormat:@"%@ (%@)", fullName, multipleAccountLabelText]; -} - -- (NSString *_Nullable)cachedFirstNameForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId]; - return signalAccount.contact.firstName.filterStringForDisplay; -} - -- (NSString *_Nullable)cachedLastNameForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId]; - return signalAccount.contact.lastName.filterStringForDisplay; -} - -#pragma mark - View Helpers - -// TODO move into Contact class. -+ (NSString *)accountLabelForContact:(Contact *)contact recipientId:(NSString *)recipientId -{ - OWSAssertDebug(contact); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug([contact.textSecureIdentifiers containsObject:recipientId]); - - if (contact.textSecureIdentifiers.count <= 1) { - return nil; - } - - // 1. Find the phone number type of this account. - NSString *phoneNumberLabel = [contact nameForPhoneNumber:recipientId]; - - // 2. Find all phone numbers for this contact of the same type. - NSMutableArray *phoneNumbersWithTheSameName = [NSMutableArray new]; - for (NSString *textSecureIdentifier in contact.textSecureIdentifiers) { - if ([phoneNumberLabel isEqualToString:[contact nameForPhoneNumber:textSecureIdentifier]]) { - [phoneNumbersWithTheSameName addObject:textSecureIdentifier]; - } - } - - OWSAssertDebug([phoneNumbersWithTheSameName containsObject:recipientId]); - if (phoneNumbersWithTheSameName.count > 1) { - NSUInteger index = - [[phoneNumbersWithTheSameName sortedArrayUsingSelector:@selector((compare:))] indexOfObject:recipientId]; - NSString *indexText = [OWSFormat formatInt:(int)index + 1]; - phoneNumberLabel = - [NSString stringWithFormat:NSLocalizedString(@"PHONE_NUMBER_TYPE_AND_INDEX_NAME_FORMAT", - @"Format for phone number label with an index. Embeds {{Phone number label " - @"(e.g. 'home')}} and {{index, e.g. 2}}."), - phoneNumberLabel, - indexText]; - } - - return phoneNumberLabel.filterStringForDisplay; -} - -- (BOOL)phoneNumber:(PhoneNumber *)phoneNumber1 matchesNumber:(PhoneNumber *)phoneNumber2 -{ - return [phoneNumber1.toE164 isEqualToString:phoneNumber2.toE164]; -} - -#pragma mark - Whisper User Management - -- (BOOL)isSystemContact:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - return self.allContactsMap[recipientId] != nil; -} - -- (BOOL)isSystemContactWithSignalAccount:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - return [self hasSignalAccountForRecipientId:recipientId]; -} - -- (BOOL)hasNameInSystemContactsForRecipientId:(NSString *)recipientId -{ - return [self cachedContactNameForRecipientId:recipientId].length > 0; -} - -- (NSString *)unknownContactName -{ - return NSLocalizedString( - @"UNKNOWN_CONTACT_NAME", @"Displayed if for some reason we can't determine a contacts phone number *or* name"); -} - -- (nullable NSString *)formattedProfileNameForRecipientId:(NSString *)recipientId -{ - NSString *_Nullable profileName = [self.profileManager profileNameForRecipientWithID:recipientId]; - if (profileName.length == 0) { - return nil; - } - - NSString *profileNameFormatString = NSLocalizedString(@"PROFILE_NAME_LABEL_FORMAT", - @"Prepend a simple marker to differentiate the profile name, embeds the contact's {{profile name}}."); - - return profileName; -} - -- (nullable NSString *)profileNameForRecipientId:(NSString *)recipientId -{ - return [self.profileManager profileNameForRecipientWithID:recipientId]; -} - -- (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId -{ - return [self cachedContactNameForRecipientId:recipientId]; -} - -- (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - return [self cachedContactNameForRecipientId:recipientId transaction:transaction]; -} - -- (NSString *)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - if (!recipientId) { - return self.unknownContactName; - } - - NSString *_Nullable displayName = [self nameFromSystemContactsForRecipientId:recipientId]; - - // Fall back to just using their recipientId - if (displayName.length < 1) { - displayName = recipientId; - } - - return displayName; -} - -- (NSString *)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - if (!recipientId) { - return self.unknownContactName; - } - - NSString *_Nullable displayName = [self nameFromSystemContactsForRecipientId:recipientId transaction:transaction]; - - // Fall back to just using their recipientId - if (displayName.length < 1) { - displayName = recipientId; - } - - return displayName; -} - -- (NSString *_Nonnull)displayNameForSignalAccount:(SignalAccount *)signalAccount -{ - OWSAssertDebug(signalAccount); - - return [self displayNameForPhoneIdentifier:signalAccount.recipientId]; -} - -- (NSAttributedString *_Nonnull)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *)font -{ - OWSAssertDebug(signalAccount); - OWSAssertDebug(font); - - return [self formattedFullNameForRecipientId:signalAccount.recipientId font:font]; -} - -- (NSAttributedString *)formattedFullNameForRecipientId:(NSString *)recipientId font:(UIFont *)font -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(font); - - UIFont *boldFont = [UIFont ows_mediumFontWithSize:font.pointSize]; - - NSDictionary *boldFontAttributes = - @{ NSFontAttributeName : boldFont, NSForegroundColorAttributeName : [Theme boldColor] }; - NSDictionary *normalFontAttributes = - @{ NSFontAttributeName : font, NSForegroundColorAttributeName : [Theme primaryColor] }; - NSDictionary *firstNameAttributes - = (self.shouldSortByGivenName ? boldFontAttributes : normalFontAttributes); - NSDictionary *lastNameAttributes - = (self.shouldSortByGivenName ? normalFontAttributes : boldFontAttributes); - - NSString *cachedFirstName = [self cachedFirstNameForRecipientId:recipientId]; - NSString *cachedLastName = [self cachedLastNameForRecipientId:recipientId]; - - NSMutableAttributedString *formattedName = [NSMutableAttributedString new]; - - if (cachedFirstName.length > 0 && cachedLastName.length > 0) { - NSAttributedString *firstName = - [[NSAttributedString alloc] initWithString:cachedFirstName attributes:firstNameAttributes]; - NSAttributedString *lastName = - [[NSAttributedString alloc] initWithString:cachedLastName attributes:lastNameAttributes]; - - NSString *_Nullable cnContactId = self.allContactsMap[recipientId].cnContactId; - CNContact *_Nullable cnContact = [self cnContactWithId:cnContactId]; - if (!cnContact) { - // If we don't have a CNContact for this recipient id, make one. - // Presumably [CNContactFormatter nameOrderForContact:] tries - // to localizes its result based on the languages/scripts used - // in the contact's fields. - CNMutableContact *formatContact = [CNMutableContact new]; - formatContact.givenName = firstName.string; - formatContact.familyName = lastName.string; - cnContact = formatContact; - } - CNContactDisplayNameOrder nameOrder = [CNContactFormatter nameOrderForContact:cnContact]; - NSAttributedString *_Nullable leftName, *_Nullable rightName; - if (nameOrder == CNContactDisplayNameOrderGivenNameFirst) { - leftName = firstName; - rightName = lastName; - } else { - leftName = lastName; - rightName = firstName; - } - - [formattedName appendAttributedString:leftName]; - [formattedName - appendAttributedString:[[NSAttributedString alloc] initWithString:@" " attributes:normalFontAttributes]]; - [formattedName appendAttributedString:rightName]; - } else if (cachedFirstName.length > 0) { - [formattedName appendAttributedString:[[NSAttributedString alloc] initWithString:cachedFirstName - attributes:firstNameAttributes]]; - } else if (cachedLastName.length > 0) { - [formattedName appendAttributedString:[[NSAttributedString alloc] initWithString:cachedLastName - attributes:lastNameAttributes]]; - } else { - // Else, fall back to using just their recipientId - NSString *phoneString = - [PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:recipientId]; - return [[NSAttributedString alloc] initWithString:phoneString attributes:normalFontAttributes]; - } - - // Append unique label for contacts with multiple Signal accounts - SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId]; - if (signalAccount && signalAccount.multipleAccountLabelText) { - OWSAssertDebug(signalAccount.multipleAccountLabelText.length > 0); - - [formattedName - appendAttributedString:[[NSAttributedString alloc] initWithString:@" (" attributes:normalFontAttributes]]; - [formattedName - appendAttributedString:[[NSAttributedString alloc] initWithString:signalAccount.multipleAccountLabelText - attributes:normalFontAttributes]]; - [formattedName - appendAttributedString:[[NSAttributedString alloc] initWithString:@")" attributes:normalFontAttributes]]; - } - - return formattedName; -} - -- (NSString *)contactOrProfileNameForPhoneIdentifier:(NSString *)recipientId -{ - // Prefer a saved name from system contacts, if available - NSString *_Nullable savedContactName = [self cachedContactNameForRecipientId:recipientId]; - if (savedContactName.length > 0) { - return savedContactName; - } - - NSString *_Nullable profileName = [self.profileManager profileNameForRecipientWithID:recipientId]; - if (profileName.length > 0) { - NSString *numberAndProfileNameFormat = NSLocalizedString(@"PROFILE_NAME_AND_PHONE_NUMBER_LABEL_FORMAT", - @"Label text combining the phone number and profile name separated by a simple demarcation character. " - @"Phone number should be most prominent. '%1$@' is replaced with {{phone number}} and '%2$@' is replaced " - @"with {{profile name}}"); - - NSString *numberAndProfileName = - [NSString stringWithFormat:numberAndProfileNameFormat, recipientId, profileName]; - return numberAndProfileName; - } - - // else fall back to recipient id - return recipientId; -} - -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId -{ - return [[NSAttributedString alloc] initWithString:[self contactOrProfileNameForPhoneIdentifier:recipientId]]; -} - -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId - primaryFont:(UIFont *)primaryFont - secondaryFont:(UIFont *)secondaryFont -{ - OWSAssertDebug(primaryFont); - OWSAssertDebug(secondaryFont); - - return [self attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId - primaryAttributes:@{ - NSFontAttributeName : primaryFont, - } - secondaryAttributes:@{ - NSFontAttributeName : secondaryFont, - }]; -} - -- (NSAttributedString *)attributedContactOrProfileNameForPhoneIdentifier:(NSString *)recipientId - primaryAttributes:(NSDictionary *)primaryAttributes - secondaryAttributes:(NSDictionary *)secondaryAttributes -{ - OWSAssertDebug(primaryAttributes.count > 0); - OWSAssertDebug(secondaryAttributes.count > 0); - - // Prefer a saved name from system contacts, if available - NSString *_Nullable savedContactName = [self cachedContactNameForRecipientId:recipientId]; - if (savedContactName.length > 0) { - return [[NSAttributedString alloc] initWithString:savedContactName attributes:primaryAttributes]; - } - - NSString *_Nullable profileName = [self.profileManager profileNameForRecipientWithID:recipientId]; - if (profileName.length > 0) { - return [[NSAttributedString alloc] initWithString:profileName]; - // Loki: Original code - // ======== -// NSAttributedString *result = -// [[NSAttributedString alloc] initWithString:recipientId attributes:primaryAttributes]; -// result = [result rtlSafeAppend:[[NSAttributedString alloc] initWithString:@" "]]; -// result = [result rtlSafeAppend:[[NSAttributedString alloc] initWithString:@"~" attributes:secondaryAttributes]]; -// result = [result -// rtlSafeAppend:[[NSAttributedString alloc] initWithString:profileName attributes:secondaryAttributes]]; -// return [result copy]; - // ======== - } - - // else fall back to recipient id - return [[NSAttributedString alloc] initWithString:recipientId attributes:primaryAttributes]; -} - -// TODO refactor attributed counterparts to use this as a helper method? -- (NSString *)stringForConversationTitleWithPhoneIdentifier:(NSString *)recipientId -{ - // Prefer a saved name from system contacts, if available - NSString *_Nullable savedContactName = [self cachedContactNameForRecipientId:recipientId]; - if (savedContactName.length > 0) { - return savedContactName; - } - - NSString *formattedPhoneNumber = - [PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:recipientId]; - NSString *_Nullable profileName = [self.profileManager profileNameForRecipientWithID:recipientId]; - if (profileName.length > 0) { - NSString *numberAndProfileNameFormat = NSLocalizedString(@"PROFILE_NAME_AND_PHONE_NUMBER_LABEL_FORMAT", - @"Label text combining the phone number and profile name separated by a simple demarcation character. " - @"Phone number should be most prominent. '%1$@' is replaced with {{phone number}} and '%2$@' is replaced " - @"with {{profile name}}"); - - NSString *numberAndProfileName = - [NSString stringWithFormat:numberAndProfileNameFormat, formattedPhoneNumber, profileName]; - - return numberAndProfileName; - } - - // else fall back phone number - return formattedPhoneNumber; -} - -- (nullable SignalAccount *)fetchSignalAccountForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - __block SignalAccount *signalAccount = self.signalAccountMap[recipientId]; - - // If contact intersection hasn't completed, it might exist on disk - // even if it doesn't exist in memory yet. - if (!signalAccount) { - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId transaction:transaction]; - }]; - } - - return signalAccount; -} - -- (nullable SignalAccount *)fetchSignalAccountForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - __block SignalAccount *signalAccount = self.signalAccountMap[recipientId]; - - // If contact intersection hasn't completed, it might exist on disk - // even if it doesn't exist in memory yet. - if (!signalAccount) { - signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId transaction:transaction]; - } - - return signalAccount; -} - -- (SignalAccount *)fetchOrBuildSignalAccountForRecipientId:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId]; - return (signalAccount ?: [[SignalAccount alloc] initWithRecipientId:recipientId]); -} - -- (BOOL)hasSignalAccountForRecipientId:(NSString *)recipientId -{ - return [self fetchSignalAccountForRecipientId:recipientId] != nil; -} - -- (UIImage *_Nullable)systemContactImageForPhoneIdentifier:(NSString *_Nullable)identifier -{ - if (identifier.length == 0) { - return nil; - } - - Contact *contact = self.allContactsMap[identifier]; - if (!contact) { - // If we haven't loaded system contacts yet, we may have a cached - // copy in the db - contact = [self fetchSignalAccountForRecipientId:identifier].contact; - } - - return [self avatarImageForCNContactId:contact.cnContactId]; -} - -- (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier -{ - if (identifier.length == 0) { - return nil; - } - - return [self.profileManager profileAvatarForRecipientId:identifier]; -} - -- (nullable NSData *)profileImageDataForPhoneIdentifier:(nullable NSString *)identifier -{ - if (identifier.length == 0) { - return nil; - } - - return [self.profileManager profileAvatarDataForRecipientId:identifier]; -} - -- (UIImage *_Nullable)imageForPhoneIdentifier:(NSString *_Nullable)identifier -{ - if (identifier.length == 0) { - return nil; - } - - // Prefer the contact image from the local address book if available - UIImage *_Nullable image = [self systemContactImageForPhoneIdentifier:identifier]; - - // Else try to use the image from their profile - if (image == nil) { - image = [self profileImageForPhoneIdentifier:identifier]; - } - - return image; -} - -- (NSComparisonResult)compareSignalAccount:(SignalAccount *)left withSignalAccount:(SignalAccount *)right -{ - return self.signalAccountComparator(left, right); -} - -- (NSComparisonResult (^)(SignalAccount *left, SignalAccount *right))signalAccountComparator -{ - return ^NSComparisonResult(SignalAccount *left, SignalAccount *right) { - NSString *leftName = [self comparableNameForSignalAccount:left]; - NSString *rightName = [self comparableNameForSignalAccount:right]; - - NSComparisonResult nameComparison = [leftName caseInsensitiveCompare:rightName]; - if (nameComparison == NSOrderedSame) { - return [left.recipientId compare:right.recipientId]; - } - - return nameComparison; - }; -} - -- (BOOL)shouldSortByGivenName -{ - return [[CNContactsUserDefaults sharedDefaults] sortOrder] == CNContactSortOrderGivenName; -} - -- (NSString *)comparableNameForSignalAccount:(SignalAccount *)signalAccount -{ - NSString *_Nullable name; - if (signalAccount.contact) { - if (self.shouldSortByGivenName) { - name = signalAccount.contact.comparableNameFirstLast; - } else { - name = signalAccount.contact.comparableNameLastFirst; - } - } - - if (name.length < 1) { - name = signalAccount.recipientId; - } - - return name; -} - -NS_ASSUME_NONNULL_END - -@end diff --git a/SignalUtilitiesKit/OWSContactsOutputStream.m b/SignalUtilitiesKit/OWSContactsOutputStream.m index 722641472..9162b76e0 100644 --- a/SignalUtilitiesKit/OWSContactsOutputStream.m +++ b/SignalUtilitiesKit/OWSContactsOutputStream.m @@ -3,7 +3,7 @@ // #import "OWSContactsOutputStream.h" -#import "Contact.h" + #import "ContactsManagerProtocol.h" #import "MIMETypeUtil.h" #import "NSData+keyVersionByte.h" @@ -47,27 +47,6 @@ disappearingMessagesConfiguration:(nullable OWSDisappearingMessagesConfiguration contactBuilder.verified = verified; } - /* - UIImage *_Nullable rawAvatar = [contactsManager avatarImageForCNContactId:signalAccount.contact.cnContactId]; - NSData *_Nullable avatarPng; - if (rawAvatar) { - avatarPng = UIImagePNGRepresentation(rawAvatar); - if (avatarPng) { - SSKProtoContactDetailsAvatarBuilder *avatarBuilder = [SSKProtoContactDetailsAvatar builder]; - [avatarBuilder setContentType:OWSMimeTypeImagePng]; - [avatarBuilder setLength:(uint32_t)avatarPng.length]; - - NSError *error; - SSKProtoContactDetailsAvatar *_Nullable avatar = [avatarBuilder buildAndReturnError:&error]; - if (error || !avatar) { - OWSLogError(@"could not build protobuf: %@", error); - return; - } - [contactBuilder setAvatar:avatar]; - } - } - */ - if (profileKeyData) { OWSAssertDebug(profileKeyData.length == kAES256_KeyByteLength); [contactBuilder setProfileKey:profileKeyData]; @@ -96,12 +75,6 @@ disappearingMessagesConfiguration:(nullable OWSDisappearingMessagesConfiguration uint32_t contactDataLength = (uint32_t)contactData.length; [self writeUInt32:contactDataLength]; [self writeData:contactData]; - - /* - if (avatarPng) { - [self writeData:avatarPng]; - } - */ } @end diff --git a/SignalUtilitiesKit/OWSConversationColor.h b/SignalUtilitiesKit/OWSConversationColor.h deleted file mode 100644 index 0af19bf4b..000000000 --- a/SignalUtilitiesKit/OWSConversationColor.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSConversationColor : NSObject - -@property (nonatomic, readonly) ConversationColorName name; -@property (nonatomic, readonly) UIColor *primaryColor; -@property (nonatomic, readonly) UIColor *shadeColor; -@property (nonatomic, readonly) UIColor *tintColor; - -@property (nonatomic, readonly) UIColor *themeColor; - -+ (OWSConversationColor *)conversationColorWithName:(ConversationColorName)name - primaryColor:(UIColor *)primaryColor - shadeColor:(UIColor *)shadeColor - tintColor:(UIColor *)tintColor; -#pragma mark - Conversation Colors - -@property (class, readonly, nonatomic) UIColor *ows_crimsonColor; -@property (class, readonly, nonatomic) UIColor *ows_vermilionColor; -@property (class, readonly, nonatomic) UIColor *ows_burlapColor; -@property (class, readonly, nonatomic) UIColor *ows_forestColor; -@property (class, readonly, nonatomic) UIColor *ows_wintergreenColor; -@property (class, readonly, nonatomic) UIColor *ows_tealColor; -@property (class, readonly, nonatomic) UIColor *ows_blueColor; -@property (class, readonly, nonatomic) UIColor *ows_indigoColor; -@property (class, readonly, nonatomic) UIColor *ows_violetColor; -@property (class, readonly, nonatomic) UIColor *ows_plumColor; -@property (class, readonly, nonatomic) UIColor *ows_taupeColor; -@property (class, readonly, nonatomic) UIColor *ows_steelColor; - -#pragma mark - Conversation Colors (Tint) - -@property (class, readonly, nonatomic) UIColor *ows_crimsonTintColor; -@property (class, readonly, nonatomic) UIColor *ows_vermilionTintColor; -@property (class, readonly, nonatomic) UIColor *ows_burlapTintColor; -@property (class, readonly, nonatomic) UIColor *ows_forestTintColor; -@property (class, readonly, nonatomic) UIColor *ows_wintergreenTintColor; -@property (class, readonly, nonatomic) UIColor *ows_tealTintColor; -@property (class, readonly, nonatomic) UIColor *ows_blueTintColor; -@property (class, readonly, nonatomic) UIColor *ows_indigoTintColor; -@property (class, readonly, nonatomic) UIColor *ows_violetTintColor; -@property (class, readonly, nonatomic) UIColor *ows_plumTintColor; -@property (class, readonly, nonatomic) UIColor *ows_taupeTintColor; -@property (class, readonly, nonatomic) UIColor *ows_steelTintColor; - -#pragma mark - Conversation Colors (Shade) - -@property (class, readonly, nonatomic) UIColor *ows_crimsonShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_vermilionShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_burlapShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_forestShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_wintergreenShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_tealShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_blueShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_indigoShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_violetShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_plumShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_taupeShadeColor; -@property (class, readonly, nonatomic) UIColor *ows_steelShadeColor; - -#pragma mark - Conversation Colors - -+ (nullable OWSConversationColor *)conversationColorForColorName:(ConversationColorName)colorName - NS_SWIFT_NAME(conversationColor(colorName:)); - -// If the conversation color name is valid, return its colors. -// Otherwise return the "default" conversation colors. -+ (OWSConversationColor *)conversationColorOrDefaultForColorName:(ConversationColorName)conversationColorName - NS_SWIFT_NAME(conversationColorOrDefault(colorName:)); - -@property (class, readonly, nonatomic) NSArray *conversationColorNames; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSConversationColor.m b/SignalUtilitiesKit/OWSConversationColor.m deleted file mode 100644 index f53cff8a5..000000000 --- a/SignalUtilitiesKit/OWSConversationColor.m +++ /dev/null @@ -1,359 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSConversationColor.h" -#import "Theme.h" -#import "UIColor+OWS.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSConversationColor () - -@property (nonatomic) ConversationColorName name; -@property (nonatomic) UIColor *primaryColor; -@property (nonatomic) UIColor *shadeColor; -@property (nonatomic) UIColor *tintColor; - -@end - -#pragma mark - - -@implementation OWSConversationColor - -+ (OWSConversationColor *)conversationColorWithName:(ConversationColorName)name - primaryColor:(UIColor *)primaryColor - shadeColor:(UIColor *)shadeColor - tintColor:(UIColor *)tintColor -{ - OWSConversationColor *instance = [OWSConversationColor new]; - instance.name = name; - instance.primaryColor = primaryColor; - instance.shadeColor = shadeColor; - instance.tintColor = tintColor; - return instance; -} - -#pragma mark - - -- (UIColor *)themeColor -{ - return Theme.isDarkThemeEnabled ? self.shadeColor : self.primaryColor; -} - -- (BOOL)isEqual:(id)other -{ - if (![other isKindOfClass:[OWSConversationColor class]]) { - return NO; - } - - OWSConversationColor *otherColor = (OWSConversationColor *)other; - return [self.name isEqual:otherColor.name]; -} - -#pragma mark - Conversation Color (Primary) - -+ (UIColor *)ows_crimsonColor -{ - return [UIColor colorWithRGBHex:0xCC163D]; -} - -+ (UIColor *)ows_vermilionColor -{ - return [UIColor colorWithRGBHex:0xC73800]; -} - -+ (UIColor *)ows_burlapColor -{ - return [UIColor colorWithRGBHex:0x746C53]; -} - -+ (UIColor *)ows_forestColor -{ - return [UIColor colorWithRGBHex:0x3B7845]; -} - -+ (UIColor *)ows_wintergreenColor -{ - return [UIColor colorWithRGBHex:0x1C8260]; -} - -+ (UIColor *)ows_tealColor -{ - return [UIColor colorWithRGBHex:0x067589]; -} - -+ (UIColor *)ows_blueColor -{ - return [UIColor colorWithRGBHex:0x336BA3]; -} - -+ (UIColor *)ows_indigoColor -{ - return [UIColor colorWithRGBHex:0x5951C8]; -} - -+ (UIColor *)ows_violetColor -{ - return [UIColor colorWithRGBHex:0x862CAF]; -} - -+ (UIColor *)ows_plumColor -{ - return [UIColor colorWithRGBHex:0xA23474]; -} - -+ (UIColor *)ows_taupeColor -{ - return [UIColor colorWithRGBHex:0x895D66]; -} - -+ (UIColor *)ows_steelColor -{ - return [UIColor colorWithRGBHex:0x6B6B78]; -} - -#pragma mark - Conversation Colors (Tint) - -+ (UIColor *)ows_crimsonTintColor -{ - return [UIColor colorWithRGBHex:0xEDA6AE]; -} - -+ (UIColor *)ows_vermilionTintColor -{ - return [UIColor colorWithRGBHex:0xEBA78E]; -} - -+ (UIColor *)ows_burlapTintColor -{ - return [UIColor colorWithRGBHex:0xC4B997]; -} - -+ (UIColor *)ows_forestTintColor -{ - return [UIColor colorWithRGBHex:0x8FCC9A]; -} - -+ (UIColor *)ows_wintergreenTintColor -{ - return [UIColor colorWithRGBHex:0x9BCFBD]; -} - -+ (UIColor *)ows_tealTintColor -{ - return [UIColor colorWithRGBHex:0xA5CAD5]; -} - -+ (UIColor *)ows_blueTintColor -{ - return [UIColor colorWithRGBHex:0xADC8E1]; -} - -+ (UIColor *)ows_indigoTintColor -{ - return [UIColor colorWithRGBHex:0xC2C1E7]; -} - -+ (UIColor *)ows_violetTintColor -{ - return [UIColor colorWithRGBHex:0xCDADDC]; -} - -+ (UIColor *)ows_plumTintColor -{ - return [UIColor colorWithRGBHex:0xDCB2CA]; -} - -+ (UIColor *)ows_taupeTintColor -{ - return [UIColor colorWithRGBHex:0xCFB5BB]; -} - -+ (UIColor *)ows_steelTintColor -{ - return [UIColor colorWithRGBHex:0xBEBEC6]; -} - -#pragma mark - Conversation Colors (Shade) - -+ (UIColor *)ows_crimsonShadeColor -{ - return [UIColor colorWithRGBHex:0x8A0F29]; -} - -+ (UIColor *)ows_vermilionShadeColor -{ - return [UIColor colorWithRGBHex:0x872600]; -} - -+ (UIColor *)ows_burlapShadeColor -{ - return [UIColor colorWithRGBHex:0x58513C]; -} - -+ (UIColor *)ows_forestShadeColor -{ - return [UIColor colorWithRGBHex:0x2B5934]; -} - -+ (UIColor *)ows_wintergreenShadeColor -{ - return [UIColor colorWithRGBHex:0x36544A]; -} - -+ (UIColor *)ows_tealShadeColor -{ - return [UIColor colorWithRGBHex:0x055968]; -} - -+ (UIColor *)ows_blueShadeColor -{ - return [UIColor colorWithRGBHex:0x285480]; -} - -+ (UIColor *)ows_indigoShadeColor -{ - return [UIColor colorWithRGBHex:0x4840A0]; -} - -+ (UIColor *)ows_violetShadeColor -{ - return [UIColor colorWithRGBHex:0x6B248A]; -} - -+ (UIColor *)ows_plumShadeColor -{ - return [UIColor colorWithRGBHex:0x881B5B]; -} - -+ (UIColor *)ows_taupeShadeColor -{ - return [UIColor colorWithRGBHex:0x6A4E54]; -} - -+ (UIColor *)ows_steelShadeColor -{ - return [UIColor colorWithRGBHex:0x5A5A63]; -} - -+ (NSArray *)allConversationColors -{ - static NSArray *allConversationColors; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - // Order here affects the order in the conversation color picker. - allConversationColors = @[ - [OWSConversationColor conversationColorWithName:ConversationColorNameCrimson - primaryColor:self.ows_crimsonColor - shadeColor:self.ows_crimsonShadeColor - tintColor:self.ows_crimsonTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameVermilion - primaryColor:self.ows_vermilionColor - shadeColor:self.ows_vermilionShadeColor - tintColor:self.ows_vermilionTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameBurlap - primaryColor:self.ows_burlapColor - shadeColor:self.ows_burlapShadeColor - tintColor:self.ows_burlapTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameForest - primaryColor:self.ows_forestColor - shadeColor:self.ows_forestShadeColor - tintColor:self.ows_forestTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameWintergreen - primaryColor:self.ows_wintergreenColor - shadeColor:self.ows_wintergreenShadeColor - tintColor:self.ows_wintergreenTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameTeal - primaryColor:self.ows_tealColor - shadeColor:self.ows_tealShadeColor - tintColor:self.ows_tealTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameBlue - primaryColor:self.ows_blueColor - shadeColor:self.ows_blueShadeColor - tintColor:self.ows_blueTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameIndigo - primaryColor:self.ows_indigoColor - shadeColor:self.ows_indigoShadeColor - tintColor:self.ows_indigoTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameViolet - primaryColor:self.ows_violetColor - shadeColor:self.ows_violetShadeColor - tintColor:self.ows_violetTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNamePlum - primaryColor:self.ows_plumColor - shadeColor:self.ows_plumShadeColor - tintColor:self.ows_plumTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameTaupe - primaryColor:self.ows_taupeColor - shadeColor:self.ows_taupeShadeColor - tintColor:self.ows_taupeTintColor], - [OWSConversationColor conversationColorWithName:ConversationColorNameSteel - primaryColor:self.ows_steelColor - shadeColor:self.ows_steelShadeColor - tintColor:self.ows_steelTintColor], - ]; - }); - - return allConversationColors; -} - -+ (NSDictionary *)conversationColorMap -{ - static NSDictionary *colorMap; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSMutableDictionary *mutableColorMap = [NSMutableDictionary new]; - for (OWSConversationColor *conversationColor in self.allConversationColors) { - mutableColorMap[conversationColor.name] = conversationColor; - } - colorMap = [mutableColorMap copy]; - }); - - return colorMap; -} - -+ (NSArray *)conversationColorNames -{ - NSMutableArray *names = [NSMutableArray new]; - for (OWSConversationColor *conversationColor in self.allConversationColors) { - [names addObject:conversationColor.name]; - } -#ifdef DEBUG - NSSet *colorNameSet = [NSSet setWithArray:names]; - // These constants are duplicated in two places. So this canary exists to make sure they stay in sync. - NSSet *threadColorNameSet = [NSSet setWithArray:TSThread.conversationColorNames]; - OWSAssertDebug([colorNameSet isEqual:threadColorNameSet]); -#endif - return [names copy]; -} - -+ (nullable OWSConversationColor *)conversationColorForColorName:(ConversationColorName)conversationColorName -{ - OWSConversationColor *_Nullable result = self.conversationColorMap[conversationColorName]; - - // Any mapping to colorNames should be done in TSThread before this method is called. - OWSAssertDebug(result != nil); - - return result; -} - -+ (OWSConversationColor *)conversationColorOrDefaultForColorName:(ConversationColorName)conversationColorName -{ - OWSConversationColor *_Nullable conversationColor = [self conversationColorForColorName:conversationColorName]; - if (conversationColor) { - return conversationColor; - } - return [self defaultConversationColor]; -} - -+ (OWSConversationColor *)defaultConversationColor -{ - return [self conversationColorForColorName:kConversationColorName_Default]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSCountryMetadata.h b/SignalUtilitiesKit/OWSCountryMetadata.h deleted file mode 100644 index f2ce56d8c..000000000 --- a/SignalUtilitiesKit/OWSCountryMetadata.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSCountryMetadata : NSObject - -@property (nonatomic) NSString *name; -@property (nonatomic) NSString *tld; -@property (nonatomic, nullable) NSString *frontingDomain; -@property (nonatomic) NSString *countryCode; -@property (nonatomic) NSString *localizedCountryName; - -+ (OWSCountryMetadata *)countryMetadataForCountryCode:(NSString *)countryCode; - -+ (NSArray *)allCountryMetadatas; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSCountryMetadata.m b/SignalUtilitiesKit/OWSCountryMetadata.m deleted file mode 100644 index 0c0987457..000000000 --- a/SignalUtilitiesKit/OWSCountryMetadata.m +++ /dev/null @@ -1,379 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSCountryMetadata.h" -#import "OWSCensorshipConfiguration.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSCountryMetadata - -+ (OWSCountryMetadata *)countryMetadataWithName:(NSString *)name - tld:(NSString *)tld - frontingDomain:(nullable NSString *)frontingDomain - countryCode:(NSString *)countryCode -{ - OWSAssertDebug(name.length > 0); - OWSAssertDebug(tld.length > 0); - OWSAssertDebug(countryCode.length > 0); - - OWSCountryMetadata *instance = [OWSCountryMetadata new]; - instance.name = name; - instance.tld = tld; - instance.frontingDomain = frontingDomain; - instance.countryCode = countryCode; - - NSString *localizedCountryName = [[NSLocale currentLocale] displayNameForKey:NSLocaleCountryCode value:countryCode]; - if (localizedCountryName.length < 1) { - localizedCountryName = name; - } - instance.localizedCountryName = localizedCountryName; - - return instance; -} - -+ (OWSCountryMetadata *)countryMetadataForCountryCode:(NSString *)countryCode -{ - OWSAssertDebug(countryCode.length > 0); - - return [self countryCodeToCountryMetadataMap][countryCode]; -} - -+ (NSDictionary *)countryCodeToCountryMetadataMap -{ - static NSDictionary *cachedValue = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSMutableDictionary *map = [NSMutableDictionary new]; - for (OWSCountryMetadata *metadata in [self allCountryMetadatas]) { - map[metadata.countryCode] = metadata; - } - cachedValue = map; - }); - return cachedValue; -} - -+ (NSArray *)allCountryMetadatas -{ - static NSArray *cachedValue = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - cachedValue = @[ - [OWSCountryMetadata countryMetadataWithName:@"Andorra" tld:@".ad" frontingDomain:nil countryCode:@"AD"], - [OWSCountryMetadata countryMetadataWithName:@"United Arab Emirates" - tld:@".ae" - frontingDomain:OWSFrontingHost_GoogleUAE - countryCode:@"AE"], - [OWSCountryMetadata countryMetadataWithName:@"Afghanistan" tld:@".af" frontingDomain:nil countryCode:@"AF"], - [OWSCountryMetadata countryMetadataWithName:@"Antigua and Barbuda" - tld:@".ag" - frontingDomain:nil - countryCode:@"AG"], - [OWSCountryMetadata countryMetadataWithName:@"Anguilla" tld:@".ai" frontingDomain:nil countryCode:@"AI"], - [OWSCountryMetadata countryMetadataWithName:@"Albania" tld:@".al" frontingDomain:nil countryCode:@"AL"], - [OWSCountryMetadata countryMetadataWithName:@"Armenia" tld:@".am" frontingDomain:nil countryCode:@"AM"], - [OWSCountryMetadata countryMetadataWithName:@"Angola" tld:@".ao" frontingDomain:nil countryCode:@"AO"], - [OWSCountryMetadata countryMetadataWithName:@"Argentina" tld:@".ar" frontingDomain:nil countryCode:@"AR"], - [OWSCountryMetadata countryMetadataWithName:@"American Samoa" - tld:@".as" - frontingDomain:nil - countryCode:@"AS"], - [OWSCountryMetadata countryMetadataWithName:@"Austria" tld:@".at" frontingDomain:nil countryCode:@"AT"], - [OWSCountryMetadata countryMetadataWithName:@"Australia" tld:@".au" frontingDomain:nil countryCode:@"AU"], - [OWSCountryMetadata countryMetadataWithName:@"Azerbaijan" tld:@".az" frontingDomain:nil countryCode:@"AZ"], - [OWSCountryMetadata countryMetadataWithName:@"Bosnia and Herzegovina" - tld:@".ba" - frontingDomain:nil - countryCode:@"BA"], - [OWSCountryMetadata countryMetadataWithName:@"Bangladesh" tld:@".bd" frontingDomain:nil countryCode:@"BD"], - [OWSCountryMetadata countryMetadataWithName:@"Belgium" tld:@".be" frontingDomain:nil countryCode:@"BE"], - [OWSCountryMetadata countryMetadataWithName:@"Burkina Faso" - tld:@".bf" - frontingDomain:nil - countryCode:@"BF"], - [OWSCountryMetadata countryMetadataWithName:@"Bulgaria" tld:@".bg" frontingDomain:nil countryCode:@"BG"], - [OWSCountryMetadata countryMetadataWithName:@"Bahrain" tld:@".bh" frontingDomain:nil countryCode:@"BH"], - [OWSCountryMetadata countryMetadataWithName:@"Burundi" tld:@".bi" frontingDomain:nil countryCode:@"BI"], - [OWSCountryMetadata countryMetadataWithName:@"Benin" tld:@".bj" frontingDomain:nil countryCode:@"BJ"], - [OWSCountryMetadata countryMetadataWithName:@"Brunei" tld:@".bn" frontingDomain:nil countryCode:@"BN"], - [OWSCountryMetadata countryMetadataWithName:@"Bolivia" tld:@".bo" frontingDomain:nil countryCode:@"BO"], - [OWSCountryMetadata countryMetadataWithName:@"Brazil" tld:@".br" frontingDomain:nil countryCode:@"BR"], - [OWSCountryMetadata countryMetadataWithName:@"Bahamas" tld:@".bs" frontingDomain:nil countryCode:@"BS"], - [OWSCountryMetadata countryMetadataWithName:@"Bhutan" tld:@".bt" frontingDomain:nil countryCode:@"BT"], - [OWSCountryMetadata countryMetadataWithName:@"Botswana" tld:@".bw" frontingDomain:nil countryCode:@"BW"], - [OWSCountryMetadata countryMetadataWithName:@"Belarus" tld:@".by" frontingDomain:nil countryCode:@"BY"], - [OWSCountryMetadata countryMetadataWithName:@"Belize" tld:@".bz" frontingDomain:nil countryCode:@"BZ"], - [OWSCountryMetadata countryMetadataWithName:@"Canada" tld:@".ca" frontingDomain:nil countryCode:@"CA"], - [OWSCountryMetadata countryMetadataWithName:@"Cambodia" tld:@".kh" frontingDomain:nil countryCode:@"KH"], - [OWSCountryMetadata countryMetadataWithName:@"Cocos (Keeling) Islands" - tld:@".cc" - frontingDomain:nil - countryCode:@"CC"], - [OWSCountryMetadata countryMetadataWithName:@"Democratic Republic of the Congo" - tld:@".cd" - frontingDomain:nil - countryCode:@"CD"], - [OWSCountryMetadata countryMetadataWithName:@"Central African Republic" - tld:@".cf" - frontingDomain:nil - countryCode:@"CF"], - [OWSCountryMetadata countryMetadataWithName:@"Republic of the Congo" - tld:@".cg" - frontingDomain:nil - countryCode:@"CG"], - [OWSCountryMetadata countryMetadataWithName:@"Switzerland" tld:@".ch" frontingDomain:nil countryCode:@"CH"], - [OWSCountryMetadata countryMetadataWithName:@"Ivory Coast" tld:@".ci" frontingDomain:nil countryCode:@"CI"], - [OWSCountryMetadata countryMetadataWithName:@"Cook Islands" - tld:@".ck" - frontingDomain:nil - countryCode:@"CK"], - [OWSCountryMetadata countryMetadataWithName:@"Chile" tld:@".cl" frontingDomain:nil countryCode:@"CL"], - [OWSCountryMetadata countryMetadataWithName:@"Cameroon" tld:@".cm" frontingDomain:nil countryCode:@"CM"], - [OWSCountryMetadata countryMetadataWithName:@"China" tld:@".cn" frontingDomain:nil countryCode:@"CN"], - [OWSCountryMetadata countryMetadataWithName:@"Colombia" tld:@".co" frontingDomain:nil countryCode:@"CO"], - [OWSCountryMetadata countryMetadataWithName:@"Costa Rica" tld:@".cr" frontingDomain:nil countryCode:@"CR"], - [OWSCountryMetadata countryMetadataWithName:@"Cuba" tld:@".cu" frontingDomain:nil countryCode:@"CU"], - [OWSCountryMetadata countryMetadataWithName:@"Cape Verde" tld:@".cv" frontingDomain:nil countryCode:@"CV"], - [OWSCountryMetadata countryMetadataWithName:@"Christmas Island" - tld:@".cx" - frontingDomain:nil - countryCode:@"CX"], - [OWSCountryMetadata countryMetadataWithName:@"Cyprus" tld:@".cy" frontingDomain:nil countryCode:@"CY"], - [OWSCountryMetadata countryMetadataWithName:@"Czech Republic" - tld:@".cz" - frontingDomain:nil - countryCode:@"CZ"], - [OWSCountryMetadata countryMetadataWithName:@"Germany" tld:@".de" frontingDomain:nil countryCode:@"DE"], - [OWSCountryMetadata countryMetadataWithName:@"Djibouti" tld:@".dj" frontingDomain:nil countryCode:@"DJ"], - [OWSCountryMetadata countryMetadataWithName:@"Denmark" tld:@".dk" frontingDomain:nil countryCode:@"DK"], - [OWSCountryMetadata countryMetadataWithName:@"Dominica" tld:@".dm" frontingDomain:nil countryCode:@"DM"], - [OWSCountryMetadata countryMetadataWithName:@"Dominican Republic" - tld:@".do" - frontingDomain:nil - countryCode:@"DO"], - [OWSCountryMetadata countryMetadataWithName:@"Algeria" tld:@".dz" frontingDomain:nil countryCode:@"DZ"], - [OWSCountryMetadata countryMetadataWithName:@"Ecuador" tld:@".ec" frontingDomain:nil countryCode:@"EC"], - [OWSCountryMetadata countryMetadataWithName:@"Estonia" tld:@".ee" frontingDomain:nil countryCode:@"EE"], - [OWSCountryMetadata countryMetadataWithName:@"Egypt" - tld:@".eg" - frontingDomain:OWSFrontingHost_GoogleEgypt - countryCode:@"EG"], - [OWSCountryMetadata countryMetadataWithName:@"Spain" tld:@".es" frontingDomain:nil countryCode:@"ES"], - [OWSCountryMetadata countryMetadataWithName:@"Ethiopia" tld:@".et" frontingDomain:nil countryCode:@"ET"], - [OWSCountryMetadata countryMetadataWithName:@"Finland" tld:@".fi" frontingDomain:nil countryCode:@"FI"], - [OWSCountryMetadata countryMetadataWithName:@"Fiji" tld:@".fj" frontingDomain:nil countryCode:@"FJ"], - [OWSCountryMetadata countryMetadataWithName:@"Federated States of Micronesia" - tld:@".fm" - frontingDomain:nil - countryCode:@"FM"], - [OWSCountryMetadata countryMetadataWithName:@"France" tld:@".fr" frontingDomain:nil countryCode:@"FR"], - [OWSCountryMetadata countryMetadataWithName:@"Gabon" tld:@".ga" frontingDomain:nil countryCode:@"GA"], - [OWSCountryMetadata countryMetadataWithName:@"Georgia" tld:@".ge" frontingDomain:nil countryCode:@"GE"], - [OWSCountryMetadata countryMetadataWithName:@"French Guiana" - tld:@".gf" - frontingDomain:nil - countryCode:@"GF"], - [OWSCountryMetadata countryMetadataWithName:@"Guernsey" tld:@".gg" frontingDomain:nil countryCode:@"GG"], - [OWSCountryMetadata countryMetadataWithName:@"Ghana" tld:@".gh" frontingDomain:nil countryCode:@"GH"], - [OWSCountryMetadata countryMetadataWithName:@"Gibraltar" tld:@".gi" frontingDomain:nil countryCode:@"GI"], - [OWSCountryMetadata countryMetadataWithName:@"Greenland" tld:@".gl" frontingDomain:nil countryCode:@"GL"], - [OWSCountryMetadata countryMetadataWithName:@"Gambia" tld:@".gm" frontingDomain:nil countryCode:@"GM"], - [OWSCountryMetadata countryMetadataWithName:@"Guadeloupe" tld:@".gp" frontingDomain:nil countryCode:@"GP"], - [OWSCountryMetadata countryMetadataWithName:@"Greece" tld:@".gr" frontingDomain:nil countryCode:@"GR"], - [OWSCountryMetadata countryMetadataWithName:@"Guatemala" tld:@".gt" frontingDomain:nil countryCode:@"GT"], - [OWSCountryMetadata countryMetadataWithName:@"Guyana" tld:@".gy" frontingDomain:nil countryCode:@"GY"], - [OWSCountryMetadata countryMetadataWithName:@"Hong Kong" tld:@".hk" frontingDomain:nil countryCode:@"HK"], - [OWSCountryMetadata countryMetadataWithName:@"Honduras" tld:@".hn" frontingDomain:nil countryCode:@"HN"], - [OWSCountryMetadata countryMetadataWithName:@"Croatia" tld:@".hr" frontingDomain:nil countryCode:@"HR"], - [OWSCountryMetadata countryMetadataWithName:@"Haiti" tld:@".ht" frontingDomain:nil countryCode:@"HT"], - [OWSCountryMetadata countryMetadataWithName:@"Hungary" tld:@".hu" frontingDomain:nil countryCode:@"HU"], - [OWSCountryMetadata countryMetadataWithName:@"Indonesia" tld:@".id" frontingDomain:nil countryCode:@"ID"], - [OWSCountryMetadata countryMetadataWithName:@"Iraq" tld:@".iq" frontingDomain:nil countryCode:@"IQ"], - [OWSCountryMetadata countryMetadataWithName:@"Ireland" tld:@".ie" frontingDomain:nil countryCode:@"IE"], - [OWSCountryMetadata countryMetadataWithName:@"Israel" tld:@".il" frontingDomain:nil countryCode:@"IL"], - [OWSCountryMetadata countryMetadataWithName:@"Isle of Man" tld:@".im" frontingDomain:nil countryCode:@"IM"], - [OWSCountryMetadata countryMetadataWithName:@"India" tld:@".in" frontingDomain:nil countryCode:@"IN"], - [OWSCountryMetadata countryMetadataWithName:@"British Indian Ocean Territory" - tld:@".io" - frontingDomain:nil - countryCode:@"IO"], - [OWSCountryMetadata countryMetadataWithName:@"Iceland" tld:@".is" frontingDomain:nil countryCode:@"IS"], - [OWSCountryMetadata countryMetadataWithName:@"Italy" tld:@".it" frontingDomain:nil countryCode:@"IT"], - [OWSCountryMetadata countryMetadataWithName:@"Jersey" tld:@".je" frontingDomain:nil countryCode:@"JE"], - [OWSCountryMetadata countryMetadataWithName:@"Jamaica" tld:@".jm" frontingDomain:nil countryCode:@"JM"], - [OWSCountryMetadata countryMetadataWithName:@"Jordan" tld:@".jo" frontingDomain:nil countryCode:@"JO"], - [OWSCountryMetadata countryMetadataWithName:@"Japan" tld:@".jp" frontingDomain:nil countryCode:@"JP"], - [OWSCountryMetadata countryMetadataWithName:@"Kenya" tld:@".ke" frontingDomain:nil countryCode:@"KE"], - [OWSCountryMetadata countryMetadataWithName:@"Kiribati" tld:@".ki" frontingDomain:nil countryCode:@"KI"], - [OWSCountryMetadata countryMetadataWithName:@"Kyrgyzstan" tld:@".kg" frontingDomain:nil countryCode:@"KG"], - [OWSCountryMetadata countryMetadataWithName:@"South Korea" tld:@".kr" frontingDomain:nil countryCode:@"KR"], - [OWSCountryMetadata countryMetadataWithName:@"Kuwait" tld:@".kw" frontingDomain:nil countryCode:@"KW"], - [OWSCountryMetadata countryMetadataWithName:@"Kazakhstan" tld:@".kz" frontingDomain:nil countryCode:@"KZ"], - [OWSCountryMetadata countryMetadataWithName:@"Laos" tld:@".la" frontingDomain:nil countryCode:@"LA"], - [OWSCountryMetadata countryMetadataWithName:@"Lebanon" tld:@".lb" frontingDomain:nil countryCode:@"LB"], - [OWSCountryMetadata countryMetadataWithName:@"Saint Lucia" tld:@".lc" frontingDomain:nil countryCode:@"LC"], - [OWSCountryMetadata countryMetadataWithName:@"Liechtenstein" - tld:@".li" - frontingDomain:nil - countryCode:@"LI"], - [OWSCountryMetadata countryMetadataWithName:@"Sri Lanka" tld:@".lk" frontingDomain:nil countryCode:@"LK"], - [OWSCountryMetadata countryMetadataWithName:@"Lesotho" tld:@".ls" frontingDomain:nil countryCode:@"LS"], - [OWSCountryMetadata countryMetadataWithName:@"Lithuania" tld:@".lt" frontingDomain:nil countryCode:@"LT"], - [OWSCountryMetadata countryMetadataWithName:@"Luxembourg" tld:@".lu" frontingDomain:nil countryCode:@"LU"], - [OWSCountryMetadata countryMetadataWithName:@"Latvia" tld:@".lv" frontingDomain:nil countryCode:@"LV"], - [OWSCountryMetadata countryMetadataWithName:@"Libya" tld:@".ly" frontingDomain:nil countryCode:@"LY"], - [OWSCountryMetadata countryMetadataWithName:@"Morocco" tld:@".ma" frontingDomain:nil countryCode:@"MA"], - [OWSCountryMetadata countryMetadataWithName:@"Moldova" tld:@".md" frontingDomain:nil countryCode:@"MD"], - [OWSCountryMetadata countryMetadataWithName:@"Montenegro" tld:@".me" frontingDomain:nil countryCode:@"ME"], - [OWSCountryMetadata countryMetadataWithName:@"Madagascar" tld:@".mg" frontingDomain:nil countryCode:@"MG"], - [OWSCountryMetadata countryMetadataWithName:@"Macedonia" tld:@".mk" frontingDomain:nil countryCode:@"MK"], - [OWSCountryMetadata countryMetadataWithName:@"Mali" tld:@".ml" frontingDomain:nil countryCode:@"ML"], - [OWSCountryMetadata countryMetadataWithName:@"Myanmar" tld:@".mm" frontingDomain:nil countryCode:@"MM"], - [OWSCountryMetadata countryMetadataWithName:@"Mongolia" tld:@".mn" frontingDomain:nil countryCode:@"MN"], - [OWSCountryMetadata countryMetadataWithName:@"Montserrat" tld:@".ms" frontingDomain:nil countryCode:@"MS"], - [OWSCountryMetadata countryMetadataWithName:@"Malta" tld:@".mt" frontingDomain:nil countryCode:@"MT"], - [OWSCountryMetadata countryMetadataWithName:@"Mauritius" tld:@".mu" frontingDomain:nil countryCode:@"MU"], - [OWSCountryMetadata countryMetadataWithName:@"Maldives" tld:@".mv" frontingDomain:nil countryCode:@"MV"], - [OWSCountryMetadata countryMetadataWithName:@"Malawi" tld:@".mw" frontingDomain:nil countryCode:@"MW"], - [OWSCountryMetadata countryMetadataWithName:@"Mexico" tld:@".mx" frontingDomain:nil countryCode:@"MX"], - [OWSCountryMetadata countryMetadataWithName:@"Malaysia" tld:@".my" frontingDomain:nil countryCode:@"MY"], - [OWSCountryMetadata countryMetadataWithName:@"Mozambique" tld:@".mz" frontingDomain:nil countryCode:@"MZ"], - [OWSCountryMetadata countryMetadataWithName:@"Namibia" tld:@".na" frontingDomain:nil countryCode:@"NA"], - [OWSCountryMetadata countryMetadataWithName:@"Niger" tld:@".ne" frontingDomain:nil countryCode:@"NE"], - [OWSCountryMetadata countryMetadataWithName:@"Norfolk Island" - tld:@".nf" - frontingDomain:nil - countryCode:@"NF"], - [OWSCountryMetadata countryMetadataWithName:@"Nigeria" tld:@".ng" frontingDomain:nil countryCode:@"NG"], - [OWSCountryMetadata countryMetadataWithName:@"Nicaragua" tld:@".ni" frontingDomain:nil countryCode:@"NI"], - [OWSCountryMetadata countryMetadataWithName:@"Netherlands" tld:@".nl" frontingDomain:nil countryCode:@"NL"], - [OWSCountryMetadata countryMetadataWithName:@"Norway" tld:@".no" frontingDomain:nil countryCode:@"NO"], - [OWSCountryMetadata countryMetadataWithName:@"Nepal" tld:@".np" frontingDomain:nil countryCode:@"NP"], - [OWSCountryMetadata countryMetadataWithName:@"Nauru" tld:@".nr" frontingDomain:nil countryCode:@"NR"], - [OWSCountryMetadata countryMetadataWithName:@"Niue" tld:@".nu" frontingDomain:nil countryCode:@"NU"], - [OWSCountryMetadata countryMetadataWithName:@"New Zealand" tld:@".nz" frontingDomain:nil countryCode:@"NZ"], - [OWSCountryMetadata countryMetadataWithName:@"Oman" - tld:@".om" - frontingDomain:OWSFrontingHost_GoogleOman - countryCode:@"OM"], - [OWSCountryMetadata countryMetadataWithName:@"Pakistan" tld:@".pk" frontingDomain:nil countryCode:@"PK"], - [OWSCountryMetadata countryMetadataWithName:@"Panama" tld:@".pa" frontingDomain:nil countryCode:@"PA"], - [OWSCountryMetadata countryMetadataWithName:@"Peru" tld:@".pe" frontingDomain:nil countryCode:@"PE"], - [OWSCountryMetadata countryMetadataWithName:@"Philippines" tld:@".ph" frontingDomain:nil countryCode:@"PH"], - [OWSCountryMetadata countryMetadataWithName:@"Poland" tld:@".pl" frontingDomain:nil countryCode:@"PL"], - [OWSCountryMetadata countryMetadataWithName:@"Papua New Guinea" - tld:@".pg" - frontingDomain:nil - countryCode:@"PG"], - [OWSCountryMetadata countryMetadataWithName:@"Pitcairn Islands" - tld:@".pn" - frontingDomain:nil - countryCode:@"PN"], - [OWSCountryMetadata countryMetadataWithName:@"Puerto Rico" tld:@".pr" frontingDomain:nil countryCode:@"PR"], - [OWSCountryMetadata countryMetadataWithName:@"Palestine[4]" - tld:@".ps" - frontingDomain:nil - countryCode:@"PS"], - [OWSCountryMetadata countryMetadataWithName:@"Portugal" tld:@".pt" frontingDomain:nil countryCode:@"PT"], - [OWSCountryMetadata countryMetadataWithName:@"Paraguay" tld:@".py" frontingDomain:nil countryCode:@"PY"], - [OWSCountryMetadata countryMetadataWithName:@"Qatar" - tld:@".qa" - frontingDomain:OWSFrontingHost_GoogleQatar - countryCode:@"QA"], - [OWSCountryMetadata countryMetadataWithName:@"Romania" tld:@".ro" frontingDomain:nil countryCode:@"RO"], - [OWSCountryMetadata countryMetadataWithName:@"Serbia" tld:@".rs" frontingDomain:nil countryCode:@"RS"], - [OWSCountryMetadata countryMetadataWithName:@"Russia" tld:@".ru" frontingDomain:nil countryCode:@"RU"], - [OWSCountryMetadata countryMetadataWithName:@"Rwanda" tld:@".rw" frontingDomain:nil countryCode:@"RW"], - [OWSCountryMetadata countryMetadataWithName:@"Saudi Arabia" - tld:@".sa" - frontingDomain:nil - countryCode:@"SA"], - [OWSCountryMetadata countryMetadataWithName:@"Solomon Islands" - tld:@".sb" - frontingDomain:nil - countryCode:@"SB"], - [OWSCountryMetadata countryMetadataWithName:@"Seychelles" tld:@".sc" frontingDomain:nil countryCode:@"SC"], - [OWSCountryMetadata countryMetadataWithName:@"Sweden" tld:@".se" frontingDomain:nil countryCode:@"SE"], - [OWSCountryMetadata countryMetadataWithName:@"Singapore" tld:@".sg" frontingDomain:nil countryCode:@"SG"], - [OWSCountryMetadata countryMetadataWithName:@"Saint Helena, Ascension and Tristan da Cunha" - tld:@".sh" - frontingDomain:nil - countryCode:@"SH"], - [OWSCountryMetadata countryMetadataWithName:@"Slovenia" tld:@".si" frontingDomain:nil countryCode:@"SI"], - [OWSCountryMetadata countryMetadataWithName:@"Slovakia" tld:@".sk" frontingDomain:nil countryCode:@"SK"], - [OWSCountryMetadata countryMetadataWithName:@"Sierra Leone" - tld:@".sl" - frontingDomain:nil - countryCode:@"SL"], - [OWSCountryMetadata countryMetadataWithName:@"Senegal" tld:@".sn" frontingDomain:nil countryCode:@"SN"], - [OWSCountryMetadata countryMetadataWithName:@"San Marino" tld:@".sm" frontingDomain:nil countryCode:@"SM"], - [OWSCountryMetadata countryMetadataWithName:@"Somalia" tld:@".so" frontingDomain:nil countryCode:@"SO"], - [OWSCountryMetadata countryMetadataWithName:@"São Tomé and Príncipe" - tld:@".st" - frontingDomain:nil - countryCode:@"ST"], - [OWSCountryMetadata countryMetadataWithName:@"Suriname" tld:@".sr" frontingDomain:nil countryCode:@"SR"], - [OWSCountryMetadata countryMetadataWithName:@"El Salvador" tld:@".sv" frontingDomain:nil countryCode:@"SV"], - [OWSCountryMetadata countryMetadataWithName:@"Chad" tld:@".td" frontingDomain:nil countryCode:@"TD"], - [OWSCountryMetadata countryMetadataWithName:@"Togo" tld:@".tg" frontingDomain:nil countryCode:@"TG"], - [OWSCountryMetadata countryMetadataWithName:@"Thailand" tld:@".th" frontingDomain:nil countryCode:@"TH"], - [OWSCountryMetadata countryMetadataWithName:@"Tajikistan" tld:@".tj" frontingDomain:nil countryCode:@"TJ"], - [OWSCountryMetadata countryMetadataWithName:@"Tokelau" tld:@".tk" frontingDomain:nil countryCode:@"TK"], - [OWSCountryMetadata countryMetadataWithName:@"Timor-Leste" tld:@".tl" frontingDomain:nil countryCode:@"TL"], - [OWSCountryMetadata countryMetadataWithName:@"Turkmenistan" - tld:@".tm" - frontingDomain:nil - countryCode:@"TM"], - [OWSCountryMetadata countryMetadataWithName:@"Tonga" tld:@".to" frontingDomain:nil countryCode:@"TO"], - [OWSCountryMetadata countryMetadataWithName:@"Tunisia" tld:@".tn" frontingDomain:nil countryCode:@"TN"], - [OWSCountryMetadata countryMetadataWithName:@"Turkey" tld:@".tr" frontingDomain:nil countryCode:@"TR"], - [OWSCountryMetadata countryMetadataWithName:@"Trinidad and Tobago" - tld:@".tt" - frontingDomain:nil - countryCode:@"TT"], - [OWSCountryMetadata countryMetadataWithName:@"Taiwan" tld:@".tw" frontingDomain:nil countryCode:@"TW"], - [OWSCountryMetadata countryMetadataWithName:@"Tanzania" tld:@".tz" frontingDomain:nil countryCode:@"TZ"], - [OWSCountryMetadata countryMetadataWithName:@"Ukraine" tld:@".ua" frontingDomain:nil countryCode:@"UA"], - [OWSCountryMetadata countryMetadataWithName:@"Uganda" tld:@".ug" frontingDomain:nil countryCode:@"UG"], - [OWSCountryMetadata countryMetadataWithName:@"United States" - tld:@".com" - frontingDomain:nil - countryCode:@"US"], - [OWSCountryMetadata countryMetadataWithName:@"Uruguay" tld:@".uy" frontingDomain:nil countryCode:@"UY"], - [OWSCountryMetadata countryMetadataWithName:@"Uzbekistan" tld:@".uz" frontingDomain:nil countryCode:@"UZ"], - [OWSCountryMetadata countryMetadataWithName:@"Saint Vincent and the Grenadines" - tld:@".vc" - frontingDomain:nil - countryCode:@"VC"], - [OWSCountryMetadata countryMetadataWithName:@"Venezuela" tld:@".ve" frontingDomain:nil countryCode:@"VE"], - [OWSCountryMetadata countryMetadataWithName:@"British Virgin Islands" - tld:@".vg" - frontingDomain:nil - countryCode:@"VG"], - [OWSCountryMetadata countryMetadataWithName:@"United States Virgin Islands" - tld:@".vi" - frontingDomain:nil - countryCode:@"VI"], - [OWSCountryMetadata countryMetadataWithName:@"Vietnam" tld:@".vn" frontingDomain:nil countryCode:@"VN"], - [OWSCountryMetadata countryMetadataWithName:@"Vanuatu" tld:@".vu" frontingDomain:nil countryCode:@"VU"], - [OWSCountryMetadata countryMetadataWithName:@"Samoa" tld:@".ws" frontingDomain:nil countryCode:@"WS"], - [OWSCountryMetadata countryMetadataWithName:@"South Africa" - tld:@".za" - frontingDomain:nil - countryCode:@"ZA"], - [OWSCountryMetadata countryMetadataWithName:@"Zambia" tld:@".zm" frontingDomain:nil countryCode:@"ZM"], - [OWSCountryMetadata countryMetadataWithName:@"Zimbabwe" tld:@".zw" frontingDomain:nil countryCode:@"ZW"], - ]; - cachedValue = [cachedValue sortedArrayUsingComparator:^NSComparisonResult( - OWSCountryMetadata *_Nonnull left, OWSCountryMetadata *_Nonnull right) { - return [left.localizedCountryName compare:right.localizedCountryName]; - }]; - }); - return cachedValue; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDevice.h b/SignalUtilitiesKit/OWSDevice.h deleted file mode 100644 index 24408a3fb..000000000 --- a/SignalUtilitiesKit/OWSDevice.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -extern uint32_t const OWSDevicePrimaryDeviceId; - -@interface OWSDeviceManager : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -+ (instancetype)sharedManager; - -- (BOOL)mayHaveLinkedDevices:(YapDatabaseConnection *)dbConnection; -- (void)setMayHaveLinkedDevices; -- (void)clearMayHaveLinkedDevices; - -- (BOOL)hasReceivedSyncMessageInLastSeconds:(NSTimeInterval)intervalSeconds; -- (void)setHasReceivedSyncMessage; - -@end - -#pragma mark - - -@interface OWSDevice : TSYapDatabaseObject - -@property (nonatomic, readonly) NSInteger deviceId; -@property (nonatomic, readonly, nullable) NSString *name; -@property (nonatomic, readonly) NSDate *createdAt; -@property (nonatomic, readonly) NSDate *lastSeenAt; - -+ (nullable instancetype)deviceFromJSONDictionary:(NSDictionary *)deviceAttributes error:(NSError **)error; - -+ (NSArray *)currentDevicesWithTransaction:(YapDatabaseReadTransaction *)transaction; - -/** - * Set local database of devices to `devices`. - * - * This will create missing devices, update existing devices, and delete stale devices. - * @param devices Removes any existing devices, replacing them with `devices` - * - * Returns YES if any devices were added or removed. - */ -+ (BOOL)replaceAll:(NSArray *)devices; - -/** - * The id of the device currently running this application - */ -+ (uint32_t)currentDeviceId; - -/** - * - * @param transaction yapTransaction - * @return - * If the user has any linked devices (apart from the device this app is running on). - */ -+ (BOOL)hasSecondaryDevicesWithTransaction:(YapDatabaseReadTransaction *)transaction; - -- (NSString *)displayName; -- (BOOL)isPrimaryDevice; - -/** - * Assign attributes to this device from another. - * - * @param other - * OWSDevice whose attributes to copy to this device - * @return - * YES if any values on self changed, else NO - */ -- (BOOL)updateAttributesWithDevice:(OWSDevice *)other; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDevice.m b/SignalUtilitiesKit/OWSDevice.m deleted file mode 100644 index 869b2bf9c..000000000 --- a/SignalUtilitiesKit/OWSDevice.m +++ /dev/null @@ -1,353 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSDevice.h" -#import "OWSError.h" -#import "OWSPrimaryStorage.h" -#import "ProfileManagerProtocol.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "YapDatabaseConnection+OWS.h" -#import "YapDatabaseConnection.h" -#import "YapDatabaseTransaction.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -uint32_t const OWSDevicePrimaryDeviceId = 1; -NSString *const kOWSPrimaryStorage_OWSDeviceCollection = @"kTSStorageManager_OWSDeviceCollection"; -NSString *const kOWSPrimaryStorage_MayHaveLinkedDevices = @"kTSStorageManager_MayHaveLinkedDevices"; - -@interface OWSDeviceManager () - -@property (atomic) NSDate *lastReceivedSyncMessage; - -@end - -#pragma mark - - -@implementation OWSDeviceManager - -+ (instancetype)sharedManager -{ - static OWSDeviceManager *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [[self alloc] initDefault]; - }); - return instance; -} - -- (instancetype)initDefault -{ - return [super init]; -} - -- (BOOL)mayHaveLinkedDevices:(YapDatabaseConnection *)dbConnection -{ - OWSAssertDebug(dbConnection); - - return [dbConnection boolForKey:kOWSPrimaryStorage_MayHaveLinkedDevices - inCollection:kOWSPrimaryStorage_OWSDeviceCollection - defaultValue:YES]; -} - -// In order to avoid skipping necessary sync messages, the default value -// for mayHaveLinkedDevices is YES. Once we've successfully sent a -// sync message with no device messages (e.g. the service has confirmed -// that we have no linked devices), we can set mayHaveLinkedDevices to NO -// to avoid unnecessary message sends for sync messages until we learn -// of a linked device (e.g. through the device linking UI or by receiving -// a sync message, etc.). -- (void)clearMayHaveLinkedDevices -{ - // Note that we write async to avoid opening transactions within transactions. - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [transaction setObject:@(NO) - forKey:kOWSPrimaryStorage_MayHaveLinkedDevices - inCollection:kOWSPrimaryStorage_OWSDeviceCollection]; - }]; -} - -- (void)setMayHaveLinkedDevices -{ - // Note that we write async to avoid opening transactions within transactions. - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [transaction setObject:@(YES) - forKey:kOWSPrimaryStorage_MayHaveLinkedDevices - inCollection:kOWSPrimaryStorage_OWSDeviceCollection]; - }]; -} - -- (BOOL)hasReceivedSyncMessageInLastSeconds:(NSTimeInterval)intervalSeconds -{ - return (self.lastReceivedSyncMessage && fabs(self.lastReceivedSyncMessage.timeIntervalSinceNow) < intervalSeconds); -} - -- (void)setHasReceivedSyncMessage -{ - self.lastReceivedSyncMessage = [NSDate new]; - - [self setMayHaveLinkedDevices]; -} - -@end - -#pragma mark - - -@interface OWSDevice () - -@property (nonatomic) NSInteger deviceId; -@property (nonatomic, nullable) NSString *name; -@property (nonatomic) NSDate *createdAt; -@property (nonatomic) NSDate *lastSeenAt; - -@end - -#pragma mark - - -@implementation OWSDevice - -#pragma mark - Dependencies - -+ (id)profileManager -{ - return SSKEnvironment.shared.profileManager; -} - -+ (id)udManager -{ - return SSKEnvironment.shared.udManager; -} - -+ (TSAccountManager *)tsAccountManager -{ - return TSAccountManager.sharedInstance; -} - -- (OWSIdentityManager *)identityManager -{ - OWSAssertDebug(SSKEnvironment.shared.identityManager); - - return SSKEnvironment.shared.identityManager; -} - -#pragma mark - - -- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [super saveWithTransaction:transaction]; -} - -+ (nullable instancetype)deviceFromJSONDictionary:(NSDictionary *)deviceAttributes error:(NSError **)error -{ - OWSDevice *device = [MTLJSONAdapter modelOfClass:[self class] fromJSONDictionary:deviceAttributes error:error]; - if (device.deviceId < OWSDevicePrimaryDeviceId) { - OWSFailDebug(@"Invalid device id: %lu", (unsigned long)device.deviceId); - *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecodeJson, @"Invalid device id."); - return nil; - } - return device; -} - -+ (NSDictionary *)JSONKeyPathsByPropertyKey -{ - return @{ - @"createdAt": @"created", - @"lastSeenAt": @"lastSeen", - @"deviceId": @"id", - @"name": @"name" - }; -} - -+ (MTLValueTransformer *)createdAtJSONTransformer -{ - return self.millisecondTimestampToDateTransformer; -} - -+ (MTLValueTransformer *)lastSeenAtJSONTransformer -{ - return self.millisecondTimestampToDateTransformer; -} - -+ (NSArray *)currentDevicesWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *result = [NSMutableArray new]; - [transaction enumerateKeysAndObjectsInCollection:OWSDevice.collection - usingBlock:^(NSString *key, OWSDevice *object, BOOL *stop) { - if (![object isKindOfClass:[OWSDevice class]]) { - OWSFailDebug(@"Unexpected object in collection: %@", object.class); - return; - } - [result addObject:object]; - }]; - return result; -} - -+ (BOOL)replaceAll:(NSArray *)currentDevices -{ - BOOL didAddOrRemove = NO; - NSMutableArray *existingDevices = [[self allObjectsInCollection] mutableCopy]; - for (OWSDevice *currentDevice in currentDevices) { - NSUInteger existingDeviceIndex = [existingDevices indexOfObject:currentDevice]; - if (existingDeviceIndex == NSNotFound) { - // New Device - OWSLogInfo(@"Adding device: %@", currentDevice); - [currentDevice save]; - didAddOrRemove = YES; - } else { - OWSDevice *existingDevice = existingDevices[existingDeviceIndex]; - if ([existingDevice updateAttributesWithDevice:currentDevice]) { - [existingDevice save]; - } - [existingDevices removeObjectAtIndex:existingDeviceIndex]; - } - } - - // Since we removed existing devices as we went, only stale devices remain - for (OWSDevice *staleDevice in existingDevices) { - OWSLogVerbose(@"Removing device: %@", staleDevice); - [staleDevice remove]; - didAddOrRemove = YES; - } - - if (didAddOrRemove) { - dispatch_async(dispatch_get_main_queue(), ^{ - // Device changes can affect the UD access mode for a recipient, - // so we need to fetch the profile for this user to update UD access mode. - [self.profileManager fetchLocalUsersProfile]; - }); - return YES; - } else { - return NO; - } -} - -+ (MTLValueTransformer *)millisecondTimestampToDateTransformer -{ - static MTLValueTransformer *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [MTLValueTransformer transformerUsingForwardBlock:^id(id value, BOOL *success, NSError **error) { - if ([value isKindOfClass:[NSNumber class]]) { - NSNumber *number = (NSNumber *)value; - NSDate *result = [NSDate ows_dateWithMillisecondsSince1970:[number longLongValue]]; - if (result) { - *success = YES; - return result; - } - } - *success = NO; - OWSLogError(@"unable to decode date from %@", value); - *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecodeJson, @"Unable to decode date from JSON."); - return nil; - } - reverseBlock:^id(id value, BOOL *success, NSError **error) { - if ([value isKindOfClass:[NSDate class]]) { - NSDate *date = (NSDate *)value; - NSNumber *result = [NSNumber numberWithLongLong:[NSDate ows_millisecondsSince1970ForDate:date]]; - if (result) { - *success = YES; - return result; - } - } - OWSLogError(@"unable to encode date from %@", value); - *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToEncodeJson, @"Unable to encode date to JSON."); - *success = NO; - return nil; - }]; - }); - return instance; -} - -+ (uint32_t)currentDeviceId -{ - // Someday it may be possible to have a non-primary iOS device, but for now - // any iOS device must be the primary device. - return OWSDevicePrimaryDeviceId; -} - -- (BOOL)isPrimaryDevice -{ - return self.deviceId == OWSDevicePrimaryDeviceId; -} - -- (NSString *)displayName -{ - if (self.name) { - ECKeyPair *_Nullable identityKeyPair = self.identityManager.identityKeyPair; - OWSAssertDebug(identityKeyPair); - if (identityKeyPair) { - NSError *error; - NSString *_Nullable decryptedName = - [DeviceNames decryptDeviceNameWithBase64String:self.name identityKeyPair:identityKeyPair error:&error]; - if (error) { - // Not necessarily an error; might be a legacy device name. - OWSLogError(@"Could not decrypt device name: %@", error); - } else if (decryptedName) { - return decryptedName; - } - } - - return self.name; - } - - if (self.deviceId == OWSDevicePrimaryDeviceId) { - return @"This Device"; - } - return NSLocalizedString(@"UNNAMED_DEVICE", @"Label text in device manager for a device with no name"); -} - -- (BOOL)updateAttributesWithDevice:(OWSDevice *)other -{ - BOOL changed = NO; - if (![self.lastSeenAt isEqual:other.lastSeenAt]) { - self.lastSeenAt = other.lastSeenAt; - changed = YES; - } - - if (![self.createdAt isEqual:other.createdAt]) { - self.createdAt = other.createdAt; - changed = YES; - } - - if (![self.name isEqual:other.name]) { - self.name = other.name; - changed = YES; - } - - return changed; -} - -+ (BOOL)hasSecondaryDevicesWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - return [self numberOfKeysInCollectionWithTransaction:transaction] > 1; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) { - return YES; - } - - if (![object isKindOfClass:[OWSDevice class]]) { - return NO; - } - - return [self isEqualToDevice:(OWSDevice *)object]; -} - -- (BOOL)isEqualToDevice:(OWSDevice *)device -{ - return self.deviceId == device.deviceId; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDeviceProvisioner.h b/SignalUtilitiesKit/OWSDeviceProvisioner.h deleted file mode 100644 index f9f93217f..000000000 --- a/SignalUtilitiesKit/OWSDeviceProvisioner.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSDeviceProvisioningCodeService; -@class OWSDeviceProvisioningService; - -@interface OWSDeviceProvisioner : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithMyPublicKey:(NSData *)myPublicKey - myPrivateKey:(NSData *)myPrivateKey - theirPublicKey:(NSData *)theirPublicKey - theirEphemeralDeviceId:(NSString *)ephemeralDeviceId - accountIdentifier:(NSString *)accountIdentifier - profileKey:(NSData *)profileKey - readReceiptsEnabled:(BOOL)areReadReceiptsEnabled - provisioningCodeService:(OWSDeviceProvisioningCodeService *)provisioningCodeService - provisioningService:(OWSDeviceProvisioningService *)provisioningService NS_DESIGNATED_INITIALIZER; - -- (instancetype)initWithMyPublicKey:(NSData *)myPublicKey - myPrivateKey:(NSData *)myPrivateKey - theirPublicKey:(NSData *)theirPublicKey - theirEphemeralDeviceId:(NSString *)ephemeralDeviceId - accountIdentifier:(NSString *)accountIdentifier - profileKey:(NSData *)profileKey - readReceiptsEnabled:(BOOL)areReadReceiptsEnabled; - -- (void)provisionWithSuccess:(void (^)(void))successCallback failure:(void (^)(NSError *))failureCallback; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDeviceProvisioner.m b/SignalUtilitiesKit/OWSDeviceProvisioner.m deleted file mode 100644 index 2deefb9b1..000000000 --- a/SignalUtilitiesKit/OWSDeviceProvisioner.m +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSDeviceProvisioner.h" -#import "OWSDeviceProvisioningCodeService.h" -#import "OWSDeviceProvisioningService.h" -#import "OWSError.h" -#import "OWSProvisioningMessage.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSDeviceProvisioner () - -@property (nonatomic, readonly) NSData *myPublicKey; -@property (nonatomic, readonly) NSData *myPrivateKey; -@property (nonatomic, readonly) NSData *theirPublicKey; -@property (nonatomic, readonly) NSString *accountIdentifier; -@property (nonatomic, readonly) NSData *profileKey; -@property (nonatomic, nullable) NSString *ephemeralDeviceId; -@property (nonatomic, readonly) BOOL areReadReceiptsEnabled; -@property (nonatomic, readonly) OWSDeviceProvisioningCodeService *provisioningCodeService; -@property (nonatomic, readonly) OWSDeviceProvisioningService *provisioningService; - -@end - -@implementation OWSDeviceProvisioner - -- (instancetype)initWithMyPublicKey:(NSData *)myPublicKey - myPrivateKey:(NSData *)myPrivateKey - theirPublicKey:(NSData *)theirPublicKey - theirEphemeralDeviceId:(NSString *)ephemeralDeviceId - accountIdentifier:(NSString *)accountIdentifier - profileKey:(NSData *)profileKey - readReceiptsEnabled:(BOOL)areReadReceiptsEnabled - provisioningCodeService:(OWSDeviceProvisioningCodeService *)provisioningCodeService - provisioningService:(OWSDeviceProvisioningService *)provisioningService -{ - self = [super init]; - if (!self) { - return self; - } - - _myPublicKey = myPublicKey; - _myPrivateKey = myPrivateKey; - _theirPublicKey = theirPublicKey; - _accountIdentifier = accountIdentifier; - _profileKey = profileKey; - _ephemeralDeviceId = ephemeralDeviceId; - _areReadReceiptsEnabled = areReadReceiptsEnabled; - _provisioningCodeService = provisioningCodeService; - _provisioningService = provisioningService; - - return self; -} - -- (instancetype)initWithMyPublicKey:(NSData *)myPublicKey - myPrivateKey:(NSData *)myPrivateKey - theirPublicKey:(NSData *)theirPublicKey - theirEphemeralDeviceId:(NSString *)ephemeralDeviceId - accountIdentifier:(NSString *)accountIdentifier - profileKey:(NSData *)profileKey - readReceiptsEnabled:(BOOL)areReadReceiptsEnabled -{ - return [self initWithMyPublicKey:myPublicKey - myPrivateKey:myPrivateKey - theirPublicKey:theirPublicKey - theirEphemeralDeviceId:ephemeralDeviceId - accountIdentifier:accountIdentifier - profileKey:profileKey - readReceiptsEnabled:areReadReceiptsEnabled - provisioningCodeService:[OWSDeviceProvisioningCodeService new] - provisioningService:[OWSDeviceProvisioningService new]]; -} - -- (void)provisionWithSuccess:(void (^)(void))successCallback failure:(void (^)(NSError *_Nonnull))failureCallback -{ - [self.provisioningCodeService - requestProvisioningCodeWithSuccess:^(NSString *provisioningCode) { - OWSLogInfo(@"Retrieved provisioning code."); - [self provisionWithCode:provisioningCode success:successCallback failure:failureCallback]; - } - failure:^(NSError *error) { - OWSLogError(@"Failed to get provisioning code with error: %@", error); - failureCallback(error); - }]; -} - -- (void)provisionWithCode:(NSString *)provisioningCode - success:(void (^)(void))successCallback - failure:(void (^)(NSError *_Nonnull))failureCallback -{ - OWSProvisioningMessage *message = [[OWSProvisioningMessage alloc] initWithMyPublicKey:self.myPublicKey - myPrivateKey:self.myPrivateKey - theirPublicKey:self.theirPublicKey - accountIdentifier:self.accountIdentifier - profileKey:self.profileKey - readReceiptsEnabled:self.areReadReceiptsEnabled - provisioningCode:provisioningCode]; - - NSData *_Nullable messageBody = [message buildEncryptedMessageBody]; - if (messageBody == nil) { - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToEncryptMessage, @"Failed building provisioning message"); - failureCallback(error); - return; - } - - [self.provisioningService provisionWithMessageBody:messageBody - ephemeralDeviceId:self.ephemeralDeviceId - success:^{ - OWSLogInfo(@"ProvisioningService SUCCEEDED"); - successCallback(); - } - failure:^(NSError *error) { - OWSLogError(@"ProvisioningService FAILED with error:%@", error); - failureCallback(error); - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDeviceProvisioningCodeService.h b/SignalUtilitiesKit/OWSDeviceProvisioningCodeService.h deleted file mode 100644 index bd0792f4b..000000000 --- a/SignalUtilitiesKit/OWSDeviceProvisioningCodeService.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright © 2016 Open Whisper Systems. All rights reserved. - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSNetworkManager; - -@interface OWSDeviceProvisioningCodeService : NSObject - -- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager NS_DESIGNATED_INITIALIZER; - -- (void)requestProvisioningCodeWithSuccess:(void (^)(NSString *))successCallback - failure:(void (^)(NSError *))failureCallback; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDeviceProvisioningCodeService.m b/SignalUtilitiesKit/OWSDeviceProvisioningCodeService.m deleted file mode 100644 index 02d967355..000000000 --- a/SignalUtilitiesKit/OWSDeviceProvisioningCodeService.m +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSDeviceProvisioningCodeService.h" -#import "OWSRequestFactory.h" -#import "TSNetworkManager.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const OWSDeviceProvisioningCodeServiceProvisioningCodeKey = @"verificationCode"; - -@interface OWSDeviceProvisioningCodeService () - -@property (readonly) TSNetworkManager *networkManager; - -@end - -@implementation OWSDeviceProvisioningCodeService - -- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager -{ - - self = [super init]; - if (!self) { - return self; - } - - _networkManager = networkManager; - - return self; -} - -- (instancetype)init -{ - return [self initWithNetworkManager:[TSNetworkManager sharedManager]]; -} - -- (void)requestProvisioningCodeWithSuccess:(void (^)(NSString *))successCallback - failure:(void (^)(NSError *))failureCallback -{ - TSRequest *request = [OWSRequestFactory deviceProvisioningCodeRequest]; - [self.networkManager makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSLogVerbose(@"ProvisioningCode request succeeded"); - if ([(NSObject *)responseObject isKindOfClass:[NSDictionary class]]) { - NSDictionary *responseDict = (NSDictionary *)responseObject; - NSString *provisioningCode = - [responseDict objectForKey:OWSDeviceProvisioningCodeServiceProvisioningCodeKey]; - successCallback(provisioningCode); - } - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSLogVerbose(@"ProvisioningCode request failed with error: %@", error); - failureCallback(error); - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDeviceProvisioningService.h b/SignalUtilitiesKit/OWSDeviceProvisioningService.h deleted file mode 100644 index fa28b686d..000000000 --- a/SignalUtilitiesKit/OWSDeviceProvisioningService.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSNetworkManager; - -@interface OWSDeviceProvisioningService : NSObject - -- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager; - -- (void)provisionWithMessageBody:(NSData *)messageBody - ephemeralDeviceId:(NSString *)deviceId - success:(void (^)(void))successCallback - failure:(void (^)(NSError *))failureCallback; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDeviceProvisioningService.m b/SignalUtilitiesKit/OWSDeviceProvisioningService.m deleted file mode 100644 index 4f8dca0e7..000000000 --- a/SignalUtilitiesKit/OWSDeviceProvisioningService.m +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSDeviceProvisioningService.h" -#import "OWSRequestFactory.h" -#import "TSNetworkManager.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSDeviceProvisioningService () - -@property (nonatomic, readonly) TSNetworkManager *networkManager; - -@end - -@implementation OWSDeviceProvisioningService - -- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager -{ - self = [super init]; - if (!self) { - return self; - } - - _networkManager = networkManager; - - return self; -} - -- (instancetype)init -{ - return [self initWithNetworkManager:[TSNetworkManager sharedManager]]; -} - -- (void)provisionWithMessageBody:(NSData *)messageBody - ephemeralDeviceId:(NSString *)deviceId - success:(void (^)(void))successCallback - failure:(void (^)(NSError *))failureCallback -{ - TSRequest *request = - [OWSRequestFactory deviceProvisioningRequestWithMessageBody:messageBody ephemeralDeviceId:deviceId]; - [self.networkManager makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSLogVerbose(@"Provisioning request succeeded"); - successCallback(); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSLogVerbose(@"Provisioning request failed with error: %@", error); - failureCallback(error); - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDevicesService.h b/SignalUtilitiesKit/OWSDevicesService.h deleted file mode 100644 index eed731e2a..000000000 --- a/SignalUtilitiesKit/OWSDevicesService.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const NSNotificationName_DeviceListUpdateSucceeded; -extern NSString *const NSNotificationName_DeviceListUpdateFailed; -extern NSString *const NSNotificationName_DeviceListUpdateModifiedDeviceList; - -@class OWSDevice; - -@interface OWSDevicesService : NSObject - -+ (void)refreshDevices; - -+ (void)unlinkDevice:(OWSDevice *)device - success:(void (^)(void))successCallback - failure:(void (^)(NSError *))failureCallback; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDevicesService.m b/SignalUtilitiesKit/OWSDevicesService.m deleted file mode 100644 index e84163d2c..000000000 --- a/SignalUtilitiesKit/OWSDevicesService.m +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSDevicesService.h" -#import "NSNotificationCenter+OWS.h" -#import "OWSDevice.h" -#import "OWSError.h" -#import "OWSRequestFactory.h" -#import "TSNetworkManager.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const NSNotificationName_DeviceListUpdateSucceeded = @"NSNotificationName_DeviceListUpdateSucceeded"; -NSString *const NSNotificationName_DeviceListUpdateFailed = @"NSNotificationName_DeviceListUpdateFailed"; -NSString *const NSNotificationName_DeviceListUpdateModifiedDeviceList - = @"NSNotificationName_DeviceListUpdateModifiedDeviceList"; - -@implementation OWSDevicesService - -+ (void)refreshDevices -{ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self - getDevicesWithSuccess:^(NSArray *devices) { - // If we have more than one device; we may have a linked device. - if (devices.count > 1) { - // Setting this flag here shouldn't be necessary, but we do so - // because the "cost" is low and it will improve robustness. - [OWSDeviceManager.sharedManager setMayHaveLinkedDevices]; - } - - BOOL didAddOrRemove = [OWSDevice replaceAll:devices]; - - [NSNotificationCenter.defaultCenter - postNotificationNameAsync:NSNotificationName_DeviceListUpdateSucceeded - object:nil]; - - if (didAddOrRemove) { - [NSNotificationCenter.defaultCenter - postNotificationNameAsync:NSNotificationName_DeviceListUpdateModifiedDeviceList - object:nil]; - } - } - failure:^(NSError *error) { - OWSLogError(@"Request device list failed with error: %@", error); - - [NSNotificationCenter.defaultCenter postNotificationNameAsync:NSNotificationName_DeviceListUpdateFailed - object:error]; - }]; - }); -} - -+ (void)getDevicesWithSuccess:(void (^)(NSArray *))successCallback - failure:(void (^)(NSError *))failureCallback -{ - TSRequest *request = [OWSRequestFactory getDevicesRequest]; - [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSLogVerbose(@"Get devices request succeeded"); - NSArray *devices = [self parseResponse:responseObject]; - - if (devices) { - successCallback(devices); - } else { - OWSLogError(@"unable to parse devices response:%@", responseObject); - NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); - failureCallback(error); - } - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSLogVerbose(@"Get devices request failed with error: %@", error); - failureCallback(error); - }]; -} - -+ (void)unlinkDevice:(OWSDevice *)device - success:(void (^)(void))successCallback - failure:(void (^)(NSError *))failureCallback -{ - TSRequest *request = [OWSRequestFactory deleteDeviceRequestWithDevice:device]; - - [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSLogVerbose(@"Delete device request succeeded"); - successCallback(); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSLogVerbose(@"Get devices request failed with error: %@", error); - failureCallback(error); - }]; -} - -+ (NSArray *)parseResponse:(id)responseObject -{ - if (![responseObject isKindOfClass:[NSDictionary class]]) { - OWSLogError(@"Device response was not a dictionary."); - return nil; - } - NSDictionary *response = (NSDictionary *)responseObject; - - NSArray *devicesAttributes = response[@"devices"]; - if (!devicesAttributes) { - OWSLogError(@"Device response had no devices."); - return nil; - } - - NSMutableArray *devices = [NSMutableArray new]; - for (NSDictionary *deviceAttributes in devicesAttributes) { - NSError *error; - OWSDevice *_Nullable device = [OWSDevice deviceFromJSONDictionary:deviceAttributes error:&error]; - if (error || !device) { - OWSLogError(@"Failed to build device from dictionary with error: %@", error); - } else { - [devices addObject:device]; - } - } - - return [devices copy]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.h b/SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.h deleted file mode 100644 index 200a18e06..000000000 --- a/SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSDisappearingMessagesConfiguration; - -@interface OWSDisappearingMessagesConfigurationMessage : TSOutgoingMessage - -// MJK TODO - remove senderTimestamp -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -- (instancetype)initWithConfiguration:(OWSDisappearingMessagesConfiguration *)configuration thread:(TSThread *)thread; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.m b/SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.m deleted file mode 100644 index e787fc317..000000000 --- a/SignalUtilitiesKit/OWSDisappearingMessagesConfigurationMessage.m +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDisappearingMessagesConfigurationMessage.h" -#import "OWSDisappearingMessagesConfiguration.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSDisappearingMessagesConfigurationMessage () - -@property (nonatomic, readonly) OWSDisappearingMessagesConfiguration *configuration; - -@end - -#pragma mark - - -@implementation OWSDisappearingMessagesConfigurationMessage - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeDisappearingMessagesConfiguration]; } - -- (instancetype)initWithConfiguration:(OWSDisappearingMessagesConfiguration *)configuration thread:(TSThread *)thread -{ - // MJK TODO - remove sender timestamp - self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - if (!self) { - return self; - } - - _configuration = configuration; - - return self; -} - - -- (nullable id)dataMessageBuilder -{ - SSKProtoDataMessageBuilder *_Nullable dataMessageBuilder = [super dataMessageBuilder]; - if (!dataMessageBuilder) { - return nil; - } - [dataMessageBuilder setTimestamp:self.timestamp]; - [dataMessageBuilder setFlags:SSKProtoDataMessageFlagsExpirationTimerUpdate]; - if (self.configuration.isEnabled) { - [dataMessageBuilder setExpireTimer:self.configuration.durationSeconds]; - } else { - [dataMessageBuilder setExpireTimer:0]; - } - - return dataMessageBuilder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesJob.m b/SignalUtilitiesKit/OWSDisappearingMessagesJob.m index 0a3dec690..7f987a1fc 100644 --- a/SignalUtilitiesKit/OWSDisappearingMessagesJob.m +++ b/SignalUtilitiesKit/OWSDisappearingMessagesJob.m @@ -6,7 +6,6 @@ #import "AppContext.h" #import "AppReadiness.h" #import "ContactsManagerProtocol.h" -#import "NSTimer+OWS.h" #import "OWSBackgroundTask.h" #import "OWSDisappearingConfigurationUpdateInfoMessage.h" #import "OWSDisappearingMessagesConfiguration.h" @@ -111,13 +110,6 @@ void AssertIsOnDisappearingMessagesQueue() return queue; } -#pragma mark - Dependencies - -- (id)contactsManager -{ - return SSKEnvironment.shared.contactsManager; -} - #pragma mark - - (NSUInteger)deleteExpiredMessages @@ -218,8 +210,7 @@ void AssertIsOnDisappearingMessagesQueue() NSString *_Nullable remoteContactName = nil; if (remoteRecipientId) { - remoteContactName = [self.contactsManager displayNameForPhoneIdentifier:remoteRecipientId - transaction:transaction]; + remoteContactName = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:remoteRecipientId avoidingWriteTransaction:YES]; } // Become eventually consistent in the case that the remote changed their settings at the same time. diff --git a/SignalUtilitiesKit/OWSDynamicOutgoingMessage.h b/SignalUtilitiesKit/OWSDynamicOutgoingMessage.h deleted file mode 100644 index ec0e0dc20..000000000 --- a/SignalUtilitiesKit/OWSDynamicOutgoingMessage.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class SSKProtoDataMessageBuilder; -@class SignalRecipient; - -typedef NSData *_Nonnull (^DynamicOutgoingMessageBlock)(SignalRecipient *); - -/// This class is only used in debug tools -@interface OWSDynamicOutgoingMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -- (instancetype)initWithPlainTextDataBlock:(DynamicOutgoingMessageBlock)block thread:(nullable TSThread *)thread; -- (instancetype)initWithPlainTextDataBlock:(DynamicOutgoingMessageBlock)block - timestamp:(uint64_t)timestamp - thread:(nullable TSThread *)thread; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSDynamicOutgoingMessage.m b/SignalUtilitiesKit/OWSDynamicOutgoingMessage.m deleted file mode 100644 index 00d212809..000000000 --- a/SignalUtilitiesKit/OWSDynamicOutgoingMessage.m +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDynamicOutgoingMessage.h" -#import - - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSDynamicOutgoingMessage () - -@property (nonatomic, readonly) DynamicOutgoingMessageBlock block; - -@end - -#pragma mark - - -@implementation OWSDynamicOutgoingMessage - -- (instancetype)initWithPlainTextDataBlock:(DynamicOutgoingMessageBlock)block thread:(nullable TSThread *)thread -{ - return [self initWithPlainTextDataBlock:block timestamp:[NSDate ows_millisecondTimeStamp] thread:thread]; -} - -// MJK TODO can we remove sender timestamp? -- (instancetype)initWithPlainTextDataBlock:(DynamicOutgoingMessageBlock)block - timestamp:(uint64_t)timestamp - thread:(nullable TSThread *)thread -{ - self = [super initOutgoingMessageWithTimestamp:timestamp - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - - if (self) { - _block = block; - } - - return self; -} - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient -{ - NSData *plainTextData = self.block(recipient); - OWSAssertDebug(plainTextData); - return plainTextData; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSEndSessionMessage.h b/SignalUtilitiesKit/OWSEndSessionMessage.h deleted file mode 100644 index ea65a0443..000000000 --- a/SignalUtilitiesKit/OWSEndSessionMessage.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -NS_SWIFT_NAME(EndSessionMessage) -@interface OWSEndSessionMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -// MJK TODO can we remove the sender timestamp? -- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(nullable TSThread *)thread NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSEndSessionMessage.m b/SignalUtilitiesKit/OWSEndSessionMessage.m deleted file mode 100644 index 287bda45d..000000000 --- a/SignalUtilitiesKit/OWSEndSessionMessage.m +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSEndSessionMessage.h" -#import "OWSPrimaryStorage+Loki.h" -#import "SignalRecipient.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSEndSessionMessage - -- (instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(nullable TSThread *)thread -{ - return [super initOutgoingMessageWithTimestamp:timestamp - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; -} - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeEphemeral]; } - -- (nullable id)dataMessageBuilder -{ - SSKProtoDataMessageBuilder *_Nullable builder = [super dataMessageBuilder]; - if (!builder) { - return nil; - } - [builder setTimestamp:self.timestamp]; - [builder setFlags:SSKProtoDataMessageFlagsEndSession]; - - return builder; -} - -- (nullable id)prepareCustomContentBuilder:(SignalRecipient *)recipient { - SSKProtoContentBuilder *builder = [super prepareCustomContentBuilder:recipient]; - - PreKeyBundle *bundle = [OWSPrimaryStorage.sharedManager generatePreKeyBundleForContact:recipient.recipientId]; - SSKProtoPrekeyBundleMessageBuilder *preKeyBuilder = [SSKProtoPrekeyBundleMessage builderFromPreKeyBundle:bundle]; - - // Build the pre key bundle message - NSError *error; - SSKProtoPrekeyBundleMessage *_Nullable message = [preKeyBuilder buildAndReturnError:&error]; - if (error || !message) { - OWSFailDebug(@"Failed to build pre key bundle for: %@ due to error: %@.", recipient.recipientId, error); - } else { - [builder setPrekeyBundleMessage:message]; - } - - return builder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSFingerprint.h b/SignalUtilitiesKit/OWSFingerprint.h deleted file mode 100644 index 36904a41d..000000000 --- a/SignalUtilitiesKit/OWSFingerprint.h +++ /dev/null @@ -1,52 +0,0 @@ -// Created by Michael Kirk on 9/14/16. -// Copyright © 2016 Open Whisper Systems. All rights reserved. - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class UIImage; - -@interface OWSFingerprint : NSObject - -#pragma mark - Initializers - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithMyStableId:(NSString *)myStableId - myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType - theirStableId:(NSString *)theirStableId - theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType - theirName:(NSString *)theirName - hashIterations:(uint32_t)hashIterations NS_DESIGNATED_INITIALIZER; - -+ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId - myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType - theirStableId:(NSString *)theirStableId - theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType - theirName:(NSString *)theirName - hashIterations:(uint32_t)hashIterations; - -+ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId - myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType - theirStableId:(NSString *)theirStableId - theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType - theirName:(NSString *)theirName; - -#pragma mark - Properties - -@property (nonatomic, readonly) NSData *myStableIdData; -@property (nonatomic, readonly) NSData *myIdentityKey; -@property (nonatomic, readonly) NSString *theirStableId; -@property (nonatomic, readonly) NSData *theirStableIdData; -@property (nonatomic, readonly) NSData *theirIdentityKey; -@property (nonatomic, readonly) NSString *displayableText; -@property (nullable, nonatomic, readonly) UIImage *image; - -#pragma mark - Instance Methods - -- (BOOL)matchesLogicalFingerprintsData:(NSData *)data error:(NSError **)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSFingerprint.m b/SignalUtilitiesKit/OWSFingerprint.m deleted file mode 100644 index 20c777d31..000000000 --- a/SignalUtilitiesKit/OWSFingerprint.m +++ /dev/null @@ -1,334 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSFingerprint.h" -#import "OWSError.h" -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -static uint32_t const OWSFingerprintHashingVersion = 0; -static uint32_t const OWSFingerprintScannableFormatVersion = 1; -static uint32_t const OWSFingerprintDefaultHashIterations = 5200; - -@interface OWSFingerprint () - -@property (nonatomic, readonly) NSUInteger hashIterations; -@property (nonatomic, readonly) NSString *text; -@property (nonatomic, readonly) NSData *myFingerprintData; -@property (nonatomic, readonly) NSData *theirFingerprintData; -@property (nonatomic, readonly) NSString *theirName; - -@end - -#pragma mark - - -@implementation OWSFingerprint - -- (instancetype)initWithMyStableId:(NSString *)myStableId - myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType - theirStableId:(NSString *)theirStableId - theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType - theirName:(NSString *)theirName - hashIterations:(uint32_t)hashIterations -{ - OWSAssertDebug(theirIdentityKeyWithoutKeyType.length == 32); - OWSAssertDebug(myIdentityKeyWithoutKeyType.length == 32); - - self = [super init]; - if (!self) { - return self; - } - - _myStableIdData = [myStableId dataUsingEncoding:NSUTF8StringEncoding]; - _myIdentityKey = [myIdentityKeyWithoutKeyType prependKeyType]; - _theirStableId = theirStableId; - _theirStableIdData = [theirStableId dataUsingEncoding:NSUTF8StringEncoding]; - _theirIdentityKey = [theirIdentityKeyWithoutKeyType prependKeyType]; - _theirName = theirName; - _hashIterations = hashIterations; - - _myFingerprintData = [self dataForStableId:_myStableIdData publicKey:_myIdentityKey]; - _theirFingerprintData = [self dataForStableId:_theirStableIdData publicKey:_theirIdentityKey]; - - return self; -} - -+ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId - myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType - theirStableId:(NSString *)theirStableId - theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType - theirName:(NSString *)theirName - hashIterations:(uint32_t)hashIterations -{ - return [[self alloc] initWithMyStableId:myStableId - myIdentityKey:myIdentityKeyWithoutKeyType - theirStableId:theirStableId - theirIdentityKey:theirIdentityKeyWithoutKeyType - theirName:theirName - hashIterations:hashIterations]; -} - -+ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId - myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType - theirStableId:(NSString *)theirStableId - theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType - theirName:(NSString *)theirName -{ - return [[self alloc] initWithMyStableId:myStableId - myIdentityKey:myIdentityKeyWithoutKeyType - theirStableId:theirStableId - theirIdentityKey:theirIdentityKeyWithoutKeyType - theirName:theirName - hashIterations:OWSFingerprintDefaultHashIterations]; -} - -- (BOOL)matchesLogicalFingerprintsData:(NSData *)data error:(NSError **)error -{ - OWSAssertDebug(data.length > 0); - OWSAssertDebug(error); - - *error = nil; - FingerprintProtoLogicalFingerprints *_Nullable logicalFingerprints; - logicalFingerprints = [FingerprintProtoLogicalFingerprints parseData:data error:error]; - if (!logicalFingerprints || *error) { - OWSFailDebug(@"fingerprint failure: %@", *error); - - NSString *description = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILURE_INVALID_QRCODE", @"alert body"); - *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); - return NO; - } - - if (logicalFingerprints.version < OWSFingerprintScannableFormatVersion) { - OWSLogWarn(@"Verification failed. They're running an old version."); - NSString *description - = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_OLD_REMOTE_VERSION", @"alert body"); - *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); - return NO; - } - - if (logicalFingerprints.version > OWSFingerprintScannableFormatVersion) { - OWSLogWarn(@"Verification failed. We're running an old version."); - NSString *description = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_OLD_LOCAL_VERSION", @"alert body"); - *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); - return NO; - } - - // Their local is *our* remote. - FingerprintProtoLogicalFingerprint *localFingerprint = logicalFingerprints.remoteFingerprint; - FingerprintProtoLogicalFingerprint *remoteFingerprint = logicalFingerprints.localFingerprint; - - if (![remoteFingerprint.identityData isEqual:[self scannableData:self.theirFingerprintData]]) { - OWSLogWarn(@"Verification failed. We have the wrong fingerprint for them"); - NSString *descriptionFormat = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_I_HAVE_WRONG_KEY_FOR_THEM", - @"Alert body when verifying with {{contact name}}"); - NSString *description = [NSString stringWithFormat:descriptionFormat, self.theirName]; - *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); - return NO; - } - - if (![localFingerprint.identityData isEqual:[self scannableData:self.myFingerprintData]]) { - OWSLogWarn(@"Verification failed. They have the wrong fingerprint for us"); - NSString *descriptionFormat = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_THEY_HAVE_WRONG_KEY_FOR_ME", - @"Alert body when verifying with {{contact name}}"); - NSString *description = [NSString stringWithFormat:descriptionFormat, self.theirName]; - *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); - return NO; - } - - OWSLogWarn(@"Verification Succeeded."); - return YES; -} - -- (NSString *)text -{ - NSString *myDisplayString = [self stringForFingerprintData:self.myFingerprintData]; - NSString *theirDisplayString = [self stringForFingerprintData:self.theirFingerprintData]; - - if ([theirDisplayString compare:myDisplayString] == NSOrderedAscending) { - return [NSString stringWithFormat:@"%@%@", theirDisplayString, myDisplayString]; - } else { - return [NSString stringWithFormat:@"%@%@", myDisplayString, theirDisplayString]; - } -} - -/** - * Formats numeric fingerprint, 3 lines in groups of 5 digits. - */ -- (NSString *)displayableText -{ - NSString *input = self.text; - - NSMutableArray *lines = [NSMutableArray new]; - - NSUInteger lineLength = self.text.length / 3; - for (uint i = 0; i < 3; i++) { - NSString *line = [input substringWithRange:NSMakeRange(i * lineLength, lineLength)]; - - NSMutableArray *chunks = [NSMutableArray new]; - for (uint i = 0; i < line.length / 5; i++) { - NSString *nextChunk = [line substringWithRange:NSMakeRange(i * 5, 5)]; - [chunks addObject:nextChunk]; - } - [lines addObject:[chunks componentsJoinedByString:@" "]]; - } - - return [lines componentsJoinedByString:@"\n"]; -} - - -- (NSData *)dataFromShort:(uint32_t)aShort -{ - uint8_t bytes[] = { - ((uint8_t)(aShort & 0xFF00) >> 8), - (uint8_t)(aShort & 0x00FF) - }; - - return [NSData dataWithBytes:bytes length:2]; -} - -/** - * An identifier for a mutable public key, belonging to an immutable identifier (stableId). - * - * This method is intended to be somewhat expensive to produce in order to be brute force adverse. - * - * @param stableIdData - * Immutable global identifier e.g. Signal Identifier, an e164 formatted phone number encoded as UTF-8 data - * @param publicKey - * The current public key for - * @return - * All-number textual representation - */ -- (NSData *)dataForStableId:(NSData *)stableIdData publicKey:(NSData *)publicKey -{ - OWSAssertDebug(stableIdData); - OWSAssertDebug(publicKey); - - NSData *versionData = [self dataFromShort:OWSFingerprintHashingVersion]; - NSMutableData *hash = [versionData mutableCopy]; - [hash appendData:publicKey]; - [hash appendData:stableIdData]; - - NSMutableData *_Nullable digestData = [[NSMutableData alloc] initWithLength:CC_SHA512_DIGEST_LENGTH]; - if (!digestData) { - @throw [NSException exceptionWithName:NSGenericException reason:@"Couldn't allocate buffer." userInfo:nil]; - } - for (int i = 0; i < self.hashIterations; i++) { - [hash appendData:publicKey]; - - if (hash.length >= UINT32_MAX) { - @throw [NSException exceptionWithName:@"Oversize Data" reason:@"Oversize hash." userInfo:nil]; - } - - CC_SHA512(hash.bytes, (uint32_t)hash.length, digestData.mutableBytes); - // TODO get rid of this loop-allocation - hash = [digestData mutableCopy]; - } - - return [hash copy]; -} - - -- (NSString *)stringForFingerprintData:(NSData *)data -{ - OWSAssertDebug(data); - - return [NSString stringWithFormat:@"%@%@%@%@%@%@", - [self encodedChunkFromData:data offset:0], - [self encodedChunkFromData:data offset:5], - [self encodedChunkFromData:data offset:10], - [self encodedChunkFromData:data offset:15], - [self encodedChunkFromData:data offset:20], - [self encodedChunkFromData:data offset:25]]; -} - -- (NSString *)encodedChunkFromData:(NSData *)data offset:(uint)offset -{ - OWSAssertDebug(data); - - uint8_t fiveBytes[5]; - [data getBytes:fiveBytes range:NSMakeRange(offset, 5)]; - - int chunk = [self uint64From5Bytes:fiveBytes] % 100000; - return [NSString stringWithFormat:@"%05d", chunk]; -} - -- (int64_t)uint64From5Bytes:(uint8_t[])bytes -{ - int64_t result = ((bytes[0] & 0xffLL) << 32) | - ((bytes[1] & 0xffLL) << 24) | - ((bytes[2] & 0xffLL) << 16) | - ((bytes[3] & 0xffLL) << 8) | - ((bytes[4] & 0xffLL)); - - return result; -} - -- (NSData *)scannableData:(NSData *)data -{ - return [data subdataWithRange:NSMakeRange(0, 32)]; -} - -- (nullable UIImage *)image -{ - FingerprintProtoLogicalFingerprintBuilder *remoteFingerprintBuilder = - [FingerprintProtoLogicalFingerprint builderWithIdentityData:[self scannableData:self.theirFingerprintData]]; - NSError *error; - FingerprintProtoLogicalFingerprint *_Nullable remoteFingerprint = - [remoteFingerprintBuilder buildAndReturnError:&error]; - if (!remoteFingerprint || error) { - OWSFailDebug(@"could not build proto: %@", error); - return nil; - } - - FingerprintProtoLogicalFingerprintBuilder *localFingerprintBuilder = - [FingerprintProtoLogicalFingerprint builderWithIdentityData:[self scannableData:self.myFingerprintData]]; - FingerprintProtoLogicalFingerprint *_Nullable localFingerprint = - [localFingerprintBuilder buildAndReturnError:&error]; - if (!localFingerprint || error) { - OWSFailDebug(@"could not build proto: %@", error); - return nil; - } - - FingerprintProtoLogicalFingerprintsBuilder *logicalFingerprintsBuilder = - [FingerprintProtoLogicalFingerprints builderWithVersion:OWSFingerprintScannableFormatVersion - localFingerprint:localFingerprint - remoteFingerprint:remoteFingerprint]; - - // Build ByteMode QR (Latin-1 encodable data) - NSData *_Nullable fingerprintData = [logicalFingerprintsBuilder buildSerializedDataAndReturnError:&error]; - if (!fingerprintData || error) { - OWSFailDebug(@"could not serialize proto: %@", error); - return nil; - } - - OWSLogDebug(@"Building fingerprint with data: %@", fingerprintData); - - CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; - [filter setDefaults]; - [filter setValue:fingerprintData forKey:@"inputMessage"]; - - CIImage *ciImage = [filter outputImage]; - if (!ciImage) { - OWSLogError(@"Failed to create QR image from fingerprint text: %@", self.text); - return nil; - } - - // UIImages backed by a CIImage won't render without antialiasing, so we convert the backign image to a CGImage, - // which can be scaled crisply. - CIContext *context = [CIContext contextWithOptions:nil]; - CGImageRef cgImage = [context createCGImage:ciImage fromRect:ciImage.extent]; - UIImage *qrImage = [UIImage imageWithCGImage:cgImage]; - CGImageRelease(cgImage); - - return qrImage; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSFingerprintBuilder.h b/SignalUtilitiesKit/OWSFingerprintBuilder.h deleted file mode 100644 index 0f0b2bb0a..000000000 --- a/SignalUtilitiesKit/OWSFingerprintBuilder.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSAccountManager; -@class OWSFingerprint; -@protocol ContactsManagerProtocol; - -@interface OWSFingerprintBuilder : NSObject - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithAccountManager:(TSAccountManager *)accountManager - contactsManager:(id)contactsManager NS_DESIGNATED_INITIALIZER; - -/** - * Builds a fingerprint combining your current credentials with their most recently accepted credentials. - */ -- (nullable OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId; - -/** - * Builds a fingerprint combining your current credentials with the specified identity key. - * You can use this to present a new identity key for verification. - */ -- (OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId theirIdentityKey:(NSData *)theirIdentityKey; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSFingerprintBuilder.m b/SignalUtilitiesKit/OWSFingerprintBuilder.m deleted file mode 100644 index 2b3df6d24..000000000 --- a/SignalUtilitiesKit/OWSFingerprintBuilder.m +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSFingerprintBuilder.h" -#import "ContactsManagerProtocol.h" -#import "OWSFingerprint.h" -#import "OWSIdentityManager.h" -#import "TSAccountManager.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSFingerprintBuilder () - -@property (nonatomic, readonly) TSAccountManager *accountManager; -@property (nonatomic, readonly) id contactsManager; - -@end - -@implementation OWSFingerprintBuilder - -- (instancetype)initWithAccountManager:(TSAccountManager *)accountManager - contactsManager:(id)contactsManager -{ - self = [super init]; - if (!self) { - return self; - } - - _accountManager = accountManager; - _contactsManager = contactsManager; - - return self; -} - -- (nullable OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId -{ - NSData *_Nullable theirIdentityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientId:theirSignalId]; - - if (theirIdentityKey == nil) { - OWSFailDebug(@"Missing their identity key"); - return nil; - } - - return [self fingerprintWithTheirSignalId:theirSignalId theirIdentityKey:theirIdentityKey]; -} - -- (OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId theirIdentityKey:(NSData *)theirIdentityKey -{ - NSString *theirName = [self.contactsManager displayNameForPhoneIdentifier:theirSignalId]; - - NSString *mySignalId = [self.accountManager localNumber]; - NSData *myIdentityKey = [[OWSIdentityManager sharedManager] identityKeyPair].publicKey; - - return [OWSFingerprint fingerprintWithMyStableId:mySignalId - myIdentityKey:myIdentityKey - theirStableId:theirSignalId - theirIdentityKey:theirIdentityKey - theirName:theirName]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSGroupAvatarBuilder.h b/SignalUtilitiesKit/OWSGroupAvatarBuilder.h deleted file mode 100644 index db48c77ba..000000000 --- a/SignalUtilitiesKit/OWSGroupAvatarBuilder.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSGroupThread; - -@interface OWSGroupAvatarBuilder : OWSAvatarBuilder - -- (instancetype)initWithThread:(TSGroupThread *)thread diameter:(NSUInteger)diameter; - -+ (nullable UIImage *)defaultAvatarForGroupId:(NSData *)groupId - conversationColorName:(NSString *)conversationColorName - diameter:(NSUInteger)diameter; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSGroupAvatarBuilder.m b/SignalUtilitiesKit/OWSGroupAvatarBuilder.m deleted file mode 100644 index 09cd5749b..000000000 --- a/SignalUtilitiesKit/OWSGroupAvatarBuilder.m +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import "OWSGroupAvatarBuilder.h" -#import "OWSContactsManager.h" -#import "TSGroupThread.h" -#import "UIColor+OWS.h" -#import "Theme.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSGroupAvatarBuilder () - -@property (nonatomic, readonly) TSGroupThread *thread; -@property (nonatomic, readonly) NSUInteger diameter; - -@end - -@implementation OWSGroupAvatarBuilder - -- (instancetype)initWithThread:(TSGroupThread *)thread diameter:(NSUInteger)diameter -{ - self = [super init]; - if (!self) { - return self; - } - - _thread = thread; - _diameter = diameter; - - return self; -} - -#pragma mark - Dependencies - -+ (OWSContactsManager *)contactsManager -{ - return (OWSContactsManager *)SSKEnvironment.shared.contactsManager; -} - -#pragma mark - - -- (nullable UIImage *)buildSavedImage -{ - return self.thread.groupModel.groupImage; -} - -- (nullable UIImage *)buildDefaultImage -{ - return [self.class defaultAvatarForGroupId:self.thread.groupModel.groupId - conversationColorName:self.thread.conversationColorName - diameter:self.diameter]; -} - -+ (nullable UIImage *)defaultAvatarForGroupId:(NSData *)groupId - conversationColorName:(NSString *)conversationColorName - diameter:(NSUInteger)diameter -{ - NSString *cacheKey = [NSString stringWithFormat:@"%@-%d", groupId.hexadecimalString, Theme.isDarkThemeEnabled]; - - UIImage *_Nullable cachedAvatar = - [OWSGroupAvatarBuilder.contactsManager.avatarCache imageForKey:cacheKey diameter:(CGFloat)diameter]; - if (cachedAvatar) { - return cachedAvatar; - } - -#ifdef SHOW_COLOR_PICKER - UIColor *backgroundColor = - [OWSConversationColor conversationColorOrDefaultForColorName:conversationColorName].themeColor; -#else - UIColor *backgroundColor = UIColor.ows_darkSkyBlueColor; -#endif - UIImage *_Nullable image = - [OWSGroupAvatarBuilder groupAvatarImageWithBackgroundColor:backgroundColor diameter:diameter]; - if (!image) { - OWSFailDebug(@"Could not create group avatar."); - return nil; - } - - [OWSGroupAvatarBuilder.contactsManager.avatarCache setImage:image forKey:cacheKey diameter:diameter]; - return image; -} - -+ (nullable UIImage *)groupAvatarImageWithBackgroundColor:(UIColor *)backgroundColor diameter:(NSUInteger)diameter -{ - UIImage *icon = [UIImage imageNamed:@"group-avatar"]; - // The group-avatar asset is designed for the kStandardAvatarSize. - // Adjust its size to reflect the actual output diameter. - CGFloat scaling = diameter / (CGFloat)kStandardAvatarSize; - CGSize iconSize = CGSizeScale(icon.size, scaling); - return - [OWSAvatarBuilder avatarImageWithIcon:icon iconSize:iconSize backgroundColor:backgroundColor diameter:diameter]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSGroupsOutputStream.m b/SignalUtilitiesKit/OWSGroupsOutputStream.m index 7c7a2af23..cd6941758 100644 --- a/SignalUtilitiesKit/OWSGroupsOutputStream.m +++ b/SignalUtilitiesKit/OWSGroupsOutputStream.m @@ -25,29 +25,11 @@ NS_ASSUME_NONNULL_BEGIN SSKProtoGroupDetailsBuilder *groupBuilder = [SSKProtoGroupDetails builderWithId:group.groupId]; [groupBuilder setName:group.groupName]; [groupBuilder setMembers:group.groupMemberIds]; - [groupBuilder setColor:groupThread.conversationColorName]; [groupBuilder setAdmins:group.groupAdminIds]; if ([OWSBlockingManager.sharedManager isGroupIdBlocked:group.groupId]) { [groupBuilder setBlocked:YES]; } - /* - NSData *avatarPng; - if (group.groupImage) { - SSKProtoGroupDetailsAvatarBuilder *avatarBuilder = [SSKProtoGroupDetailsAvatar builder]; - - [avatarBuilder setContentType:OWSMimeTypeImagePng]; - avatarPng = UIImagePNGRepresentation(group.groupImage); - [avatarBuilder setLength:(uint32_t)avatarPng.length]; - - NSError *error; - SSKProtoGroupDetailsAvatar *_Nullable avatarProto = [avatarBuilder buildAndReturnError:&error]; - if (error || !avatarProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - } else { - [groupBuilder setAvatar:avatarProto]; - } - } */ OWSDisappearingMessagesConfiguration *_Nullable disappearingMessagesConfiguration = [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:groupThread.uniqueId transaction:transaction]; @@ -72,12 +54,6 @@ NS_ASSUME_NONNULL_BEGIN [self writeUInt32:groupDataLength]; [self writeData:groupData]; - - /* - if (avatarPng) { - [self writeData:avatarPng]; - } - */ } @end diff --git a/SignalUtilitiesKit/OWSIdentityManager.h b/SignalUtilitiesKit/OWSIdentityManager.h index 49140fba6..c2e4e61a9 100644 --- a/SignalUtilitiesKit/OWSIdentityManager.h +++ b/SignalUtilitiesKit/OWSIdentityManager.h @@ -44,21 +44,6 @@ extern const NSUInteger kStoredIdentityKeyLength; - (void)generateNewIdentityKeyPair; - (void)clearIdentityKey; -- (void)setVerificationState:(OWSVerificationState)verificationState - identityKey:(NSData *)identityKey - recipientId:(NSString *)recipientId - isUserInitiatedChange:(BOOL)isUserInitiatedChange - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -- (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId; -- (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction; - -- (void)setVerificationState:(OWSVerificationState)verificationState - identityKey:(NSData *)identityKey - recipientId:(NSString *)recipientId - isUserInitiatedChange:(BOOL)isUserInitiatedChange; - - (nullable OWSRecipientIdentity *)recipientIdentityForRecipientId:(NSString *)recipientId; /** diff --git a/SignalUtilitiesKit/OWSIdentityManager.m b/SignalUtilitiesKit/OWSIdentityManager.m index c8cff86fb..9da61ac84 100644 --- a/SignalUtilitiesKit/OWSIdentityManager.m +++ b/SignalUtilitiesKit/OWSIdentityManager.m @@ -9,13 +9,9 @@ #import "NotificationsProtocol.h" #import "OWSError.h" #import "OWSFileSystem.h" -#import "OWSMessageSender.h" -#import "OWSOutgoingNullMessage.h" -#import "OWSPrimaryStorage+sessionStore.h" +#import "OWSPrimaryStorage+SessionStore.h" #import "OWSPrimaryStorage.h" #import "OWSRecipientIdentity.h" -#import "OWSVerificationStateChangeMessage.h" -#import "OWSVerificationStateSyncMessage.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" #import "TSContactThread.h" @@ -101,15 +97,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa [[NSNotificationCenter defaultCenter] removeObserver:self]; } -#pragma mark - Dependencies - -- (OWSMessageSender *)messageSender -{ - OWSAssertDebug(SSKEnvironment.shared.messageSender); - - return SSKEnvironment.shared.messageSender; -} - #pragma mark - - (void)observeNotifications @@ -283,115 +270,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa return NO; } -- (void)setVerificationState:(OWSVerificationState)verificationState - identityKey:(NSData *)identityKey - recipientId:(NSString *)recipientId - isUserInitiatedChange:(BOOL)isUserInitiatedChange -{ - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - OWSAssertDebug(recipientId.length > 0); - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self setVerificationState:verificationState - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:isUserInitiatedChange - transaction:transaction]; - }]; -} - -- (void)setVerificationState:(OWSVerificationState)verificationState - identityKey:(NSData *)identityKey - recipientId:(NSString *)recipientId - isUserInitiatedChange:(BOOL)isUserInitiatedChange - protocolContext:(nullable id)protocolContext -{ - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); - - YapDatabaseReadWriteTransaction *transaction = protocolContext; - - [self setVerificationState:verificationState - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:isUserInitiatedChange - transaction:transaction]; -} - -- (void)setVerificationState:(OWSVerificationState)verificationState - identityKey:(NSData *)identityKey - recipientId:(NSString *)recipientId - isUserInitiatedChange:(BOOL)isUserInitiatedChange - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - // Ensure a remote identity exists for this key. We may be learning about - // it for the first time. - [self saveRemoteIdentity:identityKey recipientId:recipientId protocolContext:transaction]; - - OWSRecipientIdentity *recipientIdentity = - [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId transaction:transaction]; - - if (recipientIdentity == nil) { - OWSFailDebug(@"Missing expected identity: %@", recipientId); - return; - } - - if (recipientIdentity.verificationState == verificationState) { - return; - } - - OWSLogInfo(@"setVerificationState: %@ (%@ -> %@)", - recipientId, - OWSVerificationStateToString(recipientIdentity.verificationState), - OWSVerificationStateToString(verificationState)); - - [recipientIdentity updateWithVerificationState:verificationState transaction:transaction]; - - if (isUserInitiatedChange) { - [self saveChangeMessagesForRecipientId:recipientId - verificationState:verificationState - isLocalChange:YES - transaction:transaction]; - [self enqueueSyncMessageForVerificationStateForRecipientId:recipientId transaction:transaction]; - } else { - // Cancel any pending verification state sync messages for this recipient. - [self clearSyncMessageForRecipientId:recipientId transaction:transaction]; - } - - [self fireIdentityStateChangeNotification]; -} - -- (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId -{ - __block OWSVerificationState result; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - result = [self verificationStateForRecipientId:recipientId transaction:transaction]; - }]; - return result; -} - -- (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - OWSRecipientIdentity *_Nullable currentIdentity = - [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId transaction:transaction]; - - if (!currentIdentity) { - // We might not know the identity for this recipient yet. - return OWSVerificationStateDefault; - } - - return currentIdentity.verificationState; -} - - (nullable OWSRecipientIdentity *)recipientIdentityForRecipientId:(NSString *)recipientId { OWSAssertDebug(recipientId.length > 0); @@ -585,6 +463,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (void)syncQueuedVerificationStates { + /* dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSMutableArray *recipientIds = [NSMutableArray new]; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { @@ -636,50 +515,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa } } }); -} - -- (void)sendSyncVerificationStateMessage:(OWSVerificationStateSyncMessage *)message -{ - OWSAssertDebug(message); - OWSAssertDebug(message.verificationForRecipientId.length > 0); - - TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:message.verificationForRecipientId]; - - // Send null message to appear as though we're sending a normal message to cover the sync messsage sent - // subsequently - OWSOutgoingNullMessage *nullMessage = [[OWSOutgoingNullMessage alloc] initWithContactThread:contactThread - verificationStateSyncMessage:message]; - - // DURABLE CLEANUP - we could replace the custom durability logic in this class - // with a durable JobQueue. - [self.messageSender sendMessage:nullMessage - success:^{ - OWSLogInfo(@"Successfully sent verification state NullMessage"); - [self.messageSender sendMessage:message - success:^{ - OWSLogInfo(@"Successfully sent verification state sync message"); - - // Record that this verification state was successfully synced. - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self clearSyncMessageForRecipientId:message.verificationForRecipientId - transaction:transaction]; - }]; - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send verification state sync message with error: %@", error); - }]; - } - failure:^(NSError *_Nonnull error) { - OWSLogError(@"Failed to send verification state NullMessage with error: %@", error); - if (error.code == OWSErrorCodeNoSuchSignalRecipient) { - OWSLogInfo(@"Removing retries for syncing verification state, since user is no longer registered: %@", - message.verificationForRecipientId); - // Otherwise this will fail forever. - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self clearSyncMessageForRecipientId:message.verificationForRecipientId transaction:transaction]; - }]; - } - }]; + */ } - (void)clearSyncMessageForRecipientId:(NSString *)recipientId @@ -848,50 +684,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa [recipientIdentity updateWithVerificationState:verificationState transaction:transaction]; - - [self saveChangeMessagesForRecipientId:recipientId - verificationState:verificationState - isLocalChange:NO - transaction:transaction]; - } -} - -// We only want to create change messages in response to user activity, -// on any of their devices. -- (void)saveChangeMessagesForRecipientId:(NSString *)recipientId - verificationState:(OWSVerificationState)verificationState - isLocalChange:(BOOL)isLocalChange - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - NSMutableArray *messages = [NSMutableArray new]; - - TSContactThread *contactThread = - [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; - OWSAssertDebug(contactThread); - // MJK TODO - should be safe to remove senderTimestamp - [messages addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:contactThread - recipientId:recipientId - verificationState:verificationState - isLocalChange:isLocalChange]]; - - for (TSGroupThread *groupThread in - [TSGroupThread groupThreadsWithRecipientId:recipientId transaction:transaction]) { - // MJK TODO - should be safe to remove senderTimestamp - [messages - addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:groupThread - recipientId:recipientId - verificationState:verificationState - isLocalChange:isLocalChange]]; - } - - // MJK TODO - why not save in-line, vs storing in an array and saving the array? - for (TSMessage *message in messages) { - [message saveWithTransaction:transaction]; } } diff --git a/SignalUtilitiesKit/OWSIncomingSentMessageTranscript.h b/SignalUtilitiesKit/OWSIncomingSentMessageTranscript.h deleted file mode 100644 index 02da7d4c0..000000000 --- a/SignalUtilitiesKit/OWSIncomingSentMessageTranscript.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSContact; -@class OWSLinkPreview; -@class SSKProtoAttachmentPointer; -@class SSKProtoDataMessage; -@class SSKProtoSyncMessageSent; -@class TSQuotedMessage; -@class TSThread; -@class YapDatabaseReadWriteTransaction; - -/** - * Represents notification of a message sent on our behalf from another device. - * E.g. When we send a message from Signal-Desktop we want to see it in our conversation on iPhone. - */ -@interface OWSIncomingSentMessageTranscript : NSObject - -- (instancetype)initWithProto:(SSKProtoSyncMessageSent *)sentProto - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -@property (nonatomic, readonly) SSKProtoDataMessage *dataMessage; -@property (nonatomic, readonly) NSString *recipientId; -@property (nonatomic, readonly) uint64_t timestamp; -@property (nonatomic, readonly) uint64_t expirationStartedAt; -@property (nonatomic, readonly) uint32_t expirationDuration; -@property (nonatomic, readonly) BOOL isGroupUpdate; -@property (nonatomic, readonly) BOOL isGroupQuit; -@property (nonatomic, readonly) BOOL isExpirationTimerUpdate; -@property (nonatomic, readonly) BOOL isEndSessionMessage; -@property (nonatomic, readonly, nullable) NSData *groupId; -@property (nonatomic, readonly) NSString *body; -@property (nonatomic, readonly) NSArray *attachmentPointerProtos; -@property (nonatomic, readonly, nullable) TSThread *thread; -@property (nonatomic, readonly, nullable) TSQuotedMessage *quotedMessage; -@property (nonatomic, readonly, nullable) OWSContact *contact; -@property (nonatomic, readonly, nullable) OWSLinkPreview *linkPreview; -@property (nonatomic, readonly) BOOL isRecipientUpdate; - -// If either nonUdRecipientIds or udRecipientIds is nil, -// this is either a legacy transcript or it reflects a legacy sync message. -@property (nonatomic, readonly, nullable) NSArray *nonUdRecipientIds; -@property (nonatomic, readonly, nullable) NSArray *udRecipientIds; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSIncomingSentMessageTranscript.m b/SignalUtilitiesKit/OWSIncomingSentMessageTranscript.m deleted file mode 100644 index 5c73f7347..000000000 --- a/SignalUtilitiesKit/OWSIncomingSentMessageTranscript.m +++ /dev/null @@ -1,108 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSIncomingSentMessageTranscript.h" -#import "OWSContact.h" -#import "OWSMessageManager.h" -#import "OWSPrimaryStorage.h" -#import "TSContactThread.h" -#import "TSGroupModel.h" -#import "TSGroupThread.h" -#import "TSOutgoingMessage.h" -#import "TSQuotedMessage.h" -#import "TSThread.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSIncomingSentMessageTranscript - -- (instancetype)initWithProto:(SSKProtoSyncMessageSent *)sentProto - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - self = [super init]; - if (!self) { - return self; - } - - _dataMessage = sentProto.message; - _recipientId = sentProto.destination; - _timestamp = sentProto.timestamp; - _expirationStartedAt = sentProto.expirationStartTimestamp; - _expirationDuration = sentProto.message.expireTimer; - _body = _dataMessage.body; - _groupId = _dataMessage.group.id; - _isGroupUpdate = _dataMessage.group != nil && (_dataMessage.group.type == SSKProtoGroupContextTypeUpdate); - _isGroupQuit = _dataMessage.group != nil && (_dataMessage.group.type == SSKProtoGroupContextTypeQuit); - _isExpirationTimerUpdate = (_dataMessage.flags & SSKProtoDataMessageFlagsExpirationTimerUpdate) != 0; - _isEndSessionMessage = (_dataMessage.flags & SSKProtoDataMessageFlagsEndSession) != 0; - _isRecipientUpdate = sentProto.isRecipientUpdate; - - if (self.isRecipientUpdate) { - // Fetch, don't create. We don't want recipient updates to resurrect messages or threads. - if (self.dataMessage.group) { - _thread = [TSGroupThread threadWithGroupId:_dataMessage.group.id transaction:transaction]; - } else { - OWSFailDebug(@"We should never receive a 'recipient update' for messages in contact threads."); - } - // Skip the other processing for recipient updates. - } else { - if (self.dataMessage.group) { - _thread = [TSGroupThread getOrCreateThreadWithGroupId:_dataMessage.group.id groupType:closedGroup transaction:transaction]; - } else { - _thread = [TSContactThread getOrCreateThreadWithContactId:_recipientId transaction:transaction]; - } - - _quotedMessage = - [TSQuotedMessage quotedMessageForDataMessage:_dataMessage thread:_thread transaction:transaction]; - _contact = [OWSContacts contactForDataMessage:_dataMessage transaction:transaction]; - - NSError *linkPreviewError; - _linkPreview = [OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:_dataMessage - body:_body - transaction:transaction - error:&linkPreviewError]; - if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) { - OWSLogError(@"linkPreviewError: %@", linkPreviewError); - } - } - - if (sentProto.unidentifiedStatus.count > 0) { - NSMutableArray *nonUdRecipientIds = [NSMutableArray new]; - NSMutableArray *udRecipientIds = [NSMutableArray new]; - for (SSKProtoSyncMessageSentUnidentifiedDeliveryStatus *statusProto in sentProto.unidentifiedStatus) { - if (!statusProto.hasDestination || statusProto.destination.length < 1) { - OWSFailDebug(@"Delivery status proto is missing destination."); - continue; - } - if (!statusProto.hasUnidentified) { - OWSFailDebug(@"Delivery status proto is missing value."); - continue; - } - NSString *recipientId = statusProto.destination; - if (statusProto.unidentified) { - [udRecipientIds addObject:recipientId]; - } else { - [nonUdRecipientIds addObject:recipientId]; - } - } - _nonUdRecipientIds = [nonUdRecipientIds copy]; - _udRecipientIds = [udRecipientIds copy]; - } - - return self; -} - -- (NSArray *)attachmentPointerProtos -{ - if (self.isGroupUpdate && self.dataMessage.group.avatar) { - return @[ self.dataMessage.group.avatar ]; - } else { - return self.dataMessage.attachments; - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.h b/SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.h deleted file mode 100644 index b9858bb3b..000000000 --- a/SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSLinkedDeviceReadReceipt : TSYapDatabaseObject - -@property (nonatomic, readonly) NSString *senderId; -@property (nonatomic, readonly) uint64_t messageIdTimestamp; -@property (nonatomic, readonly) uint64_t readTimestamp; - -- (instancetype)initWithSenderId:(NSString *)senderId - messageIdTimestamp:(uint64_t)messageIdtimestamp - readTimestamp:(uint64_t)readTimestamp; - -+ (nullable OWSLinkedDeviceReadReceipt *)findLinkedDeviceReadReceiptWithSenderId:(NSString *)senderId - messageIdTimestamp:(uint64_t)messageIdTimestamp - transaction: - (YapDatabaseReadTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.m b/SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.m deleted file mode 100644 index e113afa68..000000000 --- a/SignalUtilitiesKit/OWSLinkedDeviceReadReceipt.m +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSLinkedDeviceReadReceipt.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSLinkedDeviceReadReceipt - -- (instancetype)initWithSenderId:(NSString *)senderId - messageIdTimestamp:(uint64_t)messageIdTimestamp - readTimestamp:(uint64_t)readTimestamp -{ - OWSAssertDebug(senderId.length > 0 && messageIdTimestamp > 0); - - NSString *receiptId = - [OWSLinkedDeviceReadReceipt uniqueIdForSenderId:senderId messageIdTimestamp:messageIdTimestamp]; - self = [super initWithUniqueId:receiptId]; - if (!self) { - return self; - } - - _senderId = senderId; - _messageIdTimestamp = messageIdTimestamp; - _readTimestamp = readTimestamp; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - self = [super initWithCoder:coder]; - if (!self) { - return self; - } - - // renamed timestamp -> messageIdTimestamp - if (!_messageIdTimestamp) { - NSNumber *_Nullable legacyTimestamp = (NSNumber *)[coder decodeObjectForKey:@"timestamp"]; - OWSAssertDebug(legacyTimestamp.unsignedLongLongValue > 0); - _messageIdTimestamp = legacyTimestamp.unsignedLongLongValue; - } - - // For legacy objects, before we were tracking read time, use the original messages "sent" timestamp - // as the local read time. This will always be at least a little bit earlier than the message was - // actually read, which isn't ideal, but safer than persisting a disappearing message too long, especially - // since we know they read it on their linked desktop. - if (_readTimestamp == 0) { - _readTimestamp = _messageIdTimestamp; - } - - return self; -} - -+ (NSString *)uniqueIdForSenderId:(NSString *)senderId messageIdTimestamp:(uint64_t)messageIdTimestamp -{ - OWSAssertDebug(senderId.length > 0 && messageIdTimestamp > 0); - - return [NSString stringWithFormat:@"%@-%llu", senderId, messageIdTimestamp]; -} - -+ (nullable OWSLinkedDeviceReadReceipt *)findLinkedDeviceReadReceiptWithSenderId:(NSString *)senderId - messageIdTimestamp:(uint64_t)messageIdTimestamp - transaction: - (YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - NSString *receiptId = - [OWSLinkedDeviceReadReceipt uniqueIdForSenderId:senderId messageIdTimestamp:messageIdTimestamp]; - return [OWSLinkedDeviceReadReceipt fetchObjectWithUniqueID:receiptId transaction:transaction]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageServiceParams.h b/SignalUtilitiesKit/OWSMessageServiceParams.h index 3c4639e4d..42872d680 100644 --- a/SignalUtilitiesKit/OWSMessageServiceParams.h +++ b/SignalUtilitiesKit/OWSMessageServiceParams.h @@ -24,21 +24,13 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) BOOL silent; @property (nonatomic, readonly) BOOL online; -// Loki: Message ttl -@property (nonatomic, readonly) uint ttl; - -// Loki: Wether this message is a p2p ping -@property (nonatomic, readonly) BOOL isPing; - - (instancetype)initWithType:(TSWhisperMessageType)type recipientId:(NSString *)destination device:(int)deviceId content:(NSData *)content isSilent:(BOOL)isSilent isOnline:(BOOL)isOnline - registrationId:(int)registrationId - ttl:(uint)ttl - isPing:(BOOL)isPing; + registrationId:(int)registrationId; @end diff --git a/SignalUtilitiesKit/OWSMessageServiceParams.m b/SignalUtilitiesKit/OWSMessageServiceParams.m index d7a0cbf12..a2a66121c 100644 --- a/SignalUtilitiesKit/OWSMessageServiceParams.m +++ b/SignalUtilitiesKit/OWSMessageServiceParams.m @@ -22,8 +22,6 @@ NS_ASSUME_NONNULL_BEGIN isSilent:(BOOL)isSilent isOnline:(BOOL)isOnline registrationId:(int)registrationId - ttl:(uint)ttl - isPing:(BOOL)isPing { self = [super init]; @@ -38,8 +36,6 @@ NS_ASSUME_NONNULL_BEGIN _content = [content base64EncodedString]; _silent = isSilent; _online = isOnline; - _ttl = ttl; - _isPing = isPing; return self; } diff --git a/SignalUtilitiesKit/OWSMessageUtils.m b/SignalUtilitiesKit/OWSMessageUtils.m index c95c0ad1f..52ad56c4b 100644 --- a/SignalUtilitiesKit/OWSMessageUtils.m +++ b/SignalUtilitiesKit/OWSMessageUtils.m @@ -5,7 +5,7 @@ #import "OWSMessageUtils.h" #import "AppContext.h" #import "MIMETypeUtil.h" -#import "OWSMessageSender.h" + #import "OWSPrimaryStorage.h" #import "TSAccountManager.h" #import "TSAttachment.h" diff --git a/SignalUtilitiesKit/OWSOperation.m b/SignalUtilitiesKit/OWSOperation.m index 6bdfc712c..8cbd5f6e9 100644 --- a/SignalUtilitiesKit/OWSOperation.m +++ b/SignalUtilitiesKit/OWSOperation.m @@ -4,7 +4,6 @@ #import "OWSOperation.h" #import "NSError+MessageSending.h" -#import "NSTimer+OWS.h" #import "OWSBackgroundTask.h" #import "OWSError.h" #import diff --git a/SignalUtilitiesKit/OWSOutgoingCallMessage.h b/SignalUtilitiesKit/OWSOutgoingCallMessage.h deleted file mode 100644 index b7ef2f942..000000000 --- a/SignalUtilitiesKit/OWSOutgoingCallMessage.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class SSKProtoCallMessageAnswer; -@class SSKProtoCallMessageBusy; -@class SSKProtoCallMessageHangup; -@class SSKProtoCallMessageIceUpdate; -@class SSKProtoCallMessageOffer; -@class TSThread; - -/** - * WebRTC call signaling sent out of band, via the Signal Service - */ -@interface OWSOutgoingCallMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -- (instancetype)initWithThread:(TSThread *)thread offerMessage:(SSKProtoCallMessageOffer *)offerMessage; -- (instancetype)initWithThread:(TSThread *)thread answerMessage:(SSKProtoCallMessageAnswer *)answerMessage; -- (instancetype)initWithThread:(TSThread *)thread - iceUpdateMessages:(NSArray *)iceUpdateMessage; -- (instancetype)initWithThread:(TSThread *)thread hangupMessage:(SSKProtoCallMessageHangup *)hangupMessage; -- (instancetype)initWithThread:(TSThread *)thread busyMessage:(SSKProtoCallMessageBusy *)busyMessage; - -@property (nullable, nonatomic, readonly) SSKProtoCallMessageOffer *offerMessage; -@property (nullable, nonatomic, readonly) SSKProtoCallMessageAnswer *answerMessage; -@property (nullable, nonatomic, readonly) NSArray *iceUpdateMessages; -@property (nullable, nonatomic, readonly) SSKProtoCallMessageHangup *hangupMessage; -@property (nullable, nonatomic, readonly) SSKProtoCallMessageBusy *busyMessage; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSOutgoingCallMessage.m b/SignalUtilitiesKit/OWSOutgoingCallMessage.m deleted file mode 100644 index 7a59d300f..000000000 --- a/SignalUtilitiesKit/OWSOutgoingCallMessage.m +++ /dev/null @@ -1,196 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSOutgoingCallMessage.h" -#import "ProtoUtils.h" -#import "SignalRecipient.h" -#import "TSContactThread.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSOutgoingCallMessage - -- (instancetype)initWithThread:(TSThread *)thread -{ - // MJK TODO - safe to remove senderTimestamp - self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - if (!self) { - return self; - } - - return self; -} - -- (instancetype)initWithThread:(TSThread *)thread offerMessage:(SSKProtoCallMessageOffer *)offerMessage -{ - self = [self initWithThread:thread]; - if (!self) { - return self; - } - - _offerMessage = offerMessage; - - return self; -} - -- (instancetype)initWithThread:(TSThread *)thread answerMessage:(SSKProtoCallMessageAnswer *)answerMessage -{ - self = [self initWithThread:thread]; - if (!self) { - return self; - } - - _answerMessage = answerMessage; - - return self; -} - -- (instancetype)initWithThread:(TSThread *)thread - iceUpdateMessages:(NSArray *)iceUpdateMessages -{ - self = [self initWithThread:thread]; - if (!self) { - return self; - } - - _iceUpdateMessages = iceUpdateMessages; - - return self; -} - -- (instancetype)initWithThread:(TSThread *)thread hangupMessage:(SSKProtoCallMessageHangup *)hangupMessage -{ - self = [self initWithThread:thread]; - if (!self) { - return self; - } - - _hangupMessage = hangupMessage; - - return self; -} - -- (instancetype)initWithThread:(TSThread *)thread busyMessage:(SSKProtoCallMessageBusy *)busyMessage -{ - self = [self initWithThread:thread]; - if (!self) { - return self; - } - - _busyMessage = busyMessage; - - return self; -} - -#pragma mark - TSOutgoingMessage overrides - -- (BOOL)shouldSyncTranscript -{ - return NO; -} - -- (BOOL)isSilent -{ - // Avoid "phantom messages" for "outgoing call messages". - - return YES; -} - -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient -{ - OWSAssertDebug(recipient); - - SSKProtoContentBuilder *builder = [SSKProtoContent builder]; - [builder setCallMessage:[self buildCallMessage:recipient.recipientId]]; - - NSError *error; - NSData *_Nullable data = [builder buildSerializedDataAndReturnError:&error]; - if (error || !data) { - OWSFailDebug(@"could not serialize protobuf: %@", error); - return nil; - } - return data; -} - -- (nullable SSKProtoCallMessage *)buildCallMessage:(NSString *)recipientId -{ - SSKProtoCallMessageBuilder *builder = [SSKProtoCallMessage builder]; - - if (self.offerMessage) { - [builder setOffer:self.offerMessage]; - } - - if (self.answerMessage) { - [builder setAnswer:self.answerMessage]; - } - - if (self.iceUpdateMessages.count > 0) { - [builder setIceUpdate:self.iceUpdateMessages]; - } - - if (self.hangupMessage) { - [builder setHangup:self.hangupMessage]; - } - - if (self.busyMessage) { - [builder setBusy:self.busyMessage]; - } - - [ProtoUtils addLocalProfileKeyIfNecessary:self.thread recipientId:recipientId callMessageBuilder:builder]; - - NSError *error; - SSKProtoCallMessage *_Nullable result = [builder buildAndReturnError:&error]; - if (error || !result) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - return result; -} - -#pragma mark - TSYapDatabaseObject overrides - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeCall]; } - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (NSString *)debugDescription -{ - NSString *className = NSStringFromClass([self class]); - - NSString *payload; - if (self.offerMessage) { - payload = @"offerMessage"; - } else if (self.answerMessage) { - payload = @"answerMessage"; - } else if (self.iceUpdateMessages.count > 0) { - payload = [NSString stringWithFormat:@"iceUpdateMessages: %lu", (unsigned long)self.iceUpdateMessages.count]; - } else if (self.hangupMessage) { - payload = @"hangupMessage"; - } else if (self.busyMessage) { - payload = @"busyMessage"; - } else { - payload = @"none"; - } - - return [NSString stringWithFormat:@"%@ with payload: %@", className, payload]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSOutgoingNullMessage.h b/SignalUtilitiesKit/OWSOutgoingNullMessage.h deleted file mode 100644 index 1f767fb5d..000000000 --- a/SignalUtilitiesKit/OWSOutgoingNullMessage.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSVerificationStateSyncMessage; -@class TSContactThread; - -@interface OWSOutgoingNullMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview; - -- (instancetype)initWithContactThread:(TSContactThread *)contactThread - verificationStateSyncMessage:(OWSVerificationStateSyncMessage *)verificationStateSyncMessage; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSOutgoingNullMessage.m b/SignalUtilitiesKit/OWSOutgoingNullMessage.m deleted file mode 100644 index 9e27356fc..000000000 --- a/SignalUtilitiesKit/OWSOutgoingNullMessage.m +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSOutgoingNullMessage.h" -#import "OWSVerificationStateSyncMessage.h" -#import "TSContactThread.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSOutgoingNullMessage () - -@property (nonatomic, readonly) OWSVerificationStateSyncMessage *verificationStateSyncMessage; - -@end - -#pragma mark - - -@implementation OWSOutgoingNullMessage - -- (instancetype)initWithContactThread:(TSContactThread *)contactThread - verificationStateSyncMessage:(OWSVerificationStateSyncMessage *)verificationStateSyncMessage -{ - // MJK TODO - remove senderTimestamp - self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:contactThread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - if (!self) { - return self; - } - - _verificationStateSyncMessage = verificationStateSyncMessage; - - return self; -} - -#pragma mark - override TSOutgoingMessage - -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient -{ - SSKProtoNullMessageBuilder *nullMessageBuilder = [SSKProtoNullMessage builder]; - - NSUInteger contentLength; - if (self.verificationStateSyncMessage != nil) { - contentLength = self.verificationStateSyncMessage.unpaddedVerifiedLength; - - OWSAssertDebug(self.verificationStateSyncMessage.paddingBytesLength > 0); - - // We add the same amount of padding in the VerificationStateSync message and it's coresponding NullMessage so that - // the sync message is indistinguishable from an outgoing Sent transcript corresponding to the NullMessage. We pad - // the NullMessage so as to obscure it's content. The sync message (like all sync messages) will be *additionally* - // padded by the superclass while being sent. The end result is we send a NullMessage of a non-distinct size, and a - // verification sync which is ~1-512 bytes larger then that. - contentLength += self.verificationStateSyncMessage.paddingBytesLength; - } else { - contentLength = arc4random_uniform(512); - } - - OWSAssertDebug(contentLength > 0); - - nullMessageBuilder.padding = [Cryptography generateRandomBytes:contentLength]; - - NSError *error; - SSKProtoNullMessage *_Nullable nullMessage = [nullMessageBuilder buildAndReturnError:&error]; - if (error != nil || nullMessage == nil) { - OWSFailDebug(@"Couldn't build protobuf due to error: %@.", error); - return nil; - } - - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - contentBuilder.nullMessage = nullMessage; - - NSData *_Nullable contentData = [contentBuilder buildSerializedDataAndReturnError:&error]; - if (error != nil || contentData == nil) { - OWSFailDebug(@"Couldn't serialize protobuf due to error: %@.", error); - return nil; - } - - return contentData; -} - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeEphemeral]; } - -- (BOOL)shouldSyncTranscript -{ - return NO; -} - -- (BOOL)shouldBeSaved -{ - return NO; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSOutgoingReceiptManager.m b/SignalUtilitiesKit/OWSOutgoingReceiptManager.m index 64376c7a9..c66e7419a 100644 --- a/SignalUtilitiesKit/OWSOutgoingReceiptManager.m +++ b/SignalUtilitiesKit/OWSOutgoingReceiptManager.m @@ -5,9 +5,8 @@ #import "OWSOutgoingReceiptManager.h" #import "AppReadiness.h" #import "OWSError.h" -#import "OWSMessageSender.h" +#import #import "OWSPrimaryStorage.h" -#import "OWSReceiptsForSenderMessage.h" #import "SSKEnvironment.h" #import "TSContactThread.h" #import "TSYapDatabaseObject.h" @@ -79,15 +78,6 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa [[NSNotificationCenter defaultCenter] removeObserver:self]; } -#pragma mark - Dependencies - -- (OWSMessageSender *)messageSender -{ - OWSAssertDebug(SSKEnvironment.shared.messageSender); - - return SSKEnvironment.shared.messageSender; -} - #pragma mark - - (dispatch_queue_t)serialQueue @@ -178,7 +168,8 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa if (![LKSessionMetaProtocol shouldSendReceiptInThread:thread]) { continue; } - + + /* OWSReceiptsForSenderMessage *message; NSString *receiptName; switch (receiptType) { @@ -220,6 +211,7 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa }]; }]; [sendPromises addObject:sendPromise]; + */ } return [sendPromises copy]; diff --git a/SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.h b/SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.h deleted file mode 100644 index e100b72e9..000000000 --- a/SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSOutgoingMessage; - -/** - * Notifies your other registered devices (if you have any) that you've sent a message. - * This way the message you just sent can appear on all your devices. - */ -@interface OWSOutgoingSentMessageTranscript : OWSOutgoingSyncMessage - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithOutgoingMessage:(TSOutgoingMessage *)message - isRecipientUpdate:(BOOL)isRecipientUpdate NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.m b/SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.m deleted file mode 100644 index 96b96b9c7..000000000 --- a/SignalUtilitiesKit/OWSOutgoingSentMessageTranscript.m +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSOutgoingSentMessageTranscript.h" -#import "TSOutgoingMessage.h" -#import "TSThread.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface TSOutgoingMessage (OWSOutgoingSentMessageTranscript) - -/** - * Normally this is private, but we need to embed this - * data structure within our own. - * - * recipientId is nil when building "sent" sync messages for messages - * sent to groups. - */ -- (nullable SSKProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId; - -@end - -#pragma mark - - -@interface OWSOutgoingSentMessageTranscript () - -@property (nonatomic, readonly) TSOutgoingMessage *message; - -// sentRecipientId is the recipient of message, for contact thread messages. -// It is used to identify the thread/conversation to desktop. -@property (nonatomic, readonly, nullable) NSString *sentRecipientId; - -@property (nonatomic, readonly) BOOL isRecipientUpdate; - -@end - -#pragma mark - - -@implementation OWSOutgoingSentMessageTranscript - -- (instancetype)initWithOutgoingMessage:(TSOutgoingMessage *)message isRecipientUpdate:(BOOL)isRecipientUpdate -{ - self = [super initWithTimestamp:message.timestamp]; - - if (!self) { - return self; - } - - _message = message; - // This will be nil for groups. - _sentRecipientId = message.thread.contactIdentifier; - _isRecipientUpdate = isRecipientUpdate; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - SSKProtoSyncMessageSentBuilder *sentBuilder = [SSKProtoSyncMessageSent builder]; - [sentBuilder setTimestamp:self.message.timestamp]; - [sentBuilder setDestination:self.sentRecipientId]; - [sentBuilder setIsRecipientUpdate:self.isRecipientUpdate]; - - SSKProtoDataMessage *_Nullable dataMessage = [self.message buildDataMessage:self.sentRecipientId]; - if (!dataMessage) { - OWSFailDebug(@"could not build protobuf."); - return nil; - } - [sentBuilder setMessage:dataMessage]; - [sentBuilder setExpirationStartTimestamp:self.message.timestamp]; - - for (NSString *recipientId in self.message.sentRecipientIds) { - TSOutgoingMessageRecipientState *_Nullable recipientState = - [self.message recipientStateForRecipientId:recipientId]; - if (!recipientState) { - continue; - } - if (recipientState.state != OWSOutgoingMessageRecipientStateSent) { - OWSFailDebug(@"unexpected recipient state for: %@", recipientId); - continue; - } - - NSError *error; - SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder *statusBuilder = - [SSKProtoSyncMessageSentUnidentifiedDeliveryStatus builder]; - [statusBuilder setDestination:recipientId]; - [statusBuilder setUnidentified:recipientState.wasSentByUD]; - SSKProtoSyncMessageSentUnidentifiedDeliveryStatus *_Nullable status = - [statusBuilder buildAndReturnError:&error]; - if (error || !status) { - OWSFailDebug(@"Couldn't build UD status proto: %@", error); - continue; - } - [sentBuilder addUnidentifiedStatus:status]; - } - - NSError *error; - SSKProtoSyncMessageSent *_Nullable sentProto = [sentBuilder buildAndReturnError:&error]; - if (error || !sentProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - - SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder]; - [syncMessageBuilder setSent:sentProto]; - return syncMessageBuilder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSOutgoingSyncMessage.h b/SignalUtilitiesKit/OWSOutgoingSyncMessage.h deleted file mode 100644 index e5b2cf094..000000000 --- a/SignalUtilitiesKit/OWSOutgoingSyncMessage.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * Abstract base class used for the family of sync messages which take care - * of keeping your multiple registered devices consistent. E.g. sharing contacts, sharing groups, - * notifiying your devices of sent messages, and "read" receipts. - */ -@interface OWSOutgoingSyncMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -- (instancetype)initWithTimestamp:(uint64_t)timestamp; - -- (instancetype)init NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSOutgoingSyncMessage.m b/SignalUtilitiesKit/OWSOutgoingSyncMessage.m deleted file mode 100644 index a45c7b457..000000000 --- a/SignalUtilitiesKit/OWSOutgoingSyncMessage.m +++ /dev/null @@ -1,125 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSOutgoingSyncMessage.h" -#import "ProtoUtils.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSOutgoingSyncMessage - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (instancetype)init -{ - // MJK TODO - remove SenderTimestamp - self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:nil - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - - if (!self) { - return self; - } - - return self; -} - -- (instancetype)initWithTimestamp:(uint64_t)timestamp -{ - self = [super initOutgoingMessageWithTimestamp:timestamp - inThread:nil - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - - if (!self) { - return self; - } - - return self; -} - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeSync]; } - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (BOOL)shouldSyncTranscript -{ - return NO; -} - -// This method should not be overridden, since we want to add random padding to *every* sync message -- (nullable SSKProtoSyncMessage *)buildSyncMessage -{ - SSKProtoSyncMessageBuilder *_Nullable builder = [self syncMessageBuilder]; - if (!builder) { - return nil; - } - - // Add a random 1-512 bytes to obscure sync message type - size_t paddingBytesLength = arc4random_uniform(512) + 1; - builder.padding = [Cryptography generateRandomBytes:paddingBytesLength]; - - NSError *error; - SSKProtoSyncMessage *_Nullable proto = [builder buildAndReturnError:&error]; - if (error || !proto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - return proto; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - OWSAbstractMethod(); - - return [SSKProtoSyncMessage builder]; -} - -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient -{ - SSKProtoSyncMessage *_Nullable syncMessage = [self buildSyncMessage]; - if (!syncMessage) { - return nil; - } - - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - [contentBuilder setSyncMessage:syncMessage]; - - NSError *error; - NSData *_Nullable data = [contentBuilder buildSerializedDataAndReturnError:&error]; - if (error || !data) { - OWSFailDebug(@"could not serialize protobuf: %@", error); - return nil; - } - - return data; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSPreferences.m b/SignalUtilitiesKit/OWSPreferences.m index 41054c2bd..c72f9ecd1 100644 --- a/SignalUtilitiesKit/OWSPreferences.m +++ b/SignalUtilitiesKit/OWSPreferences.m @@ -215,8 +215,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (void)setShouldShowUnidentifiedDeliveryIndicators:(BOOL)value { [self setValueForKey:OWSPreferencesKeyShouldShowUnidentifiedDeliveryIndicators toValue:@(value)]; - - [SSKEnvironment.shared.syncManager sendConfigurationSyncMessage]; } #pragma mark - Calling diff --git a/SignalUtilitiesKit/OWSProfileKeyMessage.h b/SignalUtilitiesKit/OWSProfileKeyMessage.h deleted file mode 100644 index ea4ce83bb..000000000 --- a/SignalUtilitiesKit/OWSProfileKeyMessage.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSProfileKeyMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(nullable TSThread *)thread NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSProfileKeyMessage.m b/SignalUtilitiesKit/OWSProfileKeyMessage.m deleted file mode 100644 index 8682f01f4..000000000 --- a/SignalUtilitiesKit/OWSProfileKeyMessage.m +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSProfileKeyMessage.h" -#import "ProfileManagerProtocol.h" -#import "ProtoUtils.h" -#import "SSKEnvironment.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSProfileKeyMessage - -- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(nullable TSThread *)thread -{ - return [super initOutgoingMessageWithTimestamp:timestamp - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeProfileKey]; } - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (BOOL)shouldSyncTranscript -{ - return NO; -} - -- (nullable SSKProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId -{ - OWSAssertDebug(self.thread); - - SSKProtoDataMessageBuilder *_Nullable builder = [self dataMessageBuilder]; - if (!builder) { - OWSFailDebug(@"could not build protobuf."); - return nil; - } - [builder setTimestamp:self.timestamp]; - [ProtoUtils addLocalProfileKeyToDataMessageBuilder:builder]; - [builder setFlags:SSKProtoDataMessageFlagsProfileKeyUpdate]; - - if (recipientId.length > 0) { - // Once we've shared our profile key with a user (perhaps due to being - // a member of a whitelisted group), make sure they're whitelisted. - id profileManager = SSKEnvironment.shared.profileManager; - [profileManager addUserToProfileWhitelist:recipientId]; - } - - NSError *error; - SSKProtoDataMessage *_Nullable dataProto = [builder buildAndReturnError:&error]; - if (error || !dataProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - return dataProto; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSProvisioningMessage.h b/SignalUtilitiesKit/OWSProvisioningMessage.h deleted file mode 100644 index e4b22748f..000000000 --- a/SignalUtilitiesKit/OWSProvisioningMessage.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSProvisioningMessage : NSObject - -- (instancetype)initWithMyPublicKey:(NSData *)myPublicKey - myPrivateKey:(NSData *)myPrivateKey - theirPublicKey:(NSData *)theirPublicKey - accountIdentifier:(NSString *)accountIdentifier - profileKey:(NSData *)profileKey - readReceiptsEnabled:(BOOL)areReadReceiptsEnabled - provisioningCode:(NSString *)provisioningCode; - -- (nullable NSData *)buildEncryptedMessageBody; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSProvisioningMessage.m b/SignalUtilitiesKit/OWSProvisioningMessage.m deleted file mode 100644 index 91af10564..000000000 --- a/SignalUtilitiesKit/OWSProvisioningMessage.m +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSProvisioningMessage.h" -#import "OWSProvisioningCipher.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSProvisioningMessage () - -@property (nonatomic, readonly) NSData *myPublicKey; -@property (nonatomic, readonly) NSData *myPrivateKey; -@property (nonatomic, readonly) NSString *accountIdentifier; -@property (nonatomic, readonly) NSData *theirPublicKey; -@property (nonatomic, readonly) NSData *profileKey; -@property (nonatomic, readonly) BOOL areReadReceiptsEnabled; -@property (nonatomic, readonly) NSString *provisioningCode; - -@end - -@implementation OWSProvisioningMessage - -- (instancetype)initWithMyPublicKey:(NSData *)myPublicKey - myPrivateKey:(NSData *)myPrivateKey - theirPublicKey:(NSData *)theirPublicKey - accountIdentifier:(NSString *)accountIdentifier - profileKey:(NSData *)profileKey - readReceiptsEnabled:(BOOL)areReadReceiptsEnabled - provisioningCode:(NSString *)provisioningCode -{ - self = [super init]; - if (!self) { - return self; - } - - _myPublicKey = myPublicKey; - _myPrivateKey = myPrivateKey; - _theirPublicKey = theirPublicKey; - _accountIdentifier = accountIdentifier; - _profileKey = profileKey; - _areReadReceiptsEnabled = areReadReceiptsEnabled; - _provisioningCode = provisioningCode; - - return self; -} - -- (nullable NSData *)buildEncryptedMessageBody -{ - ProvisioningProtoProvisionMessageBuilder *messageBuilder = - [ProvisioningProtoProvisionMessage builderWithIdentityKeyPublic:self.myPublicKey - identityKeyPrivate:self.myPrivateKey - number:self.accountIdentifier - provisioningCode:self.provisioningCode - userAgent:@"OWI" - profileKey:self.profileKey - readReceipts:self.areReadReceiptsEnabled]; - - NSError *error; - NSData *_Nullable plainTextProvisionMessage = [messageBuilder buildSerializedDataAndReturnError:&error]; - if (!plainTextProvisionMessage || error) { - OWSFailDebug(@"could not serialize proto: %@.", error); - return nil; - } - - OWSProvisioningCipher *cipher = [[OWSProvisioningCipher alloc] initWithTheirPublicKey:self.theirPublicKey]; - NSData *_Nullable encryptedProvisionMessage = [cipher encrypt:plainTextProvisionMessage]; - if (encryptedProvisionMessage == nil) { - OWSFailDebug(@"Failed to encrypt provision message"); - return nil; - } - - // Note that this is a one-time-use *cipher* public key, not our Signal *identity* public key - ProvisioningProtoProvisionEnvelopeBuilder *envelopeBuilder = - [ProvisioningProtoProvisionEnvelope builderWithPublicKey:[cipher.ourPublicKey prependKeyType] - body:encryptedProvisionMessage]; - - NSData *_Nullable envelopeData = [envelopeBuilder buildSerializedDataAndReturnError:&error]; - if (!envelopeData || error) { - OWSFailDebug(@"could not serialize proto: %@.", error); - return nil; - } - - return envelopeData; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSQuotedReplyModel.m b/SignalUtilitiesKit/OWSQuotedReplyModel.m index a655b96a8..18a1aed67 100644 --- a/SignalUtilitiesKit/OWSQuotedReplyModel.m +++ b/SignalUtilitiesKit/OWSQuotedReplyModel.m @@ -6,7 +6,7 @@ #import "ConversationViewItem.h" #import #import -#import + #import #import #import @@ -149,26 +149,6 @@ NS_ASSUME_NONNULL_BEGIN } }(); OWSAssertDebug(authorId.length > 0); - - if (conversationItem.contactShare) { - ContactShareViewModel *contactShare = conversationItem.contactShare; - - // TODO We deliberately always pass `nil` for `thumbnailImage`, even though we might have a contactShare.avatarImage - // because the QuotedReplyViewModel has some hardcoded assumptions that only quoted attachments have - // thumbnails. Until we address that we want to be consistent about neither showing nor sending the - // contactShare avatar in the quoted reply. - return [[self alloc] initWithTimestamp:timestamp - authorId:authorId - body:[@"👤 " stringByAppendingString:contactShare.displayName] - bodySource:TSQuotedMessageContentSourceLocal - thumbnailImage:nil - contentType:nil - sourceFilename:nil - attachmentStream:nil - thumbnailAttachmentPointer:nil - thumbnailDownloadFailed:NO - threadId:@""]; - } NSString *_Nullable quotedText = message.body; BOOL hasText = quotedText.length > 0; diff --git a/SignalUtilitiesKit/OWSReadReceiptManager.m b/SignalUtilitiesKit/OWSReadReceiptManager.m index 934ce270a..161637226 100644 --- a/SignalUtilitiesKit/OWSReadReceiptManager.m +++ b/SignalUtilitiesKit/OWSReadReceiptManager.m @@ -4,12 +4,8 @@ #import "OWSReadReceiptManager.h" #import "AppReadiness.h" -#import "OWSLinkedDeviceReadReceipt.h" -#import "OWSMessageSender.h" #import "OWSOutgoingReceiptManager.h" #import "OWSPrimaryStorage.h" -#import "OWSReadReceiptsForLinkedDevicesMessage.h" -#import "OWSReceiptsForSenderMessage.h" #import "OWSStorage.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" @@ -122,7 +118,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE // we will send to our linked devices. // // Should only be accessed while synchronized on the OWSReadReceiptManager. -@property (nonatomic, readonly) NSMutableDictionary *toLinkedDevicesReadReceiptMap; +// @property (nonatomic, readonly) NSMutableDictionary *toLinkedDevicesReadReceiptMap; // Should only be accessed while synchronized on the OWSReadReceiptManager. @property (nonatomic) BOOL isProcessing; @@ -152,8 +148,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE _dbConnection = primaryStorage.newDatabaseConnection; - _toLinkedDevicesReadReceiptMap = [NSMutableDictionary new]; - OWSSingletonAssert(); // Start processing. @@ -171,11 +165,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE #pragma mark - Dependencies -- (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return SSKEnvironment.shared.messageSenderJobQueue; -} - - (OWSOutgoingReceiptManager *)outgoingReceiptManager { OWSAssertDebug(SSKEnvironment.shared.outgoingReceiptManager); @@ -206,6 +195,9 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)process { + // TODO TODO TODO + + /* @synchronized(self) { OWSLogVerbose(@"Processing read receipts."); @@ -241,6 +233,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE self.isProcessing = NO; } } + */ } #pragma mark - Mark as Read Locally @@ -262,6 +255,9 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)messageWasReadLocally:(TSIncomingMessage *)message { + // TODO TODO TODO + + /* dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(self) { @@ -298,6 +294,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE [self scheduleProcessing]; } }); + */ } #pragma mark - Read Receipts From Recipient @@ -375,6 +372,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)applyEarlyReadReceiptsForIncomingMessage:(TSIncomingMessage *)message transaction:(YapDatabaseReadWriteTransaction *)transaction { + /* OWSAssertDebug(message); OWSAssertDebug(transaction); @@ -395,12 +393,16 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE [message markAsReadAtTimestamp:readReceipt.readTimestamp sendReadReceipt:NO transaction:transaction]; [readReceipt removeWithTransaction:transaction]; + */ } - (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos readTimestamp:(uint64_t)readTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { + // TODO TODO TODO + + /* OWSAssertDebug(readReceiptProtos); OWSAssertDebug(transaction); @@ -439,6 +441,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE [readReceipt saveWithTransaction:transaction]; } } + */ } - (void)markAsReadOnLinkedDevice:(TSIncomingMessage *)message @@ -542,8 +545,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE forKey:OWSReadReceiptManagerAreReadReceiptsEnabled inCollection:OWSReadReceiptManagerCollection]; - [SSKEnvironment.shared.syncManager sendConfigurationSyncMessage]; - self.areReadReceiptsEnabledCached = @(value); } diff --git a/SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.h b/SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.h deleted file mode 100644 index cac1dc39a..000000000 --- a/SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSLinkedDeviceReadReceipt; - -@interface OWSReadReceiptsForLinkedDevicesMessage : OWSOutgoingSyncMessage - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithReadReceipts:(NSArray *)readReceipts NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.m b/SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.m deleted file mode 100644 index 72bc0dec8..000000000 --- a/SignalUtilitiesKit/OWSReadReceiptsForLinkedDevicesMessage.m +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSReadReceiptsForLinkedDevicesMessage.h" -#import "OWSLinkedDeviceReadReceipt.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSReadReceiptsForLinkedDevicesMessage () - -@property (nonatomic, readonly) NSArray *readReceipts; - -@end - -@implementation OWSReadReceiptsForLinkedDevicesMessage - -- (instancetype)initWithReadReceipts:(NSArray *)readReceipts -{ - self = [super init]; - if (!self) { - return self; - } - - _readReceipts = [readReceipts copy]; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder]; - for (OWSLinkedDeviceReadReceipt *readReceipt in self.readReceipts) { - SSKProtoSyncMessageReadBuilder *readProtoBuilder = - [SSKProtoSyncMessageRead builderWithSender:readReceipt.senderId timestamp:readReceipt.messageIdTimestamp]; - - NSError *error; - SSKProtoSyncMessageRead *_Nullable readProto = [readProtoBuilder buildAndReturnError:&error]; - if (error || !readProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - [syncMessageBuilder addRead:readProto]; - } - return syncMessageBuilder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSReceiptsForSenderMessage.h b/SignalUtilitiesKit/OWSReceiptsForSenderMessage.h deleted file mode 100644 index 30953ae87..000000000 --- a/SignalUtilitiesKit/OWSReceiptsForSenderMessage.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSDeliveryReceipt; - -@interface OWSReceiptsForSenderMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -+ (OWSReceiptsForSenderMessage *)deliveryReceiptsForSenderMessageWithThread:(nullable TSThread *)thread - messageTimestamps:(NSArray *)messageTimestamps; - -+ (OWSReceiptsForSenderMessage *)readReceiptsForSenderMessageWithThread:(nullable TSThread *)thread - messageTimestamps:(NSArray *)messageTimestamps; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSReceiptsForSenderMessage.m b/SignalUtilitiesKit/OWSReceiptsForSenderMessage.m deleted file mode 100644 index 0aca5877a..000000000 --- a/SignalUtilitiesKit/OWSReceiptsForSenderMessage.m +++ /dev/null @@ -1,139 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSReceiptsForSenderMessage.h" -#import "SignalRecipient.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSReceiptsForSenderMessage () - -@property (nonatomic, readonly) NSArray *messageTimestamps; - -@property (nonatomic, readonly) SSKProtoReceiptMessageType receiptType; - -@end - -#pragma mark - - -@implementation OWSReceiptsForSenderMessage - -+ (OWSReceiptsForSenderMessage *)deliveryReceiptsForSenderMessageWithThread:(nullable TSThread *)thread - messageTimestamps:(NSArray *)messageTimestamps -{ - return [[OWSReceiptsForSenderMessage alloc] initWithThread:thread - messageTimestamps:messageTimestamps - receiptType:SSKProtoReceiptMessageTypeDelivery]; -} - -+ (OWSReceiptsForSenderMessage *)readReceiptsForSenderMessageWithThread:(nullable TSThread *)thread - messageTimestamps:(NSArray *)messageTimestamps -{ - return [[OWSReceiptsForSenderMessage alloc] initWithThread:thread - messageTimestamps:messageTimestamps - receiptType:SSKProtoReceiptMessageTypeRead]; -} - -- (instancetype)initWithThread:(nullable TSThread *)thread - messageTimestamps:(NSArray *)messageTimestamps - receiptType:(SSKProtoReceiptMessageType)receiptType -{ - // MJK TODO - remove senderTimestamp - self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - if (!self) { - return self; - } - - _messageTimestamps = [messageTimestamps copy]; - _receiptType = receiptType; - - return self; -} - -#pragma mark - TSOutgoingMessage overrides - -- (BOOL)shouldSyncTranscript -{ - return NO; -} - -- (BOOL)isSilent -{ - // Avoid "phantom messages" for "recipient read receipts". - - return YES; -} - -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient -{ - OWSAssertDebug(recipient); - - SSKProtoReceiptMessage *_Nullable receiptMessage = [self buildReceiptMessage:recipient.recipientId]; - if (!receiptMessage) { - OWSFailDebug(@"could not build protobuf."); - return nil; - } - - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - [contentBuilder setReceiptMessage:receiptMessage]; - - NSError *error; - NSData *_Nullable contentData = [contentBuilder buildSerializedDataAndReturnError:&error]; - if (error || !contentData) { - OWSFailDebug(@"could not serialize protobuf: %@", error); - return nil; - } - return contentData; -} - -- (nullable SSKProtoReceiptMessage *)buildReceiptMessage:(NSString *)recipientId -{ - SSKProtoReceiptMessageBuilder *builder = [SSKProtoReceiptMessage builderWithType:self.receiptType]; - - OWSAssertDebug(self.messageTimestamps.count > 0); - for (NSNumber *messageTimestamp in self.messageTimestamps) { - [builder addTimestamp:[messageTimestamp unsignedLongLongValue]]; - } - - NSError *error; - SSKProtoReceiptMessage *_Nullable receiptMessage = [builder buildAndReturnError:&error]; - if (error || !receiptMessage) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - return receiptMessage; -} - -#pragma mark - TSYapDatabaseObject overrides - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (NSString *)debugDescription -{ - return [NSString - stringWithFormat:@"%@ with message timestamps: %lu", self.logTag, (unsigned long)self.messageTimestamps.count]; -} - -#pragma mark - Other - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeReceipt]; } - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSRecordTranscriptJob.m b/SignalUtilitiesKit/OWSRecordTranscriptJob.m index 6308e76ca..165734e75 100644 --- a/SignalUtilitiesKit/OWSRecordTranscriptJob.m +++ b/SignalUtilitiesKit/OWSRecordTranscriptJob.m @@ -5,14 +5,12 @@ #import "OWSRecordTranscriptJob.h" #import "OWSAttachmentDownloads.h" #import "OWSDisappearingMessagesJob.h" -#import "OWSIncomingSentMessageTranscript.h" #import "OWSPrimaryStorage+SessionStore.h" #import "OWSReadReceiptManager.h" #import "SSKEnvironment.h" #import "TSAttachmentPointer.h" #import "TSGroupThread.h" #import "TSInfoMessage.h" -#import "TSNetworkManager.h" #import "TSOutgoingMessage.h" #import "TSQuotedMessage.h" #import "TSThread.h" @@ -32,13 +30,6 @@ NS_ASSUME_NONNULL_BEGIN return SSKEnvironment.shared.primaryStorage; } -+ (TSNetworkManager *)networkManager -{ - OWSAssertDebug(SSKEnvironment.shared.networkManager); - - return SSKEnvironment.shared.networkManager; -} - + (OWSReadReceiptManager *)readReceiptManager { OWSAssert(SSKEnvironment.shared.readReceiptManager); @@ -46,13 +37,6 @@ NS_ASSUME_NONNULL_BEGIN return SSKEnvironment.shared.readReceiptManager; } -+ (id)contactsManager -{ - OWSAssertDebug(SSKEnvironment.shared.contactsManager); - - return SSKEnvironment.shared.contactsManager; -} - + (OWSAttachmentDownloads *)attachmentDownloads { return SSKEnvironment.shared.attachmentDownloads; @@ -67,6 +51,9 @@ NS_ASSUME_NONNULL_BEGIN NSArray *attachmentStreams))attachmentHandler transaction:(YapDatabaseReadWriteTransaction *)transaction { + // TODO TODO TODO + + /* OWSAssertDebug(transcript); OWSAssertDebug(transaction); @@ -108,7 +95,7 @@ NS_ASSUME_NONNULL_BEGIN if (transcript.thread.isGroupThread) { TSGroupThread *thread = (TSGroupThread *)transcript.thread; - if (thread.isPublicChat) { + if (thread.isOpenGroup) { [outgoingMessage setServerTimestampToReceivedTimestamp:serverTimestamp]; } } @@ -195,6 +182,7 @@ NS_ASSUME_NONNULL_BEGIN @"failed to fetch transcripts attachments for message: %@", outgoingMessage); }]; } + */ } #pragma mark - @@ -202,6 +190,9 @@ NS_ASSUME_NONNULL_BEGIN + (void)processRecipientUpdateWithTranscript:(OWSIncomingSentMessageTranscript *)transcript transaction:(YapDatabaseReadWriteTransaction *)transaction { + // TODO TODO TODO + + /* OWSAssertDebug(transcript); OWSAssertDebug(transaction); @@ -284,6 +275,7 @@ NS_ASSUME_NONNULL_BEGIN // This message may have disappeared. OWSLogError(@"No matching message with timestamp: %llu.", timestamp); } + */ } @end diff --git a/SignalUtilitiesKit/OWSRequestBuilder.h b/SignalUtilitiesKit/OWSRequestBuilder.h deleted file mode 100644 index b4879dc55..000000000 --- a/SignalUtilitiesKit/OWSRequestBuilder.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSRequest; - -@interface OWSRequestBuilder : NSObject - -+ (TSRequest *)profileNameSetRequestWithEncryptedPaddedName:(nullable NSData *)encryptedPaddedName; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSRequestBuilder.m b/SignalUtilitiesKit/OWSRequestBuilder.m deleted file mode 100644 index 74830bff1..000000000 --- a/SignalUtilitiesKit/OWSRequestBuilder.m +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSRequestBuilder.h" -#import "TSConstants.h" -#import "TSRequest.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -const NSUInteger kEncodedNameLength = 72; - -@implementation OWSRequestBuilder - -+ (TSRequest *)profileNameSetRequestWithEncryptedPaddedName:(nullable NSData *)encryptedPaddedName -{ - NSString *urlString; - - NSString *base64EncodedName = [encryptedPaddedName base64EncodedString]; - // name length must match exactly - if (base64EncodedName.length == kEncodedNameLength) { - // Remove any "/" in the base64 (all other base64 chars are URL safe. - // Apples built-in `stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URL*]]` doesn't offer a - // flavor for encoding "/". - NSString *urlEncodedName = [base64EncodedName stringByReplacingOccurrencesOfString:@"/" withString:@"%2F"]; - urlString = [NSString stringWithFormat:textSecureSetProfileNameAPIFormat, urlEncodedName]; - } else { - // if name length doesn't match exactly, assume blank name - OWSAssertDebug(encryptedPaddedName == nil); - urlString = [NSString stringWithFormat:textSecureSetProfileNameAPIFormat, @""]; - } - - NSURL *url = [NSURL URLWithString:urlString]; - TSRequest *request = [[TSRequest alloc] initWithURL:url]; - request.HTTPMethod = @"PUT"; - - return request; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSRequestFactory.h b/SignalUtilitiesKit/OWSRequestFactory.h deleted file mode 100644 index b3c6a28c7..000000000 --- a/SignalUtilitiesKit/OWSRequestFactory.h +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class ECKeyPair; -@class OWSDevice; -@class PreKeyRecord; -@class SMKUDAccessKey; -@class SignedPreKeyRecord; -@class TSRequest; - -typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVoice = 1, TSVerificationTransportSMS }; - -@interface OWSRequestFactory : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -+ (TSRequest *)enable2FARequestWithPin:(NSString *)pin; - -+ (TSRequest *)disable2FARequest; - -+ (TSRequest *)acknowledgeMessageDeliveryRequestWithSource:(NSString *)source timestamp:(UInt64)timestamp; - -+ (TSRequest *)acknowledgeMessageDeliveryRequestWithServerGuid:(NSString *)serverGuid; - -+ (TSRequest *)deleteDeviceRequestWithDevice:(OWSDevice *)device; - -+ (TSRequest *)deviceProvisioningCodeRequest; - -+ (TSRequest *)deviceProvisioningRequestWithMessageBody:(NSData *)messageBody ephemeralDeviceId:(NSString *)deviceId; - -+ (TSRequest *)getDevicesRequest; - -+ (TSRequest *)getMessagesRequest; - -+ (TSRequest *)getProfileRequestWithRecipientId:(NSString *)recipientId - udAccessKey:(nullable SMKUDAccessKey *)udAccessKey - NS_SWIFT_NAME(getProfileRequest(recipientId:udAccessKey:)); - -+ (TSRequest *)turnServerInfoRequest; - -+ (TSRequest *)allocAttachmentRequest; - -+ (TSRequest *)attachmentRequestWithAttachmentId:(UInt64)attachmentId; - -+ (TSRequest *)contactsIntersectionRequestWithHashesArray:(NSArray *)hashes; - -+ (TSRequest *)profileAvatarUploadFormRequest; - -+ (TSRequest *)registerForPushRequestWithPushIdentifier:(NSString *)identifier voipIdentifier:(NSString *)voipId; - -+ (TSRequest *)updateAttributesRequest; - -+ (TSRequest *)unregisterAccountRequest; - -+ (TSRequest *)requestVerificationCodeRequestWithPhoneNumber:(NSString *)phoneNumber - captchaToken:(nullable NSString *)captchaToken - transport:(TSVerificationTransport)transport; - -+ (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId - messages:(NSArray *)messages - timeStamp:(uint64_t)timeStamp - udAccessKey:(nullable SMKUDAccessKey *)udAccessKey; - -+ (TSRequest *)verifyCodeRequestWithVerificationCode:(NSString *)verificationCode - forNumber:(NSString *)phoneNumber - pin:(nullable NSString *)pin - authKey:(NSString *)authKey; - -#pragma mark - Prekeys - -+ (TSRequest *)availablePreKeysCountRequest; - -+ (TSRequest *)currentSignedPreKeyRequest; - -+ (TSRequest *)recipientPrekeyRequestWithRecipient:(NSString *)recipientNumber - deviceId:(NSString *)deviceId - udAccessKey:(nullable SMKUDAccessKey *)udAccessKey; - -+ (TSRequest *)registerSignedPrekeyRequestWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedPreKey; - -+ (TSRequest *)registerPrekeysRequestWithPrekeyArray:(NSArray *)prekeys - identityKey:(NSData *)identityKeyPublic - signedPreKey:(SignedPreKeyRecord *)signedPreKey; - -#pragma mark - CDS - -+ (TSRequest *)remoteAttestationRequest:(ECKeyPair *)keyPair - enclaveId:(NSString *)enclaveId - authUsername:(NSString *)authUsername - authPassword:(NSString *)authPassword; - -+ (TSRequest *)enclaveContactDiscoveryRequestWithId:(NSData *)requestId - addressCount:(NSUInteger)addressCount - encryptedAddressData:(NSData *)encryptedAddressData - cryptIv:(NSData *)cryptIv - cryptMac:(NSData *)cryptMac - enclaveId:(NSString *)enclaveId - authUsername:(NSString *)authUsername - authPassword:(NSString *)authPassword - cookies:(NSArray *)cookies; - -+ (TSRequest *)remoteAttestationAuthRequest; -+ (TSRequest *)cdsFeedbackRequestWithStatus:(NSString *)status - reason:(nullable NSString *)reason NS_SWIFT_NAME(cdsFeedbackRequest(status:reason:)); - -#pragma mark - UD - -+ (TSRequest *)udSenderCertificateRequest; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSRequestFactory.m b/SignalUtilitiesKit/OWSRequestFactory.m deleted file mode 100644 index 182fd35b8..000000000 --- a/SignalUtilitiesKit/OWSRequestFactory.m +++ /dev/null @@ -1,543 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSRequestFactory.h" -#import "OWS2FAManager.h" -#import "OWSDevice.h" -#import "ProfileManagerProtocol.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "TSConstants.h" -#import "TSRequest.h" -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSRequestFactory - -#pragma mark - Dependencies - -+ (TSAccountManager *)tsAccountManager -{ - return TSAccountManager.sharedInstance; -} - -+ (OWS2FAManager *)ows2FAManager -{ - return OWS2FAManager.sharedManager; -} - -+ (id)profileManager -{ - return SSKEnvironment.shared.profileManager; -} - -+ (id)udManager -{ - return SSKEnvironment.shared.udManager; -} - -#pragma mark - - -+ (TSRequest *)enable2FARequestWithPin:(NSString *)pin -{ - OWSAssertDebug(pin.length > 0); - - return [TSRequest requestWithUrl:[NSURL URLWithString:textSecure2FAAPI] - method:@"PUT" - parameters:@{ - @"pin" : pin, - }]; -} - -+ (TSRequest *)disable2FARequest -{ - return [TSRequest requestWithUrl:[NSURL URLWithString:textSecure2FAAPI] method:@"DELETE" parameters:@{}]; -} - -+ (TSRequest *)acknowledgeMessageDeliveryRequestWithSource:(NSString *)source timestamp:(UInt64)timestamp -{ - OWSAssertDebug(timestamp > 0); - - NSString *path = [NSString stringWithFormat:@"v1/messages/%@/%llu", source, timestamp]; - - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"DELETE" parameters:@{}]; -} - -+ (TSRequest *)acknowledgeMessageDeliveryRequestWithServerGuid:(NSString *)serverGuid -{ - OWSAssertDebug(serverGuid.length > 0); - - NSString *path = [NSString stringWithFormat:@"v1/messages/uuid/%@", serverGuid]; - - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"DELETE" parameters:@{}]; -} - -+ (TSRequest *)deleteDeviceRequestWithDevice:(OWSDevice *)device -{ - OWSAssertDebug(device); - - NSString *path = [NSString stringWithFormat:textSecureDevicesAPIFormat, @(device.deviceId)]; - - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"DELETE" parameters:@{}]; -} - -+ (TSRequest *)deviceProvisioningCodeRequest -{ - return [TSRequest requestWithUrl:[NSURL URLWithString:textSecureDeviceProvisioningCodeAPI] - method:@"GET" - parameters:@{}]; -} - -+ (TSRequest *)deviceProvisioningRequestWithMessageBody:(NSData *)messageBody ephemeralDeviceId:(NSString *)deviceId -{ - OWSAssertDebug(messageBody.length > 0); - OWSAssertDebug(deviceId.length > 0); - - NSString *path = [NSString stringWithFormat:textSecureDeviceProvisioningAPIFormat, deviceId]; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:@{ - @"body" : [messageBody base64EncodedString], - }]; -} - -+ (TSRequest *)getDevicesRequest -{ - NSString *path = [NSString stringWithFormat:textSecureDevicesAPIFormat, @""]; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)getMessagesRequest -{ - return [TSRequest requestWithUrl:[NSURL URLWithString:@"v1/messages"] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)getProfileRequestWithRecipientId:(NSString *)recipientId - udAccessKey:(nullable SMKUDAccessKey *)udAccessKey -{ - OWSAssertDebug(recipientId.length > 0); - - NSString *path = [NSString stringWithFormat:textSecureProfileAPIFormat, recipientId]; - TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; - if (udAccessKey != nil) { - [self useUDAuthWithRequest:request accessKey:udAccessKey]; - } - return request; -} - -+ (TSRequest *)turnServerInfoRequest -{ - return [TSRequest requestWithUrl:[NSURL URLWithString:@"v1/accounts/turn"] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)allocAttachmentRequest -{ - NSString *path = [NSString stringWithFormat:@"%@", textSecureAttachmentsAPI]; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)attachmentRequestWithAttachmentId:(UInt64)attachmentId -{ - OWSAssertDebug(attachmentId > 0); - - NSString *path = [NSString stringWithFormat:@"%@/%llu", textSecureAttachmentsAPI, attachmentId]; - - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)availablePreKeysCountRequest -{ - NSString *path = [NSString stringWithFormat:@"%@", textSecureKeysAPI]; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)contactsIntersectionRequestWithHashesArray:(NSArray *)hashes -{ - OWSAssertDebug(hashes.count > 0); - - NSString *path = [NSString stringWithFormat:@"%@/%@", textSecureDirectoryAPI, @"tokens"]; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:@{ - @"contacts" : hashes, - }]; -} - -+ (TSRequest *)currentSignedPreKeyRequest -{ - NSString *path = textSecureSignedKeysAPI; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)profileAvatarUploadFormRequest -{ - NSString *path = textSecureProfileAvatarFormAPI; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)recipientPrekeyRequestWithRecipient:(NSString *)recipientNumber - deviceId:(NSString *)deviceId - udAccessKey:(nullable SMKUDAccessKey *)udAccessKey -{ - OWSAssertDebug(recipientNumber.length > 0); - OWSAssertDebug(deviceId.length > 0); - - NSString *path = [NSString stringWithFormat:@"%@/%@/%@", textSecureKeysAPI, recipientNumber, deviceId]; - - TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; - if (udAccessKey != nil) { - [self useUDAuthWithRequest:request accessKey:udAccessKey]; - } - return request; -} - -+ (TSRequest *)registerForPushRequestWithPushIdentifier:(NSString *)identifier voipIdentifier:(NSString *)voipId -{ - OWSAssertDebug(identifier.length > 0); - OWSAssertDebug(voipId.length > 0); - - NSString *path = [NSString stringWithFormat:@"%@/%@", textSecureAccountsAPI, @"apn"]; - OWSAssertDebug(voipId); - return [TSRequest requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:@{ - @"apnRegistrationId" : identifier, - @"voipRegistrationId" : voipId ?: @"", - }]; -} - -+ (TSRequest *)updateAttributesRequest -{ - NSString *path = [textSecureAccountsAPI stringByAppendingString:textSecureAttributesAPI]; - - NSString *authKey = self.tsAccountManager.serverAuthToken; - NSString *_Nullable pin = [self.ows2FAManager pinCode]; - - NSDictionary *accountAttributes = [self accountAttributesWithPin:pin authKey:authKey]; - - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:accountAttributes]; -} - -+ (TSRequest *)unregisterAccountRequest -{ - NSString *path = [NSString stringWithFormat:@"%@/%@", textSecureAccountsAPI, @"apn"]; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"DELETE" parameters:@{}]; -} - -+ (TSRequest *)requestVerificationCodeRequestWithPhoneNumber:(NSString *)phoneNumber - captchaToken:(nullable NSString *)captchaToken - transport:(TSVerificationTransport)transport -{ - OWSAssertDebug(phoneNumber.length > 0); - - NSString *querystring = @"client=ios"; - if (captchaToken.length > 0) { - querystring = [NSString stringWithFormat:@"%@&captcha=%@", querystring, captchaToken]; - } - - NSString *path = [NSString stringWithFormat:@"%@/%@/code/%@?%@", - textSecureAccountsAPI, - [self stringForTransport:transport], - phoneNumber, - querystring]; - TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -// request.shouldHaveAuthorizationHeaders = NO; - - if (transport == TSVerificationTransportVoice) { - NSString *_Nullable localizationHeader = [self voiceCodeLocalizationHeader]; - if (localizationHeader.length > 0) { - [request setValue:localizationHeader forHTTPHeaderField:@"Accept-Language"]; - } - } - - return request; -} - -+ (nullable NSString *)voiceCodeLocalizationHeader -{ - NSLocale *locale = [NSLocale currentLocale]; - NSString *_Nullable languageCode = [locale objectForKey:NSLocaleLanguageCode]; - NSString *_Nullable countryCode = [locale objectForKey:NSLocaleCountryCode]; - - if (!languageCode) { - return nil; - } - - OWSAssertDebug([languageCode rangeOfString:@"-"].location == NSNotFound); - - if (!countryCode) { - // In the absence of a country code, just send a language code. - return languageCode; - } - - OWSAssertDebug(languageCode.length == 2); - OWSAssertDebug(countryCode.length == 2); - return [NSString stringWithFormat:@"%@-%@", languageCode, countryCode]; -} - -+ (NSString *)stringForTransport:(TSVerificationTransport)transport -{ - switch (transport) { - case TSVerificationTransportSMS: - return @"sms"; - case TSVerificationTransportVoice: - return @"voice"; - } -} - -+ (TSRequest *)verifyCodeRequestWithVerificationCode:(NSString *)verificationCode - forNumber:(NSString *)phoneNumber - pin:(nullable NSString *)pin - authKey:(NSString *)authKey -{ - OWSAssertDebug(verificationCode.length > 0); - OWSAssertDebug(phoneNumber.length > 0); - OWSAssertDebug(authKey.length > 0); - - NSString *path = [NSString stringWithFormat:@"%@/code/%@", textSecureAccountsAPI, verificationCode]; - - NSMutableDictionary *accountAttributes = - [[self accountAttributesWithPin:pin authKey:authKey] mutableCopy]; - [accountAttributes removeObjectForKey:@"AuthKey"]; - - TSRequest *request = - [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:accountAttributes]; - // The "verify code" request handles auth differently. -// request.authUsername = phoneNumber; -// request.authPassword = authKey; - return request; -} - -+ (NSDictionary *)accountAttributesWithPin:(nullable NSString *)pin - authKey:(NSString *)authKey -{ - uint32_t registrationId = [self.tsAccountManager getOrGenerateRegistrationId]; - - BOOL isManualMessageFetchEnabled = self.tsAccountManager.isManualMessageFetchEnabled; - - OWSAES256Key *profileKey = [self.profileManager localProfileKey]; - NSError *error; - SMKUDAccessKey *_Nullable udAccessKey = [[SMKUDAccessKey alloc] initWithProfileKey:profileKey.keyData error:&error]; - if (error || udAccessKey.keyData.length < 1) { - // Crash app if UD cannot be enabled. - OWSFail(@"Could not determine UD access key: %@.", error); - } - BOOL allowUnrestrictedUD = [self.udManager shouldAllowUnrestrictedAccessLocal] && udAccessKey != nil; - - // We no longer include the signalingKey. - NSMutableDictionary *accountAttributes = [@{ - @"AuthKey" : authKey, - @"voice" : @(YES), // all Signal-iOS clients support voice - @"video" : @(YES), // all Signal-iOS clients support WebRTC-based voice and video calls. - @"fetchesMessages" : @(isManualMessageFetchEnabled), // devices that don't support push must tell the server - // they fetch messages manually - @"registrationId" : [NSString stringWithFormat:@"%i", registrationId], - @"unidentifiedAccessKey" : udAccessKey.keyData.base64EncodedString, - @"unrestrictedUnidentifiedAccess" : @(allowUnrestrictedUD), - } mutableCopy]; - - if (pin.length > 0) { - accountAttributes[@"pin"] = pin; - } - - return [accountAttributes copy]; -} - -+ (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId - messages:(NSArray *)messages - timeStamp:(uint64_t)timeStamp - udAccessKey:(nullable SMKUDAccessKey *)udAccessKey -{ - // NOTE: messages may be empty; See comments in OWSDeviceManager. - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(timeStamp > 0); - - NSString *path = [textSecureMessagesAPI stringByAppendingString:recipientId]; - NSDictionary *parameters = @{ - @"messages" : messages, - @"timestamp" : @(timeStamp), - }; - - TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters]; - if (udAccessKey != nil) { - [self useUDAuthWithRequest:request accessKey:udAccessKey]; - } - return request; -} - -+ (TSRequest *)registerSignedPrekeyRequestWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedPreKey -{ - OWSAssertDebug(signedPreKey); - - NSString *path = textSecureSignedKeysAPI; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:[self dictionaryFromSignedPreKey:signedPreKey]]; -} - -+ (TSRequest *)registerPrekeysRequestWithPrekeyArray:(NSArray *)prekeys - identityKey:(NSData *)identityKeyPublic - signedPreKey:(SignedPreKeyRecord *)signedPreKey -{ - OWSAssertDebug(prekeys.count > 0); - OWSAssertDebug(identityKeyPublic.length > 0); - OWSAssertDebug(signedPreKey); - - NSString *path = textSecureKeysAPI; - NSString *publicIdentityKey = [[identityKeyPublic prependKeyType] base64EncodedStringWithOptions:0]; - NSMutableArray *serializedPrekeyList = [NSMutableArray array]; - for (PreKeyRecord *preKey in prekeys) { - [serializedPrekeyList addObject:[self dictionaryFromPreKey:preKey]]; - } - return [TSRequest requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:@{ - @"preKeys" : serializedPrekeyList, - @"signedPreKey" : [self dictionaryFromSignedPreKey:signedPreKey], - @"identityKey" : publicIdentityKey - }]; -} - -+ (NSDictionary *)dictionaryFromPreKey:(PreKeyRecord *)preKey -{ - return @{ - @"keyId" : @(preKey.Id), - @"publicKey" : [[preKey.keyPair.publicKey prependKeyType] base64EncodedStringWithOptions:0], - }; -} - -+ (NSDictionary *)dictionaryFromSignedPreKey:(SignedPreKeyRecord *)preKey -{ - return @{ - @"keyId" : @(preKey.Id), - @"publicKey" : [[preKey.keyPair.publicKey prependKeyType] base64EncodedStringWithOptions:0], - @"signature" : [preKey.signature base64EncodedStringWithOptions:0] - }; -} - -+ (TSRequest *)remoteAttestationRequest:(ECKeyPair *)keyPair - enclaveId:(NSString *)enclaveId - authUsername:(NSString *)authUsername - authPassword:(NSString *)authPassword -{ - OWSAssertDebug(keyPair); - OWSAssertDebug(enclaveId.length > 0); - OWSAssertDebug(authUsername.length > 0); - OWSAssertDebug(authPassword.length > 0); - - NSString *path = [NSString stringWithFormat:@"%@/v1/attestation/%@", contactDiscoveryURL, enclaveId]; - TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:@{ - // We DO NOT prepend the "key type" byte. - @"clientPublic" : [keyPair.publicKey base64EncodedStringWithOptions:0], - }]; -// request.authUsername = authUsername; -// request.authPassword = authPassword; - - // Don't bother with the default cookie store; - // these cookies are ephemeral. - // - // NOTE: TSNetworkManager now separately disables default cookie handling for all requests. - [request setHTTPShouldHandleCookies:NO]; - - return request; -} - -+ (TSRequest *)enclaveContactDiscoveryRequestWithId:(NSData *)requestId - addressCount:(NSUInteger)addressCount - encryptedAddressData:(NSData *)encryptedAddressData - cryptIv:(NSData *)cryptIv - cryptMac:(NSData *)cryptMac - enclaveId:(NSString *)enclaveId - authUsername:(NSString *)authUsername - authPassword:(NSString *)authPassword - cookies:(NSArray *)cookies -{ - NSString *path = [NSString stringWithFormat:@"%@/v1/discovery/%@", contactDiscoveryURL, enclaveId]; - - TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:@{ - @"requestId" : requestId.base64EncodedString, - @"addressCount" : @(addressCount), - @"data" : encryptedAddressData.base64EncodedString, - @"iv" : cryptIv.base64EncodedString, - @"mac" : cryptMac.base64EncodedString, - }]; - -// request.authUsername = authUsername; -// request.authPassword = authPassword; - - // Don't bother with the default cookie store; - // these cookies are ephemeral. - // - // NOTE: TSNetworkManager now separately disables default cookie handling for all requests. - [request setHTTPShouldHandleCookies:NO]; - // Set the cookie header. - OWSAssertDebug(request.allHTTPHeaderFields.count == 0); - [request setAllHTTPHeaderFields:[NSHTTPCookie requestHeaderFieldsWithCookies:cookies]]; - - return request; -} - -+ (TSRequest *)remoteAttestationAuthRequest -{ - NSString *path = @"/v1/directory/auth"; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (TSRequest *)cdsFeedbackRequestWithStatus:(NSString *)status - reason:(nullable NSString *)reason -{ - - NSDictionary *parameters; - if (reason == nil) { - parameters = @{}; - } else { - const NSUInteger kServerReasonLimit = 1000; - NSString *limitedReason; - if (reason.length < kServerReasonLimit) { - limitedReason = reason; - } else { - OWSFailDebug(@"failure: reason should be under 1000"); - limitedReason = [reason substringToIndex:kServerReasonLimit - 1]; - } - parameters = @{ @"reason": limitedReason }; - } - NSString *path = [NSString stringWithFormat:@"/v1/directory/feedback-v3/%@", status]; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters]; -} - -#pragma mark - UD - -+ (TSRequest *)udSenderCertificateRequest -{ - NSString *path = @"/v1/certificate/delivery"; - return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; -} - -+ (void)useUDAuthWithRequest:(TSRequest *)request accessKey:(SMKUDAccessKey *)udAccessKey -{ - OWSAssertDebug(request); - OWSAssertDebug(udAccessKey); - - // Suppress normal auth headers. -// request.shouldHaveAuthorizationHeaders = NO; - - // Add UD auth header. - [request setValue:[udAccessKey.keyData base64EncodedString] forHTTPHeaderField:@"Unidentified-Access-Key"]; - -// request.isUDRequest = YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSRequestMaker.swift b/SignalUtilitiesKit/OWSRequestMaker.swift deleted file mode 100644 index f87707b02..000000000 --- a/SignalUtilitiesKit/OWSRequestMaker.swift +++ /dev/null @@ -1,247 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - -@objc -public enum RequestMakerUDAuthError: Int, Error { - case udAuthFailure -} - -public enum RequestMakerError: Error { - case websocketRequestError(statusCode : Int, responseData : Data?, underlyingError : Error) -} - -@objc(OWSRequestMakerResult) -public class RequestMakerResult: NSObject { - @objc - public let responseObject: Any? - - @objc - public let wasSentByUD: Bool - - @objc - public let wasSentByWebsocket: Bool - - @objc - public init(responseObject: Any?, - wasSentByUD: Bool, - wasSentByWebsocket: Bool) { - self.responseObject = responseObject - self.wasSentByUD = wasSentByUD - self.wasSentByWebsocket = wasSentByWebsocket - } -} - -// A utility class that handles: -// -// * UD auth-to-Non-UD auth failover. -// * Websocket-to-REST failover. -@objc(OWSRequestMaker) -public class RequestMaker: NSObject { - - public typealias RequestFactoryBlock = (SMKUDAccessKey?) -> TSRequest - public typealias UDAuthFailureBlock = () -> Void - public typealias WebsocketFailureBlock = () -> Void - - private let label: String - private let requestFactoryBlock: RequestFactoryBlock - private let udAuthFailureBlock: UDAuthFailureBlock - private let websocketFailureBlock: WebsocketFailureBlock - private let recipientId: String - private let udAccess: OWSUDAccess? - private let canFailoverUDAuth: Bool - - @objc - public init(label: String, - requestFactoryBlock : @escaping RequestFactoryBlock, - udAuthFailureBlock : @escaping UDAuthFailureBlock, - websocketFailureBlock : @escaping WebsocketFailureBlock, - recipientId: String, - udAccess: OWSUDAccess?, - canFailoverUDAuth: Bool) { - self.label = label - self.requestFactoryBlock = requestFactoryBlock - self.udAuthFailureBlock = udAuthFailureBlock - self.websocketFailureBlock = websocketFailureBlock - self.recipientId = recipientId - self.udAccess = udAccess - self.canFailoverUDAuth = canFailoverUDAuth - } - - // MARK: - Dependencies - - private var socketManager: TSSocketManager { - return SSKEnvironment.shared.socketManager - } - - private var networkManager: TSNetworkManager { - return SSKEnvironment.shared.networkManager - } - - private var udManager: OWSUDManager { - return SSKEnvironment.shared.udManager - } - - private var profileManager: ProfileManagerProtocol { - return SSKEnvironment.shared.profileManager - } - - // MARK: - - - @objc - public func makeRequestObjc() -> AnyPromise { - let promise = makeRequest() - .recover(on: DispatchQueue.global()) { (error: Error) -> Promise in - switch error { - case NetworkManagerError.taskError(_, let underlyingError): - throw underlyingError - default: - throw error - } - } - let anyPromise = AnyPromise(promise) - anyPromise.retainUntilComplete() - return anyPromise - } - - public func makeRequest() -> Promise { - return makeRequestInternal(skipUD: false, skipWebsocket: false) - } - - private func makeRequestInternal(skipUD: Bool, skipWebsocket: Bool) -> Promise { - var udAccessForRequest: OWSUDAccess? - if !skipUD { - udAccessForRequest = udAccess - } - let isUDRequest: Bool = udAccessForRequest != nil - let request: TSRequest = requestFactoryBlock(udAccessForRequest?.udAccessKey) - let canMakeWebsocketRequests = (socketManager.canMakeRequests() && !skipWebsocket && !isUDRequest) - - if canMakeWebsocketRequests { - return Promise { resolver in - socketManager.make(request, success: { (responseObject: Any?) in - if self.udManager.isUDVerboseLoggingEnabled() { - if isUDRequest { - Logger.debug("UD websocket request '\(self.label)' succeeded.") - } else { - Logger.debug("Non-UD websocket request '\(self.label)' succeeded.") - } - } - - self.requestSucceeded(udAccess: udAccessForRequest) - - resolver.fulfill(RequestMakerResult(responseObject: responseObject, - wasSentByUD: isUDRequest, - wasSentByWebsocket: true)) - }) { (statusCode: Int, responseData: Data?, error: Error) in - resolver.reject(RequestMakerError.websocketRequestError(statusCode: statusCode, responseData: responseData, underlyingError: error)) - } - }.recover { (error: Error) -> Promise in - switch error { - case RequestMakerError.websocketRequestError(let statusCode, _, _): - if isUDRequest && (statusCode == 401 || statusCode == 403) { - // If a UD request fails due to service response (as opposed to network - // failure), mark recipient as _not_ in UD mode, then retry. - self.udManager.setUnidentifiedAccessMode(.disabled, recipientId: self.recipientId) - self.profileManager.fetchProfile(forRecipientId: self.recipientId) - self.udAuthFailureBlock() - - if self.canFailoverUDAuth { - Logger.info("UD websocket request '\(self.label)' auth failed; failing over to non-UD websocket request.") - return self.makeRequestInternal(skipUD: true, skipWebsocket: skipWebsocket) - } else { - Logger.info("UD websocket request '\(self.label)' auth failed; aborting.") - throw RequestMakerUDAuthError.udAuthFailure - } - } - break - default: - break - } - - self.websocketFailureBlock() - if isUDRequest { - Logger.info("UD Web socket request '\(self.label)' failed; failing over to REST request: \(error).") - } else { - Logger.info("Non-UD Web socket request '\(self.label)' failed; failing over to REST request: \(error).") - } - return self.makeRequestInternal(skipUD: skipUD, skipWebsocket: true) - } - } else { - return self.networkManager.makePromise(request: request) - .map(on: DispatchQueue.global()) { (networkManagerResult: TSNetworkManager.NetworkManagerResult) -> RequestMakerResult in - if self.udManager.isUDVerboseLoggingEnabled() { - if isUDRequest { - Logger.debug("UD REST request '\(self.label)' succeeded.") - } else { - Logger.debug("Non-UD REST request '\(self.label)' succeeded.") - } - } - - self.requestSucceeded(udAccess: udAccessForRequest) - - // Unwrap the network manager promise into a request maker promise. - return RequestMakerResult(responseObject: networkManagerResult.responseObject, - wasSentByUD: isUDRequest, - wasSentByWebsocket: false) - }.recover { (error: Error) -> Promise in - switch error { - case NetworkManagerError.taskError(let task, _): - let statusCode = task.statusCode() - if isUDRequest && (statusCode == 401 || statusCode == 403) { - // If a UD request fails due to service response (as opposed to network - // failure), mark recipient as _not_ in UD mode, then retry. - self.udManager.setUnidentifiedAccessMode(.disabled, recipientId: self.recipientId) - self.profileManager.fetchProfile(forRecipientId: self.recipientId) - self.udAuthFailureBlock() - - if self.canFailoverUDAuth { - Logger.info("UD REST request '\(self.label)' auth failed; failing over to non-UD REST request.") - return self.makeRequestInternal(skipUD: true, skipWebsocket: skipWebsocket) - } else { - Logger.info("UD REST request '\(self.label)' auth failed; aborting.") - throw RequestMakerUDAuthError.udAuthFailure - } - } - break - default: - break - } - - if isUDRequest { - Logger.debug("UD REST request '\(self.label)' failed: \(error).") - } else { - Logger.debug("Non-UD REST request '\(self.label)' failed: \(error).") - } - throw error - } - } - } - - private func requestSucceeded(udAccess: OWSUDAccess?) { - // If this was a UD request... - guard let udAccess = udAccess else { - return - } - // ...made for a user in "unknown" UD access mode... - guard udAccess.udAccessMode == .unknown else { - return - } - - if udAccess.isRandomKey { - // If a UD request succeeds for an unknown user with a random key, - // mark recipient as .unrestricted. - udManager.setUnidentifiedAccessMode(.unrestricted, recipientId: recipientId) - } else { - // If a UD request succeeds for an unknown user with a non-random key, - // mark recipient as .enabled. - udManager.setUnidentifiedAccessMode(.enabled, recipientId: recipientId) - } - DispatchQueue.main.async { - self.profileManager.fetchProfile(forRecipientId: self.recipientId) - } - } -} diff --git a/SignalUtilitiesKit/OWSSignalService.h b/SignalUtilitiesKit/OWSSignalService.h deleted file mode 100644 index 32d4b9583..000000000 --- a/SignalUtilitiesKit/OWSSignalService.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern NSString *const kNSNotificationName_IsCensorshipCircumventionActiveDidChange; - -@class AFHTTPSessionManager; -@class OWSPrimaryStorage; -@class TSAccountManager; - -@interface OWSSignalService : NSObject - -/// For uploading avatar assets. -@property (nonatomic, readonly) AFHTTPSessionManager *CDNSessionManager; - -+ (instancetype)sharedInstance; - -- (instancetype)init NS_UNAVAILABLE; - -#pragma mark - Censorship Circumvention - -@property (atomic, readonly) BOOL isCensorshipCircumventionActive; -@property (atomic, readonly) BOOL hasCensoredPhoneNumber; -@property (atomic) BOOL isCensorshipCircumventionManuallyActivated; -@property (atomic) BOOL isCensorshipCircumventionManuallyDisabled; -@property (atomic, nullable) NSString *manualCensorshipCircumventionCountryCode; - -/// For interacting with the Signal Service -- (AFHTTPSessionManager *)buildSignalServiceSessionManager; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSignalService.m b/SignalUtilitiesKit/OWSSignalService.m deleted file mode 100644 index 15d312f74..000000000 --- a/SignalUtilitiesKit/OWSSignalService.m +++ /dev/null @@ -1,328 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSSignalService.h" -#import "NSNotificationCenter+OWS.h" -#import "OWSCensorshipConfiguration.h" -#import "OWSError.h" -#import "OWSHTTPSecurityPolicy.h" -#import "OWSPrimaryStorage.h" -#import "TSAccountManager.h" -#import "TSConstants.h" -#import "YapDatabaseConnection+OWS.h" -#import -#import -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -NSString *const kOWSPrimaryStorage_OWSSignalService = @"kTSStorageManager_OWSSignalService"; -NSString *const kOWSPrimaryStorage_isCensorshipCircumventionManuallyActivated - = @"kTSStorageManager_isCensorshipCircumventionManuallyActivated"; -NSString *const kOWSPrimaryStorage_isCensorshipCircumventionManuallyDisabled - = @"kTSStorageManager_isCensorshipCircumventionManuallyDisabled"; -NSString *const kOWSPrimaryStorage_ManualCensorshipCircumventionDomain - = @"kTSStorageManager_ManualCensorshipCircumventionDomain"; -NSString *const kOWSPrimaryStorage_ManualCensorshipCircumventionCountryCode - = @"kTSStorageManager_ManualCensorshipCircumventionCountryCode"; - -NSString *const kNSNotificationName_IsCensorshipCircumventionActiveDidChange = - @"kNSNotificationName_IsCensorshipCircumventionActiveDidChange"; - -@interface OWSSignalService () - -@property (atomic) BOOL hasCensoredPhoneNumber; - -@property (atomic) BOOL isCensorshipCircumventionActive; - -@end - -#pragma mark - - -@implementation OWSSignalService - -@synthesize isCensorshipCircumventionActive = _isCensorshipCircumventionActive; - -+ (instancetype)sharedInstance -{ - static OWSSignalService *sharedInstance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedInstance = [[self alloc] initDefault]; - }); - return sharedInstance; -} - -- (instancetype)initDefault -{ - self = [super init]; - if (!self) { - return self; - } - - [self observeNotifications]; - - [self updateHasCensoredPhoneNumber]; - [self updateIsCensorshipCircumventionActive]; - - OWSSingletonAssert(); - - return self; -} - -- (void)observeNotifications -{ - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(registrationStateDidChange:) - name:RegistrationStateDidChangeNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(localNumberDidChange:) - name:kNSNotificationName_LocalNumberDidChange - object:nil]; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)updateHasCensoredPhoneNumber -{ - NSString *localNumber = [TSAccountManager localNumber]; - - if (localNumber) { - self.hasCensoredPhoneNumber = [OWSCensorshipConfiguration isCensoredPhoneNumber:localNumber]; - } else { - OWSLogError(@"no known phone number to check for censorship."); - self.hasCensoredPhoneNumber = NO; - } - - [self updateIsCensorshipCircumventionActive]; -} - -- (BOOL)isCensorshipCircumventionManuallyActivated -{ - return - [[OWSPrimaryStorage dbReadConnection] boolForKey:kOWSPrimaryStorage_isCensorshipCircumventionManuallyActivated - inCollection:kOWSPrimaryStorage_OWSSignalService - defaultValue:NO]; -} - -- (void)setIsCensorshipCircumventionManuallyActivated:(BOOL)value -{ - [[OWSPrimaryStorage dbReadWriteConnection] setObject:@(value) - forKey:kOWSPrimaryStorage_isCensorshipCircumventionManuallyActivated - inCollection:kOWSPrimaryStorage_OWSSignalService]; - - [self updateIsCensorshipCircumventionActive]; -} - -- (BOOL)isCensorshipCircumventionManuallyDisabled -{ - return [[OWSPrimaryStorage dbReadConnection] boolForKey:kOWSPrimaryStorage_isCensorshipCircumventionManuallyDisabled - inCollection:kOWSPrimaryStorage_OWSSignalService - defaultValue:NO]; -} - -- (void)setIsCensorshipCircumventionManuallyDisabled:(BOOL)value -{ - [[OWSPrimaryStorage dbReadWriteConnection] setObject:@(value) - forKey:kOWSPrimaryStorage_isCensorshipCircumventionManuallyDisabled - inCollection:kOWSPrimaryStorage_OWSSignalService]; - - [self updateIsCensorshipCircumventionActive]; -} - - -- (void)updateIsCensorshipCircumventionActive -{ - if (self.isCensorshipCircumventionManuallyDisabled) { - self.isCensorshipCircumventionActive = NO; - } else if (self.isCensorshipCircumventionManuallyActivated) { - self.isCensorshipCircumventionActive = YES; - } else if (self.hasCensoredPhoneNumber) { - self.isCensorshipCircumventionActive = YES; - } else { - self.isCensorshipCircumventionActive = NO; - } -} - -- (void)setIsCensorshipCircumventionActive:(BOOL)isCensorshipCircumventionActive -{ - @synchronized(self) - { - if (_isCensorshipCircumventionActive == isCensorshipCircumventionActive) { - return; - } - - _isCensorshipCircumventionActive = isCensorshipCircumventionActive; - } - - [[NSNotificationCenter defaultCenter] - postNotificationNameAsync:kNSNotificationName_IsCensorshipCircumventionActiveDidChange - object:nil - userInfo:nil]; -} - -- (BOOL)isCensorshipCircumventionActive -{ - @synchronized(self) - { - return _isCensorshipCircumventionActive; - } -} - -- (AFHTTPSessionManager *)buildSignalServiceSessionManager -{ - if (self.isCensorshipCircumventionActive) { - OWSCensorshipConfiguration *censorshipConfiguration = [self buildCensorshipConfiguration]; - OWSLogInfo(@"using reflector HTTPSessionManager via: %@", censorshipConfiguration.domainFrontBaseURL); - return [self reflectorSignalServiceSessionManagerWithCensorshipConfiguration:censorshipConfiguration]; - } else { - return self.defaultSignalServiceSessionManager; - } -} - -- (AFHTTPSessionManager *)defaultSignalServiceSessionManager -{ - NSURLSessionConfiguration *configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration; - AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration]; - AFSecurityPolicy *securityPolicy = AFSecurityPolicy.defaultPolicy; - // Snode to snode communication uses self-signed certificates but clients can safely ignore this - securityPolicy.allowInvalidCertificates = YES; - securityPolicy.validatesDomainName = NO; - sessionManager.securityPolicy = securityPolicy; - sessionManager.requestSerializer = [AFJSONRequestSerializer serializer]; - sessionManager.requestSerializer.HTTPShouldHandleCookies = NO; - sessionManager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments]; - NSMutableSet *acceptableContentTypes = sessionManager.responseSerializer.acceptableContentTypes.mutableCopy; - [acceptableContentTypes addObject:@"text/plain"]; - sessionManager.responseSerializer.acceptableContentTypes = acceptableContentTypes; - return sessionManager; -} - -- (AFHTTPSessionManager *)reflectorSignalServiceSessionManagerWithCensorshipConfiguration: - (OWSCensorshipConfiguration *)censorshipConfiguration -{ - NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; - AFHTTPSessionManager *sessionManager = - [[AFHTTPSessionManager alloc] initWithBaseURL:censorshipConfiguration.domainFrontBaseURL - sessionConfiguration:sessionConf]; - - sessionManager.securityPolicy = censorshipConfiguration.domainFrontSecurityPolicy; - - sessionManager.requestSerializer = [AFJSONRequestSerializer serializer]; - [sessionManager.requestSerializer setValue:censorshipConfiguration.signalServiceReflectorHost - forHTTPHeaderField:@"Host"]; - sessionManager.responseSerializer = [AFJSONResponseSerializer serializer]; - // Disable default cookie handling for all requests. - sessionManager.requestSerializer.HTTPShouldHandleCookies = NO; - - return sessionManager; -} - -#pragma mark - Profile Uploading - -- (AFHTTPSessionManager *)CDNSessionManager -{ - if (self.isCensorshipCircumventionActive) { - OWSCensorshipConfiguration *censorshipConfiguration = [self buildCensorshipConfiguration]; - OWSLogInfo(@"using reflector CDNSessionManager via: %@", censorshipConfiguration.domainFrontBaseURL); - return [self reflectorCDNSessionManagerWithCensorshipConfiguration:censorshipConfiguration]; - } else { - return self.defaultCDNSessionManager; - } -} - -- (AFHTTPSessionManager *)defaultCDNSessionManager -{ - NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; - AFHTTPSessionManager *sessionManager = - [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf]; - - sessionManager.securityPolicy = [OWSHTTPSecurityPolicy sharedPolicy]; - - // Default acceptable content headers are rejected by AWS - sessionManager.responseSerializer.acceptableContentTypes = nil; - - return sessionManager; -} - -- (AFHTTPSessionManager *)reflectorCDNSessionManagerWithCensorshipConfiguration: - (OWSCensorshipConfiguration *)censorshipConfiguration -{ - NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration; - - AFHTTPSessionManager *sessionManager = - [[AFHTTPSessionManager alloc] initWithBaseURL:censorshipConfiguration.domainFrontBaseURL - sessionConfiguration:sessionConf]; - - sessionManager.securityPolicy = censorshipConfiguration.domainFrontSecurityPolicy; - - sessionManager.requestSerializer = [AFJSONRequestSerializer serializer]; - [sessionManager.requestSerializer setValue:censorshipConfiguration.CDNReflectorHost forHTTPHeaderField:@"Host"]; - - sessionManager.responseSerializer = [AFJSONResponseSerializer serializer]; - - return sessionManager; -} - -#pragma mark - Events - -- (void)registrationStateDidChange:(NSNotification *)notification -{ - [self updateHasCensoredPhoneNumber]; -} - -- (void)localNumberDidChange:(NSNotification *)notification -{ - [self updateHasCensoredPhoneNumber]; -} - -#pragma mark - Manual Censorship Circumvention - -- (OWSCensorshipConfiguration *)buildCensorshipConfiguration -{ - OWSAssertDebug(self.isCensorshipCircumventionActive); - - if (self.isCensorshipCircumventionManuallyActivated) { - NSString *countryCode = self.manualCensorshipCircumventionCountryCode; - if (countryCode.length == 0) { - OWSFailDebug(@"manualCensorshipCircumventionCountryCode was unexpectedly 0"); - } - - OWSCensorshipConfiguration *configuration = - [OWSCensorshipConfiguration censorshipConfigurationWithCountryCode:countryCode]; - OWSAssertDebug(configuration); - - return configuration; - } - - OWSCensorshipConfiguration *_Nullable configuration = - [OWSCensorshipConfiguration censorshipConfigurationWithPhoneNumber:TSAccountManager.localNumber]; - if (configuration != nil) { - return configuration; - } - - return OWSCensorshipConfiguration.defaultConfiguration; -} - -- (nullable NSString *)manualCensorshipCircumventionCountryCode -{ - return - [[OWSPrimaryStorage dbReadConnection] objectForKey:kOWSPrimaryStorage_ManualCensorshipCircumventionCountryCode - inCollection:kOWSPrimaryStorage_OWSSignalService]; -} - -- (void)setManualCensorshipCircumventionCountryCode:(nullable NSString *)value -{ - [[OWSPrimaryStorage dbReadWriteConnection] setObject:value - forKey:kOWSPrimaryStorage_ManualCensorshipCircumventionCountryCode - inCollection:kOWSPrimaryStorage_OWSSignalService]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncConfigurationMessage.h b/SignalUtilitiesKit/OWSSyncConfigurationMessage.h deleted file mode 100644 index d30025fa0..000000000 --- a/SignalUtilitiesKit/OWSSyncConfigurationMessage.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSSyncConfigurationMessage : OWSOutgoingSyncMessage - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithReadReceiptsEnabled:(BOOL)readReceiptsEnabled - showUnidentifiedDeliveryIndicators:(BOOL)showUnidentifiedDeliveryIndicators - showTypingIndicators:(BOOL)showTypingIndicators - sendLinkPreviews:(BOOL)sendLinkPreviews NS_DESIGNATED_INITIALIZER; - -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncConfigurationMessage.m b/SignalUtilitiesKit/OWSSyncConfigurationMessage.m deleted file mode 100644 index 1254b7856..000000000 --- a/SignalUtilitiesKit/OWSSyncConfigurationMessage.m +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSSyncConfigurationMessage.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSSyncConfigurationMessage () - -@property (nonatomic, readonly) BOOL areReadReceiptsEnabled; -@property (nonatomic, readonly) BOOL showUnidentifiedDeliveryIndicators; -@property (nonatomic, readonly) BOOL showTypingIndicators; -@property (nonatomic, readonly) BOOL sendLinkPreviews; - -@end - -@implementation OWSSyncConfigurationMessage - -- (instancetype)initWithReadReceiptsEnabled:(BOOL)areReadReceiptsEnabled - showUnidentifiedDeliveryIndicators:(BOOL)showUnidentifiedDeliveryIndicators - showTypingIndicators:(BOOL)showTypingIndicators - sendLinkPreviews:(BOOL)sendLinkPreviews -{ - self = [super init]; - if (!self) { - return nil; - } - - _areReadReceiptsEnabled = areReadReceiptsEnabled; - _showUnidentifiedDeliveryIndicators = showUnidentifiedDeliveryIndicators; - _showTypingIndicators = showTypingIndicators; - _sendLinkPreviews = sendLinkPreviews; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - SSKProtoSyncMessageConfigurationBuilder *configurationBuilder = [SSKProtoSyncMessageConfiguration builder]; - configurationBuilder.readReceipts = self.areReadReceiptsEnabled; - configurationBuilder.unidentifiedDeliveryIndicators = self.showUnidentifiedDeliveryIndicators; - configurationBuilder.typingIndicators = self.showTypingIndicators; - configurationBuilder.linkPreviews = self.sendLinkPreviews; - - NSError *error; - SSKProtoSyncMessageConfiguration *_Nullable configurationProto = [configurationBuilder buildAndReturnError:&error]; - if (error || !configurationProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - - SSKProtoSyncMessageBuilder *builder = [SSKProtoSyncMessage builder]; - builder.configuration = configurationProto; - return builder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncContactsMessage.h b/SignalUtilitiesKit/OWSSyncContactsMessage.h deleted file mode 100644 index b91471516..000000000 --- a/SignalUtilitiesKit/OWSSyncContactsMessage.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@protocol ProfileManagerProtocol; - -@class OWSIdentityManager; -@class SignalAccount; - -@interface OWSSyncContactsMessage : OWSOutgoingSyncMessage - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithSignalAccounts:(NSArray *)signalAccounts - identityManager:(OWSIdentityManager *)identityManager - profileManager:(id)profileManager NS_DESIGNATED_INITIALIZER; - -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -- (nullable NSData *)buildPlainTextAttachmentDataWithTransaction:(YapDatabaseReadTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncContactsMessage.m b/SignalUtilitiesKit/OWSSyncContactsMessage.m deleted file mode 100644 index 8747fd31e..000000000 --- a/SignalUtilitiesKit/OWSSyncContactsMessage.m +++ /dev/null @@ -1,157 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSSyncContactsMessage.h" -#import "Contact.h" -#import "ContactsManagerProtocol.h" -#import "OWSContactsOutputStream.h" -#import "OWSIdentityManager.h" -#import "ProfileManagerProtocol.h" -#import "ProtoUtils.h" -#import "SSKEnvironment.h" -#import "SignalAccount.h" -#import "TSAccountManager.h" -#import "TSAttachment.h" -#import "TSAttachmentStream.h" -#import "TSContactThread.h" -#import -#import -#import "OWSPrimaryStorage.h" - -@import Contacts; - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSSyncContactsMessage () - -@property (nonatomic, readonly) NSArray *signalAccounts; -@property (nonatomic, readonly) OWSIdentityManager *identityManager; -@property (nonatomic, readonly) id profileManager; - -@end - -@implementation OWSSyncContactsMessage - -- (instancetype)initWithSignalAccounts:(NSArray *)signalAccounts - identityManager:(OWSIdentityManager *)identityManager - profileManager:(id)profileManager -{ - self = [super init]; - if (!self) { - return self; - } - - _signalAccounts = signalAccounts; - _identityManager = identityManager; - _profileManager = profileManager; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -#pragma mark - Dependencies - -- (id)contactsManager { - return SSKEnvironment.shared.contactsManager; -} - -- (TSAccountManager *)tsAccountManager { - return TSAccountManager.sharedInstance; -} - -#pragma mark - - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - NSError *error; - if (self.attachmentIds.count > 1) { - OWSLogError(@"Expected sync contact message to have one or zero attachments, but found %lu.", (unsigned long)self.attachmentIds.count); - } - - SSKProtoSyncMessageContactsBuilder *contactsBuilder; - if (self.attachmentIds.count == 0) { - SSKProtoAttachmentPointerBuilder *attachmentProtoBuilder = [SSKProtoAttachmentPointer builderWithId:0]; - SSKProtoAttachmentPointer *attachmentProto = [attachmentProtoBuilder buildAndReturnError:&error]; - contactsBuilder = [SSKProtoSyncMessageContacts builder]; - [contactsBuilder setBlob:attachmentProto]; - __block NSData *data; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - data = [self buildPlainTextAttachmentDataWithTransaction:transaction]; - }]; - [contactsBuilder setData:data]; - } else { - SSKProtoAttachmentPointer *attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; - if (attachmentProto == nil) { - OWSFailDebug(@"Couldn't build protobuf."); - return nil; - } - contactsBuilder = [SSKProtoSyncMessageContacts builder]; - [contactsBuilder setBlob:attachmentProto]; - } - [contactsBuilder setIsComplete:YES]; - - SSKProtoSyncMessageContacts *contactsProto = [contactsBuilder buildAndReturnError:&error]; - if (error || contactsProto == nil) { - OWSFailDebug(@"Couldn't build protobuf due to error: %@.", error); - return nil; - } - SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder]; - [syncMessageBuilder setContacts:contactsProto]; - - return syncMessageBuilder; -} - -- (nullable NSData *)buildPlainTextAttachmentDataWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - NSMutableArray *signalAccounts = [self.signalAccounts mutableCopy]; - - // TODO use temp file stream to avoid loading everything into memory at once - // First though, we need to re-engineer our attachment process to accept streams (encrypting with stream, - // and uploading with streams). - NSOutputStream *dataOutputStream = [NSOutputStream outputStreamToMemory]; - [dataOutputStream open]; - OWSContactsOutputStream *contactsOutputStream = - [[OWSContactsOutputStream alloc] initWithOutputStream:dataOutputStream]; - - for (SignalAccount *signalAccount in signalAccounts) { - OWSRecipientIdentity *_Nullable recipientIdentity = - [self.identityManager recipientIdentityForRecipientId:signalAccount.recipientId]; - NSData *_Nullable profileKeyData = [self.profileManager profileKeyDataForRecipientId:signalAccount.recipientId]; - - OWSDisappearingMessagesConfiguration *_Nullable disappearingMessagesConfiguration; - NSString *conversationColorName; - - TSContactThread *_Nullable contactThread = [TSContactThread getThreadWithContactId:signalAccount.recipientId transaction:transaction]; - if (contactThread) { - conversationColorName = contactThread.conversationColorName; - disappearingMessagesConfiguration = [contactThread disappearingMessagesConfigurationWithTransaction:transaction]; - } else { - conversationColorName = [TSThread stableColorNameForNewConversationWithString:signalAccount.recipientId]; - } - - [contactsOutputStream writeSignalAccount:signalAccount - recipientIdentity:recipientIdentity - profileKeyData:profileKeyData - contactsManager:self.contactsManager - conversationColorName:conversationColorName - disappearingMessagesConfiguration:disappearingMessagesConfiguration]; - } - - [dataOutputStream close]; - - if (contactsOutputStream.hasError) { - OWSFailDebug(@"Could not write contacts sync stream."); - return nil; - } - - return [dataOutputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncGroupsMessage.h b/SignalUtilitiesKit/OWSSyncGroupsMessage.h deleted file mode 100644 index 59f105718..000000000 --- a/SignalUtilitiesKit/OWSSyncGroupsMessage.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class YapDatabaseReadTransaction; -@class TSGroupThread; - -@interface OWSSyncGroupsMessage : OWSOutgoingSyncMessage - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithGroupThread:(TSGroupThread *)thread NS_DESIGNATED_INITIALIZER; - -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -- (nullable NSData *)buildPlainTextAttachmentDataWithTransaction:(YapDatabaseReadTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncGroupsMessage.m b/SignalUtilitiesKit/OWSSyncGroupsMessage.m deleted file mode 100644 index f4440de44..000000000 --- a/SignalUtilitiesKit/OWSSyncGroupsMessage.m +++ /dev/null @@ -1,104 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSSyncGroupsMessage.h" -#import "OWSGroupsOutputStream.h" -#import "TSAttachment.h" -#import "TSAttachmentStream.h" -#import "TSContactThread.h" -#import "TSGroupModel.h" -#import "TSGroupThread.h" -#import -#import -#import "OWSPrimaryStorage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSSyncGroupsMessage () - -@property (nonatomic, readonly) TSGroupThread *groupThread; - -@end - -@implementation OWSSyncGroupsMessage - -- (instancetype)initWithGroupThread:(TSGroupThread *)thread -{ - self = [super init]; - if (!self) { - return self; - } - - _groupThread = thread; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - NSError *error; - if (self.attachmentIds.count > 1) { - OWSLogError(@"Expected sync group message to have one or zero attachments, but found %lu.", (unsigned long)self.attachmentIds.count); - } - - SSKProtoSyncMessageGroupsBuilder *groupsBuilder; - if (self.attachmentIds.count == 0) { - SSKProtoAttachmentPointerBuilder *attachmentProtoBuilder = [SSKProtoAttachmentPointer builderWithId:0]; - SSKProtoAttachmentPointer *attachmentProto = [attachmentProtoBuilder buildAndReturnError:&error]; - groupsBuilder = [SSKProtoSyncMessageGroups builder]; - [groupsBuilder setBlob:attachmentProto]; - __block NSData *data; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - data = [self buildPlainTextAttachmentDataWithTransaction:transaction]; - }]; - [groupsBuilder setData:data]; - } else { - SSKProtoAttachmentPointer *attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; - if (attachmentProto == nil) { - OWSFailDebug(@"Couldn't build protobuf."); - return nil; - } - groupsBuilder = [SSKProtoSyncMessageGroups builder]; - [groupsBuilder setBlob:attachmentProto]; - } - - SSKProtoSyncMessageGroups *_Nullable groupsProto = [groupsBuilder buildAndReturnError:&error]; - if (error || !groupsProto) { - OWSFailDebug(@"Couldn't build protobuf due to error: %@.", error); - return nil; - } - - SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder]; - [syncMessageBuilder setGroups:groupsProto]; - - return syncMessageBuilder; -} - -- (nullable NSData *)buildPlainTextAttachmentDataWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - // TODO use temp file stream to avoid loading everything into memory at once - // First though, we need to re-engineer our attachment process to accept streams (encrypting with stream, - // and uploading with streams). - NSOutputStream *dataOutputStream = [NSOutputStream outputStreamToMemory]; - [dataOutputStream open]; - OWSGroupsOutputStream *groupsOutputStream = [[OWSGroupsOutputStream alloc] initWithOutputStream:dataOutputStream]; - [groupsOutputStream writeGroup:self.groupThread transaction:transaction]; - [dataOutputStream close]; - - if (groupsOutputStream.hasError) { - OWSFailDebug(@"Could not write groups sync stream."); - return nil; - } - - return [dataOutputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncGroupsRequestMessage.h b/SignalUtilitiesKit/OWSSyncGroupsRequestMessage.h deleted file mode 100644 index fd1a14541..000000000 --- a/SignalUtilitiesKit/OWSSyncGroupsRequestMessage.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSSyncGroupsRequestMessage : TSOutgoingMessage - -- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSMutableArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - isVoiceMessage:(BOOL)isVoiceMessage - groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; - -- (instancetype)initWithThread:(nullable TSThread *)thread groupId:(NSData *)groupId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncGroupsRequestMessage.m b/SignalUtilitiesKit/OWSSyncGroupsRequestMessage.m deleted file mode 100644 index 41962325c..000000000 --- a/SignalUtilitiesKit/OWSSyncGroupsRequestMessage.m +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSSyncGroupsRequestMessage.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSSyncGroupsRequestMessage () - -@property (nonatomic) NSData *groupId; - -@end - -#pragma mark - - -@implementation OWSSyncGroupsRequestMessage - -- (instancetype)initWithThread:(nullable TSThread *)thread groupId:(NSData *)groupId -{ - // MJK TODO - remove senderTimestamp - self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:nil - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - if (!self) { - return self; - } - - OWSAssertDebug(groupId.length > 0); - _groupId = groupId; - - return self; -} - -- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeSync]; } - -- (BOOL)shouldBeSaved -{ - return NO; -} - -- (BOOL)shouldSyncTranscript -{ - return NO; -} - -- (BOOL)isSilent -{ - // Avoid "phantom messages" - - return YES; -} - -- (nullable id)dataMessageBuilder -{ - SSKProtoGroupContextBuilder *groupContextBuilder = - [SSKProtoGroupContext builderWithId:self.groupId type:SSKProtoGroupContextTypeRequestInfo]; - - NSError *error; - SSKProtoGroupContext *_Nullable groupContextProto = [groupContextBuilder buildAndReturnError:&error]; - if (error || !groupContextProto) { - OWSFailDebug(@"could not build protobuf: %@", error); - return nil; - } - - SSKProtoDataMessageBuilder *builder = [SSKProtoDataMessage builder]; - [builder setTimestamp:self.timestamp]; - [builder setGroup:groupContextProto]; - - return builder; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncManager.h b/SignalUtilitiesKit/OWSSyncManager.h deleted file mode 100644 index cdea1f23c..000000000 --- a/SignalUtilitiesKit/OWSSyncManager.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class AnyPromise; -@class OWSContactsManager; -@class OWSIdentityManager; -@class OWSMessageSender; -@class OWSProfileManager; - -@interface OWSSyncManager : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initDefault NS_DESIGNATED_INITIALIZER; - -+ (instancetype)shared; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSSyncManager.m b/SignalUtilitiesKit/OWSSyncManager.m deleted file mode 100644 index d7e043956..000000000 --- a/SignalUtilitiesKit/OWSSyncManager.m +++ /dev/null @@ -1,337 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSSyncManager.h" -#import "Environment.h" -#import "OWSContactsManager.h" -#import "OWSPreferences.h" -#import "OWSProfileManager.h" -#import "OWSReadReceiptManager.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -NSString *const kSyncManagerCollection = @"kTSStorageManagerOWSSyncManagerCollection"; -NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManagerLastMessageKey"; - -@interface OWSSyncManager () - -@property (nonatomic, readonly) dispatch_queue_t serialQueue; - -@property (nonatomic) BOOL isRequestInFlight; - -@end - -@implementation OWSSyncManager - -+ (instancetype)shared { - OWSAssertDebug(SSKEnvironment.shared.syncManager); - - return SSKEnvironment.shared.syncManager; -} - -- (instancetype)initDefault { - self = [super init]; - - if (!self) { - return self; - } - - OWSSingletonAssert(); - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(signalAccountsDidChange:) - name:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(profileKeyDidChange:) - name:kNSNotificationName_ProfileKeyDidChange - object:nil]; - - return self; -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -#pragma mark - Dependencies - -- (OWSContactsManager *)contactsManager { - OWSAssertDebug(Environment.shared.contactsManager); - - return Environment.shared.contactsManager; -} - -- (OWSIdentityManager *)identityManager { - OWSAssertDebug(SSKEnvironment.shared.identityManager); - - return SSKEnvironment.shared.identityManager; -} - -- (OWSMessageSender *)messageSender { - OWSAssertDebug(SSKEnvironment.shared.messageSender); - - return SSKEnvironment.shared.messageSender; -} - -- (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - OWSAssertDebug(SSKEnvironment.shared.messageSenderJobQueue); - - return SSKEnvironment.shared.messageSenderJobQueue; -} - -- (OWSProfileManager *)profileManager { - OWSAssertDebug(SSKEnvironment.shared.profileManager); - - return SSKEnvironment.shared.profileManager; -} - -- (TSAccountManager *)tsAccountManager -{ - return TSAccountManager.sharedInstance; -} - -- (id)typingIndicators -{ - return SSKEnvironment.shared.typingIndicators; -} - -#pragma mark - Notifications - -- (void)signalAccountsDidChange:(id)notification { - OWSAssertIsOnMainThread(); - - [self sendSyncContactsMessageIfPossible]; -} - -- (void)profileKeyDidChange:(id)notification { - OWSAssertIsOnMainThread(); - - [self sendSyncContactsMessageIfPossible]; -} - -#pragma mark - - -- (YapDatabaseConnection *)editingDatabaseConnection -{ - return OWSPrimaryStorage.sharedManager.dbReadWriteConnection; -} - -- (YapDatabaseConnection *)readDatabaseConnection -{ - return OWSPrimaryStorage.sharedManager.dbReadConnection; -} - -#pragma mark - Methods - -- (void)sendSyncContactsMessageIfNecessary { - OWSAssertIsOnMainThread(); - - if (!self.serialQueue) { - _serialQueue = dispatch_queue_create("org.whispersystems.contacts.syncing", DISPATCH_QUEUE_SERIAL); - } - - dispatch_async(self.serialQueue, ^{ - if (self.isRequestInFlight) { - // De-bounce. It's okay if we ignore some new changes; - // `sendSyncContactsMessageIfPossible` is called fairly - // often so we'll sync soon. - return; - } - - OWSSyncContactsMessage *syncContactsMessage = - [[OWSSyncContactsMessage alloc] initWithSignalAccounts:self.contactsManager.signalAccounts - identityManager:self.identityManager - profileManager:self.profileManager]; - - __block NSData *_Nullable messageData; - __block NSData *_Nullable lastMessageData; - [self.readDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - messageData = [syncContactsMessage buildPlainTextAttachmentDataWithTransaction:transaction]; - lastMessageData = [transaction objectForKey:kSyncManagerLastContactSyncKey - inCollection:kSyncManagerCollection]; - }]; - - if (!messageData) { - OWSFailDebug(@"Failed to serialize contacts sync message."); - return; - } - - if (lastMessageData && [lastMessageData isEqual:messageData]) { - // Ignore redundant contacts sync message. - return; - } - - self.isRequestInFlight = YES; - - // DURABLE CLEANUP - we could replace the custom durability logic in this class - // with a durable JobQueue. - DataSource *dataSource = [DataSourceValue dataSourceWithSyncMessageData:messageData]; - [self.messageSender sendTemporaryAttachment:dataSource - contentType:OWSMimeTypeApplicationOctetStream - inMessage:syncContactsMessage - success:^{ - OWSLogInfo(@"Successfully sent contacts sync message."); - - [self.editingDatabaseConnection setObject:messageData - forKey:kSyncManagerLastContactSyncKey - inCollection:kSyncManagerCollection]; - - dispatch_async(self.serialQueue, ^{ - self.isRequestInFlight = NO; - }); - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send contacts sync message with error: %@", error); - - dispatch_async(self.serialQueue, ^{ - self.isRequestInFlight = NO; - }); - }]; - }); -} - -- (void)sendSyncContactsMessageIfPossible { - OWSAssertIsOnMainThread(); - - if (!self.contactsManager.isSetup) { - // Don't bother if the contacts manager hasn't finished setup. - return; - } - - if ([TSAccountManager sharedInstance].isRegisteredAndReady) { - [self sendSyncContactsMessageIfNecessary]; - } -} - -- (void)sendConfigurationSyncMessage { - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - if (!self.tsAccountManager.isRegisteredAndReady) { - return; - } - - [self sendConfigurationSyncMessage_AppReady]; - }]; -} - -- (void)sendConfigurationSyncMessage_AppReady { - DDLogInfo(@""); - - if (![TSAccountManager sharedInstance].isRegisteredAndReady) { - return; - } - - BOOL areReadReceiptsEnabled = SSKEnvironment.shared.readReceiptManager.areReadReceiptsEnabled; - BOOL showUnidentifiedDeliveryIndicators = Environment.shared.preferences.shouldShowUnidentifiedDeliveryIndicators; - BOOL showTypingIndicators = self.typingIndicators.areTypingIndicatorsEnabled; - BOOL sendLinkPreviews = SSKPreferences.areLinkPreviewsEnabled; - - OWSSyncConfigurationMessage *syncConfigurationMessage = - [[OWSSyncConfigurationMessage alloc] initWithReadReceiptsEnabled:areReadReceiptsEnabled - showUnidentifiedDeliveryIndicators:showUnidentifiedDeliveryIndicators - showTypingIndicators:showTypingIndicators - sendLinkPreviews:sendLinkPreviews]; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:syncConfigurationMessage transaction:transaction]; - }]; -} - -#pragma mark - Local Sync - -- (AnyPromise *)syncLocalContact -{ - NSString *localNumber = self.tsAccountManager.localNumber; - SignalAccount *signalAccount = [[SignalAccount alloc] initWithRecipientId:localNumber]; - signalAccount.contact = [Contact new]; - - return [self syncContactsForSignalAccounts:@[ signalAccount ]]; -} - -- (AnyPromise *)syncContact:(NSString *)hexEncodedPubKey transaction:(YapDatabaseReadTransaction *)transaction -{ - return [LKSyncMessagesProtocol syncContactWithPublicKey:hexEncodedPubKey]; -} - -- (AnyPromise *)syncAllContacts -{ - return [LKSyncMessagesProtocol syncAllContacts]; -} - -- (AnyPromise *)syncContactsForSignalAccounts:(NSArray *)signalAccounts -{ - OWSSyncContactsMessage *syncContactsMessage = [[OWSSyncContactsMessage alloc] initWithSignalAccounts:signalAccounts identityManager:self.identityManager profileManager:self.profileManager]; - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - [self.messageSender sendMessage:syncContactsMessage - success:^{ - OWSLogInfo(@"Successfully sent contacts sync message."); - resolve(@(1)); - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send contacts sync message with error: %@.", error); - resolve(error); - }]; - }]; - [promise retainUntilComplete]; - return promise; -} - -- (AnyPromise *)syncAllGroups -{ - return [LKSyncMessagesProtocol syncAllClosedGroups]; -} - -- (AnyPromise *)syncGroupForThread:(TSGroupThread *)thread -{ - if (thread.usesSharedSenderKeys) { - __block AnyPromise *promise; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - promise = [LKSyncMessagesProtocol syncClosedGroup:thread transaction:transaction]; - }]; - return promise; - } else { - OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] initWithGroupThread:thread]; - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - [self.messageSender sendMessage:syncGroupsMessage - success:^{ - OWSLogInfo(@"Successfully sent group sync message."); - resolve(@(1)); - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send group sync message due to error: %@.", error); - resolve(error); - }]; - }]; - [promise retainUntilComplete]; - return promise; - } -} - -- (AnyPromise *)syncAllOpenGroups -{ - return [LKSyncMessagesProtocol syncAllOpenGroups]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSUDManager.swift b/SignalUtilitiesKit/OWSUDManager.swift index 7d2138f75..8dc897062 100644 --- a/SignalUtilitiesKit/OWSUDManager.swift +++ b/SignalUtilitiesKit/OWSUDManager.swift @@ -77,13 +77,13 @@ public class OWSUDAccess: NSObject { func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String) @objc - func unidentifiedAccessMode(forRecipientId recipientId: RecipientIdentifier) -> UnidentifiedAccessMode + func unidentifiedAccessMode(forRecipientId recipientId: String) -> UnidentifiedAccessMode @objc - func udAccessKey(forRecipientId recipientId: RecipientIdentifier) -> SMKUDAccessKey? + func udAccessKey(forRecipientId recipientId: String) -> SMKUDAccessKey? @objc - func udAccess(forRecipientId recipientId: RecipientIdentifier, + func udAccess(forRecipientId recipientId: String, requireSyncAccess: Bool) -> OWSUDAccess? // MARK: Sender Certificate @@ -203,7 +203,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { return SMKUDAccessKey(randomKeyData: ()) } - private func unidentifiedAccessMode(forRecipientId recipientId: RecipientIdentifier, + private func unidentifiedAccessMode(forRecipientId recipientId: String, isLocalNumber: Bool, transaction: YapDatabaseReadTransaction) -> UnidentifiedAccessMode { let defaultValue: UnidentifiedAccessMode = isLocalNumber ? .enabled : .unknown @@ -218,7 +218,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { } @objc - public func unidentifiedAccessMode(forRecipientId recipientId: RecipientIdentifier) -> UnidentifiedAccessMode { + public func unidentifiedAccessMode(forRecipientId recipientId: String) -> UnidentifiedAccessMode { var isLocalNumber = false if let localNumber = tsAccountManager.localNumber() { isLocalNumber = recipientId == localNumber @@ -255,7 +255,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { // Returns the UD access key for a given recipient // if we have a valid profile key for them. @objc - public func udAccessKey(forRecipientId recipientId: RecipientIdentifier) -> SMKUDAccessKey? { + public func udAccessKey(forRecipientId recipientId: String) -> SMKUDAccessKey? { guard let profileKey = profileManager.profileKeyData(forRecipientId: recipientId) else { // Mark as "not a UD recipient". return nil @@ -271,7 +271,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { // Returns the UD access key for sending to a given recipient. @objc - public func udAccess(forRecipientId recipientId: RecipientIdentifier, + public func udAccess(forRecipientId recipientId: String, requireSyncAccess: Bool) -> OWSUDAccess? { if requireSyncAccess { guard let localNumber = tsAccountManager.localNumber() else { @@ -427,7 +427,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { return Promise<(certificateData: Data, certificate: SMKSenderCertificate)> { seal in // Loki: Generate a sender certificate locally let sender = OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey - let certificate = SMKSenderCertificate(senderDeviceId: OWSDevicePrimaryDeviceId, senderRecipientId: sender) + let certificate = SMKSenderCertificate(senderDeviceId: 1, senderRecipientId: sender) let certificateAsData = try certificate.serialized() guard isValidCertificate(certificate) else { throw OWSUDError.invalidData(description: "Invalid sender certificate.") @@ -440,7 +440,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { public func getSenderCertificate() -> SMKSenderCertificate? { do { let sender = OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey - let certificate = SMKSenderCertificate(senderDeviceId: OWSDevicePrimaryDeviceId, senderRecipientId: sender) + let certificate = SMKSenderCertificate(senderDeviceId: 1, senderRecipientId: sender) guard self.isValidCertificate(certificate) else { throw OWSUDError.invalidData(description: "Invalid sender certificate returned by server") } @@ -451,20 +451,6 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { } } - private func requestSenderCertificate() -> Promise<(certificateData: Data, certificate: SMKSenderCertificate)> { - return firstly { - SignalServiceRestClient().requestUDSenderCertificate() - }.map { certificateData -> (certificateData: Data, certificate: SMKSenderCertificate) in - let certificate = try SMKSenderCertificate.parse(data: certificateData) - - guard self.isValidCertificate(certificate) else { - throw OWSUDError.invalidData(description: "Invalid sender certificate returned by server") - } - - return (certificateData: certificateData, certificate: certificate) - } - } - private func isValidCertificate(_ certificate: SMKSenderCertificate) -> Bool { // Ensure that the certificate will not expire in the next hour. // We want a threshold long enough to ensure that any outgoing message diff --git a/SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.h b/SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.h deleted file mode 100644 index 2af96d497..000000000 --- a/SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors -// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject) -__attribute__((deprecated)) @interface OWSUnknownContactBlockOfferMessage : TSErrorMessage - -@property (nonatomic, readonly) NSString *contactId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.m b/SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.m deleted file mode 100644 index 3d11291cf..000000000 --- a/SignalUtilitiesKit/OWSUnknownContactBlockOfferMessage.m +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSUnknownContactBlockOfferMessage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSUnknownContactBlockOfferMessage () - -@property (nonatomic) NSString *contactId; - -@end - -#pragma mark - - -// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors -// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" -@implementation OWSUnknownContactBlockOfferMessage -#pragma clang diagnostic pop - -- (BOOL)shouldUseReceiptDateForSorting -{ - // Use the timestamp, not the "received at" timestamp to sort, - // since we're creating these interactions after the fact and back-dating them. - return NO; -} - -- (BOOL)isDynamicInteraction -{ - return YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSUploadOperation.m b/SignalUtilitiesKit/OWSUploadOperation.m index d7063c66f..56267ccde 100644 --- a/SignalUtilitiesKit/OWSUploadOperation.m +++ b/SignalUtilitiesKit/OWSUploadOperation.m @@ -9,10 +9,10 @@ #import "OWSDispatch.h" #import "OWSError.h" #import "OWSOperation.h" -#import "OWSRequestFactory.h" +#import #import "SSKEnvironment.h" #import "TSAttachmentStream.h" -#import "TSNetworkManager.h" + #import #import #import @@ -57,11 +57,6 @@ static const CGFloat kAttachmentUploadProgressTheta = 0.001f; return self; } -- (TSNetworkManager *)networkManager -{ - return SSKEnvironment.shared.networkManager; -} - - (void)run { __block TSAttachmentStream *attachmentStream; @@ -100,79 +95,6 @@ static const CGFloat kAttachmentUploadProgressTheta = 0.001f; }) retainUntilComplete]; } -- (void)uploadWithServerId:(UInt64)serverId - location:(NSString *)location - attachmentStream:(TSAttachmentStream *)attachmentStream -{ - OWSLogDebug(@"started uploading data for attachment: %@", self.attachmentId); - NSError *error; - NSData *attachmentData = [attachmentStream readDataFromFileAndReturnError:&error]; - if (error) { - OWSLogError(@"Failed to read attachment data with error: %@", error); - error.isRetryable = YES; - [self reportError:error]; - return; - } - - NSData *encryptionKey; - NSData *digest; - NSData *_Nullable encryptedAttachmentData = - [Cryptography encryptAttachmentData:attachmentData shouldPad:YES outKey:&encryptionKey outDigest:&digest]; - if (!encryptedAttachmentData) { - OWSFailDebug(@"could not encrypt attachment data."); - error = OWSErrorMakeFailedToSendOutgoingMessageError(); - error.isRetryable = YES; - [self reportError:error]; - return; - } - attachmentStream.encryptionKey = encryptionKey; - attachmentStream.digest = digest; - - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:location]]; - request.HTTPMethod = @"PUT"; - [request setValue:OWSMimeTypeApplicationOctetStream forHTTPHeaderField:@"Content-Type"]; - - AFURLSessionManager *manager = [[AFURLSessionManager alloc] - initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; - - NSURLSessionUploadTask *uploadTask; - uploadTask = [manager uploadTaskWithRequest:request - fromData:encryptedAttachmentData - progress:^(NSProgress *_Nonnull uploadProgress) { - [self fireNotificationWithProgress:uploadProgress.fractionCompleted]; - } - completionHandler:^(NSURLResponse *_Nonnull response, id _Nullable responseObject, NSError *_Nullable error) { - OWSAssertIsOnMainThread(); - if (error) { - error.isRetryable = YES; - [self reportError:error]; - return; - } - - NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode; - BOOL isValidResponse = (statusCode >= 200) && (statusCode < 400); - if (!isValidResponse) { - OWSLogError(@"Unexpected server response: %d", (int)statusCode); - NSError *invalidResponseError = OWSErrorMakeUnableToProcessServerResponseError(); - invalidResponseError.isRetryable = YES; - [self reportError:invalidResponseError]; - return; - } - - OWSLogInfo(@"Uploaded attachment: %p serverId: %llu, byteCount: %u", - attachmentStream.uniqueId, - attachmentStream.serverId, - attachmentStream.byteCount); - attachmentStream.serverId = serverId; - attachmentStream.isUploaded = YES; - [attachmentStream saveAsyncWithCompletionBlock:^{ - [self reportSuccess]; - }]; - }]; - - [uploadTask resume]; -} - - (void)fireNotificationWithProgress:(CGFloat)aProgress { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; diff --git a/SignalUtilitiesKit/OWSVerificationStateChangeMessage.h b/SignalUtilitiesKit/OWSVerificationStateChangeMessage.h deleted file mode 100644 index c3330aed8..000000000 --- a/SignalUtilitiesKit/OWSVerificationStateChangeMessage.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSThread; - -@interface OWSVerificationStateChangeMessage : TSInfoMessage - -@property (nonatomic, readonly) NSString *recipientId; -@property (nonatomic, readonly) OWSVerificationState verificationState; -@property (nonatomic, readonly) BOOL isLocalChange; - -- (instancetype)initWithTimestamp:(uint64_t)timestamp - thread:(TSThread *)thread - recipientId:(NSString *)recipientId - verificationState:(OWSVerificationState)verificationState - isLocalChange:(BOOL)isLocalChange; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSVerificationStateChangeMessage.m b/SignalUtilitiesKit/OWSVerificationStateChangeMessage.m deleted file mode 100644 index 8f4402281..000000000 --- a/SignalUtilitiesKit/OWSVerificationStateChangeMessage.m +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSVerificationStateChangeMessage.h" -#import "OWSDisappearingMessagesConfiguration.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSVerificationStateChangeMessage - -- (instancetype)initWithTimestamp:(uint64_t)timestamp - thread:(TSThread *)thread - recipientId:(NSString *)recipientId - verificationState:(OWSVerificationState)verificationState - isLocalChange:(BOOL)isLocalChange -{ - OWSAssertDebug(recipientId.length > 0); - - self = [super initWithTimestamp:timestamp inThread:thread messageType:TSInfoMessageVerificationStateChange]; - if (!self) { - return self; - } - - _recipientId = recipientId; - _verificationState = verificationState; - _isLocalChange = isLocalChange; - - return self; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSVerificationStateSyncMessage.h b/SignalUtilitiesKit/OWSVerificationStateSyncMessage.h deleted file mode 100644 index c381eaebc..000000000 --- a/SignalUtilitiesKit/OWSVerificationStateSyncMessage.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSVerificationStateSyncMessage : OWSOutgoingSyncMessage - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithVerificationState:(OWSVerificationState)verificationState - identityKey:(NSData *)identityKey - verificationForRecipientId:(NSString *)recipientId NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -// This is a clunky name, but we want to differentiate it from `recipientIdentifier` inherited from `TSOutgoingMessage` -@property (nonatomic, readonly) NSString *verificationForRecipientId; - -@property (nonatomic, readonly) size_t paddingBytesLength; -@property (nonatomic, readonly) size_t unpaddedVerifiedLength; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSVerificationStateSyncMessage.m b/SignalUtilitiesKit/OWSVerificationStateSyncMessage.m deleted file mode 100644 index db224c086..000000000 --- a/SignalUtilitiesKit/OWSVerificationStateSyncMessage.m +++ /dev/null @@ -1,111 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSVerificationStateSyncMessage.h" -#import "OWSIdentityManager.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - - -@interface OWSVerificationStateSyncMessage () - -@property (nonatomic, readonly) OWSVerificationState verificationState; -@property (nonatomic, readonly) NSData *identityKey; - -@end - -#pragma mark - - -@implementation OWSVerificationStateSyncMessage - -- (instancetype)initWithVerificationState:(OWSVerificationState)verificationState - identityKey:(NSData *)identityKey - verificationForRecipientId:(NSString *)verificationForRecipientId -{ - OWSAssertDebug(identityKey.length == kIdentityKeyLength); - OWSAssertDebug(verificationForRecipientId.length > 0); - - // we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device - // will figure that out on it's own. - OWSAssertDebug(verificationState != OWSVerificationStateNoLongerVerified); - - self = [super init]; - if (!self) { - return self; - } - - _verificationState = verificationState; - _identityKey = identityKey; - _verificationForRecipientId = verificationForRecipientId; - - // This sync message should be 1-512 bytes longer than the corresponding NullMessage - // we store this values so the corresponding NullMessage can subtract it from the total length. - _paddingBytesLength = arc4random_uniform(512) + 1; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder -{ - OWSAssertDebug(self.identityKey.length == kIdentityKeyLength); - OWSAssertDebug(self.verificationForRecipientId.length > 0); - - // we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device - // will figure that out on it's own. - OWSAssertDebug(self.verificationState != OWSVerificationStateNoLongerVerified); - - // We add the same amount of padding in the VerificationStateSync message and it's coresponding NullMessage so that - // the sync message is indistinguishable from an outgoing Sent transcript corresponding to the NullMessage. We pad - // the NullMessage so as to obscure it's content. The sync message (like all sync messages) will be *additionally* - // padded by the superclass while being sent. The end result is we send a NullMessage of a non-distinct size, and a - // verification sync which is ~1-512 bytes larger then that. - OWSAssertDebug(self.paddingBytesLength != 0); - - SSKProtoVerified *_Nullable verifiedProto = BuildVerifiedProtoWithRecipientId( - self.verificationForRecipientId, self.identityKey, self.verificationState, self.paddingBytesLength); - if (!verifiedProto) { - OWSFailDebug(@"could not build protobuf."); - return nil; - } - - SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder]; - [syncMessageBuilder setVerified:verifiedProto]; - return syncMessageBuilder; -} - -- (size_t)unpaddedVerifiedLength -{ - OWSAssertDebug(self.identityKey.length == kIdentityKeyLength); - OWSAssertDebug(self.verificationForRecipientId.length > 0); - - // we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device - // will figure that out on it's own. - OWSAssertDebug(self.verificationState != OWSVerificationStateNoLongerVerified); - - SSKProtoVerified *_Nullable verifiedProto = BuildVerifiedProtoWithRecipientId( - self.verificationForRecipientId, self.identityKey, self.verificationState, 0); - if (!verifiedProto) { - OWSFailDebug(@"could not build protobuf."); - return 0; - } - NSError *error; - NSData *_Nullable verifiedData = [verifiedProto serializedDataAndReturnError:&error]; - if (error || !verifiedData) { - OWSFailDebug(@"could not serialize protobuf."); - return 0; - } - return verifiedData.length; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSWebSocket.h b/SignalUtilitiesKit/OWSWebSocket.h deleted file mode 100644 index 062bf0364..000000000 --- a/SignalUtilitiesKit/OWSWebSocket.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -static void *OWSWebSocketStateObservationContext = &OWSWebSocketStateObservationContext; - -extern NSString *const kNSNotification_OWSWebSocketStateDidChange; - -typedef NS_ENUM(NSUInteger, OWSWebSocketState) { - OWSWebSocketStateClosed, - OWSWebSocketStateConnecting, - OWSWebSocketStateOpen, -}; - -typedef void (^TSSocketMessageSuccess)(id _Nullable responseObject); -// statusCode is zero by default, if request never made or failed. -typedef void (^TSSocketMessageFailure)(NSInteger statusCode, NSData *_Nullable responseData, NSError *error); - -@class TSRequest; - -@interface OWSWebSocket : NSObject - -@property (nonatomic, readonly) OWSWebSocketState state; - -- (instancetype)init NS_DESIGNATED_INITIALIZER; - -// If the app is in the foreground, we'll try to open the socket unless it's already -// open or connecting. -// -// If the app is in the background, we'll try to open the socket unless it's already -// open or connecting _and_ keep it open for at least N seconds. -// If the app is in the background and the socket is already open or connecting this -// might prolong how long we keep the socket open. -// -// This method can be called from any thread. -- (void)requestSocketOpen; - -// This can be used to force the socket to close and re-open, if it is open. -- (void)cycleSocket; - -#pragma mark - Message Sending - -@property (atomic, readonly) BOOL canMakeRequests; - -- (void)makeRequest:(TSRequest *)request - success:(TSSocketMessageSuccess)success - failure:(TSSocketMessageFailure)failure; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSWebSocket.m b/SignalUtilitiesKit/OWSWebSocket.m deleted file mode 100644 index d7bea5bca..000000000 --- a/SignalUtilitiesKit/OWSWebSocket.m +++ /dev/null @@ -1,1141 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSWebSocket.h" -#import "AppContext.h" -#import "AppReadiness.h" -#import "NSNotificationCenter+OWS.h" -#import "NSTimer+OWS.h" -#import "NotificationsProtocol.h" -#import "OWSBackgroundTask.h" -#import "OWSDevicesService.h" -#import "OWSError.h" -#import "OWSMessageManager.h" -#import "OWSMessageReceiver.h" -#import "OWSPrimaryStorage.h" -#import "OWSSignalService.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "TSConstants.h" -#import "TSErrorMessage.h" -#import "TSRequest.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -static const CGFloat kSocketHeartbeatPeriodSeconds = 30.f; -static const CGFloat kSocketReconnectDelaySeconds = 5.f; - -// If the app is in the background, it should keep the -// websocket open if: -// -// a) It has received a notification in the last 25 seconds. -static const CGFloat kBackgroundOpenSocketDurationSeconds = 25.f; -// b) It has received a message over the socket in the last 15 seconds. -static const CGFloat kBackgroundKeepSocketAliveDurationSeconds = 15.f; -// c) It is in the process of making a request. -static const CGFloat kMakeRequestKeepSocketAliveDurationSeconds = 30.f; - -NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_OWSWebSocketStateDidChange"; - -@interface TSSocketMessage : NSObject - -@property (nonatomic, readonly) UInt64 requestId; -@property (nonatomic, nullable) TSSocketMessageSuccess success; -@property (nonatomic, nullable) TSSocketMessageFailure failure; -@property (nonatomic) BOOL hasCompleted; -@property (nonatomic, readonly) OWSBackgroundTask *backgroundTask; - -- (instancetype)init NS_UNAVAILABLE; - -@end - -#pragma mark - - -@implementation TSSocketMessage - -- (instancetype)initWithRequestId:(UInt64)requestId - success:(TSSocketMessageSuccess)success - failure:(TSSocketMessageFailure)failure -{ - if (self = [super init]) { - OWSAssertDebug(success); - OWSAssertDebug(failure); - - _requestId = requestId; - _success = success; - _failure = failure; - _backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - } - - return self; -} - -- (void)didSucceedWithResponseObject:(id _Nullable)responseObject -{ - @synchronized(self) { - if (self.hasCompleted) { - return; - } - self.hasCompleted = YES; - } - - OWSAssertDebug(self.success); - OWSAssertDebug(self.failure); - - TSSocketMessageSuccess success = self.success; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - success(responseObject); - }); - - self.success = nil; - self.failure = nil; -} - -- (void)timeoutIfNecessary -{ - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageRequestFailed, - NSLocalizedString( - @"ERROR_DESCRIPTION_REQUEST_TIMED_OUT", @"Error indicating that a socket request timed out.")); - - [self didFailWithStatusCode:0 responseData:nil error:error]; -} - -- (void)didFailBeforeSending -{ - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageRequestFailed, - NSLocalizedString(@"ERROR_DESCRIPTION_REQUEST_FAILED", @"Error indicating that a socket request failed.")); - - [self didFailWithStatusCode:0 responseData:nil error:error]; -} - -- (void)didFailWithStatusCode:(NSInteger)statusCode responseData:(nullable NSData *)responseData error:(NSError *)error -{ - OWSAssertDebug(error); - - @synchronized(self) { - if (self.hasCompleted) { - return; - } - self.hasCompleted = YES; - } - - OWSLogError(@"didFailWithStatusCode: %zd, %@", statusCode, error); - - OWSAssertDebug(self.success); - OWSAssertDebug(self.failure); - - TSSocketMessageFailure failure = self.failure; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - failure(statusCode, responseData, error); - }); - - self.success = nil; - self.failure = nil; -} - -@end - -#pragma mark - - -// OWSWebSocket's properties should only be accessed from the main thread. -@interface OWSWebSocket () - -// This class has a few "tiers" of state. -// -// The first tier is the actual websocket and the timers used -// to keep it alive and connected. -@property (nonatomic, nullable) id websocket; -@property (nonatomic, nullable) NSTimer *heartbeatTimer; -@property (nonatomic, nullable) NSTimer *reconnectTimer; - -#pragma mark - - -// The second tier is the state property. We initiate changes -// to the websocket by changing this property's value, and delegate -// events from the websocket also update this value as the websocket's -// state changes. -// -// Due to concurrency, this property can fall out of sync with the -// websocket's actual state, so we're defensive and distrustful of -// this property. -// -// We only ever access this state on the main thread. -@property (nonatomic) OWSWebSocketState state; - -#pragma mark - - -// The third tier is the state that is used to determine what the -// "desired" state of the websocket is. -// -// If we're keeping the socket open in the background, all three of these -// properties will be set. Otherwise (if the app is active or if we're not -// trying to keep the socket open), all three should be clear. -// -// This represents how long we're trying to keep the socket open. -@property (nonatomic, nullable) NSDate *backgroundKeepAliveUntilDate; -// This timer is used to check periodically whether we should -// close the socket. -@property (nonatomic, nullable) NSTimer *backgroundKeepAliveTimer; -// This is used to manage the iOS "background task" used to -// keep the app alive in the background. -@property (nonatomic, nullable) OWSBackgroundTask *backgroundTask; - -// We cache this value instead of consulting [UIApplication sharedApplication].applicationState, -// because UIKit only provides a "will resign active" notification, not a "did resign active" -// notification. -@property (nonatomic) BOOL appIsActive; - -@property (nonatomic) BOOL hasObservedNotifications; - -// This property should only be accessed while synchronized on the socket manager. -@property (nonatomic, readonly) NSMutableDictionary *socketMessageMap; - -@property (atomic) BOOL canMakeRequests; - -@end - -#pragma mark - - -@implementation OWSWebSocket - -- (instancetype)init -{ - self = [super init]; - - if (!self) { - return self; - } - - OWSAssertIsOnMainThread(); - - _state = OWSWebSocketStateClosed; - _socketMessageMap = [NSMutableDictionary new]; - - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -#pragma mark - Dependencies - -- (OWSSignalService *)signalService -{ - return [OWSSignalService sharedInstance]; -} - -- (OWSMessageReceiver *)messageReceiver -{ - return SSKEnvironment.shared.messageReceiver; -} - -- (TSAccountManager *)tsAccountManager -{ - return TSAccountManager.sharedInstance; -} - -- (OutageDetection *)outageDetection -{ - return OutageDetection.sharedManager; -} - -- (OWSPrimaryStorage *)primaryStorage -{ - return SSKEnvironment.shared.primaryStorage; -} - -- (id)notificationsManager -{ - return SSKEnvironment.shared.notificationsManager; -} - -- (id)udManager { - return SSKEnvironment.shared.udManager; -} - -#pragma mark - - -// We want to observe these notifications lazily to avoid accessing -// the data store in [application: didFinishLaunchingWithOptions:]. -- (void)observeNotificationsIfNecessary -{ - if (self.hasObservedNotifications) { - return; - } - self.hasObservedNotifications = YES; - - self.appIsActive = CurrentAppContext().isMainAppAndActive; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidBecomeActive:) - name:OWSApplicationDidBecomeActiveNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationWillResignActive:) - name:OWSApplicationWillResignActiveNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(registrationStateDidChange:) - name:RegistrationStateDidChangeNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(isCensorshipCircumventionActiveDidChange:) - name:kNSNotificationName_IsCensorshipCircumventionActiveDidChange - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deviceListUpdateModifiedDeviceList:) - name:NSNotificationName_DeviceListUpdateModifiedDeviceList - object:nil]; -} - -#pragma mark - Manage Socket - -- (void)ensureWebsocketIsOpen -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(!self.signalService.isCensorshipCircumventionActive); - - // Try to reuse the existing socket (if any) if it is in a valid state. - if (self.websocket) { - switch (self.websocket.state) { - case SSKWebSocketStateOpen: - self.state = OWSWebSocketStateOpen; - return; - case SSKWebSocketStateConnecting: - OWSLogVerbose(@"WebSocket is already connecting"); - self.state = OWSWebSocketStateConnecting; - return; - default: - break; - } - } - - OWSLogWarn(@"Creating new websocket"); - - // If socket is not already open or connecting, connect now. - // - // First we need to close the existing websocket, if any. - // The websocket delegate methods are invoked _after_ the websocket - // state changes, so we may be just learning about a socket failure - // or close event now. - self.state = OWSWebSocketStateClosed; - // Now open a new socket. - self.state = OWSWebSocketStateConnecting; -} - -- (NSString *)stringFromOWSWebSocketState:(OWSWebSocketState)state -{ - switch (state) { - case OWSWebSocketStateClosed: - return @"Closed"; - case OWSWebSocketStateOpen: - return @"Open"; - case OWSWebSocketStateConnecting: - return @"Connecting"; - } -} - -// We need to keep websocket state and class state tightly aligned. -// -// Sometimes we'll need to update class state to reflect changes -// in socket state; sometimes we'll need to update socket state -// and class state to reflect changes in app state. -// -// We learn about changes to socket state through websocket -// delegate methods. These delegate methods are sometimes -// invoked _after_ web socket state changes, so we sometimes learn -// about changes to socket state in [ensureWebsocket]. Put another way, -// it's not safe to assume we'll learn of changes to websocket state -// in the websocket delegate methods. -// -// Therefore, we use the [setState:] setter to ensure alignment between -// websocket state and class state. -- (void)setState:(OWSWebSocketState)state -{ - OWSAssertIsOnMainThread(); - - // If this state update is redundant, verify that - // class state and socket state are aligned. - // - // Note: it's not safe to check the socket's readyState here as - // it may have been just updated on another thread. If so, - // we'll learn of that state change soon. - if (_state == state) { - switch (state) { - case OWSWebSocketStateClosed: - OWSAssertDebug(!self.websocket); - break; - case OWSWebSocketStateOpen: - OWSAssertDebug(self.websocket); - break; - case OWSWebSocketStateConnecting: - OWSAssertDebug(self.websocket); - break; - } - return; - } - - OWSLogWarn( - @"Socket state: %@ -> %@", [self stringFromOWSWebSocketState:_state], [self stringFromOWSWebSocketState:state]); - - // If this state update is _not_ redundant, - // update class state to reflect the new state. - switch (state) { - case OWSWebSocketStateClosed: { - [self resetSocket]; - break; - } - case OWSWebSocketStateOpen: { - OWSAssertDebug(self.state == OWSWebSocketStateConnecting); - - self.heartbeatTimer = [NSTimer timerWithTimeInterval:kSocketHeartbeatPeriodSeconds - target:self - selector:@selector(webSocketHeartBeat) - userInfo:nil - repeats:YES]; - - // Additionally, we want the ping timer to work in the background too. - [[NSRunLoop mainRunLoop] addTimer:self.heartbeatTimer forMode:NSDefaultRunLoopMode]; - - // If the socket is open, we don't need to worry about reconnecting. - [self clearReconnect]; - break; - } - case OWSWebSocketStateConnecting: { - // Discard the old socket which is already closed or is closing. - [self resetSocket]; - - // Create a new web socket. - NSString *webSocketConnect = - [textSecureWebSocketAPI stringByAppendingString:[self webSocketAuthenticationString]]; - NSURL *webSocketConnectURL = [NSURL URLWithString:webSocketConnect]; - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:webSocketConnectURL]; - - id socket = [SSKWebSocketManager buildSocketWithRequest:request]; - socket.delegate = self; - - [self setWebsocket:socket]; - - // `connect` could hypothetically call a delegate method (e.g. if - // the socket failed immediately for some reason), so we update the state - // _before_ calling it, not after. - _state = state; - self.canMakeRequests = state == OWSWebSocketStateOpen; - [socket connect]; - [self failAllPendingSocketMessagesIfNecessary]; - return; - } - } - - _state = state; - self.canMakeRequests = state == OWSWebSocketStateOpen; - - [self failAllPendingSocketMessagesIfNecessary]; - [self notifyStatusChange]; -} - -- (void)notifyStatusChange -{ - [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotification_OWSWebSocketStateDidChange - object:nil - userInfo:nil]; -} - -#pragma mark - - -- (void)resetSocket -{ - OWSAssertIsOnMainThread(); - - self.websocket.delegate = nil; - [self.websocket disconnect]; - self.websocket = nil; - [self.heartbeatTimer invalidate]; - self.heartbeatTimer = nil; -} - -- (void)closeWebSocket -{ - OWSAssertIsOnMainThread(); - - if (self.websocket) { - OWSLogWarn(@"closeWebSocket."); - } - - self.state = OWSWebSocketStateClosed; -} - -#pragma mark - Message Sending - -- (void)makeRequest:(TSRequest *)request success:(TSSocketMessageSuccess)success failure:(TSSocketMessageFailure)failure -{ - OWSAssertDebug(request); - OWSAssertDebug(request.HTTPMethod.length > 0); - OWSAssertDebug(success); - OWSAssertDebug(failure); - - TSSocketMessage *socketMessage = [[TSSocketMessage alloc] initWithRequestId:[Cryptography randomUInt64] - success:success - failure:failure]; - - @synchronized(self) { - self.socketMessageMap[@(socketMessage.requestId)] = socketMessage; - } - - NSURL *requestUrl = request.URL; - NSString *requestPath = [@"/" stringByAppendingString:requestUrl.path]; - - NSData *_Nullable jsonData = nil; - if (request.parameters) { - NSError *error; - jsonData = - [NSJSONSerialization dataWithJSONObject:request.parameters options:(NSJSONWritingOptions)0 error:&error]; - if (!jsonData || error) { - OWSFailDebug(@"could not serialize request JSON: %@", error); - [socketMessage didFailBeforeSending]; - return; - } - } - - WebSocketProtoWebSocketRequestMessageBuilder *requestBuilder = - [WebSocketProtoWebSocketRequestMessage builderWithVerb:request.HTTPMethod - path:requestPath - requestID:socketMessage.requestId]; - if (jsonData) { - // TODO: Do we need body & headers for requests with no parameters? - [requestBuilder setBody:jsonData]; - [requestBuilder addHeaders:@"content-type:application/json"]; - } - - for (NSString *headerField in request.allHTTPHeaderFields) { - NSString *headerValue = request.allHTTPHeaderFields[headerField]; - - OWSAssertDebug([headerField isKindOfClass:[NSString class]]); - OWSAssertDebug([headerValue isKindOfClass:[NSString class]]); - [requestBuilder addHeaders:[NSString stringWithFormat:@"%@:%@", headerField, headerValue]]; - } - - NSError *error; - WebSocketProtoWebSocketRequestMessage *_Nullable requestProto = [requestBuilder buildAndReturnError:&error]; - if (!requestProto || error) { - OWSFailDebug(@"could not build proto: %@", error); - return; - } - - WebSocketProtoWebSocketMessageBuilder *messageBuilder = - [WebSocketProtoWebSocketMessage builderWithType:WebSocketProtoWebSocketMessageTypeRequest]; - [messageBuilder setRequest:requestProto]; - - NSData *_Nullable messageData = [messageBuilder buildSerializedDataAndReturnError:&error]; - if (!messageData || error) { - OWSFailDebug(@"could not serialize proto: %@.", error); - [socketMessage didFailBeforeSending]; - return; - } - - if (!self.canMakeRequests) { - OWSLogError(@"makeRequest: socket not open."); - [socketMessage didFailBeforeSending]; - return; - } - - BOOL wasScheduled = [self.websocket writeData:messageData error:&error]; - if (!wasScheduled || error) { - OWSFailDebug(@"could not send socket request: %@", error); - [socketMessage didFailBeforeSending]; - return; - } - OWSLogInfo(@"making request: %llu, %@: %@, jsonData.length: %zd", - socketMessage.requestId, - request.HTTPMethod, - requestPath, - jsonData.length); - - const int64_t kSocketTimeoutSeconds = 10; - __weak TSSocketMessage *weakSocketMessage = socketMessage; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kSocketTimeoutSeconds * NSEC_PER_SEC), - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), - ^{ - [weakSocketMessage timeoutIfNecessary]; - }); -} - -- (void)processWebSocketResponseMessage:(WebSocketProtoWebSocketResponseMessage *)message -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(message); - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self processWebSocketResponseMessageAsync:message]; - }); -} - -- (void)processWebSocketResponseMessageAsync:(WebSocketProtoWebSocketResponseMessage *)message -{ - OWSAssertDebug(message); - - OWSLogInfo(@"received WebSocket response requestId: %llu, status: %u", message.requestID, message.status); - - DispatchMainThreadSafe(^{ - [self requestSocketAliveForAtLeastSeconds:kMakeRequestKeepSocketAliveDurationSeconds]; - }); - - UInt64 requestId = message.requestID; - UInt32 responseStatus = message.status; - NSString *_Nullable responseMessage; - if (message.hasMessage) { - responseMessage = message.message; - } - NSData *_Nullable responseData; - if (message.hasBody) { - responseData = message.body; - } - - BOOL hasValidResponse = YES; - id responseObject = responseData; - if (responseData) { - NSError *error; - id _Nullable responseJson = - [NSJSONSerialization JSONObjectWithData:responseData options:(NSJSONReadingOptions)0 error:&error]; - if (!responseJson || error) { - OWSFailDebug(@"could not parse WebSocket response JSON: %@.", error); - hasValidResponse = NO; - } else { - responseObject = responseJson; - } - } - - TSSocketMessage *_Nullable socketMessage; - @synchronized(self) { - socketMessage = self.socketMessageMap[@(requestId)]; - [self.socketMessageMap removeObjectForKey:@(requestId)]; - } - - if (!socketMessage) { - OWSLogError(@"received response to unknown request."); - } else { - BOOL hasSuccessStatus = 200 <= responseStatus && responseStatus <= 299; - BOOL didSucceed = hasSuccessStatus && hasValidResponse; - if (didSucceed) { - [self.tsAccountManager setIsDeregistered:NO]; - - [socketMessage didSucceedWithResponseObject:responseObject]; - } else { - if (responseStatus == 403) { - // This should be redundant with our check for the socket - // failing due to 403, but let's be thorough. - if (self.tsAccountManager.isRegisteredAndReady) { - [self.tsAccountManager setIsDeregistered:YES]; - } else { - OWSFailDebug(@"Ignoring auth failure; not registered and ready."); - } - } - - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageResponseFailed, - NSLocalizedString( - @"ERROR_DESCRIPTION_RESPONSE_FAILED", @"Error indicating that a socket response failed.")); - [socketMessage didFailWithStatusCode:(NSInteger)responseStatus responseData:responseData error:error]; - } - } -} - -- (void)failAllPendingSocketMessagesIfNecessary -{ - if (!self.canMakeRequests) { - [self failAllPendingSocketMessages]; - } -} - -- (void)failAllPendingSocketMessages -{ - NSArray *socketMessages; - @synchronized(self) { - socketMessages = self.socketMessageMap.allValues; - [self.socketMessageMap removeAllObjects]; - } - - OWSLogInfo(@"failAllPendingSocketMessages: %zd.", socketMessages.count); - - for (TSSocketMessage *socketMessage in socketMessages) { - [socketMessage didFailBeforeSending]; - } -} - -#pragma mark - SSKWebSocketDelegate - -- (void)websocketDidConnectWithSocket:(id)websocket -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(websocket); - if (websocket != self.websocket) { - // Ignore events from obsolete web sockets. - return; - } - - self.state = OWSWebSocketStateOpen; - - // If socket opens, we know we're not de-registered. - [self.tsAccountManager setIsDeregistered:NO]; - - [self.outageDetection reportConnectionSuccess]; -} - -- (void)websocketDidDisconnectWithSocket:(id)websocket error:(nullable NSError *)error -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(websocket); - if (websocket != self.websocket) { - // Ignore events from obsolete web sockets. - return; - } - - OWSLogError(@"Websocket did fail with error: %@", error); - if ([error.domain isEqualToString:SSKWebSocketError.errorDomain]) { - NSNumber *_Nullable statusCode = error.userInfo[SSKWebSocketError.kStatusCodeKey]; - if (statusCode.unsignedIntegerValue == 403) { - if (self.tsAccountManager.isRegisteredAndReady) { - [self.tsAccountManager setIsDeregistered:YES]; - } else { - OWSLogWarn(@"Ignoring auth failure; not registered and ready."); - } - } - } - - [self handleSocketFailure]; -} - -- (void)websocketDidReceiveDataWithSocket:(id)websocket data:(NSData *)data -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(websocket); - - if (websocket != self.websocket) { - // Ignore events from obsolete web sockets. - return; - } - - // If we receive a response, we know we're not de-registered. - [self.tsAccountManager setIsDeregistered:NO]; - - NSError *error; - WebSocketProtoWebSocketMessage *_Nullable wsMessage = [WebSocketProtoWebSocketMessage parseData:data error:&error]; - if (!wsMessage || error) { - OWSFailDebug(@"could not parse proto: %@", error); - return; - } - - if (wsMessage.type == WebSocketProtoWebSocketMessageTypeRequest) { - [self processWebSocketRequestMessage:wsMessage.request]; - } else if (wsMessage.type == WebSocketProtoWebSocketMessageTypeResponse) { - [self processWebSocketResponseMessage:wsMessage.response]; - } else { - OWSLogWarn(@"webSocket:didReceiveMessage: unknown."); - } -} - -#pragma mark - - -- (dispatch_queue_t)serialQueue -{ - static dispatch_queue_t _serialQueue; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _serialQueue = dispatch_queue_create("org.signal.websocket", DISPATCH_QUEUE_SERIAL); - }); - - return _serialQueue; -} - -- (void)processWebSocketRequestMessage:(WebSocketProtoWebSocketRequestMessage *)message -{ - OWSAssertIsOnMainThread(); - - OWSLogInfo(@"Got message with verb: %@ and path: %@", message.verb, message.path); - - // If we receive a message over the socket while the app is in the background, - // prolong how long the socket stays open. - [self requestSocketAliveForAtLeastSeconds:kBackgroundKeepSocketAliveDurationSeconds]; - - if ([message.path isEqualToString:@"/api/v1/message"] && [message.verb isEqualToString:@"PUT"]) { - - __block OWSBackgroundTask *_Nullable backgroundTask = - [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - - dispatch_async(self.serialQueue, ^{ - BOOL success = NO; - @try { - BOOL useSignalingKey = [message.headers containsObject:@"X-Signal-Key: true"]; - NSData *_Nullable decryptedPayload; - if (useSignalingKey) { - NSString *_Nullable signalingKey = TSAccountManager.signalingKey; - OWSAssertDebug(signalingKey); - decryptedPayload = - [Cryptography decryptAppleMessagePayload:message.body withSignalingKey:signalingKey]; - } else { - OWSAssertDebug([message.headers containsObject:@"X-Signal-Key: false"]); - - decryptedPayload = message.body; - } - - if (!decryptedPayload) { - OWSLogWarn(@"Failed to decrypt incoming payload or bad HMAC"); - } else { - [self.messageReceiver handleReceivedEnvelopeData:decryptedPayload]; - success = YES; - } - } @catch (NSException *exception) { - OWSFailDebug(@"Received an invalid envelope: %@", exception.debugDescription); - // TODO: Add analytics. - } - - if (!success) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSErrorMessage *errorMessage = [TSErrorMessage corruptedMessageInUnknownThread]; - [self.notificationsManager notifyUserForThreadlessErrorMessage:errorMessage - transaction:transaction]; - }]; - } - - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendWebSocketMessageAcknowledgement:message]; - OWSAssertDebug(backgroundTask); - backgroundTask = nil; - }); - }); - } else if ([message.path isEqualToString:@"/api/v1/queue/empty"]) { - // Queue is drained. - - [self sendWebSocketMessageAcknowledgement:message]; - } else { - OWSLogWarn(@"Unsupported WebSocket Request"); - - [self sendWebSocketMessageAcknowledgement:message]; - } -} - -- (void)sendWebSocketMessageAcknowledgement:(WebSocketProtoWebSocketRequestMessage *)request -{ - OWSAssertIsOnMainThread(); - - NSError *error; - - WebSocketProtoWebSocketResponseMessageBuilder *responseBuilder = - [WebSocketProtoWebSocketResponseMessage builderWithRequestID:request.requestID status:200]; - [responseBuilder setMessage:@"OK"]; - WebSocketProtoWebSocketResponseMessage *_Nullable response = [responseBuilder buildAndReturnError:&error]; - if (!response || error) { - OWSFailDebug(@"could not build proto: %@", error); - return; - } - - WebSocketProtoWebSocketMessageBuilder *messageBuilder = - [WebSocketProtoWebSocketMessage builderWithType:WebSocketProtoWebSocketMessageTypeResponse]; - [messageBuilder setResponse:response]; - - NSData *_Nullable messageData = [messageBuilder buildSerializedDataAndReturnError:&error]; - if (!messageData || error) { - OWSFailDebug(@"could not serialize proto: %@", error); - return; - } - - [self.websocket writeData:messageData error:&error]; - if (error) { - OWSLogWarn(@"Error while trying to write on websocket %@", error); - [self handleSocketFailure]; - } -} - -- (void)cycleSocket -{ - OWSAssertIsOnMainThread(); - - [self closeWebSocket]; - - [self applyDesiredSocketState]; -} - -- (void)handleSocketFailure -{ - OWSAssertIsOnMainThread(); - - [self closeWebSocket]; - - if ([self shouldSocketBeOpen]) { - // If we should retry, use `ensureReconnect` to - // reconnect after a delay. - [self ensureReconnect]; - } else { - // Otherwise clean up and align state. - [self applyDesiredSocketState]; - } - - [self.outageDetection reportConnectionFailure]; -} - -- (void)webSocketHeartBeat -{ - OWSAssertIsOnMainThread(); - - if ([self shouldSocketBeOpen]) { - NSError *error; - [self.websocket writePingAndReturnError:&error]; - if (error) { - OWSLogWarn(@"Error in websocket heartbeat: %@", error.localizedDescription); - [self handleSocketFailure]; - } - } else { - OWSLogWarn(@"webSocketHeartBeat closing web socket"); - [self closeWebSocket]; - [self applyDesiredSocketState]; - } -} - -- (NSString *)webSocketAuthenticationString -{ - return [NSString stringWithFormat:@"?login=%@&password=%@", - [[TSAccountManager localNumber] stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"], - [TSAccountManager serverAuthToken]]; -} - -#pragma mark - Socket LifeCycle - -- (BOOL)shouldSocketBeOpen -{ - OWSAssertIsOnMainThread(); - - // Loki: Since we don't use web sockets, disable them - return NO; - - // Don't open socket in app extensions. - if (!CurrentAppContext().isMainApp) { - return NO; - } - - if (![self.tsAccountManager isRegisteredAndReady]) { - return NO; - } - - if (self.signalService.isCensorshipCircumventionActive) { - OWSLogWarn(@"Skipping opening of websocket due to censorship circumvention."); - return NO; - } - - if (self.appIsActive) { - // If app is active, keep web socket alive. - return YES; - } else if (self.backgroundKeepAliveUntilDate && [self.backgroundKeepAliveUntilDate timeIntervalSinceNow] > 0.f) { - OWSAssertDebug(self.backgroundKeepAliveTimer); - // If app is doing any work in the background, keep web socket alive. - return YES; - } else { - return NO; - } -} - -- (void)requestSocketAliveForAtLeastSeconds:(CGFloat)durationSeconds -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(durationSeconds > 0.f); - - if (self.appIsActive) { - // If app is active, clean up state used to keep socket alive in background. - [self clearBackgroundState]; - } else if (!self.backgroundKeepAliveUntilDate) { - OWSAssertDebug(!self.backgroundKeepAliveUntilDate); - OWSAssertDebug(!self.backgroundKeepAliveTimer); - - OWSLogInfo(@"activating socket in the background"); - - // Set up state used to keep socket alive in background. - self.backgroundKeepAliveUntilDate = [NSDate dateWithTimeIntervalSinceNow:durationSeconds]; - - // To be defensive, clean up any existing backgroundKeepAliveTimer. - [self.backgroundKeepAliveTimer invalidate]; - // Start a new timer that will fire every second while the socket is open in the background. - // This timer will ensure we close the websocket when the time comes. - self.backgroundKeepAliveTimer = [NSTimer weakScheduledTimerWithTimeInterval:1.f - target:self - selector:@selector(backgroundKeepAliveFired) - userInfo:nil - repeats:YES]; - // Additionally, we want the reconnect timer to work in the background too. - [[NSRunLoop mainRunLoop] addTimer:self.backgroundKeepAliveTimer forMode:NSDefaultRunLoopMode]; - - __weak typeof(self) weakSelf = self; - self.backgroundTask = - [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__ - completionBlock:^(BackgroundTaskState backgroundTaskState) { - OWSAssertIsOnMainThread(); - __strong typeof(self) strongSelf = weakSelf; - if (!strongSelf) { - return; - } - - if (backgroundTaskState == BackgroundTaskState_Expired) { - [strongSelf clearBackgroundState]; - } - [strongSelf applyDesiredSocketState]; - }]; - } else { - OWSAssertDebug(self.backgroundKeepAliveUntilDate); - OWSAssertDebug(self.backgroundKeepAliveTimer); - OWSAssertDebug([self.backgroundKeepAliveTimer isValid]); - - if ([self.backgroundKeepAliveUntilDate timeIntervalSinceNow] < durationSeconds) { - // Update state used to keep socket alive in background. - self.backgroundKeepAliveUntilDate = [NSDate dateWithTimeIntervalSinceNow:durationSeconds]; - } - } - - [self applyDesiredSocketState]; -} - -- (void)backgroundKeepAliveFired -{ - OWSAssertIsOnMainThread(); - - [self applyDesiredSocketState]; -} - -- (void)requestSocketOpen -{ - DispatchMainThreadSafe(^{ - [self observeNotificationsIfNecessary]; - - // If the app is active and the user is registered, this will - // simply open the websocket. - // - // If the app is inactive, it will open the websocket for a - // period of time. - [self requestSocketAliveForAtLeastSeconds:kBackgroundOpenSocketDurationSeconds]; - }); -} - -// This method aligns the socket state with the "desired" socket state. -- (void)applyDesiredSocketState -{ - OWSAssertIsOnMainThread(); - -#ifdef DEBUG - if (CurrentAppContext().isRunningTests) { - OWSLogWarn(@"Suppressing socket in tests."); - return; - } -#endif - - if (!AppReadiness.isAppReady) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - [self applyDesiredSocketState]; - }]; - }); - return; - } - - if ([self shouldSocketBeOpen]) { - if (self.state != OWSWebSocketStateOpen) { - // If we want the socket to be open and it's not open, - // start up the reconnect timer immediately (don't wait for an error). - // There's little harm in it and this will make us more robust to edge - // cases. - [self ensureReconnect]; - } - [self ensureWebsocketIsOpen]; - } else { - [self clearBackgroundState]; - [self clearReconnect]; - [self closeWebSocket]; - } -} - -- (void)clearBackgroundState -{ - OWSAssertIsOnMainThread(); - - self.backgroundKeepAliveUntilDate = nil; - [self.backgroundKeepAliveTimer invalidate]; - self.backgroundKeepAliveTimer = nil; - self.backgroundTask = nil; -} - -#pragma mark - Reconnect - -- (void)ensureReconnect -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug([self shouldSocketBeOpen]); - - if (self.reconnectTimer) { - OWSAssertDebug([self.reconnectTimer isValid]); - } else { - // TODO: It'd be nice to do exponential backoff. - self.reconnectTimer = [NSTimer timerWithTimeInterval:kSocketReconnectDelaySeconds - target:self - selector:@selector(applyDesiredSocketState) - userInfo:nil - repeats:YES]; - // Additionally, we want the reconnect timer to work in the background too. - [[NSRunLoop mainRunLoop] addTimer:self.reconnectTimer forMode:NSDefaultRunLoopMode]; - } -} - -- (void)clearReconnect -{ - OWSAssertIsOnMainThread(); - - [self.reconnectTimer invalidate]; - self.reconnectTimer = nil; -} - -#pragma mark - Notifications - -- (void)applicationDidBecomeActive:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - self.appIsActive = YES; - [self applyDesiredSocketState]; -} - -- (void)applicationWillResignActive:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - self.appIsActive = NO; - // TODO: It might be nice to use `requestSocketAliveForAtLeastSeconds:` to - // keep the socket open for a few seconds after the app is - // inactivated. - [self applyDesiredSocketState]; -} - -- (void)registrationStateDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [self applyDesiredSocketState]; -} - -- (void)isCensorshipCircumventionActiveDidChange:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [self applyDesiredSocketState]; -} - -- (void)deviceListUpdateModifiedDeviceList:(NSNotification *)notification -{ - OWSAssertIsOnMainThread(); - - [self cycleSocket]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OldSnodeAPI.swift b/SignalUtilitiesKit/OldSnodeAPI.swift deleted file mode 100644 index fa3809a8e..000000000 --- a/SignalUtilitiesKit/OldSnodeAPI.swift +++ /dev/null @@ -1,44 +0,0 @@ -import PromiseKit - -@objc(LKSnodeAPI) -public final class OldSnodeAPI : NSObject { - - // MARK: Sending - @objc(sendSignalMessage:) - public static func objc_sendSignalMessage(_ signalMessage: SignalMessage) -> AnyPromise { - let promise = sendSignalMessage(signalMessage).mapValues2 { AnyPromise.from($0) }.map2 { Set($0) } - return AnyPromise.from(promise) - } - - public static func sendSignalMessage(_ signalMessage: SignalMessage) -> Promise>> { - // Convert the message to a Loki message - guard let lokiMessage = LokiMessage.from(signalMessage: signalMessage) else { return Promise(error: SnodeAPI.Error.generic) } - let publicKey = lokiMessage.recipientPublicKey - let notificationCenter = NotificationCenter.default - notificationCenter.post(name: .calculatingPoW, object: NSNumber(value: signalMessage.timestamp)) - // Calculate proof of work - return lokiMessage.calculatePoW().then2 { lokiMessageWithPoW -> Promise>> in - notificationCenter.post(name: .routing, object: NSNumber(value: signalMessage.timestamp)) - // Get the target snodes - return SnodeAPI.getTargetSnodes(for: publicKey).map2 { snodes in - notificationCenter.post(name: .messageSending, object: NSNumber(value: signalMessage.timestamp)) - let parameters = lokiMessageWithPoW.toJSON() - return Set(snodes.map { snode in - // Send the message to the target snode - return attempt(maxRetryCount: 4, recoveringOn: SnodeAPI.workQueue) { - SnodeAPI.invoke(.sendMessage, on: snode, associatedWith: publicKey, parameters: parameters) - }.map2 { rawResponse in - if let json = rawResponse as? JSON, let powDifficulty = json["difficulty"] as? Int { - guard powDifficulty != SnodeAPI.powDifficulty, powDifficulty < 100 else { return rawResponse } - print("[Loki] Setting proof of work difficulty to \(powDifficulty).") - SnodeAPI.powDifficulty = UInt(powDifficulty) - } else { - print("[Loki] Failed to update proof of work difficulty from: \(rawResponse).") - } - return rawResponse - } - }) - } - } - } -} diff --git a/SignalUtilitiesKit/OnionRequestAPI+Encryption.swift b/SignalUtilitiesKit/OnionRequestAPI+Encryption.swift deleted file mode 100644 index 86dfec1f0..000000000 --- a/SignalUtilitiesKit/OnionRequestAPI+Encryption.swift +++ /dev/null @@ -1,72 +0,0 @@ -import CryptoSwift -import PromiseKit - -extension OnionRequestAPI { - - internal static func encode(ciphertext: Data, json: JSON) throws -> Data { - // The encoding of V2 onion requests looks like: | 4 bytes: size N of ciphertext | N bytes: ciphertext | json as utf8 | - guard JSONSerialization.isValidJSONObject(json) else { throw HTTP.Error.invalidJSON } - let jsonAsData = try JSONSerialization.data(withJSONObject: json, options: [ .fragmentsAllowed ]) - let ciphertextSize = Int32(ciphertext.count).littleEndian - let ciphertextSizeAsData = withUnsafePointer(to: ciphertextSize) { Data(bytes: $0, count: MemoryLayout.size) } - return ciphertextSizeAsData + ciphertext + jsonAsData - } - - /// Encrypts `payload` for `destination` and returns the result. Use this to build the core of an onion request. - internal static func encrypt(_ payload: JSON, for destination: Destination) -> Promise { - let (promise, seal) = Promise.pending() - DispatchQueue.global(qos: .userInitiated).async { - do { - guard JSONSerialization.isValidJSONObject(payload) else { return seal.reject(HTTP.Error.invalidJSON) } - // Wrapping isn't needed for file server or open group onion requests - switch destination { - case .snode(let snode): - let snodeX25519PublicKey = snode.publicKeySet.x25519Key - let payloadAsData = try JSONSerialization.data(withJSONObject: payload, options: [ .fragmentsAllowed ]) - let plaintext = try encode(ciphertext: payloadAsData, json: [ "headers" : "" ]) - let result = try EncryptionUtilities.encrypt(plaintext, using: snodeX25519PublicKey) - seal.fulfill(result) - case .server(_, _, let serverX25519PublicKey): - let plaintext = try JSONSerialization.data(withJSONObject: payload, options: [ .fragmentsAllowed ]) - let result = try EncryptionUtilities.encrypt(plaintext, using: serverX25519PublicKey) - seal.fulfill(result) - } - } catch (let error) { - seal.reject(error) - } - } - return promise - } - - /// Encrypts the previous encryption result (i.e. that of the hop after this one) for this hop. Use this to build the layers of an onion request. - internal static func encryptHop(from lhs: Destination, to rhs: Destination, using previousEncryptionResult: EncryptionResult) -> Promise { - let (promise, seal) = Promise.pending() - DispatchQueue.global(qos: .userInitiated).async { - var parameters: JSON - switch rhs { - case .snode(let snode): - let snodeED25519PublicKey = snode.publicKeySet.ed25519Key - parameters = [ "destination" : snodeED25519PublicKey ] - case .server(let host, let target, _): - parameters = [ "host" : host, "target" : target, "method" : "POST" ] - } - parameters["ephemeral_key"] = previousEncryptionResult.ephemeralPublicKey.toHexString() - let x25519PublicKey: String - switch lhs { - case .snode(let snode): - let snodeX25519PublicKey = snode.publicKeySet.x25519Key - x25519PublicKey = snodeX25519PublicKey - case .server(_, _, let serverX25519PublicKey): - x25519PublicKey = serverX25519PublicKey - } - do { - let plaintext = try encode(ciphertext: previousEncryptionResult.ciphertext, json: parameters) - let result = try EncryptionUtilities.encrypt(plaintext, using: x25519PublicKey) - seal.fulfill(result) - } catch (let error) { - seal.reject(error) - } - } - return promise - } -} diff --git a/SignalUtilitiesKit/OutageDetection.swift b/SignalUtilitiesKit/OutageDetection.swift index 2717dc570..8f680505f 100644 --- a/SignalUtilitiesKit/OutageDetection.swift +++ b/SignalUtilitiesKit/OutageDetection.swift @@ -27,9 +27,8 @@ public class OutageDetection: NSObject { } private var shouldCheckForOutage = false { didSet { - // Loki: Don't check for outages -// AssertIsOnMainThread() -// ensureCheckTimer() + AssertIsOnMainThread() + ensureCheckTimer() } } diff --git a/SignalUtilitiesKit/PhoneNumber.h b/SignalUtilitiesKit/PhoneNumber.h deleted file mode 100644 index 0e7cb9e30..000000000 --- a/SignalUtilitiesKit/PhoneNumber.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -#define COUNTRY_CODE_PREFIX @"+" - -/** - * - * PhoneNumber is used to deal with the nitty details of parsing/canonicalizing phone numbers. - * Everything that expects a valid phone number should take a PhoneNumber, not a string, to avoid stringly typing. - * - */ -@interface PhoneNumber : NSObject - -+ (nullable PhoneNumber *)phoneNumberFromE164:(NSString *)text; - -+ (nullable PhoneNumber *)tryParsePhoneNumberFromUserSpecifiedText:(NSString *)text; -+ (nullable PhoneNumber *)tryParsePhoneNumberFromE164:(NSString *)text; - -// This will try to parse the input text as a phone number using -// the default region and the country code for this client's phone -// number. -// -// Order matters; better results will appear first. -+ (NSArray *)tryParsePhoneNumbersFromsUserSpecifiedText:(NSString *)text - clientPhoneNumber:(NSString *)clientPhoneNumber; - -+ (NSString *)removeFormattingCharacters:(NSString *)inputString; -+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input; -+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input - withSpecifiedCountryCodeString:(NSString *)countryCodeString; -+ (NSString *)bestEffortLocalizedPhoneNumberWithE164:(NSString *)phoneNumber; - -+ (NSString *)regionCodeFromCountryCodeString:(NSString *)countryCodeString; - -- (NSURL *)toSystemDialerURL; -- (NSString *)toE164; -- (nullable NSNumber *)getCountryCode; -@property (nonatomic, readonly, nullable) NSString *nationalNumber; -- (BOOL)isValid; - -- (NSComparisonResult)compare:(PhoneNumber *)other; - -+ (NSString *)defaultCountryCode; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/PhoneNumber.m b/SignalUtilitiesKit/PhoneNumber.m deleted file mode 100644 index e279f5053..000000000 --- a/SignalUtilitiesKit/PhoneNumber.m +++ /dev/null @@ -1,584 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "PhoneNumber.h" -#import "PhoneNumberUtil.h" -#import "AppContext.h" -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -static NSString *const RPDefaultsKeyPhoneNumberString = @"RPDefaultsKeyPhoneNumberString"; -static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneNumberCanonical"; - -@interface PhoneNumber () - -@property (nonatomic, readonly) NBPhoneNumber *phoneNumber; -@property (nonatomic, readonly) NSString *e164; - -@end - -#pragma mark - - -@implementation PhoneNumber - -- (instancetype)initWithPhoneNumber:(NBPhoneNumber *)phoneNumber e164:(NSString *)e164 -{ - if (self = [self init]) { - OWSAssertDebug(phoneNumber); - OWSAssertDebug(e164.length > 0); - - _phoneNumber = phoneNumber; - _e164 = e164; - } - return self; -} - -+ (nullable PhoneNumber *)phoneNumberFromText:(NSString *)text andRegion:(NSString *)regionCode { - OWSAssertDebug(text != nil); - OWSAssertDebug(regionCode != nil); - - PhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedThreadLocal]; - - NSError *parseError = nil; - NBPhoneNumber *number = [phoneUtil parse:text defaultRegion:regionCode error:&parseError]; - - if (parseError) { - return nil; - } - - NSError *toE164Error; - NSString *e164 = [phoneUtil format:number numberFormat:NBEPhoneNumberFormatE164 error:&toE164Error]; - if (toE164Error) { - OWSLogDebug(@"Issue while formatting number: %@", [toE164Error description]); - return nil; - } - - return [[PhoneNumber alloc] initWithPhoneNumber:number e164:e164]; -} - -+ (nullable PhoneNumber *)phoneNumberFromUserSpecifiedText:(NSString *)text { - OWSAssertDebug(text != nil); - - return [PhoneNumber phoneNumberFromText:text andRegion:[self defaultCountryCode]]; -} - -+ (NSString *)defaultCountryCode -{ - NSLocale *locale = [NSLocale currentLocale]; - - NSString *_Nullable countryCode = nil; -#if TARGET_OS_IPHONE - countryCode = [[PhoneNumberUtil sharedThreadLocal].nbPhoneNumberUtil countryCodeByCarrier]; - - if ([countryCode isEqualToString:@"ZZ"]) { - countryCode = [locale objectForKey:NSLocaleCountryCode]; - } -#else - countryCode = [locale objectForKey:NSLocaleCountryCode]; -#endif - if (!countryCode) { - OWSFailDebug(@"Could not identify country code for locale: %@", locale); - countryCode = @"US"; - } - return countryCode; -} - -+ (nullable PhoneNumber *)phoneNumberFromE164:(NSString *)text { - return [[PhoneNumber alloc] initWithPhoneNumber:[NBPhoneNumber new] e164:text]; - // Loki: Original code: - // ======== -// OWSAssertDebug(text != nil); -// OWSAssertDebug([text hasPrefix:COUNTRY_CODE_PREFIX]); -// PhoneNumber *number = [PhoneNumber phoneNumberFromText:text andRegion:@"ZZ"]; -// OWSAssertDebug(number != nil); -// return number; - // ======== -} - -+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input { - return [PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:input - withSpecifiedRegionCode:[self defaultCountryCode]]; -} - -+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input - withSpecifiedCountryCodeString:(NSString *)countryCodeString { - return [PhoneNumber - bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:input - withSpecifiedRegionCode: - [PhoneNumber regionCodeFromCountryCodeString:countryCodeString]]; -} - -+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input - withSpecifiedRegionCode:(NSString *)regionCode { - NBAsYouTypeFormatter *formatter = [[NBAsYouTypeFormatter alloc] initWithRegionCode:regionCode]; - - NSString *result = input; - for (NSUInteger i = 0; i < input.length; i++) { - result = [formatter inputDigit:[input substringWithRange:NSMakeRange(i, 1)]]; - } - return result; -} - -+ (NSString *)formatIntAsEN:(int)value -{ - static NSNumberFormatter *formatter = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - formatter = [NSNumberFormatter new]; - formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"]; - }); - return [formatter stringFromNumber:@(value)]; -} - -+ (NSString *)bestEffortLocalizedPhoneNumberWithE164:(NSString *)phoneNumber -{ - OWSAssertDebug(phoneNumber); - - if (![phoneNumber hasPrefix:COUNTRY_CODE_PREFIX]) { - return phoneNumber; - } - - PhoneNumber *_Nullable parsedPhoneNumber = [self tryParsePhoneNumberFromE164:phoneNumber]; - if (!parsedPhoneNumber) { - OWSLogWarn(@"could not parse phone number."); - return phoneNumber; - } - NSNumber *_Nullable countryCode = [parsedPhoneNumber getCountryCode]; - if (!countryCode) { - OWSLogWarn(@"parsed phone number has no country code."); - return phoneNumber; - } - NSString *countryCodeString = [self formatIntAsEN:countryCode.intValue]; - if (countryCodeString.length < 1) { - OWSLogWarn(@"invalid country code."); - return phoneNumber; - } - NSString *_Nullable formattedPhoneNumber = - [self bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:phoneNumber - withSpecifiedRegionCode:countryCodeString]; - if (!countryCode) { - OWSLogWarn(@"could not format phone number."); - return phoneNumber; - } - return formattedPhoneNumber; -} - -+ (NSString *)regionCodeFromCountryCodeString:(NSString *)countryCodeString { - NBPhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedThreadLocal].nbPhoneNumberUtil; - NSString *regionCode = - [phoneUtil getRegionCodeForCountryCode:@([[countryCodeString substringFromIndex:1] integerValue])]; - return regionCode; -} - -+ (nullable PhoneNumber *)tryParsePhoneNumberFromUserSpecifiedText:(NSString *)text { - OWSAssertDebug(text != nil); - - if ([text isEqualToString:@""]) { - return nil; - } - NSString *sanitizedString = [self removeFormattingCharacters:text]; - - return [self phoneNumberFromUserSpecifiedText:sanitizedString]; -} - -+ (nullable NSString *)nationalPrefixTransformRuleForDefaultRegion -{ - static NSString *result = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSString *defaultCountryCode = [self defaultCountryCode]; - NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; - NBPhoneMetaData *defaultRegionMetadata = [helper getMetadataForRegion:defaultCountryCode]; - result = defaultRegionMetadata.nationalPrefixTransformRule; - }); - return result; -} - -// clientPhoneNumber is the local user's phone number and should never change. -+ (nullable NSString *)nationalPrefixTransformRuleForClientPhoneNumber:(NSString *)clientPhoneNumber -{ - if (clientPhoneNumber.length < 1) { - return nil; - } - static NSString *result = nil; - static NSString *cachedClientPhoneNumber = nil; - static dispatch_once_t onceToken; - - // clientPhoneNumber is the local user's phone number and should never change. - static void (^updateCachedClientPhoneNumber)(void); - updateCachedClientPhoneNumber = ^(void) { - NSNumber *localCallingCode = [[PhoneNumber phoneNumberFromE164:clientPhoneNumber] getCountryCode]; - if (localCallingCode != nil) { - NSString *localCallingCodePrefix = [NSString stringWithFormat:@"+%@", localCallingCode]; - NSString *localCountryCode = - [PhoneNumberUtil.sharedThreadLocal probableCountryCodeForCallingCode:localCallingCodePrefix]; - if (localCountryCode && ![localCountryCode isEqualToString:[self defaultCountryCode]]) { - NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; - NBPhoneMetaData *localNumberRegionMetadata = [helper getMetadataForRegion:localCountryCode]; - result = localNumberRegionMetadata.nationalPrefixTransformRule; - } else { - result = nil; - } - } - cachedClientPhoneNumber = [clientPhoneNumber copy]; - }; - -#ifdef DEBUG - // For performance, we want to cahce this result, but it breaks tests since local number - // can change. - if (CurrentAppContext().isRunningTests) { - updateCachedClientPhoneNumber(); - } else { - dispatch_once(&onceToken, ^{ - updateCachedClientPhoneNumber(); - }); - } -#else - dispatch_once(&onceToken, ^{ - updateCachedClientPhoneNumber(); - }); - OWSAssertDebug([cachedClientPhoneNumber isEqualToString:clientPhoneNumber]); -#endif - - return result; -} - -+ (NSArray *)tryParsePhoneNumbersFromsUserSpecifiedText:(NSString *)text - clientPhoneNumber:(NSString *)clientPhoneNumber -{ - NSMutableArray *result = - [[self tryParsePhoneNumbersFromNormalizedText:text clientPhoneNumber:clientPhoneNumber] mutableCopy]; - - // A handful of countries (Mexico, Argentina, etc.) require a "national" prefix after - // their country calling code. - // - // It's a bit hacky, but we reconstruct these national prefixes from libPhoneNumber's - // parsing logic. It's okay if we botch this a little. The risk is that we end up with - // some misformatted numbers with extra non-numeric regex syntax. These erroneously - // parsed numbers will never be presented to the user, since they'll never survive the - // contacts intersection. - // - // 1. Try to apply a "national prefix" using the phone's region. - NSString *nationalPrefixTransformRuleForDefaultRegion = [self nationalPrefixTransformRuleForDefaultRegion]; - if ([nationalPrefixTransformRuleForDefaultRegion containsString:@"$1"]) { - NSString *normalizedText = - [nationalPrefixTransformRuleForDefaultRegion stringByReplacingOccurrencesOfString:@"$1" withString:text]; - if (![normalizedText containsString:@"$"]) { - [result addObjectsFromArray:[self tryParsePhoneNumbersFromNormalizedText:normalizedText - clientPhoneNumber:clientPhoneNumber]]; - } - } - - // 2. Try to apply a "national prefix" using the region that corresponds to the - // calling code for the local phone number. - NSString *nationalPrefixTransformRuleForClientPhoneNumber = - [self nationalPrefixTransformRuleForClientPhoneNumber:clientPhoneNumber]; - if ([nationalPrefixTransformRuleForClientPhoneNumber containsString:@"$1"]) { - NSString *normalizedText = - [nationalPrefixTransformRuleForClientPhoneNumber stringByReplacingOccurrencesOfString:@"$1" - withString:text]; - if (![normalizedText containsString:@"$"]) { - [result addObjectsFromArray:[self tryParsePhoneNumbersFromNormalizedText:normalizedText - clientPhoneNumber:clientPhoneNumber]]; - } - } - - return [result copy]; -} - -+ (NSArray *)tryParsePhoneNumbersFromNormalizedText:(NSString *)text - clientPhoneNumber:(NSString *)clientPhoneNumber -{ - OWSAssertDebug(text != nil); - - text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - if ([text isEqualToString:@""]) { - return nil; - } - - NSString *sanitizedString = [self removeFormattingCharacters:text]; - OWSAssertDebug(sanitizedString != nil); - - NSMutableArray *result = [NSMutableArray new]; - NSMutableSet *phoneNumberSet = [NSMutableSet new]; - void (^tryParsingWithCountryCode)(NSString *, NSString *) = ^(NSString *text, - NSString *countryCode) { - PhoneNumber *phoneNumber = [PhoneNumber phoneNumberFromText:text - andRegion:countryCode]; - if (phoneNumber && [phoneNumber toE164] && ![phoneNumberSet containsObject:[phoneNumber toE164]]) { - [result addObject:phoneNumber]; - [phoneNumberSet addObject:[phoneNumber toE164]]; - } - }; - - tryParsingWithCountryCode(sanitizedString, [self defaultCountryCode]); - - if ([sanitizedString hasPrefix:@"+"]) { - // If the text starts with "+", don't try prepending - // anything else. - return result; - } - - // Try just adding "+" and parsing it. - tryParsingWithCountryCode([NSString stringWithFormat:@"+%@", sanitizedString], [self defaultCountryCode]); - - // Order matters; better results should appear first so prefer - // matches with the same country code as this client's phone number. - if (clientPhoneNumber.length == 0) { - OWSFailDebug(@"clientPhoneNumber had unexpected length"); - return result; - } - - // Note that NBPhoneNumber uses "country code" to refer to what we call a - // "calling code" (i.e. 44 in +44123123). Within SSK we use "country code" - // (and sometimes "region code") to refer to a country's ISO 2-letter code - // (ISO 3166-1 alpha-2). - NSNumber *callingCodeForLocalNumber = [[PhoneNumber phoneNumberFromE164:clientPhoneNumber] getCountryCode]; - if (callingCodeForLocalNumber == nil) { - OWSFailDebug(@"callingCodeForLocalNumber was unexpectedly nil"); - return result; - } - - NSString *callingCodePrefix = [NSString stringWithFormat:@"+%@", callingCodeForLocalNumber]; - - tryParsingWithCountryCode([callingCodePrefix stringByAppendingString:sanitizedString], [self defaultCountryCode]); - - // Try to determine what the country code is for the local phone number - // and also try parsing the phone number using that country code if it - // differs from the device's region code. - // - // For example, a French person living in Italy might have an - // Italian phone number but use French region/language for their - // phone. They're likely to have both Italian and French contacts. - NSString *localCountryCode = - [PhoneNumberUtil.sharedThreadLocal probableCountryCodeForCallingCode:callingCodePrefix]; - if (localCountryCode && ![localCountryCode isEqualToString:[self defaultCountryCode]]) { - tryParsingWithCountryCode([callingCodePrefix stringByAppendingString:sanitizedString], localCountryCode); - } - - NSString *_Nullable phoneNumberByApplyingMissingAreaCode = - [self applyMissingAreaCodeWithCallingCodeForReferenceNumber:callingCodeForLocalNumber - referenceNumber:clientPhoneNumber - sanitizedInputText:sanitizedString]; - if (phoneNumberByApplyingMissingAreaCode) { - tryParsingWithCountryCode(phoneNumberByApplyingMissingAreaCode, localCountryCode); - } - - return result; -} - -#pragma mark - missing area code - -+ (nullable NSString *)applyMissingAreaCodeWithCallingCodeForReferenceNumber:(NSNumber *)callingCodeForReferenceNumber - referenceNumber:(NSString *)referenceNumber - sanitizedInputText:(NSString *)sanitizedInputText -{ - if ([callingCodeForReferenceNumber isEqual:@(55)]) { - return - [self applyMissingBrazilAreaCodeWithReferenceNumber:referenceNumber sanitizedInputText:sanitizedInputText]; - } else if ([callingCodeForReferenceNumber isEqual:@(1)]) { - return [self applyMissingUnitedStatesAreaCodeWithReferenceNumber:referenceNumber - sanitizedInputText:sanitizedInputText]; - } else { - return nil; - } -} - -#pragma mark - missing brazil area code - -+ (nullable NSString *)applyMissingBrazilAreaCodeWithReferenceNumber:(NSString *)referenceNumber - sanitizedInputText:(NSString *)sanitizedInputText -{ - NSError *error; - NSRegularExpression *missingAreaCodeRegex = - [[NSRegularExpression alloc] initWithPattern:@"^(9?\\d{8})$" options:0 error:&error]; - if (error) { - OWSFailDebug(@"failure: %@", error); - return nil; - } - - if ([missingAreaCodeRegex firstMatchInString:sanitizedInputText - options:0 - range:NSMakeRange(0, sanitizedInputText.length)] - == nil) { - } - - NSString *_Nullable referenceAreaCode = [self brazilAreaCodeFromReferenceNumberE164:referenceNumber]; - if (!referenceAreaCode) { - return nil; - } - return [NSString stringWithFormat:@"+55%@%@", referenceAreaCode, sanitizedInputText]; -} - -+ (nullable NSString *)brazilAreaCodeFromReferenceNumberE164:(NSString *)referenceNumberE164 -{ - NSError *error; - NSRegularExpression *areaCodeRegex = - [[NSRegularExpression alloc] initWithPattern:@"^\\+55(\\d{2})9?\\d{8}" options:0 error:&error]; - if (error) { - OWSFailDebug(@"failure: %@", error); - return nil; - } - - NSArray *matches = - [areaCodeRegex matchesInString:referenceNumberE164 options:0 range:NSMakeRange(0, referenceNumberE164.length)]; - if (matches.count == 0) { - OWSFailDebug(@"failure: unexpectedly unable to extract area code from US number"); - return nil; - } - NSTextCheckingResult *match = matches[0]; - - NSRange firstCaptureRange = [match rangeAtIndex:1]; - return [referenceNumberE164 substringWithRange:firstCaptureRange]; -} - -#pragma mark - missing US area code - -+ (nullable NSString *)applyMissingUnitedStatesAreaCodeWithReferenceNumber:(NSString *)referenceNumber - sanitizedInputText:(NSString *)sanitizedInputText -{ - NSError *error; - NSRegularExpression *missingAreaCodeRegex = - [[NSRegularExpression alloc] initWithPattern:@"^(\\d{7})$" options:0 error:&error]; - if (error) { - OWSFailDebug(@"failure: %@", error); - return nil; - } - - if ([missingAreaCodeRegex firstMatchInString:sanitizedInputText - options:0 - range:NSMakeRange(0, sanitizedInputText.length)] - == nil) { - // area code isn't missing - return nil; - } - - NSString *_Nullable referenceAreaCode = [self unitedStateAreaCodeFromReferenceNumberE164:referenceNumber]; - if (!referenceAreaCode) { - return nil; - } - return [NSString stringWithFormat:@"+1%@%@", referenceAreaCode, sanitizedInputText]; -} - -+ (nullable NSString *)unitedStateAreaCodeFromReferenceNumberE164:(NSString *)referenceNumberE164 -{ - NSError *error; - NSRegularExpression *areaCodeRegex = - [[NSRegularExpression alloc] initWithPattern:@"^\\+1(\\d{3})" options:0 error:&error]; - if (error) { - OWSFailDebug(@"failure: %@", error); - return nil; - } - - NSArray *matches = - [areaCodeRegex matchesInString:referenceNumberE164 options:0 range:NSMakeRange(0, referenceNumberE164.length)]; - if (matches.count == 0) { - OWSFailDebug(@"failure: unexpectedly unable to extract area code from US number"); - return nil; - } - NSTextCheckingResult *match = matches[0]; - - NSRange firstCaptureRange = [match rangeAtIndex:1]; - return [referenceNumberE164 substringWithRange:firstCaptureRange]; -} - -#pragma mark - - -+ (NSString *)removeFormattingCharacters:(NSString *)inputString { - char outputString[inputString.length + 1]; - - int outputLength = 0; - for (NSUInteger i = 0; i < inputString.length; i++) { - unichar c = [inputString characterAtIndex:i]; - if (c == '+' || (c >= '0' && c <= '9')) { - outputString[outputLength++] = (char)c; - } - } - - outputString[outputLength] = 0; - return [NSString stringWithUTF8String:(void *)outputString]; -} - -+ (nullable PhoneNumber *)tryParsePhoneNumberFromE164:(NSString *)text { - OWSAssertDebug(text != nil); - if (![text hasPrefix:COUNTRY_CODE_PREFIX]) { - return nil; - } - - return [self phoneNumberFromE164:text]; -} - -- (NSURL *)toSystemDialerURL { - NSString *link = [NSString stringWithFormat:@"telprompt://%@", self.e164]; - return [NSURL URLWithString:link]; -} - -- (NSString *)toE164 { - return self.e164; -} - -- (nullable NSNumber *)getCountryCode { - return self.phoneNumber.countryCode; -} - -- (nullable NSString *)nationalNumber -{ - NSError *error; - NSString *nationalNumber = [[PhoneNumberUtil sharedThreadLocal] format:self.phoneNumber - numberFormat:NBEPhoneNumberFormatNATIONAL - error:&error]; - if (error) { - OWSLogVerbose(@"error parsing number into national format: %@", error); - return nil; - } - - return nationalNumber; -} - -- (BOOL)isValid -{ - return [[PhoneNumberUtil sharedThreadLocal].nbPhoneNumberUtil isValidNumber:self.phoneNumber]; -} - -- (NSString *)description { - return self.e164; -} - -- (void)encodeWithCoder:(NSCoder *)encoder { - [encoder encodeObject:self.phoneNumber forKey:RPDefaultsKeyPhoneNumberString]; - [encoder encodeObject:self.e164 forKey:RPDefaultsKeyPhoneNumberCanonical]; -} - -- (id)initWithCoder:(NSCoder *)decoder { - if ((self = [super init])) { - _phoneNumber = [decoder decodeObjectForKey:RPDefaultsKeyPhoneNumberString]; - _e164 = [decoder decodeObjectForKey:RPDefaultsKeyPhoneNumberCanonical]; - } - return self; -} - -- (NSComparisonResult)compare:(PhoneNumber *)other -{ - return [self.toE164 compare:other.toE164]; -} - -- (BOOL)isEqual:(id)other -{ - if (![other isMemberOfClass:[self class]]) { - return NO; - } - PhoneNumber *otherPhoneNumber = (PhoneNumber *)other; - - return [self.phoneNumber isEqual:otherPhoneNumber.phoneNumber]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/PhoneNumberUtil.h b/SignalUtilitiesKit/PhoneNumberUtil.h deleted file mode 100644 index 1d5c3ef37..000000000 --- a/SignalUtilitiesKit/PhoneNumberUtil.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface PhoneNumberUtil : NSObject - -@property (nonatomic, retain) NBPhoneNumberUtil *nbPhoneNumberUtil; - -- (instancetype)init NS_UNAVAILABLE; - -+ (instancetype)sharedThreadLocal; - -+ (BOOL)name:(NSString *)nameString matchesQuery:(NSString *)queryString; - -+ (NSString *)callingCodeFromCountryCode:(NSString *)countryCode; -+ (nullable NSString *)countryNameFromCountryCode:(NSString *)countryCode; -+ (NSArray *)countryCodesForSearchTerm:(nullable NSString *)searchTerm; - -// Returns a list of country codes for a calling code in descending -// order of population. -- (NSArray *)countryCodesFromCallingCode:(NSString *)callingCode; -// Returns the most likely country code for a calling code based on population. -- (NSString *)probableCountryCodeForCallingCode:(NSString *)callingCode; - -+ (NSUInteger)translateCursorPosition:(NSUInteger)offset - from:(NSString *)source - to:(NSString *)target - stickingRightward:(bool)preferHigh; - -+ (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode; - -- (nullable NBPhoneNumber *)parse:(NSString *)numberToParse defaultRegion:(NSString *)defaultRegion error:(NSError **)error; -- (NSString *)format:(NBPhoneNumber *)phoneNumber - numberFormat:(NBEPhoneNumberFormat)numberFormat - error:(NSError **)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/PhoneNumberUtil.m b/SignalUtilitiesKit/PhoneNumberUtil.m deleted file mode 100644 index 16bb85545..000000000 --- a/SignalUtilitiesKit/PhoneNumberUtil.m +++ /dev/null @@ -1,610 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "PhoneNumberUtil.h" -#import "ContactsManagerProtocol.h" -#import "FunctionalUtil.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface PhoneNumberUtil () - -@property (nonatomic, readonly) NSMutableDictionary *countryCodesFromCallingCodeCache; -@property (nonatomic, readonly) NSCache *parsedPhoneNumberCache; - -@end - -#pragma mark - - -@implementation PhoneNumberUtil - -+ (PhoneNumberUtil *)sharedThreadLocal -{ - NSString *key = PhoneNumberUtil.logTag; - PhoneNumberUtil *_Nullable threadLocal = NSThread.currentThread.threadDictionary[key]; - if (!threadLocal) { - threadLocal = [PhoneNumberUtil new]; - NSThread.currentThread.threadDictionary[key] = threadLocal; - } - return threadLocal; -} - -- (instancetype)init { - self = [super init]; - - if (self) { - _nbPhoneNumberUtil = [[NBPhoneNumberUtil alloc] init]; - _countryCodesFromCallingCodeCache = [NSMutableDictionary new]; - _parsedPhoneNumberCache = [NSCache new]; - } - - return self; -} - -- (nullable NBPhoneNumber *)parse:(NSString *)numberToParse - defaultRegion:(NSString *)defaultRegion - error:(NSError **)error -{ - NSString *hashKey = [NSString stringWithFormat:@"numberToParse:%@defaultRegion:%@", numberToParse, defaultRegion]; - - NBPhoneNumber *result = [self.parsedPhoneNumberCache objectForKey:hashKey]; - - if (!result) { - result = [self.nbPhoneNumberUtil parse:numberToParse defaultRegion:defaultRegion error:error]; - if (error && *error) { - OWSAssertDebug(!result); - return nil; - } - - OWSAssertDebug(result); - - if (result) { - [self.parsedPhoneNumberCache setObject:result forKey:hashKey]; - } else { - [self.parsedPhoneNumberCache setObject:[NSNull null] forKey:hashKey]; - } - } - - if ([result class] == [NSNull class]) { - return nil; - } else { - return result; - } -} - -- (NSString *)format:(NBPhoneNumber *)phoneNumber - numberFormat:(NBEPhoneNumberFormat)numberFormat - error:(NSError **)error -{ - return [self.nbPhoneNumberUtil format:phoneNumber numberFormat:numberFormat error:error]; -} - -// country code -> country name -+ (nullable NSString *)countryNameFromCountryCode:(NSString *)countryCode -{ - OWSAssertDebug(countryCode); - - NSDictionary *countryCodeComponent = @{NSLocaleCountryCode : countryCode}; - NSString *identifier = [NSLocale localeIdentifierFromComponents:countryCodeComponent]; - NSString *countryName = [NSLocale.currentLocale displayNameForKey:NSLocaleIdentifier value:identifier]; - if (countryName.length < 1) { - countryName = [NSLocale.systemLocale displayNameForKey:NSLocaleIdentifier value:identifier]; - } - if (countryName.length < 1) { - countryName = NSLocalizedString(@"UNKNOWN_VALUE", "Indicates an unknown or unrecognizable value."); - } - return countryName; -} - -// country code -> calling code -+ (NSString *)callingCodeFromCountryCode:(NSString *)countryCode -{ - if ([countryCode isEqualToString:@"AQ"]) { - // Antarctica - return @"+672"; - } else if ([countryCode isEqualToString:@"BV"]) { - // Bouvet Island - return @"+55"; - } else if ([countryCode isEqualToString:@"IC"]) { - // Canary Islands - return @"+34"; - } else if ([countryCode isEqualToString:@"EA"]) { - // Ceuta & Melilla - return @"+34"; - } else if ([countryCode isEqualToString:@"CP"]) { - // Clipperton Island - // - // This country code should be filtered - it does not appear to have a calling code. - return nil; - } else if ([countryCode isEqualToString:@"DG"]) { - // Diego Garcia - return @"+246"; - } else if ([countryCode isEqualToString:@"TF"]) { - // French Southern Territories - return @"+262"; - } else if ([countryCode isEqualToString:@"HM"]) { - // Heard & McDonald Islands - return @"+672"; - } else if ([countryCode isEqualToString:@"XK"]) { - // Kosovo - return @"+383"; - } else if ([countryCode isEqualToString:@"PN"]) { - // Pitcairn Islands - return @"+64"; - } else if ([countryCode isEqualToString:@"GS"]) { - // So. Georgia & So. Sandwich Isl. - return @"+500"; - } else if ([countryCode isEqualToString:@"UM"]) { - // U.S. Outlying Islands - return @"+1"; - } - - NSString *callingCode = - [NSString stringWithFormat:@"%@%@", - COUNTRY_CODE_PREFIX, - [[[self sharedThreadLocal] nbPhoneNumberUtil] getCountryCodeForRegion:countryCode]]; - return callingCode; -} - -- (NSDictionary *)countryCodeToPopulationMap -{ - static dispatch_once_t onceToken; - static NSDictionary *instance = nil; - dispatch_once(&onceToken, ^{ - instance = @{ - @"AD" : @(84000), - @"AE" : @(4975593), - @"AF" : @(29121286), - @"AG" : @(86754), - @"AI" : @(13254), - @"AL" : @(2986952), - @"AM" : @(2968000), - @"AN" : @(300000), - @"AO" : @(13068161), - @"AQ" : @(0), - @"AR" : @(41343201), - @"AS" : @(57881), - @"AT" : @(8205000), - @"AU" : @(21515754), - @"AW" : @(71566), - @"AX" : @(26711), - @"AZ" : @(8303512), - @"BA" : @(4590000), - @"BB" : @(285653), - @"BD" : @(156118464), - @"BE" : @(10403000), - @"BF" : @(16241811), - @"BG" : @(7148785), - @"BH" : @(738004), - @"BI" : @(9863117), - @"BJ" : @(9056010), - @"BL" : @(8450), - @"BM" : @(65365), - @"BN" : @(395027), - @"BO" : @(9947418), - @"BQ" : @(18012), - @"BR" : @(201103330), - @"BS" : @(301790), - @"BT" : @(699847), - @"BV" : @(0), - @"BW" : @(2029307), - @"BY" : @(9685000), - @"BZ" : @(314522), - @"CA" : @(33679000), - @"CC" : @(628), - @"CD" : @(70916439), - @"CF" : @(4844927), - @"CG" : @(3039126), - @"CH" : @(7581000), - @"CI" : @(21058798), - @"CK" : @(21388), - @"CL" : @(16746491), - @"CM" : @(19294149), - @"CN" : @(1330044000), - @"CO" : @(47790000), - @"CR" : @(4516220), - @"CS" : @(10829175), - @"CU" : @(11423000), - @"CV" : @(508659), - @"CW" : @(141766), - @"CX" : @(1500), - @"CY" : @(1102677), - @"CZ" : @(10476000), - @"DE" : @(81802257), - @"DJ" : @(740528), - @"DK" : @(5484000), - @"DM" : @(72813), - @"DO" : @(9823821), - @"DZ" : @(34586184), - @"EC" : @(14790608), - @"EE" : @(1291170), - @"EG" : @(80471869), - @"EH" : @(273008), - @"ER" : @(5792984), - @"ES" : @(46505963), - @"ET" : @(88013491), - @"FI" : @(5244000), - @"FJ" : @(875983), - @"FK" : @(2638), - @"FM" : @(107708), - @"FO" : @(48228), - @"FR" : @(64768389), - @"GA" : @(1545255), - @"GB" : @(62348447), - @"GD" : @(107818), - @"GE" : @(4630000), - @"GF" : @(195506), - @"GG" : @(65228), - @"GH" : @(24339838), - @"GI" : @(27884), - @"GL" : @(56375), - @"GM" : @(1593256), - @"GN" : @(10324025), - @"GP" : @(443000), - @"GQ" : @(1014999), - @"GR" : @(11000000), - @"GS" : @(30), - @"GT" : @(13550440), - @"GU" : @(159358), - @"GW" : @(1565126), - @"GY" : @(748486), - @"HK" : @(6898686), - @"HM" : @(0), - @"HN" : @(7989415), - @"HR" : @(4284889), - @"HT" : @(9648924), - @"HU" : @(9982000), - @"ID" : @(242968342), - @"IE" : @(4622917), - @"IL" : @(7353985), - @"IM" : @(75049), - @"IN" : @(1173108018), - @"IO" : @(4000), - @"IQ" : @(29671605), - @"IR" : @(76923300), - @"IS" : @(308910), - @"IT" : @(60340328), - @"JE" : @(90812), - @"JM" : @(2847232), - @"JO" : @(6407085), - @"JP" : @(127288000), - @"KE" : @(40046566), - @"KG" : @(5776500), - @"KH" : @(14453680), - @"KI" : @(92533), - @"KM" : @(773407), - @"KN" : @(51134), - @"KP" : @(22912177), - @"KR" : @(48422644), - @"KW" : @(2789132), - @"KY" : @(44270), - @"KZ" : @(15340000), - @"LA" : @(6368162), - @"LB" : @(4125247), - @"LC" : @(160922), - @"LI" : @(35000), - @"LK" : @(21513990), - @"LR" : @(3685076), - @"LS" : @(1919552), - @"LT" : @(2944459), - @"LU" : @(497538), - @"LV" : @(2217969), - @"LY" : @(6461454), - @"MA" : @(33848242), - @"MC" : @(32965), - @"MD" : @(4324000), - @"ME" : @(666730), - @"MF" : @(35925), - @"MG" : @(21281844), - @"MH" : @(65859), - @"MK" : @(2062294), - @"ML" : @(13796354), - @"MM" : @(53414374), - @"MN" : @(3086918), - @"MO" : @(449198), - @"MP" : @(53883), - @"MQ" : @(432900), - @"MR" : @(3205060), - @"MS" : @(9341), - @"MT" : @(403000), - @"MU" : @(1294104), - @"MV" : @(395650), - @"MW" : @(15447500), - @"MX" : @(112468855), - @"MY" : @(28274729), - @"MZ" : @(22061451), - @"NA" : @(2128471), - @"NC" : @(216494), - @"NE" : @(15878271), - @"NF" : @(1828), - @"NG" : @(154000000), - @"NI" : @(5995928), - @"NL" : @(16645000), - @"NO" : @(5009150), - @"NP" : @(28951852), - @"NR" : @(10065), - @"NU" : @(2166), - @"NZ" : @(4252277), - @"OM" : @(2967717), - @"PA" : @(3410676), - @"PE" : @(29907003), - @"PF" : @(270485), - @"PG" : @(6064515), - @"PH" : @(99900177), - @"PK" : @(184404791), - @"PL" : @(38500000), - @"PM" : @(7012), - @"PN" : @(46), - @"PR" : @(3916632), - @"PS" : @(3800000), - @"PT" : @(10676000), - @"PW" : @(19907), - @"PY" : @(6375830), - @"QA" : @(840926), - @"RE" : @(776948), - @"RO" : @(21959278), - @"RS" : @(7344847), - @"RU" : @(140702000), - @"RW" : @(11055976), - @"SA" : @(25731776), - @"SB" : @(559198), - @"SC" : @(88340), - @"SD" : @(35000000), - @"SE" : @(9828655), - @"SG" : @(4701069), - @"SH" : @(7460), - @"SI" : @(2007000), - @"SJ" : @(2550), - @"SK" : @(5455000), - @"SL" : @(5245695), - @"SM" : @(31477), - @"SN" : @(12323252), - @"SO" : @(10112453), - @"SR" : @(492829), - @"SS" : @(8260490), - @"ST" : @(175808), - @"SV" : @(6052064), - @"SX" : @(37429), - @"SY" : @(22198110), - @"SZ" : @(1354051), - @"TC" : @(20556), - @"TD" : @(10543464), - @"TF" : @(140), - @"TG" : @(6587239), - @"TH" : @(67089500), - @"TJ" : @(7487489), - @"TK" : @(1466), - @"TL" : @(1154625), - @"TM" : @(4940916), - @"TN" : @(10589025), - @"TO" : @(122580), - @"TR" : @(77804122), - @"TT" : @(1328019), - @"TV" : @(10472), - @"TW" : @(22894384), - @"TZ" : @(41892895), - @"UA" : @(45415596), - @"UG" : @(33398682), - @"UM" : @(0), - @"US" : @(310232863), - @"UY" : @(3477000), - @"UZ" : @(27865738), - @"VA" : @(921), - @"VC" : @(104217), - @"VE" : @(27223228), - @"VG" : @(21730), - @"VI" : @(108708), - @"VN" : @(89571130), - @"VU" : @(221552), - @"WF" : @(16025), - @"WS" : @(192001), - @"XK" : @(1800000), - @"YE" : @(23495361), - @"YT" : @(159042), - @"ZA" : @(49000000), - @"ZM" : @(13460305), - @"ZW" : @(13061000), - }; - }); - return instance; -} - -- (NSArray *)countryCodesSortedByPopulationDescending -{ - NSDictionary *countryCodeToPopulationMap = [self countryCodeToPopulationMap]; - NSArray *result = [NSLocale.ISOCountryCodes - sortedArrayUsingComparator:^NSComparisonResult(NSString *_Nonnull left, NSString *_Nonnull right) { - int leftPopulation = [countryCodeToPopulationMap[left] intValue]; - int rightPopulation = [countryCodeToPopulationMap[right] intValue]; - // Invert the values for a descending sort. - return [@(-leftPopulation) compare:@(-rightPopulation)]; - }]; - return result; -} - -- (NSArray *)countryCodesFromCallingCode:(NSString *)callingCode -{ - @synchronized(self) - { - OWSAssertDebug(callingCode.length > 0); - - NSArray *result = self.countryCodesFromCallingCodeCache[callingCode]; - if (!result) { - NSMutableArray *countryCodes = [NSMutableArray new]; - for (NSString *countryCode in [self countryCodesSortedByPopulationDescending]) { - NSString *callingCodeForCountryCode = [PhoneNumberUtil callingCodeFromCountryCode:countryCode]; - if ([callingCode isEqualToString:callingCodeForCountryCode]) { - [countryCodes addObject:countryCode]; - } - } - result = [countryCodes copy]; - self.countryCodesFromCallingCodeCache[callingCode] = result; - } - return result; - } -} - -- (NSString *)probableCountryCodeForCallingCode:(NSString *)callingCode -{ - OWSAssertDebug(callingCode.length > 0); - - NSArray *countryCodes = [self countryCodesFromCallingCode:callingCode]; - return (countryCodes.count > 0 ? countryCodes[0] : nil); -} - -+ (BOOL)name:(NSString *)nameString matchesQuery:(NSString *)queryString { - NSCharacterSet *whitespaceSet = NSCharacterSet.whitespaceCharacterSet; - NSArray *queryStrings = [queryString componentsSeparatedByCharactersInSet:whitespaceSet]; - NSArray *nameStrings = [nameString componentsSeparatedByCharactersInSet:whitespaceSet]; - - return [queryStrings all:^int(NSString *query) { - if (query.length == 0) - return YES; - return [nameStrings any:^int(NSString *nameWord) { - NSStringCompareOptions searchOpts = NSCaseInsensitiveSearch | NSAnchoredSearch; - return [nameWord rangeOfString:query options:searchOpts].location != NSNotFound; - }]; - }]; -} - -// search term -> country codes -+ (NSArray *)countryCodesForSearchTerm:(nullable NSString *)searchTerm { - searchTerm = [searchTerm stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - - NSArray *countryCodes = NSLocale.ISOCountryCodes; - - countryCodes = [countryCodes filter:^int(NSString *countryCode) { - NSString *countryName = [self countryNameFromCountryCode:countryCode]; - NSString *callingCode = [self callingCodeFromCountryCode:countryCode]; - - if (countryName.length < 1 || callingCode.length < 1 || [callingCode isEqualToString:@"+0"]) { - // Filter out countries without a valid calling code. - return NO; - } - - if (searchTerm.length < 1) { - return YES; - } - - if ([self name:countryName matchesQuery:searchTerm]) { - return YES; - } - - if ([self name:countryCode matchesQuery:searchTerm]) { - return YES; - } - - // We rely on the already internationalized string; as that is what - // the user would see entered (i.e. with COUNTRY_CODE_PREFIX). - - if ([callingCode containsString:searchTerm]) { - return YES; - } - - return NO; - }]; - - return [self sortedCountryCodesByName:countryCodes]; -} - -+ (NSArray *)sortedCountryCodesByName:(NSArray *)countryCodesByISOCode { - return [countryCodesByISOCode sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { - return [[self countryNameFromCountryCode:obj1] caseInsensitiveCompare:[self countryNameFromCountryCode:obj2]]; - }]; -} - -// black magic -+ (NSUInteger)translateCursorPosition:(NSUInteger)offset - from:(NSString *)source - to:(NSString *)target - stickingRightward:(bool)preferHigh { - OWSAssertDebug(source != nil); - OWSAssertDebug(target != nil); - OWSAssertDebug(offset <= source.length); - - NSUInteger n = source.length; - NSUInteger m = target.length; - - int moves[n + 1][m + 1]; - { - // Wagner-Fischer algorithm for computing edit distance, with a tweaks: - // - Tracks best moves at each location, to allow reconstruction of edit path - // - Does not allow substitutions - // - Over-values digits relative to other characters, so they're "harder" to delete or insert - const int DIGIT_VALUE = 10; - NSUInteger scores[n + 1][m + 1]; - moves[0][0] = 0; // (match) move up and left - scores[0][0] = 0; - for (NSUInteger i = 1; i <= n; i++) { - scores[i][0] = i; - moves[i][0] = -1; // (deletion) move left - } - for (NSUInteger j = 1; j <= m; j++) { - scores[0][j] = j; - moves[0][j] = +1; // (insertion) move up - } - - NSCharacterSet *digits = NSCharacterSet.decimalDigitCharacterSet; - for (NSUInteger i = 1; i <= n; i++) { - unichar c1 = [source characterAtIndex:i - 1]; - bool isDigit1 = [digits characterIsMember:c1]; - for (NSUInteger j = 1; j <= m; j++) { - unichar c2 = [target characterAtIndex:j - 1]; - bool isDigit2 = [digits characterIsMember:c2]; - if (c1 == c2) { - scores[i][j] = scores[i - 1][j - 1]; - moves[i][j] = 0; // move up-and-left - } else { - NSUInteger del = scores[i - 1][j] + (isDigit1 ? DIGIT_VALUE : 1); - NSUInteger ins = scores[i][j - 1] + (isDigit2 ? DIGIT_VALUE : 1); - bool isDel = del < ins; - scores[i][j] = isDel ? del : ins; - moves[i][j] = isDel ? -1 : +1; - } - } - } - } - - // Backtrack to find desired corresponding offset - for (NSUInteger i = n, j = m;; i -= 1) { - if (i == offset && preferHigh) - return j; // early exit - while (moves[i][j] == +1) - j -= 1; // zip upward - if (i == offset) - return j; // late exit - if (moves[i][j] == 0) - j -= 1; - } -} - -+ (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode -{ - PhoneNumberUtil *sharedUtil = [self sharedThreadLocal]; - - // Signal users are very likely using mobile devices, so prefer that kind of example. - NSError *error; - NBPhoneNumber *nbPhoneNumber = - [sharedUtil.nbPhoneNumberUtil getExampleNumberForType:countryCode type:NBEPhoneNumberTypeMOBILE error:&error]; - OWSAssertDebug(!error); - if (!nbPhoneNumber) { - // For countries that with similar mobile and land lines, use "line or mobile" - // examples. - nbPhoneNumber = [sharedUtil.nbPhoneNumberUtil getExampleNumberForType:countryCode - type:NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE - error:&error]; - OWSAssertDebug(!error); - } - NSString *result = (nbPhoneNumber - ? [sharedUtil.nbPhoneNumberUtil format:nbPhoneNumber numberFormat:NBEPhoneNumberFormatE164 error:&error] - : nil); - OWSAssertDebug(!error); - return result; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Poller.swift b/SignalUtilitiesKit/Poller.swift index 8387361ca..9a819c981 100644 --- a/SignalUtilitiesKit/Poller.swift +++ b/SignalUtilitiesKit/Poller.swift @@ -93,7 +93,7 @@ public final class Poller : NSObject { print("[Loki] Received \(messages.count) new message(s).") } messages.forEach { json in - guard let envelope = SSKProtoEnvelope.from(json) else { return } + guard let envelope = SNProtoEnvelope.from(json) else { return } do { let data = try envelope.serializedData() let job = MessageReceiveJob(data: data) diff --git a/SignalUtilitiesKit/PreKeyRefreshOperation.swift b/SignalUtilitiesKit/PreKeyRefreshOperation.swift index a23349651..ed440fabe 100644 --- a/SignalUtilitiesKit/PreKeyRefreshOperation.swift +++ b/SignalUtilitiesKit/PreKeyRefreshOperation.swift @@ -16,10 +16,6 @@ public class RefreshPreKeysOperation: OWSOperation { return TSAccountManager.sharedInstance() } - private var accountServiceClient: AccountServiceClient { - return AccountServiceClient.shared - } - private var primaryStorage: OWSPrimaryStorage { return OWSPrimaryStorage.shared() } @@ -36,48 +32,10 @@ public class RefreshPreKeysOperation: OWSOperation { return } - // Loki: Doing this on the global queue to match Signal DispatchQueue.global().async { SessionManagementProtocol.refreshSignedPreKey() self.reportSuccess() } - - /* Loki: Original code - * ================ - firstly { - self.accountServiceClient.getPreKeysCount() - }.then(on: DispatchQueue.global()) { preKeysCount -> Promise in - Logger.debug("preKeysCount: \(preKeysCount)") - guard preKeysCount < kEphemeralPreKeysMinimumCount || self.primaryStorage.currentSignedPrekeyId() == nil else { - Logger.debug("Available keys sufficient: \(preKeysCount)") - return Promise.value(()) - } - - let identityKey: Data = self.identityKeyManager.identityKeyPair()!.publicKey - let signedPreKeyRecord: SignedPreKeyRecord = self.primaryStorage.generateRandomSignedRecord() - let preKeyRecords: [PreKeyRecord] = self.primaryStorage.generatePreKeyRecords() - - self.primaryStorage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - self.primaryStorage.storePreKeyRecords(preKeyRecords) - - return firstly { - self.accountServiceClient.setPreKeys(identityKey: identityKey, signedPreKeyRecord: signedPreKeyRecord, preKeyRecords: preKeyRecords) - }.done { - signedPreKeyRecord.markAsAcceptedByService() - self.primaryStorage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - self.primaryStorage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - - TSPreKeyManager.clearPreKeyUpdateFailureCount() - TSPreKeyManager.clearSignedPreKeyRecords() - } - }.done { - Logger.debug("done") - self.reportSuccess() - }.catch { error in - self.reportError(error) - }.retainUntilComplete() - * ================ - */ } public override func didSucceed() { @@ -85,21 +43,6 @@ public class RefreshPreKeysOperation: OWSOperation { } override public func didFail(error: Error) { - switch error { - case let networkManagerError as NetworkManagerError: - guard !networkManagerError.isNetworkError else { - Logger.debug("Don't report SPK rotation failure w/ network error") - return - } - - guard networkManagerError.statusCode >= 400 && networkManagerError.statusCode <= 599 else { - Logger.debug("Don't report SPK rotation failure w/ non application error") - return - } - - TSPreKeyManager.incrementPreKeyUpdateFailureCount() - default: - Logger.debug("Don't report SPK rotation failure w/ non NetworkManager error: \(error)") - } + Logger.debug("Don't report SPK rotation failure w/ non NetworkManager error: \(error)") } } diff --git a/SignalUtilitiesKit/ProfileFetcherJob.swift b/SignalUtilitiesKit/ProfileFetcherJob.swift deleted file mode 100644 index 89e11bf99..000000000 --- a/SignalUtilitiesKit/ProfileFetcherJob.swift +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - -@objc -public class ProfileFetcherJob: NSObject { - - // This property is only accessed on the main queue. - static var fetchDateMap = [String: Date]() - - let ignoreThrottling: Bool - - var backgroundTask: OWSBackgroundTask? - - @objc - public class func run(thread: TSThread) { - guard CurrentAppContext().isMainApp else { - return - } - - ProfileFetcherJob().run(recipientIds: thread.recipientIdentifiers) - } - - @objc - public class func run(recipientId: String, ignoreThrottling: Bool) { - guard CurrentAppContext().isMainApp else { - return - } - - ProfileFetcherJob(ignoreThrottling: ignoreThrottling).run(recipientIds: [recipientId]) - } - - public init(ignoreThrottling: Bool = false) { - self.ignoreThrottling = ignoreThrottling - } - - // MARK: - Dependencies - - private var networkManager: TSNetworkManager { - return SSKEnvironment.shared.networkManager - } - - private var socketManager: TSSocketManager { - return TSSocketManager.shared - } - - private var primaryStorage: OWSPrimaryStorage { - return SSKEnvironment.shared.primaryStorage - } - - private var udManager: OWSUDManager { - return SSKEnvironment.shared.udManager - } - - private var profileManager: OWSProfileManager { - return OWSProfileManager.shared() - } - - private var identityManager: OWSIdentityManager { - return SSKEnvironment.shared.identityManager - } - - private var signalServiceClient: SignalServiceClient { - // TODO hang on SSKEnvironment - return SignalServiceRestClient() - } - - private var tsAccountManager: TSAccountManager { - return SSKEnvironment.shared.tsAccountManager - } - - // MARK: - - - public func run(recipientIds: [String]) { - AssertIsOnMainThread() - - /* Loki: Original code - * Disabled as we don't have an endpoint for fetching profiles - * ================ - guard CurrentAppContext().isMainApp else { - // Only refresh profiles in the MainApp to decrease the chance of missed SN notifications - // in the AppExtension for our users who choose not to verify contacts. - owsFailDebug("Should only fetch profiles in the main app") - return - } - - backgroundTask = OWSBackgroundTask(label: "\(#function)", completionBlock: { [weak self] status in - AssertIsOnMainThread() - - guard status == .expired else { - return - } - guard let _ = self else { - return - } - Logger.error("background task time ran out before profile fetch completed.") - }) - - DispatchQueue.global().async { - for recipientId in recipientIds { - self.getAndUpdateProfile(recipientId: recipientId) - } - } - * ================ - */ - } - - enum ProfileFetcherJobError: Error { - case throttled(lastTimeInterval: TimeInterval) - } - - public func getAndUpdateProfile(recipientId: String, remainingRetries: Int = 3) { - self.getProfile(recipientId: recipientId).map(on: DispatchQueue.global()) { profile in - self.updateProfile(signalServiceProfile: profile) - }.catch(on: DispatchQueue.global()) { error in - switch error { - case ProfileFetcherJobError.throttled(let lastTimeInterval): - // skipping - break - case let error as SignalServiceProfile.ValidationError: - Logger.warn("skipping updateProfile retry. Invalid profile for: \(recipientId) error: \(error)") - default: - if remainingRetries > 0 { - self.getAndUpdateProfile(recipientId: recipientId, remainingRetries: remainingRetries - 1) - } else { - Logger.error("failed to get profile with error: \(error)") - } - } - }.retainUntilComplete() - } - - public func getProfile(recipientId: String) -> Promise { - if !ignoreThrottling { - if let lastDate = ProfileFetcherJob.fetchDateMap[recipientId] { - let lastTimeInterval = fabs(lastDate.timeIntervalSinceNow) - // Don't check a profile more often than every N seconds. - // - // Throttle less in debug to make it easier to test problems - // with our fetching logic. - let kGetProfileMaxFrequencySeconds = _isDebugAssertConfiguration() ? 60 : 60.0 * 5.0 - guard lastTimeInterval > kGetProfileMaxFrequencySeconds else { - return Promise(error: ProfileFetcherJobError.throttled(lastTimeInterval: lastTimeInterval)) - } - } - } - ProfileFetcherJob.fetchDateMap[recipientId] = Date() - - Logger.error("getProfile: \(recipientId)") - - // Don't use UD for "self" profile fetches. - var udAccess: OWSUDAccess? - if recipientId != tsAccountManager.localNumber() { - udAccess = udManager.udAccess(forRecipientId: recipientId, - requireSyncAccess: false) - } - - return requestProfile(recipientId: recipientId, - udAccess: udAccess, - canFailoverUDAuth: true) - } - - private func requestProfile(recipientId: String, - udAccess: OWSUDAccess?, - canFailoverUDAuth: Bool) -> Promise { - let requestMaker = RequestMaker(label: "Profile Fetch", - requestFactoryBlock: { (udAccessKeyForRequest) -> TSRequest in - return OWSRequestFactory.getProfileRequest(recipientId: recipientId, udAccessKey: udAccessKeyForRequest) - }, udAuthFailureBlock: { - // Do nothing - }, websocketFailureBlock: { - // Do nothing - }, recipientId: recipientId, - udAccess: udAccess, - canFailoverUDAuth: canFailoverUDAuth) - return requestMaker.makeRequest() - .map(on: DispatchQueue.global()) { (result: RequestMakerResult) -> SignalServiceProfile in - try SignalServiceProfile(recipientId: recipientId, responseObject: result.responseObject) - } - } - - private func updateProfile(signalServiceProfile: SignalServiceProfile) { - let recipientId = signalServiceProfile.recipientId - verifyIdentityUpToDateAsync(recipientId: recipientId, latestIdentityKey: signalServiceProfile.identityKey) - - profileManager.updateProfile(forRecipientId: recipientId, - profileNameEncrypted: signalServiceProfile.profileNameEncrypted, - avatarUrlPath: signalServiceProfile.avatarUrlPath) - - updateUnidentifiedAccess(recipientId: recipientId, - verifier: signalServiceProfile.unidentifiedAccessVerifier, - hasUnrestrictedAccess: signalServiceProfile.hasUnrestrictedUnidentifiedAccess) - } - - private func updateUnidentifiedAccess(recipientId: String, verifier: Data?, hasUnrestrictedAccess: Bool) { - guard let verifier = verifier else { - // If there is no verifier, at least one of this user's devices - // do not support UD. - udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId) - return - } - - if hasUnrestrictedAccess { - udManager.setUnidentifiedAccessMode(.unrestricted, recipientId: recipientId) - return - } - - guard let udAccessKey = udManager.udAccessKey(forRecipientId: recipientId) else { - udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId) - return - } - - let dataToVerify = Data(count: 32) - guard let expectedVerifier = Cryptography.computeSHA256HMAC(dataToVerify, withHMACKey: udAccessKey.keyData) else { - owsFailDebug("could not compute verification") - udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId) - return - } - - guard expectedVerifier.ows_constantTimeIsEqual(to: verifier) else { - Logger.verbose("verifier mismatch, new profile key?") - udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId) - return - } - - udManager.setUnidentifiedAccessMode(.enabled, recipientId: recipientId) - } - - private func verifyIdentityUpToDateAsync(recipientId: String, latestIdentityKey: Data) { - primaryStorage.newDatabaseConnection().asyncReadWrite { (transaction) in - if self.identityManager.saveRemoteIdentity(latestIdentityKey, recipientId: recipientId, protocolContext: transaction) { - Logger.info("updated identity key with fetched profile for recipient: \(recipientId)") - self.primaryStorage.archiveAllSessions(forContact: recipientId, protocolContext: transaction) - } else { - // no change in identity. - } - } - } -} diff --git a/SignalUtilitiesKit/Promise+retainUntilComplete.swift b/SignalUtilitiesKit/Promise+retainUntilComplete.swift deleted file mode 100644 index 34a9f60c0..000000000 --- a/SignalUtilitiesKit/Promise+retainUntilComplete.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import PromiseKit - -@objc -public extension AnyPromise { - /** - * Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the - * promise to self retain, until it completes to avoid the risk it's GC'd before completion. - */ - @objc - func retainUntilComplete() { - var retainCycle: AnyPromise? = self - _ = self.ensure { - assert(retainCycle != nil) - retainCycle = nil - } - } -} - -public extension PMKFinalizer { - /** - * Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the - * promise to self retain, until it completes to avoid the risk it's GC'd before completion. - */ - func retainUntilComplete() { - var retainCycle: PMKFinalizer? = self - _ = self.finally { - assert(retainCycle != nil) - retainCycle = nil - } - } -} - -public extension Promise { - /** - * Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the - * promise to self retain, until it completes to avoid the risk it's GC'd before completion. - */ - func retainUntilComplete() { - var retainCycle: Promise? = self - _ = self.ensure { - assert(retainCycle != nil) - retainCycle = nil - } - } -} - -public extension Guarantee { - /** - * Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the - * promise to self retain, until it completes to avoid the risk it's GC'd before completion. - */ - func retainUntilComplete() { - var retainCycle: Guarantee? = self - _ = self.done { _ in - assert(retainCycle != nil) - retainCycle = nil - } - } -} diff --git a/SignalUtilitiesKit/ProofOfWork.swift b/SignalUtilitiesKit/ProofOfWork.swift deleted file mode 100644 index cbcfb5e4e..000000000 --- a/SignalUtilitiesKit/ProofOfWork.swift +++ /dev/null @@ -1,109 +0,0 @@ -import CryptoSwift - -private extension UInt64 { - - fileprivate init(_ decimal: Decimal) { - self.init(truncating: decimal as NSDecimalNumber) - } - - // Convert a UInt8 array to a UInt64 - fileprivate init(_ bytes: [UInt8]) { - precondition(bytes.count <= MemoryLayout.size) - var value: UInt64 = 0 - for byte in bytes { - value <<= 8 - value |= UInt64(byte) - } - self.init(value) - } -} - -private extension MutableCollection where Element == UInt8, Index == Int { - - /// Increment every element by the given amount - /// - /// - Parameter amount: The amount to increment by - /// - Returns: The incremented collection - fileprivate func increment(by amount: Int) -> Self { - var result = self - var increment = amount - for i in (0.. 0 else { break } - let sum = Int(result[i]) + increment - result[i] = UInt8(sum % 256) - increment = sum / 256 - } - return result - } -} - -/** - * The main proof of work logic. - * - * This was copied from the desktop messenger. - * Ref: libloki/proof-of-work.js - */ -public enum ProofOfWork { - - // If this changes then we also have to use something other than UInt64 to support the new length - private static let nonceLength = 8 - - /// Calculate a proof of work with the given configuration - /// - /// Ref: https://bitmessage.org/wiki/Proof_of_work - /// - /// - Parameters: - /// - data: The message data - /// - pubKey: The message recipient - /// - timestamp: The timestamp - /// - ttl: The message time to live in milliseconds - /// - Returns: A nonce string or `nil` if it failed - public static func calculate(data: String, pubKey: String, timestamp: UInt64, ttl: UInt64) -> String? { - let payload = createPayload(pubKey: pubKey, data: data, timestamp: timestamp, ttl: ttl) - let target = calcTarget(ttl: ttl, payloadLength: payload.count, nonceTrials: Int(SnodeAPI.powDifficulty)) - - // Start with the max value - var trialValue = UInt64.max - - let initialHash = payload.sha512() - var nonce = [UInt8](repeating: 0, count: nonceLength) - - while trialValue > target { - nonce = nonce.increment(by: 1) - - // This is different to the bitmessage PoW - // resultHash = hash(nonce + hash(data)) ==> hash(nonce + initialHash) - let resultHash = (nonce + initialHash).sha512() - let trialValueArray = Array(resultHash[0..<8]) - trialValue = UInt64(trialValueArray) - } - - return nonce.toBase64() - } - - /// Get the proof of work payload - private static func createPayload(pubKey: String, data: String, timestamp: UInt64, ttl: UInt64) -> [UInt8] { - let timestampString = String(timestamp) - let ttlString = String(ttl) - let payloadString = timestampString + ttlString + pubKey + data - return payloadString.bytes - } - - /// Calculate the target we need to reach - private static func calcTarget(ttl: UInt64, payloadLength: Int, nonceTrials: Int) -> UInt64 { - let two16 = UInt64(pow(2, 16) - 1) - let two64 = UInt64(pow(2, 64) - 1) - - // Do all the calculations - let totalLength = UInt64(payloadLength + nonceLength) - let ttlInSeconds = ttl / 1000 - let ttlMult = ttlInSeconds * totalLength - - // UInt64 values - let innerFrac = ttlMult / two16 - let lenPlusInnerFrac = totalLength + innerFrac - let denominator = UInt64(nonceTrials) * lenPlusInnerFrac - - return two64 / denominator - } -} diff --git a/SignalUtilitiesKit/PublicChatPoller.swift b/SignalUtilitiesKit/PublicChatPoller.swift index 9d1dbf10c..27ca5dc4d 100644 --- a/SignalUtilitiesKit/PublicChatPoller.swift +++ b/SignalUtilitiesKit/PublicChatPoller.swift @@ -61,171 +61,102 @@ public final class PublicChatPoller : NSObject { let userPublicKey = getUserHexEncodedPublicKey() return OpenGroupAPI.getMessages(for: publicChat.channel, on: publicChat.server).done(on: DispatchQueue.global(qos: .default)) { messages in self.isPolling = false - let uniquePublicKeys = Set(messages.map { $0.senderPublicKey }) - func proceed() { - let storage = OWSPrimaryStorage.shared() - /* - var newDisplayNameUpdatees: Set = [] - storage.dbReadConnection.read { transaction in - newDisplayNameUpdatees = Set(uniquePublicKeys.filter { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) != $0 }.compactMap { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) }) + let storage = OWSPrimaryStorage.shared() + // Sorting the messages by timestamp before importing them fixes an issue where messages that quote older messages can't find those older messages + messages.sorted { $0.serverTimestamp < $1.serverTimestamp }.forEach { message in + let senderPublicKey = message.senderPublicKey + var wasSentByCurrentUser = (senderPublicKey == getUserHexEncodedPublicKey()) + func generateDisplayName(from rawDisplayName: String) -> String { + let endIndex = senderPublicKey.endIndex + let cutoffIndex = senderPublicKey.index(endIndex, offsetBy: -8) + return "\(rawDisplayName) (...\(senderPublicKey[cutoffIndex.. String { - let endIndex = senderPublicKey.endIndex - let cutoffIndex = senderPublicKey.index(endIndex, offsetBy: -8) - return "\(rawDisplayName) (...\(senderPublicKey[cutoffIndex.. 0) { - SSKEnvironment.shared.profileManager.updateProfileForContact(withID: masterPublicKey!, displayName: message.displayName, with: transaction) - } - SSKEnvironment.shared.profileManager.updateService(withProfileName: message.displayName, avatarURL: profilePicture.url) - SSKEnvironment.shared.profileManager.setProfileKeyData(profilePicture.profileKey, forRecipientId: masterPublicKey!, avatarURL: profilePicture.url) - } + dataMessage.setAttachments(attachments) + if let linkPreview = message.attachments.first(where: { $0.kind == .linkPreview }) { + let signalLinkPreview = SSKProtoDataMessagePreview.builder(url: linkPreview.linkPreviewURL!) + signalLinkPreview.setTitle(linkPreview.linkPreviewTitle!) + let attachment = SSKProtoAttachmentPointer.builder(id: linkPreview.serverID) + attachment.setContentType(linkPreview.contentType) + attachment.setSize(UInt32(linkPreview.size)) + attachment.setFileName(linkPreview.fileName) + attachment.setFlags(UInt32(linkPreview.flags)) + attachment.setWidth(UInt32(linkPreview.width)) + attachment.setHeight(UInt32(linkPreview.height)) + if let caption = linkPreview.caption { + attachment.setCaption(caption) } + attachment.setUrl(linkPreview.url) + signalLinkPreview.setImage(try! attachment.build()) + dataMessage.setPreview([ try! signalLinkPreview.build() ]) } - } - /* - let hexEncodedPublicKeysToUpdate = uniquePublicKeys.filter { hexEncodedPublicKey in - let timeSinceLastUpdate: TimeInterval - if let lastDeviceLinkUpdate = MultiDeviceProtocol.lastDeviceLinkUpdate[hexEncodedPublicKey] { - timeSinceLastUpdate = Date().timeIntervalSince(lastDeviceLinkUpdate) + let profile = SSKProtoDataMessageLokiProfile.builder() + profile.setDisplayName(message.displayName) + if let profilePicture = message.profilePicture { + profile.setProfilePicture(profilePicture.url) + dataMessage.setProfileKey(profilePicture.profileKey) + } + dataMessage.setProfile(try! profile.build()) + dataMessage.setTimestamp(message.timestamp) + dataMessage.setGroup(try! groupContext.build()) + if let quote = message.quote { + let signalQuote = SSKProtoDataMessageQuote.builder(id: quote.quotedMessageTimestamp, author: quote.quoteePublicKey) + signalQuote.setText(quote.quotedMessageBody) + dataMessage.setQuote(try! signalQuote.build()) + } + let body = (message.body == message.timestamp.description) ? "" : message.body // Workaround for the fact that the back-end doesn't accept messages without a body + dataMessage.setBody(body) + if let messageServerID = message.serverID { + let publicChatInfo = SSKProtoPublicChatInfo.builder() + publicChatInfo.setServerID(messageServerID) + dataMessage.setPublicChatInfo(try! publicChatInfo.build()) + } + let content = SSKProtoContent.builder() + if !wasSentByCurrentUser { + content.setDataMessage(try! dataMessage.build()) } else { - timeSinceLastUpdate = .infinity + let syncMessageSentBuilder = SSKProtoSyncMessageSent.builder() + syncMessageSentBuilder.setMessage(try! dataMessage.build()) + syncMessageSentBuilder.setDestination(userPublicKey) + syncMessageSentBuilder.setTimestamp(message.timestamp) + let syncMessageSent = try! syncMessageSentBuilder.build() + let syncMessageBuilder = SSKProtoSyncMessage.builder() + syncMessageBuilder.setSent(syncMessageSent) + content.setSyncMessage(try! syncMessageBuilder.build()) } - return timeSinceLastUpdate > MultiDeviceProtocol.deviceLinkUpdateInterval - } - if !hexEncodedPublicKeysToUpdate.isEmpty { - FileServerAPI.getDeviceLinks(associatedWith: hexEncodedPublicKeysToUpdate).done(on: DispatchQueue.global(qos: .default)) { _ in - proceed() - hexEncodedPublicKeysToUpdate.forEach { - MultiDeviceProtocol.lastDeviceLinkUpdate[$0] = Date() // TODO: Doing this from a global queue seems a bit iffy + let envelope = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp) + envelope.setSource(senderPublicKey) + envelope.setSourceDevice(1) + envelope.setContent(try! content.build().serializedData()) + envelope.setServerTimestamp(message.serverTimestamp) + Storage.writeSync { transaction in + transaction.setObject(senderDisplayName, forKey: senderPublicKey, inCollection: publicChat.id) + let messageServerID = message.serverID + let job = MessageReceiveJob(data: try! envelope.buildSerializedData(), messageServerID: messageServerID) + Storage.write { transaction in + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } - }.catch(on: DispatchQueue.global(qos: .default)) { error in - if (error as? DotNetAPI.DotNetAPIError) == DotNetAPI.DotNetAPIError.parsingFailed { - // Don't immediately re-fetch in case of failure due to a parsing error - hexEncodedPublicKeysToUpdate.forEach { - MultiDeviceProtocol.lastDeviceLinkUpdate[$0] = Date() // TODO: Doing this from a global queue seems a bit iffy - } - } - proceed() } - } else { - */ - DispatchQueue.global(qos: .default).async { - proceed() - } - /* } - */ } } diff --git a/SignalUtilitiesKit/ContactCellView.h b/SignalUtilitiesKit/Remove Later/ContactCellView.h similarity index 100% rename from SignalUtilitiesKit/ContactCellView.h rename to SignalUtilitiesKit/Remove Later/ContactCellView.h diff --git a/SignalUtilitiesKit/ContactCellView.m b/SignalUtilitiesKit/Remove Later/ContactCellView.m similarity index 96% rename from SignalUtilitiesKit/ContactCellView.m rename to SignalUtilitiesKit/Remove Later/ContactCellView.m index 0819889f7..38a45d2cb 100644 --- a/SignalUtilitiesKit/ContactCellView.m +++ b/SignalUtilitiesKit/Remove Later/ContactCellView.m @@ -3,8 +3,6 @@ // #import "ContactCellView.h" -#import "OWSContactAvatarBuilder.h" -#import "OWSContactsManager.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" #import @@ -48,13 +46,6 @@ const CGFloat kContactCellAvatarTextMargin = 12; #pragma mark - Dependencies -- (OWSContactsManager *)contactsManager -{ - OWSAssertDebug(Environment.shared.contactsManager); - - return Environment.shared.contactsManager; -} - - (OWSPrimaryStorage *)primaryStorage { OWSAssertDebug(SSKEnvironment.shared.primaryStorage); @@ -150,8 +141,7 @@ const CGFloat kContactCellAvatarTextMargin = 12; NSFontAttributeName : self.nameLabel.font, }]; } else { - self.nameLabel.attributedText = - [self.contactsManager formattedFullNameForRecipientId:recipientId font:self.nameLabel.font]; + self.nameLabel.text = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:recipientId avoidingWriteTransaction:YES]; } [[NSNotificationCenter defaultCenter] addObserver:self diff --git a/SignalUtilitiesKit/ContactTableViewCell.h b/SignalUtilitiesKit/Remove Later/ContactTableViewCell.h similarity index 100% rename from SignalUtilitiesKit/ContactTableViewCell.h rename to SignalUtilitiesKit/Remove Later/ContactTableViewCell.h diff --git a/SignalUtilitiesKit/ContactTableViewCell.m b/SignalUtilitiesKit/Remove Later/ContactTableViewCell.m similarity index 100% rename from SignalUtilitiesKit/ContactTableViewCell.m rename to SignalUtilitiesKit/Remove Later/ContactTableViewCell.m diff --git a/SignalUtilitiesKit/OWSProfileManager.h b/SignalUtilitiesKit/Remove Later/OWSProfileManager.h similarity index 100% rename from SignalUtilitiesKit/OWSProfileManager.h rename to SignalUtilitiesKit/Remove Later/OWSProfileManager.h diff --git a/SignalUtilitiesKit/OWSProfileManager.m b/SignalUtilitiesKit/Remove Later/OWSProfileManager.m similarity index 94% rename from SignalUtilitiesKit/OWSProfileManager.m rename to SignalUtilitiesKit/Remove Later/OWSProfileManager.m index 3f1a35349..c503fffce 100644 --- a/SignalUtilitiesKit/OWSProfileManager.m +++ b/SignalUtilitiesKit/Remove Later/OWSProfileManager.m @@ -7,8 +7,6 @@ #import "OWSUserProfile.h" #import #import - - #import "UIUtil.h" #import #import @@ -18,15 +16,10 @@ #import #import #import -#import #import -#import -#import -#import #import #import #import -#import #import #import #import @@ -128,36 +121,16 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); return TSAccountManager.sharedInstance; } -- (AFHTTPSessionManager *)avatarHTTPManager -{ - return [OWSSignalService sharedInstance].CDNSessionManager; -} - - (OWSIdentityManager *)identityManager { return SSKEnvironment.shared.identityManager; } -- (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return SSKEnvironment.shared.messageSenderJobQueue; -} - -- (TSNetworkManager *)networkManager -{ - return SSKEnvironment.shared.networkManager; -} - - (OWSBlockingManager *)blockingManager { return SSKEnvironment.shared.blockingManager; } -- (id)syncManager -{ - return SSKEnvironment.shared.syncManager; -} - - (id)udManager { OWSAssertDebug(SSKEnvironment.shared.udManager); @@ -249,22 +222,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); // Ensure that the success and failure blocks are called on the main thread. void (^failureBlock)(NSError *) = ^(NSError *error) { OWSLogError(@"Updating service with profile failed."); - - /* - // We use a "self-only" contact sync to indicate to desktop - // that we've changed our profile and that it should do a - // profile fetch for "self". - // - // NOTE: We also inform the desktop in the failure case, - // since that _may have_ affected service state. - if (requiresSync) { - [[self.syncManager syncLocalContact] retainUntilComplete]; - } - */ - - if (requiresSync) { - [LKSyncMessagesProtocol syncProfile]; - } dispatch_async(dispatch_get_main_queue(), ^{ failureBlockParameter(error); @@ -272,19 +229,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); }; void (^successBlock)(void) = ^{ OWSLogInfo(@"Successfully updated service with profile."); - - /* - // We use a "self-only" contact sync to indicate to desktop - // that we've changed our profile and that it should do a - // profile fetch for "self". - if (requiresSync) { - [[self.syncManager syncLocalContact] retainUntilComplete]; - } - */ - - if (requiresSync) { - [LKSyncMessagesProtocol syncProfile]; - } dispatch_async(dispatch_get_main_queue(), ^{ successBlockParameter(); @@ -483,24 +427,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); [self updateServiceWithProfileName:localProfileName avatarUrl:avatarURL success:^{} failure:^(NSError * _Nonnull error) {}]; } -- (void)fetchLocalUsersProfile -{ - OWSAssertIsOnMainThread(); - - NSString *_Nullable localNumber = self.tsAccountManager.localNumber; - if (!localNumber) { - return; - } - [self fetchProfileForRecipientId:localNumber]; -} - -- (void)fetchProfileForRecipientId:(NSString *)recipientId -{ - OWSAssertIsOnMainThread(); - - [ProfileFetcherJob runWithRecipientId:recipientId ignoreThrottling:YES]; -} - #pragma mark - Profile Key Rotation - (nullable NSString *)groupKeyForGroupId:(NSData *)groupId { @@ -735,11 +661,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); return @(1); }); - // Sync local profile key. - promise = promise.then(^(id value) { - return [self.syncManager syncLocalContact]; - }); - promise = promise.then(^(id value) { [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_ProfileKeyDidChange object:nil @@ -1191,12 +1112,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); OWSLogError(@"avatar image for %@ could not be loaded.", userProfile.recipientId); } else { [self updateProfileAvatarCache:image filename:fileName]; - - [latestUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:^{ - [[NSNotificationCenter defaultCenter] - postNotificationNameAsync:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; - }]; } // If we're updating the profile that corresponds to our local number, @@ -1454,7 +1369,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"share_profile") style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) { - [self userAddedThreadToProfileWhitelist:thread]; successHandler(); }]]; [alert addAction:[OWSAlerts cancelAction]]; @@ -1462,27 +1376,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); [fromViewController presentAlert:alert]; } -- (void)userAddedThreadToProfileWhitelist:(TSThread *)thread -{ - OWSAssertIsOnMainThread(); - - BOOL isFeatureEnabled = NO; - if (!isFeatureEnabled) { - OWSLogWarn(@"skipping sending profile-key message because the feature is not yet fully available."); - [OWSProfileManager.sharedManager addThreadToProfileWhitelist:thread]; - return; - } - - // MJK TODO - should be safe to remove this senderTimestamp - OWSProfileKeyMessage *message = - [[OWSProfileKeyMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread]; - [OWSProfileManager.sharedManager addThreadToProfileWhitelist:thread]; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; -} - #pragma mark - Notifications - (void)applicationDidBecomeActive:(NSNotification *)notification diff --git a/SignalUtilitiesKit/OWSUserProfile.h b/SignalUtilitiesKit/Remove Later/OWSUserProfile.h similarity index 100% rename from SignalUtilitiesKit/OWSUserProfile.h rename to SignalUtilitiesKit/Remove Later/OWSUserProfile.h diff --git a/SignalUtilitiesKit/OWSUserProfile.m b/SignalUtilitiesKit/Remove Later/OWSUserProfile.m similarity index 96% rename from SignalUtilitiesKit/OWSUserProfile.m rename to SignalUtilitiesKit/Remove Later/OWSUserProfile.m index 973fe3295..bedb81b7d 100644 --- a/SignalUtilitiesKit/OWSUserProfile.m +++ b/SignalUtilitiesKit/Remove Later/OWSUserProfile.m @@ -118,11 +118,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; #pragma mark - Dependencies -- (id)syncManager -{ - return SSKEnvironment.shared.syncManager; -} - - (TSAccountManager *)tsAccountManager { OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); @@ -250,16 +245,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; dispatch_async(dispatch_get_main_queue(), ^{ if (isLocalUserProfile) { - // We populate an initial (empty) profile on launch of a new install, but until - // we have a registered account, syncing will fail (and there could not be any - // linked device to sync to at this point anyway). - - NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults; - BOOL hasLaunchedOnce = [userDefaults boolForKey:@"hasLaunchedOnce"]; - if ([self.tsAccountManager isRegistered] && CurrentAppContext().isMainApp && hasLaunchedOnce) { - [[self.syncManager syncLocalContact] retainUntilComplete]; - } - [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_LocalProfileDidChange object:nil userInfo:nil]; diff --git a/SignalUtilitiesKit/ProfileManagerProtocol.h b/SignalUtilitiesKit/Remove Later/ProfileManagerProtocol.h similarity index 79% rename from SignalUtilitiesKit/ProfileManagerProtocol.h rename to SignalUtilitiesKit/Remove Later/ProfileManagerProtocol.h index 01694420a..ae4204dac 100644 --- a/SignalUtilitiesKit/ProfileManagerProtocol.h +++ b/SignalUtilitiesKit/Remove Later/ProfileManagerProtocol.h @@ -23,18 +23,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)setProfileKeyData:(NSData *)profileKeyData forRecipientId:(NSString *)recipientId; - (void)setProfileKeyData:(NSData *)profileKeyData forRecipientId:(NSString *)recipientId avatarURL:(nullable NSString *)avatarURL; -- (BOOL)isUserInProfileWhitelist:(NSString *)recipientId; - -- (BOOL)isThreadInProfileWhitelist:(TSThread *)thread; - -- (void)addUserToProfileWhitelist:(NSString *)recipientId; -- (void)addGroupIdToProfileWhitelist:(NSData *)groupId; -- (void)addThreadToProfileWhitelist:(TSThread *)thread; - -- (void)fetchLocalUsersProfile; - -- (void)fetchProfileForRecipientId:(NSString *)recipientId; - - (void)updateProfileForContactWithID:(NSString *)contactID displayName:(NSString *)displayName with:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateServiceWithProfileName:(nullable NSString *)localProfileName avatarURL:(nullable NSString *)avatarURL; diff --git a/SignalUtilitiesKit/SessionManagementProtocol.swift b/SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift similarity index 61% rename from SignalUtilitiesKit/SessionManagementProtocol.swift rename to SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift index f8f5b13a4..1455a715d 100644 --- a/SignalUtilitiesKit/SessionManagementProtocol.swift +++ b/SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift @@ -62,27 +62,30 @@ public final class SessionManagementProtocol : NSObject { @objc(isSessionRequiredForMessage:recipientID:transaction:) public static func isSessionRequired(for message: TSOutgoingMessage, recipientID: String, transaction: YapDatabaseReadWriteTransaction) -> Bool { - if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { - return false - } else { - return !shouldUseFallbackEncryption(for: message, recipientID: recipientID, transaction: transaction) - } + return false +// if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { +// return false +// } else { +// return !shouldUseFallbackEncryption(for: message, recipientID: recipientID, transaction: transaction) +// } } @objc(shouldUseFallbackEncryptionForMessage:recipientID:transaction:) public static func shouldUseFallbackEncryption(for message: TSOutgoingMessage, recipientID: String, transaction: YapDatabaseReadWriteTransaction) -> Bool { - if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { return false } - else if message is SessionRequestMessage { return true } - else if message is EndSessionMessage { return true } - else if let message = message as? DeviceLinkMessage, message.kind == .request { return true } - else if message is OWSOutgoingNullMessage { return false } - return !storage.containsSession(recipientID, deviceId: Int32(OWSDevicePrimaryDeviceId), protocolContext: transaction) + return true +// if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { return false } +// else if message is SessionRequestMessage { return true } +// else if message is EndSessionMessage { return true } +// else if let message = message as? DeviceLinkMessage, message.kind == .request { return true } +// else if message is OWSOutgoingNullMessage { return false } +// return !storage.containsSession(recipientID, deviceId: Int32(OWSDevicePrimaryDeviceId), protocolContext: transaction) } private static func hasSentSessionRequestExpired(for publicKey: String) -> Bool { - let timestamp = Storage.getSessionRequestSentTimestamp(for: publicKey) - let expiration = timestamp + TTLUtilities.getTTL(for: .sessionRequest) - return NSDate.ows_millisecondTimeStamp() > expiration + return false +// let timestamp = Storage.getSessionRequestSentTimestamp(for: publicKey) +// let expiration = timestamp + TTLUtilities.getTTL(for: .sessionRequest) +// return NSDate.ows_millisecondTimeStamp() > expiration } @objc(sendSessionRequestIfNeededToPublicKey:transaction:) @@ -90,7 +93,7 @@ public final class SessionManagementProtocol : NSObject { // It's never necessary to establish a session with self guard publicKey != getUserHexEncodedPublicKey() else { return } // Check that we don't already have a session - let hasSession = storage.containsSession(publicKey, deviceId: Int32(OWSDevicePrimaryDeviceId), protocolContext: transaction) + let hasSession = storage.containsSession(publicKey, deviceId: Int32(1), protocolContext: transaction) guard !hasSession else { return } // Check that we didn't already send a session request let hasSentSessionRequest = (Storage.getSessionRequestSentTimestamp(for: publicKey) > 0) @@ -134,51 +137,51 @@ public final class SessionManagementProtocol : NSObject { @objc(startSessionResetInThread:transaction:) public static func startSessionReset(in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { - // Check preconditions - guard let thread = thread as? TSContactThread else { - return print("[Loki] Can't restore session for non contact thread.") - } - // Send end session messages to the devices requiring session restoration - let devices = thread.sessionRestoreDevices // TODO: Rename this to something that reads better - for device in devices { - guard ECKeyPair.isValidHexEncodedPublicKey(candidate: device) else { continue } - let thread = TSContactThread.getOrCreateThread(withContactId: device, transaction: transaction) - thread.save(with: transaction) - /* - let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread) - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue - messageSenderJobQueue.add(message: endSessionMessage, transaction: transaction) - */ - } - thread.removeAllSessionRestoreDevices(with: transaction) - // Notify the user - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) - infoMessage.save(with: transaction) - // Update the session reset status - thread.sessionResetStatus = .initiated - thread.save(with: transaction) +// // Check preconditions +// guard let thread = thread as? TSContactThread else { +// return print("[Loki] Can't restore session for non contact thread.") +// } +// // Send end session messages to the devices requiring session restoration +// let devices = thread.sessionRestoreDevices // TODO: Rename this to something that reads better +// for device in devices { +// guard ECKeyPair.isValidHexEncodedPublicKey(candidate: device) else { continue } +// let thread = TSContactThread.getOrCreateThread(withContactId: device, transaction: transaction) +// thread.save(with: transaction) +// /* +// let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread) +// let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue +// messageSenderJobQueue.add(message: endSessionMessage, transaction: transaction) +// */ +// } +// thread.removeAllSessionRestoreDevices(with: transaction) +// // Notify the user +// let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) +// infoMessage.save(with: transaction) +// // Update the session reset status +// thread.sessionResetStatus = .initiated +// thread.save(with: transaction) } // MARK: - Receiving @objc(handleDecryptionError:forPublicKey:transaction:) public static func handleDecryptionError(_ errorMessage: TSErrorMessage, for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - let type = errorMessage.errorType - let masterPublicKey = storage.getMasterHexEncodedPublicKey(for: publicKey, in: transaction) ?? publicKey - let thread = TSContactThread.getOrCreateThread(withContactId: masterPublicKey, transaction: transaction) - let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) - // Show the session reset prompt upon certain errors - switch type { - case .noSession, .invalidMessage, .invalidKeyException: - if restorationTimeInMs > errorMessage.timestamp { - // Automatically rebuild session after restoration - sendSessionRequestIfNeeded(to: publicKey, using: transaction) - } else { - // Store the source device's public key in case it was a secondary device - thread.addSessionRestoreDevice(publicKey, transaction: transaction) - } - default: break - } +// let type = errorMessage.errorType +// let masterPublicKey = storage.getMasterHexEncodedPublicKey(for: publicKey, in: transaction) ?? publicKey +// let thread = TSContactThread.getOrCreateThread(withContactId: masterPublicKey, transaction: transaction) +// let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) +// // Show the session reset prompt upon certain errors +// switch type { +// case .noSession, .invalidMessage, .invalidKeyException: +// if restorationTimeInMs > errorMessage.timestamp { +// // Automatically rebuild session after restoration +// sendSessionRequestIfNeeded(to: publicKey, using: transaction) +// } else { +// // Store the source device's public key in case it was a secondary device +// thread.addSessionRestoreDevice(publicKey, transaction: transaction) +// } +// default: break +// } } private static func shouldProcessSessionRequest(from publicKey: String, at timestamp: UInt64) -> Bool { @@ -190,33 +193,33 @@ public final class SessionManagementProtocol : NSObject { @objc(handlePreKeyBundleMessageIfNeeded:wrappedIn:transaction:) public static func handlePreKeyBundleMessageIfNeeded(_ protoContent: SSKProtoContent, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = envelope.source! // Set during UD decryption - guard let preKeyBundleMessage = protoContent.prekeyBundleMessage else { return } - print("[Loki] Received a pre key bundle message from: \(publicKey).") - guard let preKeyBundle = preKeyBundleMessage.getPreKeyBundle(with: transaction) else { - return print("[Loki] Couldn't parse pre key bundle received from: \(publicKey).") - } - if !shouldProcessSessionRequest(from: publicKey, at: envelope.timestamp) { - return print("[Loki] Ignoring session request from: \(publicKey).") - } - storage.setPreKeyBundle(preKeyBundle, forContact: publicKey, transaction: transaction) - Storage.setSessionRequestProcessedTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) - sendNullMessage(to: publicKey, in: transaction) +// let publicKey = envelope.source! // Set during UD decryption +// guard let preKeyBundleMessage = protoContent.prekeyBundleMessage else { return } +// print("[Loki] Received a pre key bundle message from: \(publicKey).") +// guard let preKeyBundle = preKeyBundleMessage.getPreKeyBundle(with: transaction) else { +// return print("[Loki] Couldn't parse pre key bundle received from: \(publicKey).") +// } +// if !shouldProcessSessionRequest(from: publicKey, at: envelope.timestamp) { +// return print("[Loki] Ignoring session request from: \(publicKey).") +// } +// storage.setPreKeyBundle(preKeyBundle, forContact: publicKey, transaction: transaction) +// Storage.setSessionRequestProcessedTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) +// sendNullMessage(to: publicKey, in: transaction) } @objc(handleEndSessionMessageReceivedInThread:using:) public static func handleEndSessionMessageReceived(in thread: TSContactThread, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = thread.contactIdentifier() - print("[Loki] End session message received from: \(publicKey).") - // Notify the user - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) - infoMessage.save(with: transaction) - // Archive all sessions - storage.archiveAllSessions(forContact: publicKey, protocolContext: transaction) - // Update the session reset status - thread.sessionResetStatus = .requestReceived - thread.save(with: transaction) - // Send a null message - sendNullMessage(to: publicKey, in: transaction) +// let publicKey = thread.contactIdentifier() +// print("[Loki] End session message received from: \(publicKey).") +// // Notify the user +// let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) +// infoMessage.save(with: transaction) +// // Archive all sessions +// storage.archiveAllSessions(forContact: publicKey, protocolContext: transaction) +// // Update the session reset status +// thread.sessionResetStatus = .requestReceived +// thread.save(with: transaction) +// // Send a null message +// sendNullMessage(to: publicKey, in: transaction) } } diff --git a/SignalUtilitiesKit/SessionMetaProtocol.swift b/SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift similarity index 98% rename from SignalUtilitiesKit/SessionMetaProtocol.swift rename to SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift index d15e4802b..bcbc2ee13 100644 --- a/SignalUtilitiesKit/SessionMetaProtocol.swift +++ b/SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift @@ -26,7 +26,7 @@ public final class SessionMetaProtocol : NSObject { public static func getDestinations(for outgoingGroupMessage: TSOutgoingMessage, in thread: TSThread) -> NSMutableSet { guard let thread = thread as? TSGroupThread else { preconditionFailure("Can't get destinations for group message in non-group thread.") } var result: Set = [] - if thread.isPublicChat { + if thread.isOpenGroup { storage.dbReadConnection.read { transaction in if let openGroup = LokiDatabaseUtilities.getPublicChat(for: thread.uniqueId!, in: transaction) { result = [ openGroup.server ] // Aim the message at the open group server @@ -65,7 +65,7 @@ public final class SessionMetaProtocol : NSObject { @objc(shouldSendTranscriptForMessage:inThread:) public static func shouldSendTranscript(for message: TSOutgoingMessage, in thread: TSThread) -> Bool { guard message.shouldSyncTranscript() else { return false } - let isOpenGroupMessage = (thread as? TSGroupThread)?.isPublicChat == true + let isOpenGroupMessage = (thread as? TSGroupThread)?.isOpenGroup == true let wouldSignalRequireTranscript = (AreRecipientUpdatesEnabled() || !message.hasSyncedTranscript) guard wouldSignalRequireTranscript && !isOpenGroupMessage else { return false } return false diff --git a/SignalUtilitiesKit/ReturnToCallViewController.swift b/SignalUtilitiesKit/ReturnToCallViewController.swift deleted file mode 100644 index 9fb941cdb..000000000 --- a/SignalUtilitiesKit/ReturnToCallViewController.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PureLayout - -@objc -public protocol ReturnToCallViewControllerDelegate: class { - func returnToCallWasTapped(_ viewController: ReturnToCallViewController) -} - -@objc -public class ReturnToCallViewController: UIViewController { - - @objc - public weak var delegate: ReturnToCallViewControllerDelegate? - - let returnToCallLabel = UILabel() - - @objc - public func startAnimating() { - NotificationCenter.default.addObserver(self, selector: #selector(didTapStatusBar(notification:)), name: .TappedStatusBar, object: nil) - self.returnToCallLabel.layer.removeAllAnimations() - self.returnToCallLabel.alpha = 1 - UIView.animate(withDuration: 1, - delay: 0, - options: [.repeat, .autoreverse], - animations: { self.returnToCallLabel.alpha = 0 }, - completion: { _ in self.returnToCallLabel.alpha = 1 }) - } - - @objc - public func stopAnimating() { - NotificationCenter.default.removeObserver(self, name: .TappedStatusBar, object: nil) - self.returnToCallLabel.layer.removeAllAnimations() - } - - override public func loadView() { - self.view = UIView() - - // This is the color of the iOS "return to call" banner. - view.backgroundColor = UIColor(rgbHex: 0x4cd964) - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapView)) - view.addGestureRecognizer(tapGesture) - - view.addSubview(returnToCallLabel) - - // System UI doesn't use dynamic type for status bar; neither do we. - returnToCallLabel.font = UIFont.ows_regularFont(withSize: 14) - returnToCallLabel.text = NSLocalizedString("CALL_WINDOW_RETURN_TO_CALL", comment: "Label for the 'return to call' banner.") - returnToCallLabel.textColor = .white - - returnToCallLabel.autoPinEdge(toSuperviewEdge: .bottom, withInset: 2) - returnToCallLabel.setCompressionResistanceHigh() - returnToCallLabel.setContentHuggingHigh() - returnToCallLabel.autoHCenterInSuperview() - } - - @objc - public func didTapView(gestureRecognizer: UITapGestureRecognizer) { - self.delegate?.returnToCallWasTapped(self) - } - - @objc - public func didTapStatusBar(notification: Notification) { - self.delegate?.returnToCallWasTapped(self) - } - - override public func viewWillLayoutSubviews() { - Logger.debug("") - - super.viewWillLayoutSubviews() - } - - override public func viewDidLayoutSubviews() { - Logger.debug("") - - super.viewDidLayoutSubviews() - } - - // MARK: Orientation - - public override var supportedInterfaceOrientations: UIInterfaceOrientationMask { - return .portrait - } - -} diff --git a/SignalUtilitiesKit/RotateSignedKeyOperation.swift b/SignalUtilitiesKit/RotateSignedKeyOperation.swift index 1fc9368dd..578cb77f7 100644 --- a/SignalUtilitiesKit/RotateSignedKeyOperation.swift +++ b/SignalUtilitiesKit/RotateSignedKeyOperation.swift @@ -11,10 +11,6 @@ public class RotateSignedPreKeyOperation: OWSOperation { return TSAccountManager.sharedInstance() } - private var accountServiceClient: AccountServiceClient { - return AccountServiceClient.shared - } - private var primaryStorage: OWSPrimaryStorage { return OWSPrimaryStorage.shared() } @@ -27,53 +23,13 @@ public class RotateSignedPreKeyOperation: OWSOperation { return } - // Loki: Doing this on the global queue to match Signal DispatchQueue.global().async { SessionManagementProtocol.rotateSignedPreKey() self.reportSuccess() } - - /* Loki: Original code - * ================ - let signedPreKeyRecord: SignedPreKeyRecord = self.primaryStorage.generateRandomSignedRecord() - - self.primaryStorage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - firstly { - return self.accountServiceClient.setSignedPreKey(signedPreKeyRecord) - }.done(on: DispatchQueue.global()) { - Logger.info("Successfully uploaded signed PreKey") - signedPreKeyRecord.markAsAcceptedByService() - self.primaryStorage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - self.primaryStorage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - - TSPreKeyManager.clearPreKeyUpdateFailureCount() - TSPreKeyManager.clearSignedPreKeyRecords() - - Logger.debug("done") - self.reportSuccess() - }.catch { error in - self.reportError(error) - }.retainUntilComplete() - * ================ - */ } override public func didFail(error: Error) { - switch error { - case let networkManagerError as NetworkManagerError: - guard !networkManagerError.isNetworkError else { - Logger.debug("don't report SPK rotation failure w/ network error") - return - } - - guard networkManagerError.statusCode >= 400 && networkManagerError.statusCode <= 599 else { - Logger.debug("don't report SPK rotation failure w/ non application error") - return - } - - TSPreKeyManager.incrementPreKeyUpdateFailureCount() - default: - Logger.debug("don't report SPK rotation failure w/ non NetworkManager error: \(error)") - } + Logger.debug("don't report SPK rotation failure w/ non NetworkManager error: \(error)") } } diff --git a/SignalUtilitiesKit/SSKEnvironment.h b/SignalUtilitiesKit/SSKEnvironment.h index a81965968..4ac8cae53 100644 --- a/SignalUtilitiesKit/SSKEnvironment.h +++ b/SignalUtilitiesKit/SSKEnvironment.h @@ -23,7 +23,6 @@ NS_ASSUME_NONNULL_BEGIN @class OWSReadReceiptManager; @class SSKMessageSenderJobQueue; @class TSAccountManager; -@class TSNetworkManager; @class TSSocketManager; @class YapDatabaseConnection; @@ -38,31 +37,18 @@ NS_ASSUME_NONNULL_BEGIN @interface SSKEnvironment : NSObject -- (instancetype)initWithContactsManager:(id)contactsManager - messageSender:(OWSMessageSender *)messageSender - messageSenderJobQueue:(SSKMessageSenderJobQueue *)messageSenderJobQueue - profileManager:(id)profileManager - primaryStorage:(OWSPrimaryStorage *)primaryStorage - contactsUpdater:(ContactsUpdater *)contactsUpdater - networkManager:(TSNetworkManager *)networkManager - messageManager:(OWSMessageManager *)messageManager - blockingManager:(OWSBlockingManager *)blockingManager - identityManager:(OWSIdentityManager *)identityManager - udManager:(id)udManager - messageDecrypter:(OWSMessageDecrypter *)messageDecrypter - batchMessageProcessor:(OWSBatchMessageProcessor *)batchMessageProcessor - messageReceiver:(OWSMessageReceiver *)messageReceiver - socketManager:(TSSocketManager *)socketManager - tsAccountManager:(TSAccountManager *)tsAccountManager - ows2FAManager:(OWS2FAManager *)ows2FAManager - disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob - contactDiscoveryService:(ContactDiscoveryService *)contactDiscoveryService - readReceiptManager:(OWSReadReceiptManager *)readReceiptManager - outgoingReceiptManager:(OWSOutgoingReceiptManager *)outgoingReceiptManager - reachabilityManager:(id)reachabilityManager - syncManager:(id)syncManager - typingIndicators:(id)typingIndicators - attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithProfileManager:(id)profileManager + primaryStorage:(OWSPrimaryStorage *)primaryStorage + blockingManager:(OWSBlockingManager *)blockingManager + identityManager:(OWSIdentityManager *)identityManager + udManager:(id)udManager + tsAccountManager:(TSAccountManager *)tsAccountManager + disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob + readReceiptManager:(OWSReadReceiptManager *)readReceiptManager + outgoingReceiptManager:(OWSOutgoingReceiptManager *)outgoingReceiptManager + reachabilityManager:(id)reachabilityManager + typingIndicators:(id)typingIndicators + attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE; @@ -75,28 +61,15 @@ NS_ASSUME_NONNULL_BEGIN + (void)clearSharedForTests; #endif -@property (nonatomic, readonly) id contactsManager; -@property (nonatomic, readonly) OWSMessageSender *messageSender; -@property (nonatomic, readonly) SSKMessageSenderJobQueue *messageSenderJobQueue; @property (nonatomic, readonly) id profileManager; @property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage; -@property (nonatomic, readonly) ContactsUpdater *contactsUpdater; -@property (nonatomic, readonly) TSNetworkManager *networkManager; -@property (nonatomic, readonly) OWSMessageManager *messageManager; @property (nonatomic, readonly) OWSBlockingManager *blockingManager; @property (nonatomic, readonly) OWSIdentityManager *identityManager; @property (nonatomic, readonly) id udManager; -@property (nonatomic, readonly) OWSMessageDecrypter *messageDecrypter; -@property (nonatomic, readonly) OWSBatchMessageProcessor *batchMessageProcessor; -@property (nonatomic, readonly) OWSMessageReceiver *messageReceiver; -@property (nonatomic, readonly) TSSocketManager *socketManager; @property (nonatomic, readonly) TSAccountManager *tsAccountManager; -@property (nonatomic, readonly) OWS2FAManager *ows2FAManager; @property (nonatomic, readonly) OWSDisappearingMessagesJob *disappearingMessagesJob; -@property (nonatomic, readonly) ContactDiscoveryService *contactDiscoveryService; @property (nonatomic, readonly) OWSReadReceiptManager *readReceiptManager; @property (nonatomic, readonly) OWSOutgoingReceiptManager *outgoingReceiptManager; -@property (nonatomic, readonly) id syncManager; @property (nonatomic, readonly) id reachabilityManager; @property (nonatomic, readonly) id typingIndicators; @property (nonatomic, readonly) OWSAttachmentDownloads *attachmentDownloads; diff --git a/SignalUtilitiesKit/SSKEnvironment.m b/SignalUtilitiesKit/SSKEnvironment.m index f690a5391..b0e233b16 100644 --- a/SignalUtilitiesKit/SSKEnvironment.m +++ b/SignalUtilitiesKit/SSKEnvironment.m @@ -13,27 +13,15 @@ static SSKEnvironment *sharedSSKEnvironment; @interface SSKEnvironment () -@property (nonatomic) id contactsManager; -@property (nonatomic) OWSMessageSender *messageSender; @property (nonatomic) id profileManager; @property (nonatomic) OWSPrimaryStorage *primaryStorage; -@property (nonatomic) ContactsUpdater *contactsUpdater; -@property (nonatomic) TSNetworkManager *networkManager; -@property (nonatomic) OWSMessageManager *messageManager; @property (nonatomic) OWSBlockingManager *blockingManager; @property (nonatomic) OWSIdentityManager *identityManager; @property (nonatomic) id udManager; -@property (nonatomic) OWSMessageDecrypter *messageDecrypter; -@property (nonatomic) OWSBatchMessageProcessor *batchMessageProcessor; -@property (nonatomic) OWSMessageReceiver *messageReceiver; -@property (nonatomic) TSSocketManager *socketManager; @property (nonatomic) TSAccountManager *tsAccountManager; -@property (nonatomic) OWS2FAManager *ows2FAManager; @property (nonatomic) OWSDisappearingMessagesJob *disappearingMessagesJob; -@property (nonatomic) ContactDiscoveryService *contactDiscoveryService; @property (nonatomic) OWSReadReceiptManager *readReceiptManager; @property (nonatomic) OWSOutgoingReceiptManager *outgoingReceiptManager; -@property (nonatomic) id syncManager; @property (nonatomic) id reachabilityManager; @property (nonatomic) id typingIndicators; @property (nonatomic) OWSAttachmentDownloads *attachmentDownloads; @@ -51,85 +39,47 @@ static SSKEnvironment *sharedSSKEnvironment; @synthesize migrationDBConnection = _migrationDBConnection; @synthesize analyticsDBConnection = _analyticsDBConnection; -- (instancetype)initWithContactsManager:(id)contactsManager - messageSender:(OWSMessageSender *)messageSender - messageSenderJobQueue:(SSKMessageSenderJobQueue *)messageSenderJobQueue - profileManager:(id)profileManager - primaryStorage:(OWSPrimaryStorage *)primaryStorage - contactsUpdater:(ContactsUpdater *)contactsUpdater - networkManager:(TSNetworkManager *)networkManager - messageManager:(OWSMessageManager *)messageManager - blockingManager:(OWSBlockingManager *)blockingManager - identityManager:(OWSIdentityManager *)identityManager - udManager:(id)udManager - messageDecrypter:(OWSMessageDecrypter *)messageDecrypter - batchMessageProcessor:(OWSBatchMessageProcessor *)batchMessageProcessor - messageReceiver:(OWSMessageReceiver *)messageReceiver - socketManager:(TSSocketManager *)socketManager - tsAccountManager:(TSAccountManager *)tsAccountManager - ows2FAManager:(OWS2FAManager *)ows2FAManager - disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob - contactDiscoveryService:(ContactDiscoveryService *)contactDiscoveryService - readReceiptManager:(OWSReadReceiptManager *)readReceiptManager - outgoingReceiptManager:(OWSOutgoingReceiptManager *)outgoingReceiptManager - reachabilityManager:(id)reachabilityManager - syncManager:(id)syncManager - typingIndicators:(id)typingIndicators - attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads +- (instancetype)initWithProfileManager:(id)profileManager + primaryStorage:(OWSPrimaryStorage *)primaryStorage + blockingManager:(OWSBlockingManager *)blockingManager + identityManager:(OWSIdentityManager *)identityManager + udManager:(id)udManager + tsAccountManager:(TSAccountManager *)tsAccountManager + disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob + readReceiptManager:(OWSReadReceiptManager *)readReceiptManager + outgoingReceiptManager:(OWSOutgoingReceiptManager *)outgoingReceiptManager + reachabilityManager:(id)reachabilityManager + typingIndicators:(id)typingIndicators + attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads { self = [super init]; + if (!self) { return self; } - OWSAssertDebug(contactsManager); - OWSAssertDebug(messageSender); - OWSAssertDebug(messageSenderJobQueue); OWSAssertDebug(profileManager); OWSAssertDebug(primaryStorage); - OWSAssertDebug(contactsUpdater); - OWSAssertDebug(networkManager); - OWSAssertDebug(messageManager); OWSAssertDebug(blockingManager); OWSAssertDebug(identityManager); OWSAssertDebug(udManager); - OWSAssertDebug(messageDecrypter); - OWSAssertDebug(batchMessageProcessor); - OWSAssertDebug(messageReceiver); - OWSAssertDebug(socketManager); OWSAssertDebug(tsAccountManager); - OWSAssertDebug(ows2FAManager); OWSAssertDebug(disappearingMessagesJob); - OWSAssertDebug(contactDiscoveryService); OWSAssertDebug(readReceiptManager); OWSAssertDebug(outgoingReceiptManager); - OWSAssertDebug(syncManager); OWSAssertDebug(reachabilityManager); OWSAssertDebug(typingIndicators); OWSAssertDebug(attachmentDownloads); - _contactsManager = contactsManager; - _messageSender = messageSender; - _messageSenderJobQueue = messageSenderJobQueue; _profileManager = profileManager; _primaryStorage = primaryStorage; - _contactsUpdater = contactsUpdater; - _networkManager = networkManager; - _messageManager = messageManager; _blockingManager = blockingManager; _identityManager = identityManager; _udManager = udManager; - _messageDecrypter = messageDecrypter; - _batchMessageProcessor = batchMessageProcessor; - _messageReceiver = messageReceiver; - _socketManager = socketManager; _tsAccountManager = tsAccountManager; - _ows2FAManager = ows2FAManager; _disappearingMessagesJob = disappearingMessagesJob; - _contactDiscoveryService = contactDiscoveryService; _readReceiptManager = readReceiptManager; _outgoingReceiptManager = outgoingReceiptManager; - _syncManager = syncManager; _reachabilityManager = reachabilityManager; _typingIndicators = typingIndicators; _attachmentDownloads = attachmentDownloads; @@ -158,26 +108,6 @@ static SSKEnvironment *sharedSSKEnvironment; } #pragma mark - Mutable Accessors -/* -- (nullable id)callMessageHandler -{ - @synchronized(self) { - OWSAssertDebug(_callMessageHandler); - - return _callMessageHandler; - } -} - -- (void)setCallMessageHandler:(nullable id)callMessageHandler -{ - @synchronized(self) { - OWSAssertDebug(callMessageHandler); - OWSAssertDebug(!_callMessageHandler); - - _callMessageHandler = callMessageHandler; - } -} - */ - (nullable id)notificationsManager { diff --git a/SignalUtilitiesKit/SSKPreferences.swift b/SignalUtilitiesKit/SSKPreferences.swift index 655903fd2..9d4c34f5d 100644 --- a/SignalUtilitiesKit/SSKPreferences.swift +++ b/SignalUtilitiesKit/SSKPreferences.swift @@ -22,8 +22,6 @@ public class SSKPreferences: NSObject { } set { setBool(newValue, key: areLinkPreviewsEnabledKey) - - SSKEnvironment.shared.syncManager.sendConfigurationSyncMessage() } } diff --git a/SignalUtilitiesKit/SSKProtoPrekeyBundleMessage+Loki.swift b/SignalUtilitiesKit/SSKProtoPrekeyBundleMessage+Loki.swift deleted file mode 100644 index 387bf4415..000000000 --- a/SignalUtilitiesKit/SSKProtoPrekeyBundleMessage+Loki.swift +++ /dev/null @@ -1,23 +0,0 @@ - -@objc public extension SSKProtoPrekeyBundleMessage { - - @objc(builderFromPreKeyBundle:) - public static func builder(from preKeyBundle: PreKeyBundle) -> SSKProtoPrekeyBundleMessageBuilder { - let builder = self.builder() - builder.setIdentityKey(preKeyBundle.identityKey) - builder.setDeviceID(UInt32(preKeyBundle.deviceId)) - builder.setPrekeyID(UInt32(preKeyBundle.preKeyId)) - builder.setPrekey(preKeyBundle.preKeyPublic) - builder.setSignedKeyID(UInt32(preKeyBundle.signedPreKeyId)) - builder.setSignedKey(preKeyBundle.signedPreKeyPublic) - builder.setSignature(preKeyBundle.signedPreKeySignature) - return builder - } - - @objc(getPreKeyBundleWithTransaction:) - public func getPreKeyBundle(with transaction: YapDatabaseReadWriteTransaction) -> PreKeyBundle? { - let registrationId = TSAccountManager.sharedInstance().getOrGenerateRegistrationId(transaction) - return PreKeyBundle(registrationId: Int32(registrationId), deviceId: Int32(deviceID), preKeyId: Int32(prekeyID), preKeyPublic: prekey, - signedPreKeyPublic: signedKey, signedPreKeyId: Int32(signedKeyID), signedPreKeySignature: signature, identityKey: identityKey) - } -} diff --git a/SignalUtilitiesKit/SSKWebSocket.swift b/SignalUtilitiesKit/SSKWebSocket.swift deleted file mode 100644 index b72a680ad..000000000 --- a/SignalUtilitiesKit/SSKWebSocket.swift +++ /dev/null @@ -1,185 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import Starscream - -@objc -public enum SSKWebSocketState: UInt { - case open, connecting, disconnected -} - -@objc -public class SSKWebSocketError: NSObject, CustomNSError { - - init(underlyingError: Starscream.WSError) { - self.underlyingError = underlyingError - } - - // MARK: - CustomNSError - - @objc - public static let errorDomain = "SignalServiceKit.SSKWebSocketError" - - public var errorUserInfo: [String: Any] { - return [ - type(of: self).kStatusCodeKey: underlyingError.code, - NSUnderlyingErrorKey: (underlyingError as NSError) - ] - } - - // MARK: - - - @objc - public static let kStatusCodeKey = "SSKWebSocketErrorStatusCode" - - let underlyingError: Starscream.WSError -} - -@objc -public protocol SSKWebSocket { - - @objc - var delegate: SSKWebSocketDelegate? { get set } - - @objc - var state: SSKWebSocketState { get } - - @objc - func connect() - - @objc - func disconnect() - - @objc(writeData:error:) - func write(data: Data) throws - - @objc - func writePing() throws -} - -@objc -public protocol SSKWebSocketDelegate: class { - func websocketDidConnect(socket: SSKWebSocket) - - func websocketDidDisconnect(socket: SSKWebSocket, error: Error?) - - func websocketDidReceiveData(socket: SSKWebSocket, data: Data) - - @objc optional func websocketDidReceiveMessage(socket: SSKWebSocket, text: String) -} - -@objc -public class SSKWebSocketManager: NSObject { - - @objc - public class func buildSocket(request: URLRequest) -> SSKWebSocket { - return SSKWebSocketImpl(request: request) - } -} - -class SSKWebSocketImpl: SSKWebSocket { - - private let socket: Starscream.WebSocket - - init(request: URLRequest) { - let socket = WebSocket(request: request) - - socket.disableSSLCertValidation = true - socket.socketSecurityLevel = StreamSocketSecurityLevel.tlSv1_2 - let security = SSLSecurity(certs: [TextSecureCertificate()], usePublicKeys: false) - security.validateEntireChain = false - socket.security = security - - // TODO cipher suite selection - // socket.enabledSSLCipherSuites = [TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256] - - self.socket = socket - - socket.delegate = self - } - - // MARK: - SSKWebSocket - - weak var delegate: SSKWebSocketDelegate? - - var hasEverConnected = false - var state: SSKWebSocketState { - if socket.isConnected { - return .open - } - - if hasEverConnected { - return .disconnected - } - - return .connecting - } - - func connect() { - socket.connect() - } - - func disconnect() { - socket.disconnect() - } - - func write(data: Data) throws { - socket.write(data: data) - } - - func writePing() throws { - socket.write(ping: Data()) - } -} - -extension SSKWebSocketImpl: WebSocketDelegate { - func websocketDidConnect(socket: WebSocketClient) { - hasEverConnected = true - delegate?.websocketDidConnect(socket: self) - } - - func websocketDidDisconnect(socket: WebSocketClient, error: Error?) { - let websocketError: Error? - switch error { - case let wsError as WSError: - websocketError = SSKWebSocketError(underlyingError: wsError) - case let nsError as NSError: - // Assert that error is either a Starscream.WSError or an OS level networking error - if #available(iOS 10, *) { - let networkDownCode = 50 - assert(nsError.domain == "NSPOSIXErrorDomain" && nsError.code == networkDownCode) - } else { - assert(nsError.domain == kCFErrorDomainCFNetwork as String) - } - websocketError = error - default: - assert(error == nil, "unexpected error type: \(String(describing: error))") - websocketError = error - } - - delegate?.websocketDidDisconnect(socket: self, error: websocketError) - } - - func websocketDidReceiveMessage(socket: WebSocketClient, text: String) { - if let websocketDidReceiveMessage = self.delegate?.websocketDidReceiveMessage { - websocketDidReceiveMessage(self, text) - } - } - - func websocketDidReceiveData(socket: WebSocketClient, data: Data) { - delegate?.websocketDidReceiveData(socket: self, data: data) - } -} - -private func TextSecureCertificate() -> SSLCert { - let data = SSKTextSecureServiceCertificateData() - return SSLCert(data: data) -} - -private extension StreamSocketSecurityLevel { - static var tlSv1_2: StreamSocketSecurityLevel { - return StreamSocketSecurityLevel(rawValue: "kCFStreamSocketSecurityLevelTLSv1_2") - } -} diff --git a/SignalUtilitiesKit/SessionRequestMessage.swift b/SignalUtilitiesKit/SessionRequestMessage.swift deleted file mode 100644 index b612b1608..000000000 --- a/SignalUtilitiesKit/SessionRequestMessage.swift +++ /dev/null @@ -1,51 +0,0 @@ - -@objc(LKSessionRequestMessage) -internal final class SessionRequestMessage : TSOutgoingMessage { - - @objc internal override var ttl: UInt32 { return UInt32(TTLUtilities.getTTL(for: .sessionRequest)) } - - @objc internal override func shouldBeSaved() -> Bool { return false } - @objc internal override func shouldSyncTranscript() -> Bool { return false } - - @objc internal init(thread: TSThread) { - super.init(outgoingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageBody: "", - attachmentIds: NSMutableArray(), expiresInSeconds: 0, expireStartedAt: 0, isVoiceMessage: false, - groupMetaMessage: .unspecified, quotedMessage: nil, contactShare: nil, linkPreview: nil) - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - required init(dictionary: [String:Any]) throws { - try super.init(dictionary: dictionary) - } - - override func prepareCustomContentBuilder(_ recipient: SignalRecipient) -> Any? { - guard let contentBuilder = super.prepareCustomContentBuilder(recipient) as? SSKProtoContent.SSKProtoContentBuilder else { return nil } - // Attach a null message - let nullMessageBuilder = SSKProtoNullMessage.builder() - let paddingSize = UInt.random(in: 0..<512) // random(in:) uses the system's default random generator, which is cryptographically secure - let padding = Cryptography.generateRandomBytes(paddingSize) - nullMessageBuilder.setPadding(padding) - do { - let nullMessage = try nullMessageBuilder.build() - contentBuilder.setNullMessage(nullMessage) - } catch { - owsFailDebug("Failed to build session request message for: \(recipient.recipientId()) due to error: \(error).") - return nil - } - // Generate a pre key bundle for the recipient and attach it - let preKeyBundle = OWSPrimaryStorage.shared().generatePreKeyBundle(forContact: recipient.recipientId()) - let preKeyBundleMessageBuilder = SSKProtoPrekeyBundleMessage.builder(from: preKeyBundle) - do { - let preKeyBundleMessage = try preKeyBundleMessageBuilder.build() - contentBuilder.setPrekeyBundleMessage(preKeyBundleMessage) - } catch { - owsFailDebug("Failed to build session request message for: \(recipient.recipientId()) due to error: \(error).") - return nil - } - // Return - return contentBuilder - } -} diff --git a/SignalUtilitiesKit/SharedSenderKeysImplementation.swift b/SignalUtilitiesKit/SharedSenderKeysImplementation.swift deleted file mode 100644 index 6f5f8bc0d..000000000 --- a/SignalUtilitiesKit/SharedSenderKeysImplementation.swift +++ /dev/null @@ -1,220 +0,0 @@ -import CryptoSwift -import PromiseKit - - -@objc(LKSharedSenderKeysImplementation) -public final class SharedSenderKeysImplementation : NSObject { - private static let gcmTagSize: UInt = 16 - private static let ivSize: UInt = 12 - - // MARK: Documentation - // A quick overview of how shared sender key based closed groups work: - // - // • When a user creates a group, they generate a key pair for the group along with a ratchet for - // every member of the group. They bundle this together with some other group info such as the group - // name in a `ClosedGroupUpdateMessage` and send that using established channels to every member of - // the group. Note that because a user can only pick from their existing contacts when selecting - // the group members they shouldn't need to establish sessions before being able to send the - // `ClosedGroupUpdateMessage`. Another way to optimize the performance of the group creation process - // is to batch fetch the device links of all members involved ahead of time, rather than letting - // the sending pipeline do it separately for every user the `ClosedGroupUpdateMessage` is sent to. - // • After the group is created, every user polls for the public key associated with the group. - // • Upon receiving a `ClosedGroupUpdateMessage` of type `.new`, a user sends session requests to all - // other members of the group they don't yet have a session with for reasons outlined below. - // • When a user sends a message they step their ratchet and use the resulting message key to encrypt - // the message. - // • When another user receives that message, they step the ratchet associated with the sender and - // use the resulting message key to decrypt the message. - // • When a user leaves or is kicked from a group, all members must generate new ratchets to ensure that - // removed users can't decrypt messages going forward. To this end every user deletes all ratchets - // associated with the group in question upon receiving a group update message that indicates that - // a user left. They then generate a new ratchet for themselves and send it out to all members of - // the group (again fetching device links ahead of time). The user should already have established - // sessions with all other members at this point because of the behavior outlined a few points above. - // • When a user adds a new member to the group, they generate a ratchet for that new member and - // send that bundled in a `ClosedGroupUpdateMessage` to the group. They send a - // `ClosedGroupUpdateMessage` with the newly generated ratchet but also the existing ratchets of - // every other member of the group to the user that joined. - - // MARK: Ratcheting Error - public enum RatchetingError : LocalizedError { - case loadingFailed(groupPublicKey: String, senderPublicKey: String) - case messageKeyMissing(targetKeyIndex: UInt, groupPublicKey: String, senderPublicKey: String) - case generic - - public var errorDescription: String? { - switch self { - case .loadingFailed(let groupPublicKey, let senderPublicKey): return "Couldn't get ratchet for closed group with public key: \(groupPublicKey), sender public key: \(senderPublicKey)." - case .messageKeyMissing(let targetKeyIndex, let groupPublicKey, let senderPublicKey): return "Couldn't find message key for old key index: \(targetKeyIndex), public key: \(groupPublicKey), sender public key: \(senderPublicKey)." - case .generic: return "An error occurred" - } - } - } - - // MARK: Initialization - @objc public static let shared = SharedSenderKeysImplementation() - - private override init() { } - - // MARK: Private/Internal API - internal func generateRatchet(for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> ClosedGroupRatchet { - let rootChainKey = Data.getSecureRandomData(ofSize: 32)!.toHexString() - let ratchet = ClosedGroupRatchet(chainKey: rootChainKey, keyIndex: 0, messageKeys: []) - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: ratchet, using: transaction) - return ratchet - } - - private func step(_ ratchet: ClosedGroupRatchet) throws -> ClosedGroupRatchet { - let nextMessageKey = try HMAC(key: Data(hex: ratchet.chainKey).bytes, variant: .sha256).authenticate([ UInt8(1) ]) - let nextChainKey = try HMAC(key: Data(hex: ratchet.chainKey).bytes, variant: .sha256).authenticate([ UInt8(2) ]) - let nextKeyIndex = ratchet.keyIndex + 1 - let messageKeys = ratchet.messageKeys + [ nextMessageKey.toHexString() ] - return ClosedGroupRatchet(chainKey: nextChainKey.toHexString(), keyIndex: nextKeyIndex, messageKeys: messageKeys) - } - - /// - Note: Sync. Don't call from the main thread. - private func stepRatchetOnce(for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) throws -> ClosedGroupRatchet { - #if DEBUG - assert(!Thread.isMainThread) - #endif - guard let ratchet = Storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey) else { - let error = RatchetingError.loadingFailed(groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey) - print("[Loki] \(error.errorDescription!)") - throw error - } - do { - let result = try step(ratchet) - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: result, using: transaction) - return result - } catch { - print("[Loki] Couldn't step ratchet due to error: \(error).") - throw error - } - } - - /// - Note: Sync. Don't call from the main thread. - private func stepRatchet(for groupPublicKey: String, senderPublicKey: String, until targetKeyIndex: UInt, using transaction: YapDatabaseReadWriteTransaction, isRetry: Bool = false) throws -> ClosedGroupRatchet { - #if DEBUG - assert(!Thread.isMainThread) - #endif - let collection: Storage.ClosedGroupRatchetCollectionType = (isRetry) ? .old : .current - guard let ratchet = Storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, from: collection) else { - let error = RatchetingError.loadingFailed(groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey) - print("[Loki] \(error.errorDescription!)") - throw error - } - if targetKeyIndex < ratchet.keyIndex { - // There's no need to advance the ratchet if this is invoked for an old key index - guard ratchet.messageKeys.count > targetKeyIndex else { - let error = RatchetingError.messageKeyMissing(targetKeyIndex: targetKeyIndex, groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey) - print("[Loki] \(error.errorDescription!)") - throw error - } - return ratchet - } else { - var currentKeyIndex = ratchet.keyIndex - var result = ratchet - while currentKeyIndex < targetKeyIndex { - do { - result = try step(result) - currentKeyIndex = result.keyIndex - } catch { - print("[Loki] Couldn't step ratchet due to error: \(error).") - throw error - } - } - let collection: Storage.ClosedGroupRatchetCollectionType = (isRetry) ? .old : .current - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: result, in: collection, using: transaction) - return result - } - } - - // MARK: Public API - @objc(encrypt:forGroupWithPublicKey:senderPublicKey:protocolContext:error:) - public func encrypt(_ plaintext: Data, forGroupWithPublicKey groupPublicKey: String, senderPublicKey: String, protocolContext: Any) throws -> [Any] { - let transaction = protocolContext as! YapDatabaseReadWriteTransaction - let (ivAndCiphertext, keyIndex) = try encrypt(plaintext, for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) - return [ ivAndCiphertext, NSNumber(value: keyIndex) ] - } - - public func encrypt(_ plaintext: Data, for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) throws -> (ivAndCiphertext: Data, keyIndex: UInt) { - let ratchet: ClosedGroupRatchet - do { - ratchet = try stepRatchetOnce(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) - } catch { - // FIXME: It'd be cleaner to handle this in OWSMessageDecrypter (where all the other decryption errors are handled), but this was a lot more - // convenient because there's an easy way to get the sender public key from here. - if case RatchetingError.loadingFailed(_, _) = error { - ClosedGroupsProtocol.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) - } - throw error - } - let iv = Data.getSecureRandomData(ofSize: SharedSenderKeysImplementation.ivSize)! - let gcm = GCM(iv: iv.bytes, tagLength: Int(SharedSenderKeysImplementation.gcmTagSize), mode: .combined) - let messageKey = ratchet.messageKeys.last! - let aes = try AES(key: Data(hex: messageKey).bytes, blockMode: gcm, padding: .noPadding) - let ciphertext = try aes.encrypt(plaintext.bytes) - return (ivAndCiphertext: iv + Data(bytes: ciphertext), ratchet.keyIndex) - } - - @objc(decrypt:forGroupWithPublicKey:senderPublicKey:keyIndex:protocolContext:error:) - public func decrypt(_ ivAndCiphertext: Data, forGroupWithPublicKey groupPublicKey: String, senderPublicKey: String, keyIndex: UInt, protocolContext: Any) throws -> Data { - let transaction = protocolContext as! YapDatabaseReadWriteTransaction - return try decrypt(ivAndCiphertext, for: groupPublicKey, senderPublicKey: senderPublicKey, keyIndex: keyIndex, using: transaction) - } - - public func decrypt(_ ivAndCiphertext: Data, for groupPublicKey: String, senderPublicKey: String, keyIndex: UInt, using transaction: YapDatabaseReadWriteTransaction, isRetry: Bool = false) throws -> Data { - let ratchet: ClosedGroupRatchet - do { - ratchet = try stepRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, until: keyIndex, using: transaction, isRetry: isRetry) - } catch { - if !isRetry { - return try decrypt(ivAndCiphertext, for: groupPublicKey, senderPublicKey: senderPublicKey, keyIndex: keyIndex, using: transaction, isRetry: true) - } else { - // FIXME: It'd be cleaner to handle this in OWSMessageDecrypter (where all the other decryption errors are handled), but this was a lot more - // convenient because there's an easy way to get the sender public key from here. - if case RatchetingError.loadingFailed(_, _) = error { - ClosedGroupsProtocol.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) - } - throw error - } - } - let iv = ivAndCiphertext[0.. 16 { // Pick an arbitrary number of message keys to try; this helps resolve issues caused by messages arriving out of order - lastNMessageKeys = [String](messageKeys[messageKeys.index(messageKeys.endIndex, offsetBy: -16).. Bool { - return Storage.getUserClosedGroupPublicKeys().contains(publicKey) - } - - public func getKeyPair(forGroupWithPublicKey groupPublicKey: String) -> ECKeyPair { - let privateKey = Storage.getClosedGroupPrivateKey(for: groupPublicKey)! - return try! ECKeyPair(publicKeyData: Data(hex: groupPublicKey.removing05PrefixIfNeeded()), privateKeyData: Data(hex: privateKey)) - } -} diff --git a/SignalUtilitiesKit/SignalAccount.h b/SignalUtilitiesKit/SignalAccount.h index cd7f91f8d..e8b54290e 100644 --- a/SignalUtilitiesKit/SignalAccount.h +++ b/SignalUtilitiesKit/SignalAccount.h @@ -33,8 +33,6 @@ NS_ASSUME_NONNULL_BEGIN // this is a label for the account. @property (nonatomic) NSString *multipleAccountLabelText; -- (nullable NSString *)contactFullName; - - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithSignalRecipient:(SignalRecipient *)signalRecipient; diff --git a/SignalUtilitiesKit/SignalAccount.m b/SignalUtilitiesKit/SignalAccount.m index 3e837f2c3..36fad15a5 100644 --- a/SignalUtilitiesKit/SignalAccount.m +++ b/SignalUtilitiesKit/SignalAccount.m @@ -3,7 +3,7 @@ // #import "SignalAccount.h" -#import "Contact.h" + #import "NSString+SSK.h" #import "OWSPrimaryStorage.h" #import "SignalRecipient.h" @@ -42,11 +42,6 @@ NS_ASSUME_NONNULL_BEGIN return _recipientId; } -- (nullable NSString *)contactFullName -{ - return self.contact.fullName.filterStringForDisplay; -} - - (NSString *)multipleAccountLabelText { return _multipleAccountLabelText.filterStringForDisplay; diff --git a/SignalUtilitiesKit/SignalRecipient.m b/SignalUtilitiesKit/SignalRecipient.m index 17e01c84e..60932e04b 100644 --- a/SignalUtilitiesKit/SignalRecipient.m +++ b/SignalUtilitiesKit/SignalRecipient.m @@ -3,11 +3,10 @@ // #import "SignalRecipient.h" -#import "OWSDevice.h" + #import "ProfileManagerProtocol.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" -#import "TSSocketManager.h" #import @@ -42,13 +41,6 @@ NS_ASSUME_NONNULL_BEGIN return SSKEnvironment.shared.tsAccountManager; } -- (TSSocketManager *)socketManager -{ - OWSAssertDebug(SSKEnvironment.shared.socketManager); - - return SSKEnvironment.shared.socketManager; -} - #pragma mark - + (instancetype)getOrBuildUnsavedRecipientForRecipientId:(NSString *)recipientId @@ -72,7 +64,7 @@ NS_ASSUME_NONNULL_BEGIN return self; } - _devices = [NSOrderedSet orderedSetWithObject:@(OWSDevicePrimaryDeviceId)]; + _devices = [NSOrderedSet orderedSetWithObject:@(1)]; return self; } @@ -90,10 +82,10 @@ NS_ASSUME_NONNULL_BEGIN // Since we use device count to determine whether a user is registered or not, // ensure the local user always has at least *this* device. - if (![_devices containsObject:@(OWSDevicePrimaryDeviceId)]) { + if (![_devices containsObject:@(1)]) { if ([self.uniqueId isEqualToString:self.tsAccountManager.localNumber]) { DDLogInfo(@"Adding primary device to self recipient."); - [self addDevices:[NSSet setWithObject:@(OWSDevicePrimaryDeviceId)]]; + [self addDevices:[NSSet setWithObject:@(1)]]; } } @@ -147,17 +139,6 @@ NS_ASSUME_NONNULL_BEGIN if (devicesToRemove.count > 0) { [self removeDevicesFromRecipient:[NSSet setWithArray:devicesToRemove] transaction:transaction]; } - - // Device changes - dispatch_async(dispatch_get_main_queue(), ^{ - // Device changes can affect the UD access mode for a recipient, - // so we need to fetch the profile for this user to update UD access mode. - [self.profileManager fetchProfileForRecipientId:self.recipientId]; - - if ([self.recipientId isEqualToString:self.tsAccountManager.localNumber]) { - [self.socketManager cycleSocket]; - } - }); } - (void)addDevicesToRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction diff --git a/SignalUtilitiesKit/SignalServiceClient.swift b/SignalUtilitiesKit/SignalServiceClient.swift deleted file mode 100644 index b7bd546b4..000000000 --- a/SignalUtilitiesKit/SignalServiceClient.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - - -public typealias RecipientIdentifier = String - -@objc -public protocol SignalServiceClientObjC { - @objc func updateAccountAttributesObjC() -> AnyPromise -} - -public protocol SignalServiceClient: SignalServiceClientObjC { - func getAvailablePreKeys() -> Promise - func registerPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise - func setCurrentSignedPreKey(_ signedPreKey: SignedPreKeyRecord) -> Promise - func requestUDSenderCertificate() -> Promise - func updateAccountAttributes() -> Promise -} - -/// Based on libsignal-service-java's PushServiceSocket class -@objc -public class SignalServiceRestClient: NSObject, SignalServiceClient { - - var networkManager: TSNetworkManager { - return TSNetworkManager.shared() - } - - private var udManager: OWSUDManager { - return SSKEnvironment.shared.udManager - } - - func unexpectedServerResponseError() -> Error { - return OWSErrorMakeUnableToProcessServerResponseError() - } - - public func getAvailablePreKeys() -> Promise { - Logger.debug("") - - let request = OWSRequestFactory.availablePreKeysCountRequest() - return firstly { - networkManager.makePromise(request: request) - }.map { _, responseObject in - Logger.debug("got response") - guard let params = ParamParser(responseObject: responseObject) else { - throw self.unexpectedServerResponseError() - } - - let count: Int = try params.required(key: "count") - - return count - } - } - - public func registerPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise { - Logger.debug("") - - let request = OWSRequestFactory.registerPrekeysRequest(withPrekeyArray: preKeyRecords, identityKey: identityKey, signedPreKey: signedPreKeyRecord) - return networkManager.makePromise(request: request).asVoid() - } - - public func setCurrentSignedPreKey(_ signedPreKey: SignedPreKeyRecord) -> Promise { - Logger.debug("") - - let request = OWSRequestFactory.registerSignedPrekeyRequest(with: signedPreKey) - return networkManager.makePromise(request: request).asVoid() - } - - public func requestUDSenderCertificate() -> Promise { - let request = OWSRequestFactory.udSenderCertificateRequest() - return firstly { - self.networkManager.makePromise(request: request) - }.map { _, responseObject in - guard let parser = ParamParser(responseObject: responseObject) else { - throw OWSUDError.invalidData(description: "Invalid sender certificate response") - } - - return try parser.requiredBase64EncodedData(key: "certificate") - } - } - - @objc - public func updateAccountAttributesObjC() -> AnyPromise { - return AnyPromise(updateAccountAttributes()) - } - - public func updateAccountAttributes() -> Promise { - let request = OWSRequestFactory.updateAttributesRequest() - return networkManager.makePromise(request: request).asVoid() - } -} diff --git a/SignalUtilitiesKit/SyncMessagesProtocol.swift b/SignalUtilitiesKit/SyncMessagesProtocol.swift deleted file mode 100644 index 077354442..000000000 --- a/SignalUtilitiesKit/SyncMessagesProtocol.swift +++ /dev/null @@ -1,293 +0,0 @@ -import PromiseKit - -// A few notes about making changes in this file: -// -// • Don't use a database transaction if you can avoid it. -// • If you do need to use a database transaction, use a read transaction if possible. -// • For write transactions, consider making it the caller's responsibility to manage the database transaction (this helps avoid unnecessary transactions). -// • Think carefully about adding a function; there might already be one for what you need. -// • Document the expected cases in which a function will be used -// • Express those cases in tests. - -@objc(LKSyncMessagesProtocol) -public final class SyncMessagesProtocol : NSObject { - - /// Only ever modified from the message processing queue (`OWSBatchMessageProcessor.processingQueue`). - private static var syncMessageTimestamps: [String:Set] = [:] - - internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } - - // MARK: - Error - - @objc(LKSyncMessagesProtocolError) - public class SyncMessagesProtocolError : NSError { // Not called `Error` for Obj-C interoperablity - - @objc public static let privateKeyMissing = SyncMessagesProtocolError(domain: "SyncMessagesProtocolErrorDomain", code: 1, userInfo: [ NSLocalizedDescriptionKey : "Couldn't get private key for SSK based closed group." ]) - } - - // MARK: - Sending - - @objc public static func syncProfile() { - /* - Storage.writeSync { transaction in - let userPublicKey = getUserHexEncodedPublicKey() - let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: userPublicKey, in: transaction) - for device in userLinkedDevices { - guard device != userPublicKey else { continue } - let thread = TSContactThread.getOrCreateThread(withContactId: device, transaction: transaction) - thread.save(with: transaction) - let syncMessage = OWSOutgoingSyncMessage(in: thread, messageBody: "", attachmentId: nil) - syncMessage.save(with: transaction) - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue - messageSenderJobQueue.add(message: syncMessage, transaction: transaction) - } - } - */ - } - - @objc(syncContactWithPublicKey:) - public static func syncContact(_ publicKey: String) -> AnyPromise { - let syncManager = SSKEnvironment.shared.syncManager - return syncManager.syncContacts(for: [ SignalAccount(recipientId: publicKey) ]) - } - - private static func getContactsToSync(using transaction: YapDatabaseReadTransaction) -> Set { - return Set(TSContactThread.allObjectsInCollection().compactMap { $0 as? TSContactThread } - .filter { $0.shouldThreadBeVisible } - .map { $0.contactIdentifier() } - .filter { ECKeyPair.isValidHexEncodedPublicKey(candidate: $0) } - .filter { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) == nil } // Exclude secondary devices - .filter { !LokiDatabaseUtilities.isUserLinkedDevice($0, transaction: transaction) }) - } - - @objc public static func syncAllContacts() -> AnyPromise { - var publicKeys: [String] = [] - storage.dbReadConnection.read { transaction in - publicKeys = [String](getContactsToSync(using: transaction)) - } - let accounts = Set(publicKeys).map { SignalAccount(recipientId: $0) } - let syncManager = SSKEnvironment.shared.syncManager - let promises = accounts.chunked(by: 3).map { accounts -> Promise in // TODO: Does this always fit? - return Promise(syncManager.syncContacts(for: accounts)).map2 { _ in } - } - return AnyPromise.from(when(fulfilled: promises)) - } - - @objc(syncClosedGroup:transaction:) - public static func syncClosedGroup(_ thread: TSGroupThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { - /* - // Prepare - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue - let group = thread.groupModel - let groupPublicKey = LKGroupUtilities.getDecodedGroupID(group.groupId) - let name = group.groupName! - let members = group.groupMemberIds.map { Data(hex: $0) } - let admins = group.groupAdminIds.map { Data(hex: $0) } - guard let groupPrivateKey = Storage.getClosedGroupPrivateKey(for: groupPublicKey) else { - print("[Loki] Couldn't get private key for SSK based closed group.") - return AnyPromise.from(Promise(error: SyncMessagesProtocolError.privateKeyMissing)) - } - // Generate ratchets for the user's linked devices - let userPublicKey = getUserHexEncodedPublicKey() - let masterPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? userPublicKey - let deviceLinks = storage.getDeviceLinks(for: masterPublicKey, in: transaction) - let linkedDevices = deviceLinks.flatMap { [ $0.master.publicKey, $0.slave.publicKey ] }.filter { $0 != userPublicKey } - let senderKeys: [ClosedGroupSenderKey] = linkedDevices.map { publicKey in - let ratchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) - return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) - } - // Send a closed group update message to the existing members with the linked devices' ratchets (this message is aimed at the group) - func sendMessageToGroup() { - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: senderKeys, - members: members, admins: admins) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) - } - sendMessageToGroup() - // Send closed group update messages to the linked devices using established channels - func sendMessageToLinkedDevices() { - var allSenderKeys = Storage.getAllClosedGroupSenderKeys(for: groupPublicKey) - allSenderKeys.formUnion(senderKeys) - let thread = TSContactThread.getOrCreateThread(withContactId: masterPublicKey, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, - groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: members, admins: admins) - let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) - messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // This internally takes care of multi device - } - sendMessageToLinkedDevices() - */ - // Return a dummy promise - return AnyPromise.from(Promise { $0.fulfill(()) }) - } - - @objc public static func syncAllClosedGroups() -> AnyPromise { - var closedGroups: [TSGroupThread] = [] - TSGroupThread.enumerateCollectionObjects { object, _ in - guard let closedGroup = object as? TSGroupThread, closedGroup.groupModel.groupType == .closedGroup, - closedGroup.shouldThreadBeVisible else { return } - closedGroups.append(closedGroup) - } - let syncManager = SSKEnvironment.shared.syncManager - let promises = closedGroups.map { group -> Promise in - return Promise(syncManager.syncGroup(for: group)).map2 { _ in } - } - return AnyPromise.from(when(fulfilled: promises)) - } - - @objc public static func syncAllOpenGroups() -> AnyPromise { - fatalError("Not implemented.") - } - - // MARK: - Receiving - - @objc(isValidSyncMessage:transaction:) - public static func isValidSyncMessage(_ envelope: SSKProtoEnvelope, transaction: YapDatabaseReadTransaction) -> Bool { - let publicKey = envelope.source! // Set during UD decryption - return LokiDatabaseUtilities.isUserLinkedDevice(publicKey, transaction: transaction) - } - - public static func dropFromSyncMessageTimestampCache(_ timestamp: UInt64, for publicKey: String) { - var timestamps: Set = syncMessageTimestamps[publicKey] ?? [] - if timestamps.contains(timestamp) { timestamps.remove(timestamp) } - syncMessageTimestamps[publicKey] = timestamps - } - - @objc(isDuplicateSyncMessage:fromPublicKey:) - public static func isDuplicateSyncMessage(_ protoContent: SSKProtoContent, from publicKey: String) -> Bool { - guard let syncMessage = protoContent.syncMessage?.sent else { return false } - var timestamps: Set = syncMessageTimestamps[publicKey] ?? [] - let hasTimestamp = syncMessage.timestamp != 0 - guard hasTimestamp else { return false } - let result = timestamps.contains(syncMessage.timestamp) - timestamps.insert(syncMessage.timestamp) - syncMessageTimestamps[publicKey] = timestamps - return result - } - - @objc(updateProfileFromSyncMessageIfNeeded:wrappedIn:transaction:) - public static func updateProfileFromSyncMessageIfNeeded(_ dataMessage: SSKProtoDataMessage, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = envelope.source! // Set during UD decryption - guard let userMasterPublicKey = storage.getMasterHexEncodedPublicKey(for: getUserHexEncodedPublicKey(), in: transaction) else { return } - let wasSentByMasterDevice = (userMasterPublicKey == publicKey) - guard wasSentByMasterDevice else { return } - SessionMetaProtocol.updateDisplayNameIfNeeded(for: userMasterPublicKey, using: dataMessage, in: transaction) - SessionMetaProtocol.updateProfileKeyIfNeeded(for: userMasterPublicKey, using: dataMessage) - } - - /// - Note: Deprecated. - @objc(handleClosedGroupUpdateSyncMessageIfNeeded:wrappedIn:transaction:) - public static func handleClosedGroupUpdateSyncMessageIfNeeded(_ transcript: OWSIncomingSentMessageTranscript, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - // Check preconditions - let publicKey = envelope.source! // Set during UD decryption - let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: getUserHexEncodedPublicKey(), in: transaction) - let wasSentByLinkedDevice = userLinkedDevices.contains(publicKey) - guard wasSentByLinkedDevice, let group = transcript.dataMessage.group, let name = group.name else { return } - // Create or update the group - let id = group.id - let members = group.members - let newGroupThread = TSGroupThread.getOrCreateThread(withGroupId: id, groupType: .closedGroup, transaction: transaction) - let newGroupModel = TSGroupModel(title: name, memberIds: members, image: nil, groupId: id, groupType: .closedGroup, adminIds: group.admins) - newGroupThread.save(with: transaction) - newGroupThread.setGroupModel(newGroupModel, with: transaction) - OWSDisappearingMessagesJob.shared().becomeConsistent(withDisappearingDuration: transcript.dataMessage.expireTimer, thread: newGroupThread, createdByRemoteRecipientId: nil, createdInExistingGroup: true, transaction: transaction) - // Try to establish sessions with all members for which none exists yet when a group is created or updated - ClosedGroupsProtocol.establishSessionsIfNeeded(with: members, using: transaction) - // Notify the user - let contactsManager = SSKEnvironment.shared.contactsManager - let infoMessageText = newGroupThread.groupModel.getInfoStringAboutUpdate(to: newGroupModel, contactsManager: contactsManager) - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: newGroupThread, messageType: .typeGroupUpdate, customMessage: infoMessageText) - infoMessage.save(with: transaction) - } - - /// - Note: Deprecated. - @objc(handleClosedGroupQuitSyncMessageIfNeeded:wrappedIn:transaction:) - public static func handleClosedGroupQuitSyncMessageIfNeeded(_ transcript: OWSIncomingSentMessageTranscript, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - // Check preconditions - let publicKey = envelope.source! // Set during UD decryption - let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: getUserHexEncodedPublicKey(), in: transaction) - let wasSentByLinkedDevice = userLinkedDevices.contains(publicKey) - guard wasSentByLinkedDevice, let group = transcript.dataMessage.group else { return } - // Leave the group - let groupThread = TSGroupThread.getOrCreateThread(withGroupId: group.id, groupType: .closedGroup, transaction: transaction) - groupThread.save(with: transaction) - groupThread.leaveGroup(with: transaction) - // Notify the user - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: groupThread, messageType: .typeGroupQuit, customMessage: NSLocalizedString("GROUP_YOU_LEFT", comment: "")) - infoMessage.save(with: transaction) - } - - @objc(handleContactSyncMessageIfNeeded:wrappedIn:transaction:) - public static func handleContactSyncMessageIfNeeded(_ syncMessage: SSKProtoSyncMessage, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = envelope.source! // Set during UD decryption - let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: getUserHexEncodedPublicKey(), in: transaction) - let wasSentByLinkedDevice = userLinkedDevices.contains(publicKey) - guard wasSentByLinkedDevice, let contacts = syncMessage.contacts, let contactsAsData = contacts.data, !contactsAsData.isEmpty else { return } - print("[Loki] Contact sync message received.") - handleContactSyncMessageData(contactsAsData, using: transaction) - } - - public static func handleContactSyncMessageData(_ data: Data, using transaction: YapDatabaseReadWriteTransaction) { - let parser = ContactParser(data: data) - let tuples = parser.parse() - let blockedPublicKeys = tuples.filter { $0.isBlocked }.map { $0.publicKey } - let userPublicKey = getUserHexEncodedPublicKey() - let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: userPublicKey, in: transaction) - // Try to establish sessions - for (publicKey, isBlocked) in tuples { - guard !userLinkedDevices.contains(publicKey) else { continue } // Skip self and linked devices - let thread = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) - thread.shouldThreadBeVisible = true - thread.save(with: transaction) - if !isBlocked { - SessionManagementProtocol.sendSessionRequestIfNeeded(to: publicKey, using: transaction) - } - } - // Update the blocked contacts list - transaction.addCompletionQueue(DispatchQueue.main) { - SSKEnvironment.shared.blockingManager.setBlockedPhoneNumbers(blockedPublicKeys, sendSyncMessage: false) - NotificationCenter.default.post(name: .blockedContactsUpdated, object: nil) - } - } - - /// - Note: Deprecated. - @objc(handleClosedGroupSyncMessageIfNeeded:wrappedIn:transaction:) - public static func handleClosedGroupSyncMessageIfNeeded(_ syncMessage: SSKProtoSyncMessage, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = envelope.source! // Set during UD decryption - let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: getUserHexEncodedPublicKey(), in: transaction) - let wasSentByLinkedDevice = userLinkedDevices.contains(publicKey) - guard wasSentByLinkedDevice, let groups = syncMessage.groups, let groupsAsData = groups.data, !groupsAsData.isEmpty else { return } - print("[Loki] Closed group sync message received.") - let parser = ClosedGroupParser(data: groupsAsData) - let closedGroups = parser.parseGroupModels() - for closedGroup in closedGroups { - var thread: TSGroupThread! = TSGroupThread(groupId: closedGroup.groupId, transaction: transaction) - if thread == nil { - thread = TSGroupThread.getOrCreateThread(with: closedGroup, transaction: transaction) - thread.shouldThreadBeVisible = true - thread.save(with: transaction) - } - ClosedGroupsProtocol.establishSessionsIfNeeded(with: closedGroup.groupMemberIds, using: transaction) - } - } - - @objc(handleOpenGroupSyncMessageIfNeeded:wrappedIn:transaction:) - public static func handleOpenGroupSyncMessageIfNeeded(_ syncMessage: SSKProtoSyncMessage, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { - let publicKey = envelope.source! // Set during UD decryption - let userLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: getUserHexEncodedPublicKey(), in: transaction) - let wasSentByLinkedDevice = userLinkedDevices.contains(publicKey) - guard wasSentByLinkedDevice else { return } - let openGroups = syncMessage.openGroups - guard !openGroups.isEmpty else { return } - print("[Loki] Open group sync message received.") - let openGroupManager = PublicChatManager.shared - let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey() - let userDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: userPublicKey, transaction: transaction) - for openGroup in openGroups { - guard openGroupManager.getChat(server: openGroup.url, channel: openGroup.channelID) == nil else { return } - openGroupManager.addChat(server: openGroup.url, channel: openGroup.channelID) - OpenGroupAPI.setDisplayName(to: userDisplayName, on: openGroup.url) - // TODO: Should we also set the profile picture here? - } - } -} diff --git a/SignalUtilitiesKit/SystemContactsFetcher.swift b/SignalUtilitiesKit/SystemContactsFetcher.swift deleted file mode 100644 index ea02c3e35..000000000 --- a/SignalUtilitiesKit/SystemContactsFetcher.swift +++ /dev/null @@ -1,411 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import Contacts -import ContactsUI - - -enum Result { - case success(T) - case error(ErrorType) -} - -protocol ContactStoreAdaptee { - var authorizationStatus: ContactStoreAuthorizationStatus { get } - var supportsContactEditing: Bool { get } - func requestAccess(completionHandler: @escaping (Bool, Error?) -> Void) - func fetchContacts() -> Result<[Contact], Error> - func fetchCNContact(contactId: String) -> CNContact? - func startObservingChanges(changeHandler: @escaping () -> Void) -} - -public -class ContactsFrameworkContactStoreAdaptee: NSObject, ContactStoreAdaptee { - private let contactStore = CNContactStore() - private var changeHandler: (() -> Void)? - private var initializedObserver = false - private var lastSortOrder: CNContactSortOrder? - - let supportsContactEditing = true - - public static let allowedContactKeys: [CNKeyDescriptor] = [ - CNContactFormatter.descriptorForRequiredKeys(for: .fullName), - CNContactThumbnailImageDataKey as CNKeyDescriptor, // TODO full image instead of thumbnail? - CNContactPhoneNumbersKey as CNKeyDescriptor, - CNContactEmailAddressesKey as CNKeyDescriptor, - CNContactPostalAddressesKey as CNKeyDescriptor, - CNContactViewController.descriptorForRequiredKeys(), - CNContactVCardSerialization.descriptorForRequiredKeys() - ] - - var authorizationStatus: ContactStoreAuthorizationStatus { - switch CNContactStore.authorizationStatus(for: CNEntityType.contacts) { - case .notDetermined: - return .notDetermined - case .restricted: - return .restricted - case .denied: - return .denied - case .authorized: - return .authorized - } - } - - func startObservingChanges(changeHandler: @escaping () -> Void) { - // should only call once - assert(self.changeHandler == nil) - self.changeHandler = changeHandler - self.lastSortOrder = CNContactsUserDefaults.shared().sortOrder - NotificationCenter.default.addObserver(self, selector: #selector(runChangeHandler), name: .CNContactStoreDidChange, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: .OWSApplicationDidBecomeActive, object: nil) - } - - @objc - func didBecomeActive() { - AppReadiness.runNowOrWhenAppDidBecomeReady { - let currentSortOrder = CNContactsUserDefaults.shared().sortOrder - - guard currentSortOrder != self.lastSortOrder else { - // sort order unchanged - return - } - - Logger.info("sort order changed: \(String(describing: self.lastSortOrder)) -> \(String(describing: currentSortOrder))") - self.lastSortOrder = currentSortOrder - self.runChangeHandler() - } - } - - @objc - func runChangeHandler() { - guard let changeHandler = self.changeHandler else { - owsFailDebug("trying to run change handler before it was registered") - return - } - changeHandler() - } - - func requestAccess(completionHandler: @escaping (Bool, Error?) -> Void) { - self.contactStore.requestAccess(for: .contacts, completionHandler: completionHandler) - } - - func fetchContacts() -> Result<[Contact], Error> { - var systemContacts = [CNContact]() - do { - let contactFetchRequest = CNContactFetchRequest(keysToFetch: ContactsFrameworkContactStoreAdaptee.allowedContactKeys) - contactFetchRequest.sortOrder = .userDefault - try self.contactStore.enumerateContacts(with: contactFetchRequest) { (contact, _) -> Void in - systemContacts.append(contact) - } - } catch let error as NSError { - owsFailDebug("Failed to fetch contacts with error:\(error)") - return .error(error) - } - - let contacts = systemContacts.map { Contact(systemContact: $0) } - return .success(contacts) - } - - func fetchCNContact(contactId: String) -> CNContact? { - var result: CNContact? - do { - let contactFetchRequest = CNContactFetchRequest(keysToFetch: ContactsFrameworkContactStoreAdaptee.allowedContactKeys) - contactFetchRequest.sortOrder = .userDefault - contactFetchRequest.predicate = CNContact.predicateForContacts(withIdentifiers: [contactId]) - - try self.contactStore.enumerateContacts(with: contactFetchRequest) { (contact, _) -> Void in - guard result == nil else { - owsFailDebug("More than one contact with contact id.") - return - } - result = contact - } - } catch let error as NSError { - owsFailDebug("Failed to fetch contact with error:\(error)") - return nil - } - - return result - } -} - -@objc -public enum ContactStoreAuthorizationStatus: UInt { - case notDetermined, - restricted, - denied, - authorized -} - -@objc public protocol SystemContactsFetcherDelegate: class { - func systemContactsFetcher(_ systemContactsFetcher: SystemContactsFetcher, updatedContacts contacts: [Contact], isUserRequested: Bool) - func systemContactsFetcher(_ systemContactsFetcher: SystemContactsFetcher, hasAuthorizationStatus authorizationStatus: ContactStoreAuthorizationStatus) -} - -@objc -public class SystemContactsFetcher: NSObject { - - private let serialQueue = DispatchQueue(label: "SystemContactsFetcherQueue") - - var lastContactUpdateHash: Int? - var lastDelegateNotificationDate: Date? - let contactStoreAdapter: ContactsFrameworkContactStoreAdaptee - - @objc - public weak var delegate: SystemContactsFetcherDelegate? - - public var authorizationStatus: ContactStoreAuthorizationStatus { - return contactStoreAdapter.authorizationStatus - } - - @objc - public var isAuthorized: Bool { - guard self.authorizationStatus != .notDetermined else { - owsFailDebug("should have called `requestOnce` before checking authorization status.") - return false - } - - return self.authorizationStatus == .authorized - } - - @objc - public var isDenied: Bool { - return self.authorizationStatus == .denied - } - - @objc - public private(set) var systemContactsHaveBeenRequestedAtLeastOnce = false - private var hasSetupObservation = false - - @objc public override init() { - self.contactStoreAdapter = ContactsFrameworkContactStoreAdaptee() - - super.init() - - SwiftSingletons.register(self) - } - - @objc - public var supportsContactEditing: Bool { - return self.contactStoreAdapter.supportsContactEditing - } - - private func setupObservationIfNecessary() { - AssertIsOnMainThread() - guard !hasSetupObservation else { - return - } - hasSetupObservation = true - self.contactStoreAdapter.startObservingChanges { [weak self] in - DispatchQueue.main.async { - self?.refreshAfterContactsChange() - } - } - } - - /** - * Ensures we've requested access for system contacts. This can be used in multiple places, - * where we might need contact access, but will ensure we don't wastefully reload contacts - * if we have already fetched contacts. - * - * @param completionParam completion handler is called on main thread. - */ - @objc - public func requestOnce(completion completionParam: ((Error?) -> Void)?) { - AssertIsOnMainThread() - - // Ensure completion is invoked on main thread. - let completion = { error in - DispatchMainThreadSafe({ - completionParam?(error) - }) - } - - guard !systemContactsHaveBeenRequestedAtLeastOnce else { - completion(nil) - return - } - setupObservationIfNecessary() - - switch authorizationStatus { - case .notDetermined: - return completion(nil) - case .authorized: - self.updateContacts(completion: completion) - case .denied, .restricted: - Logger.debug("contacts were \(self.authorizationStatus)") - self.delegate?.systemContactsFetcher(self, hasAuthorizationStatus: authorizationStatus) - completion(nil) - } - } - - @objc - public func fetchOnceIfAlreadyAuthorized() { - AssertIsOnMainThread() - guard authorizationStatus == .authorized else { - self.delegate?.systemContactsFetcher(self, hasAuthorizationStatus: authorizationStatus) - return - } - guard !systemContactsHaveBeenRequestedAtLeastOnce else { - return - } - - updateContacts(completion: nil, isUserRequested: false) - } - - @objc - public func userRequestedRefresh(completion: @escaping (Error?) -> Void) { - AssertIsOnMainThread() - - guard authorizationStatus == .authorized else { - owsFailDebug("should have already requested contact access") - self.delegate?.systemContactsFetcher(self, hasAuthorizationStatus: authorizationStatus) - completion(nil) - return - } - - updateContacts(completion: completion, isUserRequested: true) - } - - @objc - public func refreshAfterContactsChange() { - AssertIsOnMainThread() - - guard authorizationStatus == .authorized else { - Logger.info("ignoring contacts change; no access.") - self.delegate?.systemContactsFetcher(self, hasAuthorizationStatus: authorizationStatus) - return - } - - updateContacts(completion: nil, isUserRequested: false) - } - - private func updateContacts(completion completionParam: ((Error?) -> Void)?, isUserRequested: Bool = false) { - AssertIsOnMainThread() - - var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: "\(#function)", completionBlock: { [weak self] status in - AssertIsOnMainThread() - - guard status == .expired else { - return - } - - guard let _ = self else { - return - } - Logger.error("background task time ran out before contacts fetch completed.") - }) - - // Ensure completion is invoked on main thread. - let completion: (Error?) -> Void = { error in - DispatchMainThreadSafe({ - completionParam?(error) - - assert(backgroundTask != nil) - backgroundTask = nil - }) - } - - systemContactsHaveBeenRequestedAtLeastOnce = true - setupObservationIfNecessary() - - serialQueue.async { - - Logger.info("fetching contacts") - - var fetchedContacts: [Contact]? - switch self.contactStoreAdapter.fetchContacts() { - case .success(let result): - fetchedContacts = result - case .error(let error): - completion(error) - return - } - - guard let contacts = fetchedContacts else { - owsFailDebug("contacts was unexpectedly not set.") - return completion(nil) - } - - Logger.info("fetched \(contacts.count) contacts.") - let contactsHash = HashableArray(contacts).hashValue - - DispatchQueue.main.async { - var shouldNotifyDelegate = false - - if self.lastContactUpdateHash != contactsHash { - Logger.info("contact hash changed. new contactsHash: \(contactsHash)") - shouldNotifyDelegate = true - } else if isUserRequested { - Logger.info("ignoring debounce due to user request") - shouldNotifyDelegate = true - } else { - - // If nothing has changed, only notify delegate (to perform contact intersection) every N hours - if let lastDelegateNotificationDate = self.lastDelegateNotificationDate { - let kDebounceInterval = TimeInterval(12 * 60 * 60) - - let expiresAtDate = Date(timeInterval: kDebounceInterval, since: lastDelegateNotificationDate) - if Date() > expiresAtDate { - Logger.info("debounce interval expired at: \(expiresAtDate)") - shouldNotifyDelegate = true - } else { - Logger.info("ignoring since debounce interval hasn't expired") - } - } else { - Logger.info("first contact fetch. contactsHash: \(contactsHash)") - shouldNotifyDelegate = true - } - } - - guard shouldNotifyDelegate else { - Logger.info("no reason to notify delegate.") - - completion(nil) - - return - } - - self.lastDelegateNotificationDate = Date() - self.lastContactUpdateHash = contactsHash - - self.delegate?.systemContactsFetcher(self, updatedContacts: contacts, isUserRequested: isUserRequested) - completion(nil) - } - } - } - - @objc - public func fetchCNContact(contactId: String) -> CNContact? { - guard authorizationStatus == .authorized else { - Logger.error("contact fetch failed; no access.") - return nil - } - - return contactStoreAdapter.fetchCNContact(contactId: contactId) - } -} - -struct HashableArray: Hashable { - var elements: [Element] - init(_ elements: [Element]) { - self.elements = elements - } - - var hashValue: Int { - // random generated 32bit number - let base = 224712574 - var position = 0 - return elements.reduce(base) { (result, element) -> Int in - // Make sure change in sort order invalidates hash - position += 1 - return result ^ element.hashValue + position - } - } - - static func == (lhs: HashableArray, rhs: HashableArray) -> Bool { - return lhs.hashValue == rhs.hashValue - } -} diff --git a/SignalUtilitiesKit/TSAccountManager.m b/SignalUtilitiesKit/TSAccountManager.m index 724cdfbad..685b76fb5 100644 --- a/SignalUtilitiesKit/TSAccountManager.m +++ b/SignalUtilitiesKit/TSAccountManager.m @@ -9,10 +9,10 @@ #import "NSURLSessionDataTask+StatusCode.h" #import "OWSError.h" #import "OWSPrimaryStorage+SessionStore.h" -#import "OWSRequestFactory.h" + #import "ProfileManagerProtocol.h" #import "SSKEnvironment.h" -#import "TSNetworkManager.h" + #import "TSPreKeyManager.h" #import "YapDatabaseConnection+OWS.h" #import "YapDatabaseTransaction+OWS.h" @@ -107,13 +107,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa #pragma mark - Dependencies -- (TSNetworkManager *)networkManager -{ - OWSAssertDebug(SSKEnvironment.shared.networkManager); - - return SSKEnvironment.shared.networkManager; -} - - (id)profileManager { OWSAssertDebug(SSKEnvironment.shared.profileManager); @@ -318,41 +311,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa }); } -- (void)registerWithPhoneNumber:(NSString *)phoneNumber - captchaToken:(nullable NSString *)captchaToken - success:(void (^)(void))successBlock - failure:(void (^)(NSError *error))failureBlock - smsVerification:(BOOL)isSMS - -{ - if ([self isRegistered]) { - failureBlock([NSError errorWithDomain:@"tsaccountmanager.verify" code:4000 userInfo:nil]); - return; - } - - // The country code of TSAccountManager.phoneNumberAwaitingVerification is used to - // determine whether or not to use domain fronting, so it needs to be set _before_ - // we make our verification code request. - self.phoneNumberAwaitingVerification = phoneNumber; - - TSRequest *request = - [OWSRequestFactory requestVerificationCodeRequestWithPhoneNumber:phoneNumber - captchaToken:captchaToken - transport:(isSMS ? TSVerificationTransportSMS - : TSVerificationTransportVoice)]; - [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSLogInfo(@"Successfully requested verification code request for number: %@ method:%@", - phoneNumber, - isSMS ? @"SMS" : @"Voice"); - successBlock(); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSLogError(@"Failed to request verification code request with error:%@", error); - failureBlock(error); - }]; -} - - (void)rerequestSMSWithCaptchaToken:(nullable NSString *)captchaToken success:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock @@ -382,107 +340,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa smsVerification:NO]; } -- (void)verifyAccountWithCode:(NSString *)verificationCode - pin:(nullable NSString *)pin - success:(void (^)(void))successBlock - failure:(void (^)(NSError *error))failureBlock -{ - NSString *authToken = [[self class] generateNewAccountAuthenticationToken]; - NSString *phoneNumber = self.phoneNumberAwaitingVerification; - - OWSAssertDebug(authToken); - OWSAssertDebug(phoneNumber); - - TSRequest *request = [OWSRequestFactory verifyCodeRequestWithVerificationCode:verificationCode - forNumber:phoneNumber - pin:pin - authKey:authToken]; - - [self.networkManager makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; - long statuscode = response.statusCode; - - switch (statuscode) { - case 200: - case 204: { - OWSLogInfo(@"Verification code accepted."); - - [self storeServerAuthToken:authToken]; - - [[[SignalServiceRestClient new] updateAccountAttributesObjC] - .thenInBackground(^{ - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - [TSPreKeyManager - createPreKeysWithSuccess:^{ - resolve(@(1)); - } - failure:^(NSError *error) { - resolve(error); - }]; - }]; - }) - .then(^{ - [self.profileManager fetchLocalUsersProfile]; - }) - .then(^{ - successBlock(); - }) - .catchInBackground(^(NSError *error) { - OWSLogError(@"Error: %@", error); - failureBlock(error); - }) retainUntilComplete]; - - break; - } - default: { - OWSLogError(@"Unexpected status while verifying code: %ld", statuscode); - NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); - failureBlock(error); - break; - } - } - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSAssertDebug([error.domain isEqualToString:TSNetworkManagerErrorDomain]); - - OWSLogWarn(@"Error verifying code: %@", error.debugDescription); - - switch (error.code) { - case 403: { - NSError *userError = OWSErrorWithCodeDescription(OWSErrorCodeUserError, - NSLocalizedString(@"REGISTRATION_VERIFICATION_FAILED_WRONG_CODE_DESCRIPTION", - "Error message indicating that registration failed due to a missing or incorrect " - "verification code.")); - failureBlock(userError); - break; - } - case 413: { - // In the case of the "rate limiting" error, we want to show the - // "recovery suggestion", not the error's "description." - NSError *userError - = OWSErrorWithCodeDescription(OWSErrorCodeUserError, error.localizedRecoverySuggestion); - failureBlock(userError); - break; - } - case 423: { - NSString *localizedMessage = NSLocalizedString(@"REGISTRATION_VERIFICATION_FAILED_WRONG_PIN", - "Error message indicating that registration failed due to a missing or incorrect 2FA PIN."); - OWSLogError(@"2FA PIN required: %ld", (long)error.code); - NSError *error - = OWSErrorWithCodeDescription(OWSErrorCodeRegistrationMissing2FAPIN, localizedMessage); - failureBlock(error); - break; - } - default: { - OWSLogError(@"verifying code failed with unknown error: %@", error); - failureBlock(error); - break; - } - } - }]; -} - #pragma mark Server keying material + (NSString *)generateNewAccountAuthenticationToken { @@ -522,28 +379,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa }]; } -+ (void)unregisterTextSecureWithSuccess:(void (^)(void))success failure:(void (^)(NSError *error))failureBlock -{ - TSRequest *request = [OWSRequestFactory unregisterAccountRequest]; - [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSLogInfo(@"Successfully unregistered"); - success(); - - // This is called from `[AppSettingsViewController proceedToUnregistration]` whose - // success handler calls `[Environment resetAppData]`. - // This method, after calling that success handler, fires - // `RegistrationStateDidChangeNotification` which is only safe to fire after - // the data store is reset. - - [self.sharedInstance postRegistrationStateDidChangeNotification]; - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - OWSLogError(@"Failed to unregister with error: %@", error); - failureBlock(error); - }]; -} - - (void)yapDatabaseModifiedExternally:(NSNotification *)notification { OWSAssertIsOnMainThread(); @@ -727,20 +562,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa return promise; } -- (AnyPromise *)performUpdateAccountAttributes -{ - AnyPromise *promise = [[SignalServiceRestClient new] updateAccountAttributesObjC]; - promise = promise.then(^(id value) { - // Fetch the local profile, as we may have changed its - // account attributes. Specifically, we need to determine - // if all devices for our account now support UD for sync - // messages. - [self.profileManager fetchLocalUsersProfile]; - }); - [promise retainUntilComplete]; - return promise; -} - - (void)reachabilityChanged { OWSAssertIsOnMainThread(); diff --git a/SignalUtilitiesKit/TSConstants.h b/SignalUtilitiesKit/TSConstants.h index 8ddac95c1..3d8542585 100644 --- a/SignalUtilitiesKit/TSConstants.h +++ b/SignalUtilitiesKit/TSConstants.h @@ -19,7 +19,7 @@ typedef NS_ENUM(NSInteger, TSWhisperMessageType) { TSUnencryptedWhisperMessageType = 4, TSUnidentifiedSenderMessageType = 6, TSClosedGroupCiphertextMessageType = 7, - TSFallbackMessageType = 101 // Loki: Encrypted using the fallback session cipher. Contains a pre key bundle if it's a session request. + TSFallbackMessageType = 101 }; #pragma mark Server Address diff --git a/SignalUtilitiesKit/TSDatabaseView.h b/SignalUtilitiesKit/TSDatabaseView.h index 554d5b985..bdd52ee8b 100644 --- a/SignalUtilitiesKit/TSDatabaseView.h +++ b/SignalUtilitiesKit/TSDatabaseView.h @@ -65,8 +65,6 @@ extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName; + (void)asyncRegisterThreadSpecialMessagesDatabaseView:(OWSStorage *)storage; -+ (void)asyncRegisterSecondaryDevicesDatabaseView:(OWSStorage *)storage; - + (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage; @end diff --git a/SignalUtilitiesKit/TSDatabaseView.m b/SignalUtilitiesKit/TSDatabaseView.m index e7d0f15f7..86b1658ec 100644 --- a/SignalUtilitiesKit/TSDatabaseView.m +++ b/SignalUtilitiesKit/TSDatabaseView.m @@ -3,7 +3,7 @@ // #import "TSDatabaseView.h" -#import "OWSDevice.h" + #import "OWSReadTracking.h" #import "TSAttachment.h" #import "TSAttachmentPointer.h" @@ -282,7 +282,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" return nil; } TSThread *thread = (TSThread *)object; - if (thread.isSlaveThread) { return nil; } if (thread.shouldThreadBeVisible) { // Do nothing; we never hide threads that have ever had a message. @@ -371,56 +370,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" }]; } -+ (void)asyncRegisterSecondaryDevicesDatabaseView:(OWSStorage *)storage -{ - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[OWSDevice class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); - return nil; - } - OWSDevice *device = (OWSDevice *)object; - if (![device isPrimaryDevice]) { - return TSSecondaryDevicesGroup; - } - return nil; - }]; - - YapDatabaseViewSorting *viewSorting = [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult( - YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[OWSDevice class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - if (![object2 isKindOfClass:[OWSDevice class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - OWSDevice *device1 = (OWSDevice *)object1; - OWSDevice *device2 = (OWSDevice *)object2; - - return [device2.createdAt compare:device1.createdAt]; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.isPersistent = YES; - - NSSet *deviceCollection = [NSSet setWithObject:[OWSDevice collection]]; - options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:deviceCollection]; - - YapDatabaseView *view = - [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options]; - - [storage asyncRegisterExtension:view withName:TSSecondaryDevicesDatabaseViewExtensionName]; -} - + (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage { YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable( diff --git a/SignalUtilitiesKit/TSNetworkManager.h b/SignalUtilitiesKit/TSNetworkManager.h deleted file mode 100644 index 0dda2495a..000000000 --- a/SignalUtilitiesKit/TSNetworkManager.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern NSErrorDomain const TSNetworkManagerErrorDomain; -typedef NS_ERROR_ENUM(TSNetworkManagerErrorDomain, TSNetworkManagerError){ - // It's a shame to use 0 as an enum value for anything other than something like default or unknown, because it's - // indistinguishable from "not set" in Objc. - // However this value was existing behavior for connectivity errors, and since we might be using this in other - // places I didn't want to change it out of hand - TSNetworkManagerErrorFailedConnection = 0, - // Other TSNetworkManagerError's use HTTP status codes (e.g. 404, etc) -}; - -BOOL IsNSErrorNetworkFailure(NSError *_Nullable error); - -typedef void (^TSNetworkManagerSuccess)(NSURLSessionDataTask *task, _Nullable id responseObject); -typedef void (^TSNetworkManagerFailure)(NSURLSessionDataTask *task, NSError *error); - -@class TSRequest; - -@interface TSNetworkManager : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initDefault; - -+ (instancetype)sharedManager; - -- (void)makeRequest:(TSRequest *)request - success:(TSNetworkManagerSuccess)success - failure:(TSNetworkManagerFailure)failure NS_SWIFT_NAME(makeRequest(_:success:failure:)); - -- (void)makeRequest:(TSRequest *)request - completionQueue:(dispatch_queue_t)completionQueue - success:(TSNetworkManagerSuccess)success - failure:(TSNetworkManagerFailure)failure NS_SWIFT_NAME(makeRequest(_:completionQueue:success:failure:)); - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSNetworkManager.m b/SignalUtilitiesKit/TSNetworkManager.m deleted file mode 100644 index 20c39fb0b..000000000 --- a/SignalUtilitiesKit/TSNetworkManager.m +++ /dev/null @@ -1,588 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "TSNetworkManager.h" -#import "AppContext.h" -#import "NSError+messageSending.h" -#import "NSURLSessionDataTask+StatusCode.h" -#import "OWSError.h" -#import "OWSQueues.h" -#import "OWSSignalService.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "TSRequest.h" -#import -#import -#import -#import "SSKAsserts.h" - -NS_ASSUME_NONNULL_BEGIN - -NSErrorDomain const TSNetworkManagerErrorDomain = @"SignalServiceKit.TSNetworkManager"; - -BOOL IsNSErrorNetworkFailure(NSError *_Nullable error) -{ - return ([error.domain isEqualToString:TSNetworkManagerErrorDomain] - && error.code == TSNetworkManagerErrorFailedConnection); -} - -dispatch_queue_t NetworkManagerQueue() -{ - static dispatch_queue_t serialQueue; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - serialQueue = dispatch_queue_create("org.whispersystems.networkManager", DISPATCH_QUEUE_SERIAL); - }); - return serialQueue; -} - -#pragma mark - - -@interface OWSSessionManager : NSObject - -@property (nonatomic, readonly) AFHTTPSessionManager *sessionManager; -@property (nonatomic, readonly) NSDictionary *defaultHeaders; - -@end - -#pragma mark - - -@implementation OWSSessionManager - -#pragma mark - Dependencies - -- (OWSSignalService *)signalService -{ - return [OWSSignalService sharedInstance]; -} - -#pragma mark - - -- (instancetype)init -{ - AssertOnDispatchQueue(NetworkManagerQueue()); - - self = [super init]; - if (!self) { - return self; - } - - _sessionManager = [self.signalService buildSignalServiceSessionManager]; - self.sessionManager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - // NOTE: We could enable HTTPShouldUsePipelining here. - // Make a copy of the default headers for this session manager. - _defaultHeaders = [self.sessionManager.requestSerializer.HTTPRequestHeaders copy]; - - return self; -} - -// TSNetworkManager.serialQueue -- (void)performRequest:(TSRequest *)request - canUseAuth:(BOOL)canUseAuth - success:(TSNetworkManagerSuccess)success - failure:(TSNetworkManagerFailure)failure -{ - AssertOnDispatchQueue(NetworkManagerQueue()); - OWSAssertDebug(request); - OWSAssertDebug(success); - OWSAssertDebug(failure); - - // Clear all headers so that we don't retain headers from previous requests. - for (NSString *headerField in self.sessionManager.requestSerializer.HTTPRequestHeaders.allKeys.copy) { - [self.sessionManager.requestSerializer setValue:nil forHTTPHeaderField:headerField]; - } - - // Apply the default headers for this session manager. - for (NSString *headerField in self.defaultHeaders) { - NSString *headerValue = self.defaultHeaders[headerField]; - [self.sessionManager.requestSerializer setValue:headerValue forHTTPHeaderField:headerField]; - } - -// if (canUseAuth && request.shouldHaveAuthorizationHeaders) { -// [self.sessionManager.requestSerializer setAuthorizationHeaderFieldWithUsername:request.authUsername -// password:request.authPassword]; -// } - - // Honor the request's headers. - for (NSString *headerField in request.allHTTPHeaderFields) { - NSString *headerValue = request.allHTTPHeaderFields[headerField]; - [self.sessionManager.requestSerializer setValue:headerValue forHTTPHeaderField:headerField]; - } - - self.sessionManager.requestSerializer.timeoutInterval = request.timeoutInterval; - - if ([request.HTTPMethod isEqualToString:@"GET"]) { - [self.sessionManager GET:request.URL.absoluteString - parameters:request.parameters - headers:request.allHTTPHeaderFields - progress:nil - success:success - failure:failure]; - } else if ([request.HTTPMethod isEqualToString:@"POST"]) { - [self.sessionManager POST:request.URL.absoluteString - parameters:request.parameters - headers:request.allHTTPHeaderFields - progress:nil - success:success - failure:failure]; - } else if ([request.HTTPMethod isEqualToString:@"PUT"]) { - [self.sessionManager PUT:request.URL.absoluteString - parameters:request.parameters - headers:request.allHTTPHeaderFields - success:success - failure:failure]; - } else if ([request.HTTPMethod isEqualToString:@"DELETE"]) { - [self.sessionManager DELETE:request.URL.absoluteString - parameters:request.parameters - headers:request.allHTTPHeaderFields - success:success - failure:failure]; - } else if ([request.HTTPMethod isEqualToString:@"PATCH"]) { - [self.sessionManager PATCH:request.URL.absoluteString - parameters:request.parameters - headers:request.allHTTPHeaderFields - success:success - failure:failure]; - } else { - OWSLogError(@"Trying to perform HTTP operation with unknown verb: %@", request.HTTPMethod); - } -} - -@end - -#pragma mark - - -// You might be asking: "why use a pool at all? We're only using the session manager -// on the serial queue, so can't we just have two session managers (1 UD, 1 non-UD) -// that we use for all requests?" -// -// That assumes that the session managers are not stateful in a way where concurrent -// requests can interfere with each other. I audited the AFNetworking codebase and my -// reading is that sessions managers are safe to use in that way - that the state of -// their properties (e.g. header values) is only used when building the request and -// can be safely changed after performRequest is complete. -// -// But I decided that I didn't want to (silently) bake that assumption into the -// codebase, since the stakes are high. The session managers aren't expensive. IMO -// better to use a pool and not re-use a session manager until its request succeeds -// or fails. -@interface OWSSessionManagerPool : NSObject - -@property (nonatomic) NSMutableArray *pool; - -@end - -#pragma mark - - -@implementation OWSSessionManagerPool - -- (instancetype)init -{ - self = [super init]; - if (!self) { - return self; - } - - self.pool = [NSMutableArray new]; - - return self; -} - -- (OWSSessionManager *)get -{ - AssertOnDispatchQueue(NetworkManagerQueue()); - - OWSSessionManager *_Nullable sessionManager = [self.pool lastObject]; - if (sessionManager) { - [self.pool removeLastObject]; - } else { - sessionManager = [OWSSessionManager new]; - } - OWSAssertDebug(sessionManager); - return sessionManager; -} - -- (void)returnToPool:(OWSSessionManager *)sessionManager -{ - AssertOnDispatchQueue(NetworkManagerQueue()); - - OWSAssertDebug(sessionManager); - const NSUInteger kMaxPoolSize = 3; - if (self.pool.count >= kMaxPoolSize) { - // Discard - return; - } - [self.pool addObject:sessionManager]; -} - -@end - -#pragma mark - - -@interface TSNetworkManager () - -// These properties should only be accessed on serialQueue. -@property (atomic, readonly) OWSSessionManagerPool *udSessionManagerPool; -@property (atomic, readonly) OWSSessionManagerPool *nonUdSessionManagerPool; - -@end - -#pragma mark - - -@implementation TSNetworkManager - -#pragma mark - Dependencies - -+ (TSAccountManager *)tsAccountManager -{ - return TSAccountManager.sharedInstance; -} - -#pragma mark - Singleton - -+ (instancetype)sharedManager -{ - OWSAssertDebug(SSKEnvironment.shared.networkManager); - - return SSKEnvironment.shared.networkManager; -} - -- (instancetype)initDefault -{ - self = [super init]; - if (!self) { - return self; - } - - _udSessionManagerPool = [OWSSessionManagerPool new]; - _nonUdSessionManagerPool = [OWSSessionManagerPool new]; - - OWSSingletonAssert(); - - return self; -} - -#pragma mark Manager Methods - -- (void)makeRequest:(TSRequest *)request - success:(TSNetworkManagerSuccess)success - failure:(TSNetworkManagerFailure)failure -{ - return [self makeRequest:request completionQueue:dispatch_get_main_queue() success:success failure:failure]; -} - -- (void)makeRequest:(TSRequest *)request - completionQueue:(dispatch_queue_t)completionQueue - success:(TSNetworkManagerSuccess)success - failure:(TSNetworkManagerFailure)failure -{ - OWSAssertDebug(request); - OWSAssertDebug(success); - OWSAssertDebug(failure); - - dispatch_async(NetworkManagerQueue(), ^{ - [self makeRequestSync:request completionQueue:completionQueue success:success failure:failure]; - }); -} - -- (void)makeRequestSync:(TSRequest *)request - completionQueue:(dispatch_queue_t)completionQueue - success:(TSNetworkManagerSuccess)successParam - failure:(TSNetworkManagerFailure)failureParam -{ - OWSAssertDebug(request); - OWSAssertDebug(successParam); - OWSAssertDebug(failureParam); - -// BOOL isUDRequest = request.isUDRequest; - NSString *label = @"UD request"; -// BOOL canUseAuth = !isUDRequest; -// if (isUDRequest) { -// OWSAssert(!request.shouldHaveAuthorizationHeaders); -// } -// OWSLogInfo(@"Making %@: %@", label, request); - - OWSSessionManagerPool *sessionManagerPool = self.udSessionManagerPool; - OWSSessionManager *sessionManager = [sessionManagerPool get]; - - TSNetworkManagerSuccess success = ^(NSURLSessionDataTask *task, _Nullable id responseObject) { - dispatch_async(NetworkManagerQueue(), ^{ - [sessionManagerPool returnToPool:sessionManager]; - }); - - dispatch_async(completionQueue, ^{ - OWSLogInfo(@"%@ succeeded : %@", label, request); - -// if (canUseAuth && request.shouldHaveAuthorizationHeaders) { -// [TSNetworkManager.tsAccountManager setIsDeregistered:NO]; -// } - - successParam(task, responseObject); - - [OutageDetection.sharedManager reportConnectionSuccess]; - }); - }; - TSNetworkManagerFailure failure = ^(NSURLSessionDataTask *task, NSError *error) { - dispatch_async(NetworkManagerQueue(), ^{ - [sessionManagerPool returnToPool:sessionManager]; - }); - - [TSNetworkManager - handleNetworkFailure:^(NSURLSessionDataTask *task, NSError *error) { - dispatch_async(completionQueue, ^{ - failureParam(task, error); - }); - } - request:request - task:task - error:error]; - }; - - [sessionManager performRequest:request canUseAuth:NO success:success failure:failure]; -} - -#ifdef DEBUG -+ (void)logCurlForTask:(NSURLSessionDataTask *)task -{ - NSMutableArray *curlComponents = [NSMutableArray new]; - [curlComponents addObject:@"curl"]; - // Verbose - [curlComponents addObject:@"-v"]; - // Insecure - [curlComponents addObject:@"-k"]; - // Method, e.g. GET - [curlComponents addObject:@"-X"]; - [curlComponents addObject:task.originalRequest.HTTPMethod]; - // Headers - for (NSString *header in task.originalRequest.allHTTPHeaderFields) { - NSString *headerValue = task.originalRequest.allHTTPHeaderFields[header]; - // We don't yet support escaping header values. - // If these asserts trip, we'll need to add that. - OWSAssertDebug([header rangeOfString:@"'"].location == NSNotFound); - OWSAssertDebug([headerValue rangeOfString:@"'"].location == NSNotFound); - - [curlComponents addObject:@"-H"]; - [curlComponents addObject:[NSString stringWithFormat:@"'%@: %@'", header, headerValue]]; - } - // Body/parameters (e.g. JSON payload) - if (task.originalRequest.HTTPBody) { - NSString *jsonBody = - [[NSString alloc] initWithData:task.originalRequest.HTTPBody encoding:NSUTF8StringEncoding]; - // We don't yet support escaping JSON. - // If these asserts trip, we'll need to add that. - OWSAssertDebug([jsonBody rangeOfString:@"'"].location == NSNotFound); - [curlComponents addObject:@"--data-ascii"]; - [curlComponents addObject:[NSString stringWithFormat:@"'%@'", jsonBody]]; - } - // TODO: Add support for cookies. - [curlComponents addObject:task.originalRequest.URL.absoluteString]; - NSString *curlCommand = [curlComponents componentsJoinedByString:@" "]; - OWSLogVerbose(@"curl for failed request: %@", curlCommand); -} -#endif - -+ (void)handleNetworkFailure:(TSNetworkManagerFailure)failureBlock - request:(TSRequest *)request - task:(NSURLSessionDataTask *)task - error:(NSError *)networkError -{ - OWSAssertDebug(failureBlock); - OWSAssertDebug(request); - OWSAssertDebug(networkError); - - NSInteger statusCode = [task statusCode]; - -#ifdef DEBUG - [TSNetworkManager logCurlForTask:task]; -#endif - - [OutageDetection.sharedManager reportConnectionFailure]; - - NSError *error = [self errorWithHTTPCode:statusCode - description:nil - failureReason:nil - recoverySuggestion:nil - fallbackError:networkError]; - - switch (statusCode) { - case 0: { - NSError *connectivityError = - [self errorWithHTTPCode:TSNetworkManagerErrorFailedConnection - description:NSLocalizedString(@"ERROR_DESCRIPTION_NO_INTERNET", - @"Generic error used whenever Signal can't contact the server") - failureReason:networkError.localizedFailureReason - recoverySuggestion:NSLocalizedString(@"NETWORK_ERROR_RECOVERY", nil) - fallbackError:networkError]; - connectivityError.isRetryable = YES; - - OWSLogWarn(@"The network request failed because of a connectivity error: %@", request); - failureBlock(task, connectivityError); - break; - } - case 400: { - OWSLogError(@"The request contains an invalid parameter : %@, %@", networkError.debugDescription, request); - - error.isRetryable = NO; - - failureBlock(task, error); - break; - } - case 401: { - OWSLogError(@"The server returned an error about the authorization header: %@, %@", - networkError.debugDescription, - request); - error.isRetryable = NO; - [self deregisterAfterAuthErrorIfNecessary:task request:request statusCode:statusCode]; - failureBlock(task, error); - break; - } - case 403: { - OWSLogError( - @"The server returned an authentication failure: %@, %@", networkError.debugDescription, request); - error.isRetryable = NO; - [self deregisterAfterAuthErrorIfNecessary:task request:request statusCode:statusCode]; - failureBlock(task, error); - break; - } - case 404: { - OWSLogError(@"The requested resource could not be found: %@, %@", networkError.debugDescription, request); - error.isRetryable = NO; - failureBlock(task, error); - break; - } - case 411: { - OWSLogInfo(@"Multi-device pairing: %ld, %@, %@", (long)statusCode, networkError.debugDescription, request); - NSError *customError = [self errorWithHTTPCode:statusCode - description:NSLocalizedString(@"MULTIDEVICE_PAIRING_MAX_DESC", - @"alert title: cannot link - reached max linked devices") - failureReason:networkError.localizedFailureReason - recoverySuggestion:NSLocalizedString(@"MULTIDEVICE_PAIRING_MAX_RECOVERY", - @"alert body: cannot link - reached max linked devices") - fallbackError:networkError]; - customError.isRetryable = NO; - failureBlock(task, customError); - break; - } - case 413: { - OWSLogWarn(@"Rate limit exceeded: %@", request); - NSError *customError = [self errorWithHTTPCode:statusCode - description:NSLocalizedString(@"REGISTER_RATE_LIMITING_ERROR", nil) - failureReason:networkError.localizedFailureReason - recoverySuggestion:NSLocalizedString(@"REGISTER_RATE_LIMITING_BODY", nil) - fallbackError:networkError]; - customError.isRetryable = NO; - failureBlock(task, customError); - break; - } - case 417: { - // TODO: Is this response code obsolete? - OWSLogWarn(@"The number is already registered on a relay. Please unregister there first: %@", request); - NSError *customError = [self errorWithHTTPCode:statusCode - description:NSLocalizedString(@"REGISTRATION_ERROR", nil) - failureReason:networkError.localizedFailureReason - recoverySuggestion:NSLocalizedString(@"RELAY_REGISTERED_ERROR_RECOVERY", nil) - fallbackError:networkError]; - customError.isRetryable = NO; - failureBlock(task, customError); - break; - } - case 422: { - OWSLogError(@"The registration was requested over an unknown transport: %@, %@", - networkError.debugDescription, - request); - error.isRetryable = NO; - failureBlock(task, error); - break; - } - default: { - OWSLogWarn(@"Unknown error: %ld, %@, %@", (long)statusCode, networkError.debugDescription, request); - error.isRetryable = NO; - failureBlock(task, error); - break; - } - } -} - -+ (void)deregisterAfterAuthErrorIfNecessary:(NSURLSessionDataTask *)task - request:(TSRequest *)request - statusCode:(NSInteger)statusCode { - /* Loki: Original code - * We don't care about invalid auth - * ======== - - OWSLogVerbose(@"Invalid auth: %@", task.originalRequest.allHTTPHeaderFields); - - // We only want to de-register for: - // - // * Auth errors... - // * ...received from Signal service... - // * ...that used standard authorization. - // - // * We don't want want to deregister for: - // - // * CDS requests. - // * Requests using UD auth. - // * etc. - if ([task.originalRequest.URL.absoluteString hasPrefix:textSecureServerURL] - && request.shouldHaveAuthorizationHeaders) { - dispatch_async(dispatch_get_main_queue(), ^{ - if (self.tsAccountManager.isRegisteredAndReady) { - [self.tsAccountManager setIsDeregistered:YES]; - } else { - OWSLogWarn( - @"Ignoring auth failure; not registered and ready: %@.", task.originalRequest.URL.absoluteString); - } - }); - } else { - OWSLogWarn(@"Ignoring %d for URL: %@", (int)statusCode, task.originalRequest.URL.absoluteString); - } - - * ======== - */ -} - -+ (NSError *)errorWithHTTPCode:(NSInteger)code - description:(nullable NSString *)description - failureReason:(nullable NSString *)failureReason - recoverySuggestion:(nullable NSString *)recoverySuggestion - fallbackError:(NSError *)fallbackError -{ - OWSAssertDebug(fallbackError); - - if (!description) { - description = fallbackError.localizedDescription; - } - if (!failureReason) { - failureReason = fallbackError.localizedFailureReason; - } - if (!recoverySuggestion) { - recoverySuggestion = fallbackError.localizedRecoverySuggestion; - } - - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - - if (description) { - [dict setObject:description forKey:NSLocalizedDescriptionKey]; - } - if (failureReason) { - [dict setObject:failureReason forKey:NSLocalizedFailureReasonErrorKey]; - } - if (recoverySuggestion) { - [dict setObject:recoverySuggestion forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - - NSData *failureData = fallbackError.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; - - if (failureData) { - [dict setObject:failureData forKey:AFNetworkingOperationFailingURLResponseDataErrorKey]; - } - - dict[NSUnderlyingErrorKey] = fallbackError; - - return [NSError errorWithDomain:TSNetworkManagerErrorDomain code:code userInfo:dict]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSPreKeyManager.m b/SignalUtilitiesKit/TSPreKeyManager.m index acf3e5905..612265b73 100644 --- a/SignalUtilitiesKit/TSPreKeyManager.m +++ b/SignalUtilitiesKit/TSPreKeyManager.m @@ -8,7 +8,7 @@ #import "OWSIdentityManager.h" #import "OWSPrimaryStorage+SignedPreKeyStore.h" #import "SSKEnvironment.h" -#import "TSNetworkManager.h" + #import "TSStorageHeaders.h" #import #import diff --git a/SignalUtilitiesKit/TSSocketManager.h b/SignalUtilitiesKit/TSSocketManager.h deleted file mode 100644 index 29353c0c2..000000000 --- a/SignalUtilitiesKit/TSSocketManager.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSRequest; - -@interface TSSocketManager : NSObject - -@property (class, readonly, nonatomic) TSSocketManager *shared; - -- (instancetype)init NS_DESIGNATED_INITIALIZER; - -// Returns the "best" state of any of the sockets. -// -// We surface the socket state in various places in the UI. -// We generally are trying to indicate/help resolve network -// connectivity issues. We want to show the "best" or "highest" -// socket state of the sockets. e.g. the UI should reflect -// "open" if any of the sockets is open. -- (OWSWebSocketState)highestSocketState; - -// If the app is in the foreground, we'll try to open the socket unless it's already -// open or connecting. -// -// If the app is in the background, we'll try to open the socket unless it's already -// open or connecting _and_ keep it open for at least N seconds. -// If the app is in the background and the socket is already open or connecting this -// might prolong how long we keep the socket open. -// -// This method can be called from any thread. -- (void)requestSocketOpen; - -// This can be used to force the socket to close and re-open, if it is open. -- (void)cycleSocket; - -#pragma mark - Message Sending - -- (BOOL)canMakeRequests; - -- (void)makeRequest:(TSRequest *)request - success:(TSSocketMessageSuccess)success - failure:(TSSocketMessageFailure)failure; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSSocketManager.m b/SignalUtilitiesKit/TSSocketManager.m deleted file mode 100644 index 4fee91411..000000000 --- a/SignalUtilitiesKit/TSSocketManager.m +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "TSSocketManager.h" -#import "SSKEnvironment.h" -#import "SSKAsserts.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface TSSocketManager () - -@property (nonatomic) OWSWebSocket *websocket; - -@end - -#pragma mark - - -@implementation TSSocketManager - -- (instancetype)init -{ - self = [super init]; - - if (!self) { - return self; - } - - OWSAssertIsOnMainThread(); - - _websocket = [[OWSWebSocket alloc] init]; - - OWSSingletonAssert(); - - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -+ (instancetype)shared -{ - OWSAssert(SSKEnvironment.shared.socketManager); - - return SSKEnvironment.shared.socketManager; -} - -- (BOOL)canMakeRequests -{ - return self.websocket.canMakeRequests; -} - -- (void)makeRequest:(TSRequest *)request - success:(TSSocketMessageSuccess)success - failure:(TSSocketMessageFailure)failure -{ - [self.websocket makeRequest:request success:success failure:failure]; -} - -- (void)requestSocketOpen -{ - [self.websocket requestSocketOpen]; -} - -- (void)cycleSocket -{ - [self.websocket cycleSocket]; -} - -- (OWSWebSocketState)highestSocketState -{ - return self.websocket.state; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TTLUtilities.swift b/SignalUtilitiesKit/TTLUtilities.swift deleted file mode 100644 index ebe8219db..000000000 --- a/SignalUtilitiesKit/TTLUtilities.swift +++ /dev/null @@ -1,32 +0,0 @@ - -@objc(LKTTLUtilities) -public final class TTLUtilities : NSObject { - - /// If a message type specifies an invalid TTL, this will be used. - public static let fallbackMessageTTL: UInt64 = 2 * kDayInMs - - @objc(LKMessageType) - public enum MessageType : Int { - // Unimportant control messages - case call, typingIndicator - // Somewhat important control messages - case linkDevice - // Important control messages - case closedGroupUpdate, disappearingMessagesConfiguration, ephemeral, profileKey, receipt, sessionRequest, sync, unlinkDevice - // Visible messages - case regular - } - - @objc public static func getTTL(for messageType: MessageType) -> UInt64 { - switch messageType { - // Unimportant control messages - case .call, .typingIndicator: return 1 * kMinuteInMs - // Somewhat important control messages - case .linkDevice: return 1 * kHourInMs - // Important control messages - case .closedGroupUpdate, .disappearingMessagesConfiguration, .ephemeral, .profileKey, .receipt, .sessionRequest, .sync, .unlinkDevice: return 2 * kDayInMs - 1 * kHourInMs - // Visible messages - case .regular: return 2 * kDayInMs - } - } -} diff --git a/SignalUtilitiesKit/ThreadUtil.h b/SignalUtilitiesKit/ThreadUtil.h new file mode 100644 index 000000000..28ca1f27e --- /dev/null +++ b/SignalUtilitiesKit/ThreadUtil.h @@ -0,0 +1,83 @@ +// +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// + +NS_ASSUME_NONNULL_BEGIN + +@class OWSBlockingManager; +@class OWSLinkPreviewDraft; +@class OWSQuotedReplyModel; +@class OWSUnreadIndicator; +@class SignalAttachment; +@class TSContactThread; +@class TSGroupThread; +@class TSInteraction; +@class TSOutgoingMessage; +@class TSThread; +@class YapDatabaseConnection; +@class YapDatabaseReadTransaction; +@class YapDatabaseReadWriteTransaction; + +@interface ThreadDynamicInteractions : NSObject + +// Represents the "reverse index" of the focus message, if any. +// The "reverse index" is the distance of this interaction from +// the last interaction in the thread. Therefore the last interaction +// will have a "reverse index" of zero. +// +// We use "reverse indices" because (among other uses) we use this to +// determine the initial load window size. +@property (nonatomic, nullable, readonly) NSNumber *focusMessagePosition; + +@property (nonatomic, nullable, readonly) OWSUnreadIndicator *unreadIndicator; + +- (void)clearUnreadIndicatorState; + +@end + +#pragma mark - + +@interface ThreadUtil : NSObject + +#pragma mark - dynamic interactions + +// This method will create and/or remove any offers and indicators +// necessary for this thread. This includes: +// +// * Block offers. +// * "Add to contacts" offers. +// * Unread indicators. +// +// Parameters: +// +// * hideUnreadMessagesIndicator: If YES, the "unread indicator" has +// been cleared and should not be shown. +// * firstUnseenInteractionTimestamp: A snapshot of unseen message state +// when we entered the conversation view. See comments on +// ThreadOffersAndIndicators. +// * maxRangeSize: Loading a lot of messages in conversation view is +// slow and unwieldy. This number represents the maximum current +// size of the "load window" in that view. The unread indicator should +// always be inserted within that window. ++ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread + blockingManager:(OWSBlockingManager *)blockingManager + dbConnection:(YapDatabaseConnection *)dbConnection + hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator + lastUnreadIndicator:(nullable OWSUnreadIndicator *)lastUnreadIndicator + focusMessageId:(nullable NSString *)focusMessageId + maxRangeSize:(int)maxRangeSize; + +#pragma mark - Delete Content + ++ (void)deleteAllContent; + +#pragma mark - Find Content + ++ (nullable TSInteraction *)findInteractionInThreadByTimestamp:(uint64_t)timestamp + authorId:(NSString *)authorId + threadUniqueId:(NSString *)threadUniqueId + transaction:(YapDatabaseReadTransaction *)transaction; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ThreadUtil.m b/SignalUtilitiesKit/ThreadUtil.m new file mode 100644 index 000000000..b69fded03 --- /dev/null +++ b/SignalUtilitiesKit/ThreadUtil.m @@ -0,0 +1,409 @@ +// +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// + +#import "ThreadUtil.h" +#import "OWSQuotedReplyModel.h" +#import "OWSUnreadIndicator.h" +#import "TSUnreadIndicatorInteraction.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN + +@interface ThreadDynamicInteractions () + +@property (nonatomic, nullable) NSNumber *focusMessagePosition; + +@property (nonatomic, nullable) OWSUnreadIndicator *unreadIndicator; + +@end + +#pragma mark - + +@implementation ThreadDynamicInteractions + +- (void)clearUnreadIndicatorState +{ + self.unreadIndicator = nil; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[ThreadDynamicInteractions class]]) { + return NO; + } + + ThreadDynamicInteractions *other = (ThreadDynamicInteractions *)object; + return ([NSObject isNullableObject:self.focusMessagePosition equalTo:other.focusMessagePosition] && + [NSObject isNullableObject:self.unreadIndicator equalTo:other.unreadIndicator]); +} + +@end + +@implementation ThreadUtil + +#pragma mark - Dependencies + ++ (YapDatabaseConnection *)dbConnection +{ + return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection; +} + +#pragma mark - Dynamic Interactions + ++ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread + blockingManager:(OWSBlockingManager *)blockingManager + dbConnection:(YapDatabaseConnection *)dbConnection + hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator + lastUnreadIndicator:(nullable OWSUnreadIndicator *)lastUnreadIndicator + focusMessageId:(nullable NSString *)focusMessageId + maxRangeSize:(int)maxRangeSize +{ + OWSAssertDebug(thread); + OWSAssertDebug(dbConnection); + OWSAssertDebug(blockingManager); + OWSAssertDebug(maxRangeSize > 0); + + ThreadDynamicInteractions *result = [ThreadDynamicInteractions new]; + + [dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + // Find any "dynamic" interactions and safety number changes. + // + // We use different views for performance reasons. + NSMutableArray *blockingSafetyNumberChanges = [NSMutableArray new]; + NSMutableArray *nonBlockingSafetyNumberChanges = [NSMutableArray new]; + [[TSDatabaseView threadSpecialMessagesDatabaseView:transaction] + enumerateKeysAndObjectsInGroup:thread.uniqueId + usingBlock:^( + NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { + if ([object isKindOfClass:[TSInvalidIdentityKeyErrorMessage class]]) { + [blockingSafetyNumberChanges addObject:object]; + } else if ([object isKindOfClass:[TSErrorMessage class]]) { + TSErrorMessage *errorMessage = (TSErrorMessage *)object; + OWSAssertDebug( + errorMessage.errorType == TSErrorMessageNonBlockingIdentityChange); + [nonBlockingSafetyNumberChanges addObject:errorMessage]; + } else { + OWSFailDebug(@"Unexpected dynamic interaction type: %@", [object class]); + } + }]; + + // Determine if there are "unread" messages in this conversation. + // If we've been passed a firstUnseenInteractionTimestampParameter, + // just use that value in order to preserve continuity of the + // unread messages indicator after all messages in the conversation + // have been marked as read. + // + // IFF this variable is non-null, there are unseen messages in the thread. + NSNumber *_Nullable firstUnseenSortId = nil; + if (lastUnreadIndicator) { + firstUnseenSortId = @(lastUnreadIndicator.firstUnseenSortId); + } else { + TSInteraction *_Nullable firstUnseenInteraction = + [[TSDatabaseView unseenDatabaseViewExtension:transaction] firstObjectInGroup:thread.uniqueId]; + if (firstUnseenInteraction && firstUnseenInteraction.sortId != NULL) { + firstUnseenSortId = @(firstUnseenInteraction.sortId); + } + } + + [self ensureUnreadIndicator:result + thread:thread + transaction:transaction + maxRangeSize:maxRangeSize + blockingSafetyNumberChanges:blockingSafetyNumberChanges + nonBlockingSafetyNumberChanges:nonBlockingSafetyNumberChanges + hideUnreadMessagesIndicator:hideUnreadMessagesIndicator + firstUnseenSortId:firstUnseenSortId]; + + // Determine the position of the focus message _after_ performing any mutations + // around dynamic interactions. + if (focusMessageId != nil) { + result.focusMessagePosition = + [self focusMessagePositionForThread:thread transaction:transaction focusMessageId:focusMessageId]; + } + }]; + + return result; +} + ++ (void)ensureUnreadIndicator:(ThreadDynamicInteractions *)dynamicInteractions + thread:(TSThread *)thread + transaction:(YapDatabaseReadTransaction *)transaction + maxRangeSize:(int)maxRangeSize + blockingSafetyNumberChanges:(NSArray *)blockingSafetyNumberChanges + nonBlockingSafetyNumberChanges:(NSArray *)nonBlockingSafetyNumberChanges + hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator + firstUnseenSortId:(nullable NSNumber *)firstUnseenSortId +{ + OWSAssertDebug(dynamicInteractions); + OWSAssertDebug(thread); + OWSAssertDebug(transaction); + OWSAssertDebug(blockingSafetyNumberChanges); + OWSAssertDebug(nonBlockingSafetyNumberChanges); + + if (hideUnreadMessagesIndicator) { + return; + } + if (!firstUnseenSortId) { + // If there are no unseen interactions, don't show an unread indicator. + return; + } + + YapDatabaseViewTransaction *threadMessagesTransaction = [transaction ext:TSMessageDatabaseViewExtensionName]; + OWSAssertDebug([threadMessagesTransaction isKindOfClass:[YapDatabaseViewTransaction class]]); + + // Determine unread indicator position, if necessary. + // + // Enumerate in reverse to count the number of messages + // after the unseen messages indicator. Not all of + // them are unnecessarily unread, but we need to tell + // the messages view the position of the unread indicator, + // so that it can widen its "load window" to always show + // the unread indicator. + __block long visibleUnseenMessageCount = 0; + __block TSInteraction *interactionAfterUnreadIndicator = nil; + __block BOOL hasMoreUnseenMessages = NO; + [threadMessagesTransaction + enumerateKeysAndObjectsInGroup:thread.uniqueId + withOptions:NSEnumerationReverse + usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { + if (![object isKindOfClass:[TSInteraction class]]) { + OWSFailDebug(@"Expected a TSInteraction: %@", [object class]); + return; + } + + TSInteraction *interaction = (TSInteraction *)object; + + if (interaction.isDynamicInteraction) { + // Ignore dynamic interactions, if any. + return; + } + + if (interaction.sortId < firstUnseenSortId.unsignedLongLongValue) { + // By default we want the unread indicator to appear just before + // the first unread message. + *stop = YES; + return; + } + + visibleUnseenMessageCount++; + + interactionAfterUnreadIndicator = interaction; + + if (visibleUnseenMessageCount + 1 >= maxRangeSize) { + // If there are more unseen messages than can be displayed in the + // messages view, show the unread indicator at the top of the + // displayed messages. + *stop = YES; + hasMoreUnseenMessages = YES; + } + }]; + + if (!interactionAfterUnreadIndicator) { + // If we can't find an interaction after the unread indicator, + // don't show it. All unread messages may have been deleted or + // expired. + return; + } + OWSAssertDebug(visibleUnseenMessageCount > 0); + + NSUInteger missingUnseenSafetyNumberChangeCount = 0; + if (hasMoreUnseenMessages) { + NSMutableSet *missingUnseenSafetyNumberChanges = [NSMutableSet set]; + for (TSInvalidIdentityKeyErrorMessage *safetyNumberChange in blockingSafetyNumberChanges) { + BOOL isUnseen = safetyNumberChange.sortId >= firstUnseenSortId.unsignedLongLongValue; + if (!isUnseen) { + continue; + } + + BOOL isMissing = safetyNumberChange.sortId < interactionAfterUnreadIndicator.sortId; + if (!isMissing) { + continue; + } + + @try { + NSData *_Nullable newIdentityKey = [safetyNumberChange throws_newIdentityKey]; + if (newIdentityKey == nil) { + OWSFailDebug(@"Safety number change was missing it's new identity key."); + continue; + } + + [missingUnseenSafetyNumberChanges addObject:newIdentityKey]; + } @catch (NSException *exception) { + OWSFailDebug(@"exception: %@", exception); + } + } + + // Count the de-duplicated "blocking" safety number changes and all + // of the "non-blocking" safety number changes. + missingUnseenSafetyNumberChangeCount + = (missingUnseenSafetyNumberChanges.count + nonBlockingSafetyNumberChanges.count); + } + + NSInteger unreadIndicatorPosition = visibleUnseenMessageCount; + + dynamicInteractions.unreadIndicator = + [[OWSUnreadIndicator alloc] initWithFirstUnseenSortId:firstUnseenSortId.unsignedLongLongValue + hasMoreUnseenMessages:hasMoreUnseenMessages + missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount + unreadIndicatorPosition:unreadIndicatorPosition]; + OWSLogInfo(@"Creating Unread Indicator: %llu", dynamicInteractions.unreadIndicator.firstUnseenSortId); +} + ++ (nullable NSNumber *)focusMessagePositionForThread:(TSThread *)thread + transaction:(YapDatabaseReadTransaction *)transaction + focusMessageId:(NSString *)focusMessageId +{ + OWSAssertDebug(thread); + OWSAssertDebug(transaction); + OWSAssertDebug(focusMessageId); + + YapDatabaseViewTransaction *databaseView = [transaction ext:TSMessageDatabaseViewExtensionName]; + + NSString *_Nullable group = nil; + NSUInteger index; + BOOL success = + [databaseView getGroup:&group index:&index forKey:focusMessageId inCollection:TSInteraction.collection]; + if (!success) { + // This might happen if the focus message has disappeared + // before this view could appear. + OWSFailDebug(@"failed to find focus message index."); + return nil; + } + if (![group isEqualToString:thread.uniqueId]) { + OWSFailDebug(@"focus message has invalid group."); + return nil; + } + NSUInteger count = [databaseView numberOfItemsInGroup:thread.uniqueId]; + if (index >= count) { + OWSFailDebug(@"focus message has invalid index."); + return nil; + } + NSUInteger position = (count - index) - 1; + return @(position); +} + +#pragma mark - Delete Content + ++ (void)deleteAllContent +{ + OWSLogInfo(@""); + + [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [self removeAllObjectsInCollection:[TSThread collection] + class:[TSThread class] + transaction:transaction]; + [self removeAllObjectsInCollection:[TSInteraction collection] + class:[TSInteraction class] + transaction:transaction]; + [self removeAllObjectsInCollection:[TSAttachment collection] + class:[TSAttachment class] + transaction:transaction]; + @try { + [self removeAllObjectsInCollection:[SignalRecipient collection] + class:[SignalRecipient class] + transaction:transaction]; + } @catch (NSException *exception) { + // Do nothing + } + }]; + [TSAttachmentStream deleteAttachments]; +} + ++ (void)removeAllObjectsInCollection:(NSString *)collection + class:(Class) class + transaction:(YapDatabaseReadWriteTransaction *)transaction { + OWSAssertDebug(collection.length > 0); + OWSAssertDebug(class); + OWSAssertDebug(transaction); + + NSArray *_Nullable uniqueIds = [transaction allKeysInCollection:collection]; + if (!uniqueIds) { + OWSFailDebug(@"couldn't load uniqueIds for collection: %@.", collection); + return; + } + OWSLogInfo(@"Deleting %lu objects from: %@", (unsigned long)uniqueIds.count, collection); + NSUInteger count = 0; + for (NSString *uniqueId in uniqueIds) { + // We need to fetch each object, since [TSYapDatabaseObject removeWithTransaction:] sometimes does important + // work. + TSYapDatabaseObject *_Nullable object = [class fetchObjectWithUniqueID:uniqueId transaction:transaction]; + if (!object) { + OWSFailDebug(@"couldn't load object for deletion: %@.", collection); + continue; + } + [object removeWithTransaction:transaction]; + count++; + }; + OWSLogInfo(@"Deleted %lu/%lu objects from: %@", (unsigned long)count, (unsigned long)uniqueIds.count, collection); +} + +#pragma mark - Find Content + ++ (nullable TSInteraction *)findInteractionInThreadByTimestamp:(uint64_t)timestamp + authorId:(NSString *)authorId + threadUniqueId:(NSString *)threadUniqueId + transaction:(YapDatabaseReadTransaction *)transaction +{ + OWSAssertDebug(timestamp > 0); + OWSAssertDebug(authorId.length > 0); + + NSString *localNumber = [TSAccountManager localNumber]; + if (localNumber.length < 1) { + OWSFailDebug(@"missing long number."); + return nil; + } + + NSArray *interactions = + [TSInteraction interactionsWithTimestamp:timestamp + filter:^(TSInteraction *interaction) { + NSString *_Nullable messageAuthorId = nil; + if ([interaction isKindOfClass:[TSIncomingMessage class]]) { + TSIncomingMessage *incomingMessage = (TSIncomingMessage *)interaction; + messageAuthorId = incomingMessage.authorId; + } else if ([interaction isKindOfClass:[TSOutgoingMessage class]]) { + messageAuthorId = localNumber; + } + if (messageAuthorId.length < 1) { + return NO; + } + + if (![authorId isEqualToString:messageAuthorId]) { + return NO; + } + if (![interaction.uniqueThreadId isEqualToString:threadUniqueId]) { + return NO; + } + return YES; + } + withTransaction:transaction]; + if (interactions.count < 1) { + return nil; + } + if (interactions.count > 1) { + // In case of collision, take the first. + OWSLogError(@"more than one matching interaction in thread."); + } + return interactions.firstObject; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ThreadViewHelper.m b/SignalUtilitiesKit/ThreadViewHelper.m index 9b570dd23..54dede175 100644 --- a/SignalUtilitiesKit/ThreadViewHelper.m +++ b/SignalUtilitiesKit/ThreadViewHelper.m @@ -204,9 +204,7 @@ NS_ASSUME_NONNULL_BEGIN if ([thread isKindOfClass:TSContactThread.class]) { NSString *publicKey = thread.contactIdentifier; if ([LKUserDisplayNameUtilities getPrivateChatDisplayNameFor:publicKey] == nil) { continue; } - if ([LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:publicKey in:transaction] == nil) { - [threads addObject:thread]; - } + [threads addObject:thread]; } else { [threads addObject:thread]; } diff --git a/SignalUtilitiesKit/TSContactThread.h b/SignalUtilitiesKit/Threads/TSContactThread.h similarity index 59% rename from SignalUtilitiesKit/TSContactThread.h rename to SignalUtilitiesKit/Threads/TSContactThread.h index 72a5262fe..15c63d31f 100644 --- a/SignalUtilitiesKit/TSContactThread.h +++ b/SignalUtilitiesKit/Threads/TSContactThread.h @@ -12,9 +12,7 @@ typedef NS_ENUM(NSInteger, SNSessionRestorationStatus); @interface TSContactThread : TSThread -@property (atomic) SNSessionRestorationStatus sessionResetStatus; -@property (atomic, readonly) NSArray *sessionRestoreDevices; - +@property (atomic) SNSessionRestorationStatus sessionRestorationStatus; @property (nonatomic) BOOL hasDismissedOffers; - (instancetype)initWithContactId:(NSString *)contactId; @@ -33,17 +31,6 @@ typedef NS_ENUM(NSInteger, SNSessionRestorationStatus); + (NSString *)threadIdFromContactId:(NSString *)contactId; -// This method can be used to get the conversation color for a given -// recipient without using a read/write transaction to create a -// contact thread. -+ (NSString *)conversationColorNameForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction; - -#pragma mark - Loki Session Restore - -- (void)addSessionRestoreDevice:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction; -- (void)removeAllSessionRestoreDevicesWithTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction; - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSContactThread.m b/SignalUtilitiesKit/Threads/TSContactThread.m similarity index 53% rename from SignalUtilitiesKit/TSContactThread.m rename to SignalUtilitiesKit/Threads/TSContactThread.m index 6b0d5e219..e7896f555 100644 --- a/SignalUtilitiesKit/TSContactThread.m +++ b/SignalUtilitiesKit/Threads/TSContactThread.m @@ -4,7 +4,6 @@ #import "TSContactThread.h" #import "ContactsManagerProtocol.h" -#import "ContactsUpdater.h" #import "NotificationsProtocol.h" #import "OWSIdentityManager.h" #import "SSKEnvironment.h" @@ -24,11 +23,9 @@ NSString *const TSContactThreadPrefix = @"c"; OWSAssertDebug(contactId.length > 0); self = [super initWithUniqueId:uniqueIdentifier]; - - // No session reset ongoing - _sessionResetStatus = SNSessionRestorationStatusNone; - _sessionRestoreDevices = @[]; + _sessionRestorationStatus = SNSessionRestorationStatusNone; + return self; } @@ -82,12 +79,6 @@ NSString *const TSContactThreadPrefix = @"c"; return !![[OWSIdentityManager sharedManager] identityKeyForRecipientId:self.contactIdentifier]; } -// TODO deprecate this? seems weird to access the displayName in the DB model -- (NSString *)name -{ - return [SSKEnvironment.shared.contactsManager displayNameForPhoneIdentifier:self.contactIdentifier]; -} - + (NSString *)threadIdFromContactId:(NSString *)contactId { return [TSContactThreadPrefix stringByAppendingString:contactId]; } @@ -96,47 +87,6 @@ NSString *const TSContactThreadPrefix = @"c"; return [threadId substringWithRange:NSMakeRange(1, threadId.length - 1)]; } -+ (NSString *)conversationColorNameForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - - TSContactThread *_Nullable contactThread = - [TSContactThread getThreadWithContactId:recipientId transaction:transaction]; - if (contactThread) { - return contactThread.conversationColorName; - } - return [self stableColorNameForNewConversationWithString:recipientId]; -} - -#pragma mark - Loki Session Restore - -- (void)addSessionRestoreDevice:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction -{ - NSMutableSet *set = [[NSMutableSet alloc] initWithArray:_sessionRestoreDevices]; - [set addObject:hexEncodedPublicKey]; - [self setSessionRestoreDevices:set.allObjects transaction:transaction]; -} - -- (void)removeAllSessionRestoreDevicesWithTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction -{ - [self setSessionRestoreDevices:@[] transaction:transaction]; -} - -- (void)setSessionRestoreDevices:(NSArray *)sessionRestoreDevices transaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction { - _sessionRestoreDevices = sessionRestoreDevices; - void (^postNotification)() = ^() { - [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.threadSessionRestoreDevicesChanged object:self.uniqueId]; - }; - if (transaction == nil) { - [self save]; - [self.dbReadWriteConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{ postNotification(); }]; - } else { - [self saveWithTransaction:transaction]; - [transaction.connection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{ postNotification(); }]; - } -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSGroupModel.h b/SignalUtilitiesKit/Threads/TSGroupModel.h similarity index 84% rename from SignalUtilitiesKit/TSGroupModel.h rename to SignalUtilitiesKit/Threads/TSGroupModel.h index e80d99425..bf567fb81 100644 --- a/SignalUtilitiesKit/TSGroupModel.h +++ b/SignalUtilitiesKit/Threads/TSGroupModel.h @@ -10,9 +10,8 @@ NS_ASSUME_NONNULL_BEGIN typedef NS_ENUM(NSInteger, GroupType) { - closedGroup = 0, // a.k.a. private group chat - openGroup = 1, // a.k.a. public group chat - rssFeed = 2 + closedGroup = 0, + openGroup = 1, }; extern const int32_t kGroupIdLength; @@ -38,7 +37,7 @@ extern const int32_t kGroupIdLength; - (BOOL)isEqual:(id)other; - (BOOL)isEqualToGroupModel:(TSGroupModel *)model; -- (NSString *)getInfoStringAboutUpdateTo:(TSGroupModel *)model contactsManager:(id)contactsManager; +- (NSString *)getInfoStringAboutUpdateTo:(TSGroupModel *)model; - (void)updateGroupId: (NSData *)newGroupId; #endif diff --git a/SignalUtilitiesKit/TSGroupModel.m b/SignalUtilitiesKit/Threads/TSGroupModel.m similarity index 99% rename from SignalUtilitiesKit/TSGroupModel.m rename to SignalUtilitiesKit/Threads/TSGroupModel.m index 5b0564b1b..fac56262a 100644 --- a/SignalUtilitiesKit/TSGroupModel.m +++ b/SignalUtilitiesKit/Threads/TSGroupModel.m @@ -100,7 +100,7 @@ const int32_t kGroupIdLength = 16; return YES; } -- (NSString *)getInfoStringAboutUpdateTo:(TSGroupModel *)newModel contactsManager:(id)contactsManager { +- (NSString *)getInfoStringAboutUpdateTo:(TSGroupModel *)newModel { NSString *updatedGroupInfoString = @""; if (self == newModel) { return NSLocalizedString(@"GROUP_UPDATED", @""); diff --git a/SignalUtilitiesKit/TSGroupThread.h b/SignalUtilitiesKit/Threads/TSGroupThread.h similarity index 81% rename from SignalUtilitiesKit/TSGroupThread.h rename to SignalUtilitiesKit/Threads/TSGroupThread.h index 54bfea575..141247a2b 100644 --- a/SignalUtilitiesKit/TSGroupThread.h +++ b/SignalUtilitiesKit/Threads/TSGroupThread.h @@ -17,8 +17,7 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId; @interface TSGroupThread : TSThread @property (nonatomic, strong) TSGroupModel *groupModel; -@property (nonatomic, readonly) BOOL isRSSFeed; -@property (nonatomic, readonly) BOOL isPublicChat; +@property (nonatomic, readonly) BOOL isOpenGroup; @property (nonatomic) BOOL usesSharedSenderKeys; + (instancetype)getOrCreateThreadWithGroupModel:(TSGroupModel *)groupModel; @@ -37,10 +36,9 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId; + (NSString *)defaultGroupName; -- (BOOL)isLocalUserInGroup; -- (BOOL)isCurrentUserInGroupWithTransaction:(YapDatabaseReadTransaction *)transaction; -- (BOOL)isUserMemberInGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadTransaction *)transaction; -- (BOOL)isUserAdminInGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadTransaction *)transaction; +- (BOOL)isCurrentUserInGroup; +- (BOOL)isUserMemberInGroup:(NSString *)publicKey; +- (BOOL)isUserAdminInGroup:(NSString *)publicKey; // all group threads containing recipient as a member + (NSArray *)groupThreadsWithRecipientId:(NSString *)recipientId @@ -60,8 +58,6 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId; - (void)fireAvatarChangedNotification; -+ (ConversationColorName)defaultConversationColorNameForGroupId:(NSData *)groupId; - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSGroupThread.m b/SignalUtilitiesKit/Threads/TSGroupThread.m similarity index 78% rename from SignalUtilitiesKit/TSGroupThread.m rename to SignalUtilitiesKit/Threads/TSGroupThread.m index 938e198bf..e100cb933 100644 --- a/SignalUtilitiesKit/TSGroupThread.m +++ b/SignalUtilitiesKit/Threads/TSGroupThread.m @@ -189,50 +189,27 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific return true; } -- (BOOL)isPublicChat +- (BOOL)isOpenGroup { return (self.groupModel.groupType == openGroup); } -- (BOOL)isRSSFeed +- (BOOL)isCurrentUserMemberInGroup { - return (self.groupModel.groupType == rssFeed); + NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; + return [self isUserMemberInGroup:userPublicKey]; } -- (BOOL)isContactFriend +- (BOOL)isUserMemberInGroup:(NSString *)publicKey { - return false; + if (publicKey == nil) { return NO; } + return [self.groupModel.groupMemberIds containsObject:publicKey]; } -- (BOOL)isLocalUserInGroup +- (BOOL)isUserAdminInGroup:(NSString *)publicKey { - __block BOOL result = NO; - - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - result = [self isCurrentUserInGroupWithTransaction:transaction]; - }]; - - return result; -} - -- (BOOL)isCurrentUserInGroupWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - NSString *userHexEncodedPublicKey = TSAccountManager.localNumber; - return [self isUserMemberInGroup:userHexEncodedPublicKey transaction:transaction]; -} - -- (BOOL)isUserMemberInGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadTransaction *)transaction -{ - if (hexEncodedPublicKey == nil) { return NO; } - NSSet *linkedDeviceHexEncodedPublicKeys = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:hexEncodedPublicKey in:transaction]; - return [linkedDeviceHexEncodedPublicKeys intersectsSet:[NSSet setWithArray:self.groupModel.groupMemberIds]]; -} - -- (BOOL)isUserAdminInGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadTransaction *)transaction -{ - if (hexEncodedPublicKey == nil) { return NO; } - NSSet *linkedDeviceHexEncodedPublicKeys = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:hexEncodedPublicKey in:transaction]; - return [linkedDeviceHexEncodedPublicKeys intersectsSet:[NSSet setWithArray:self.groupModel.groupAdminIds]]; + if (publicKey == nil) { return NO; } + return [self.groupModel.groupAdminIds containsObject:publicKey]; } - (NSString *)name @@ -269,16 +246,16 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (void)leaveGroupWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - NSMutableSet *newGroupMemberIDs = [NSMutableSet setWithArray:self.groupModel.groupMemberIds]; - NSString *userPublicKey = TSAccountManager.localNumber; - if (userPublicKey == nil) { return; } - NSSet *userLinkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:userPublicKey in:transaction]; - [newGroupMemberIDs minusSet:userLinkedDevices]; - self.groupModel.groupMemberIds = newGroupMemberIDs.allObjects; - [self saveWithTransaction:transaction]; - [transaction addCompletionQueue:dispatch_get_main_queue() completionBlock:^{ - [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.groupThreadUpdated object:self.uniqueId]; - }]; +// NSMutableSet *newGroupMemberIDs = [NSMutableSet setWithArray:self.groupModel.groupMemberIds]; +// NSString *userPublicKey = TSAccountManager.localNumber; +// if (userPublicKey == nil) { return; } +// NSSet *userLinkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:userPublicKey in:transaction]; +// [newGroupMemberIDs minusSet:userLinkedDevices]; +// self.groupModel.groupMemberIds = newGroupMemberIDs.allObjects; +// [self saveWithTransaction:transaction]; +// [transaction addCompletionQueue:dispatch_get_main_queue() completionBlock:^{ +// [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.groupThreadUpdated object:self.uniqueId]; +// }]; } - (void)softDeleteGroupThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction @@ -327,13 +304,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific userInfo:userInfo]; } -+ (ConversationColorName)defaultConversationColorNameForGroupId:(NSData *)groupId -{ - OWSAssertDebug(groupId.length > 0); - - return [self.class stableColorNameForNewConversationWithString:[self threadIdFromGroupId:groupId]]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSThread.h b/SignalUtilitiesKit/Threads/TSThread.h similarity index 78% rename from SignalUtilitiesKit/TSThread.h rename to SignalUtilitiesKit/Threads/TSThread.h index bcf077447..08e8f8ecb 100644 --- a/SignalUtilitiesKit/TSThread.h +++ b/SignalUtilitiesKit/Threads/TSThread.h @@ -12,23 +12,6 @@ BOOL IsNoteToSelfEnabled(void); @class TSInteraction; @class TSInvalidIdentityKeyReceivingErrorMessage; -typedef NSString *ConversationColorName NS_STRING_ENUM; - -extern ConversationColorName const ConversationColorNameCrimson; -extern ConversationColorName const ConversationColorNameVermilion; -extern ConversationColorName const ConversationColorNameBurlap; -extern ConversationColorName const ConversationColorNameForest; -extern ConversationColorName const ConversationColorNameWintergreen; -extern ConversationColorName const ConversationColorNameTeal; -extern ConversationColorName const ConversationColorNameBlue; -extern ConversationColorName const ConversationColorNameIndigo; -extern ConversationColorName const ConversationColorNameViolet; -extern ConversationColorName const ConversationColorNamePlum; -extern ConversationColorName const ConversationColorNameTaupe; -extern ConversationColorName const ConversationColorNameSteel; - -extern ConversationColorName const kConversationColorName_Default; - /** * TSThread is the superclass of TSContactThread and TSGroupThread */ @@ -53,13 +36,6 @@ extern ConversationColorName const kConversationColorName_Default; */ - (NSString *)name; -@property (nonatomic, readonly) ConversationColorName conversationColorName; - -- (void)updateConversationColorName:(ConversationColorName)colorName - transaction:(YapDatabaseReadWriteTransaction *)transaction; -+ (ConversationColorName)stableColorNameForNewConversationWithString:(NSString *)colorSeed; -@property (class, nonatomic, readonly) NSArray *conversationColorNames; - /** * @returns * Signal Id (e164) of the contact if it's a contact thread. @@ -95,8 +71,6 @@ extern ConversationColorName const kConversationColorName_Default; - (NSUInteger)unreadMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(unreadMessageCount(transaction:)); -- (BOOL)hasSafetyNumbers; - - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; /** diff --git a/SignalUtilitiesKit/TSThread.m b/SignalUtilitiesKit/Threads/TSThread.m similarity index 68% rename from SignalUtilitiesKit/TSThread.m rename to SignalUtilitiesKit/Threads/TSThread.m index 773c00a1c..6bd591aa7 100644 --- a/SignalUtilitiesKit/TSThread.m +++ b/SignalUtilitiesKit/Threads/TSThread.m @@ -27,25 +27,9 @@ BOOL IsNoteToSelfEnabled(void) return YES; } -ConversationColorName const ConversationColorNameCrimson = @"red"; -ConversationColorName const ConversationColorNameVermilion = @"orange"; -ConversationColorName const ConversationColorNameBurlap = @"brown"; -ConversationColorName const ConversationColorNameForest = @"green"; -ConversationColorName const ConversationColorNameWintergreen = @"light_green"; -ConversationColorName const ConversationColorNameTeal = @"teal"; -ConversationColorName const ConversationColorNameBlue = @"blue"; -ConversationColorName const ConversationColorNameIndigo = @"indigo"; -ConversationColorName const ConversationColorNameViolet = @"purple"; -ConversationColorName const ConversationColorNamePlum = @"pink"; -ConversationColorName const ConversationColorNameTaupe = @"blue_grey"; -ConversationColorName const ConversationColorNameSteel = @"grey"; - -ConversationColorName const kConversationColorName_Default = ConversationColorNameSteel; - @interface TSThread () @property (nonatomic) NSDate *creationDate; -@property (nonatomic) NSString *conversationColorName; @property (nonatomic, nullable) NSNumber *archivedAsOfMessageSortId; @property (nonatomic, copy, nullable) NSString *messageDraft; @property (atomic, nullable) NSDate *mutedUntilDate; @@ -84,14 +68,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa if (self) { _creationDate = [NSDate date]; _messageDraft = nil; - - NSString *_Nullable contactId = self.contactIdentifier; - if (contactId.length > 0) { - // To be consistent with colors synced to desktop - _conversationColorName = [self.class stableColorNameForNewConversationWithString:contactId]; - } else { - _conversationColorName = [self.class stableColorNameForNewConversationWithString:self.uniqueId]; - } } return self; @@ -113,36 +89,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa } } - if (_conversationColorName.length == 0) { - NSString *_Nullable colorSeed = self.contactIdentifier; - if (colorSeed.length > 0) { - // group threads - colorSeed = self.uniqueId; - } - - // To be consistent with colors synced to desktop - ConversationColorName colorName = [self.class stableColorNameForLegacyConversationWithString:colorSeed]; - OWSAssertDebug(colorName); - - _conversationColorName = colorName; - } else if (![[[self class] conversationColorNames] containsObject:_conversationColorName]) { - // If we'd persisted a non-mapped color name - ConversationColorName _Nullable mappedColorName = self.class.legacyConversationColorMap[_conversationColorName]; - - if (!mappedColorName) { - // We previously used the wrong values for the new colors, it's possible we persited them. - // map them to the proper value - mappedColorName = self.class.legacyFixupConversationColorMap[_conversationColorName]; - } - - if (!mappedColorName) { - OWSFailDebug(@"failure: unexpected unmappable conversationColorName: %@", _conversationColorName); - mappedColorName = kConversationColorName_Default; - } - - _conversationColorName = mappedColorName; - } - NSDate *_Nullable lastMessageDate = [coder decodeObjectOfClass:NSDate.class forKey:@"lastMessageDate"]; NSDate *_Nullable archivalDate = [coder decodeObjectOfClass:NSDate.class forKey:@"archivalDate"]; _isArchivedByLegacyTimestampForSorting = @@ -206,10 +152,9 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa - (BOOL)isNoteToSelf { - if (!IsNoteToSelfEnabled()) { - return NO; - } - return [LKSessionMetaProtocol isThreadNoteToSelf:self]; + if (!IsNoteToSelfEnabled()) { return NO; } + if (![self isKindOfClass:TSContactThread.class]) { return NO; } + return [self.contactIdentifier isEqual:OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey]; } #pragma mark - To be subclassed. @@ -239,11 +184,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa return @[]; } -- (BOOL)hasSafetyNumbers -{ - return NO; -} - #pragma mark - Interactions /** @@ -451,11 +391,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa // there was no meaningful interaction. return NO; } - } else if ([interaction isKindOfClass:[TSInfoMessage class]]) { - TSInfoMessage *infoMessage = (TSInfoMessage *)interaction; - if (infoMessage.messageType == TSInfoMessageVerificationStateChange) { - return NO; - } } return YES; @@ -579,157 +514,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa }]; } -#pragma mark - Conversation Color - -- (ConversationColorName)conversationColorName -{ - OWSAssertDebug([self.class.conversationColorNames containsObject:_conversationColorName]); - return _conversationColorName; -} - -+ (NSArray *)colorNamesForNewConversation -{ - // all conversation colors except "steel" - return @[ - ConversationColorNameCrimson, - ConversationColorNameVermilion, - ConversationColorNameBurlap, - ConversationColorNameForest, - ConversationColorNameWintergreen, - ConversationColorNameTeal, - ConversationColorNameBlue, - ConversationColorNameIndigo, - ConversationColorNameViolet, - ConversationColorNamePlum, - ConversationColorNameTaupe, - ]; -} - -+ (NSArray *)conversationColorNames -{ - return [self.colorNamesForNewConversation arrayByAddingObject:kConversationColorName_Default]; -} - -+ (ConversationColorName)stableConversationColorNameForString:(NSString *)colorSeed - colorNames:(NSArray *)colorNames -{ - NSData *contactData = [colorSeed dataUsingEncoding:NSUTF8StringEncoding]; - - unsigned long long hash = 0; - NSUInteger hashingLength = sizeof(hash); - NSData *_Nullable hashData = [Cryptography computeSHA256Digest:contactData truncatedToBytes:hashingLength]; - if (hashData) { - [hashData getBytes:&hash length:hashingLength]; - } else { - OWSFailDebug(@"could not compute hash for color seed."); - } - - NSUInteger index = (hash % colorNames.count); - return [colorNames objectAtIndex:index]; -} - -+ (ConversationColorName)stableColorNameForNewConversationWithString:(NSString *)colorSeed -{ - return [self stableConversationColorNameForString:colorSeed colorNames:self.colorNamesForNewConversation]; -} - -// After introducing new conversation colors, we want to try to maintain as close as possible to the old color for an -// existing thread. -+ (ConversationColorName)stableColorNameForLegacyConversationWithString:(NSString *)colorSeed -{ - NSString *legacyColorName = - [self stableConversationColorNameForString:colorSeed colorNames:self.legacyConversationColorNames]; - ConversationColorName _Nullable mappedColorName = self.class.legacyConversationColorMap[legacyColorName]; - - if (!mappedColorName) { - OWSFailDebug(@"failure: unexpected unmappable legacyColorName: %@", legacyColorName); - return kConversationColorName_Default; - } - - return mappedColorName; -} - -+ (NSArray *)legacyConversationColorNames -{ - return @[ - @"red", - @"pink", - @"purple", - @"indigo", - @"blue", - @"cyan", - @"teal", - @"green", - @"deep_orange", - @"grey" - ]; -} - -+ (NSDictionary *)legacyConversationColorMap -{ - static NSDictionary *colorMap; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - colorMap = @{ - @"red" : ConversationColorNameCrimson, - @"deep_orange" : ConversationColorNameCrimson, - @"orange" : ConversationColorNameVermilion, - @"amber" : ConversationColorNameVermilion, - @"brown" : ConversationColorNameBurlap, - @"yellow" : ConversationColorNameBurlap, - @"pink" : ConversationColorNamePlum, - @"purple" : ConversationColorNameViolet, - @"deep_purple" : ConversationColorNameViolet, - @"indigo" : ConversationColorNameIndigo, - @"blue" : ConversationColorNameBlue, - @"light_blue" : ConversationColorNameBlue, - @"cyan" : ConversationColorNameTeal, - @"teal" : ConversationColorNameTeal, - @"green" : ConversationColorNameForest, - @"light_green" : ConversationColorNameWintergreen, - @"lime" : ConversationColorNameWintergreen, - @"blue_grey" : ConversationColorNameTaupe, - @"grey" : ConversationColorNameSteel, - }; - }); - - return colorMap; -} - -// we temporarily used the wrong value for the new color names. -+ (NSDictionary *)legacyFixupConversationColorMap -{ - static NSDictionary *colorMap; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - colorMap = @{ - @"crimson" : ConversationColorNameCrimson, - @"vermilion" : ConversationColorNameVermilion, - @"burlap" : ConversationColorNameBurlap, - @"forest" : ConversationColorNameForest, - @"wintergreen" : ConversationColorNameWintergreen, - @"teal" : ConversationColorNameTeal, - @"blue" : ConversationColorNameBlue, - @"indigo" : ConversationColorNameIndigo, - @"violet" : ConversationColorNameViolet, - @"plum" : ConversationColorNamePlum, - @"taupe" : ConversationColorNameTaupe, - @"steel" : ConversationColorNameSteel, - }; - }); - - return colorMap; -} - -- (void)updateConversationColorName:(ConversationColorName)colorName - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSThread *thread) { - thread.conversationColorName = colorName; - }]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TypingIndicatorMessage.swift b/SignalUtilitiesKit/TypingIndicatorMessage.swift deleted file mode 100644 index 1788289c1..000000000 --- a/SignalUtilitiesKit/TypingIndicatorMessage.swift +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc(OWSTypingIndicatorAction) -public enum TypingIndicatorAction: Int { - case started - case stopped -} - -@objc(OWSTypingIndicatorMessage) -public class TypingIndicatorMessage: TSOutgoingMessage { - private let action: TypingIndicatorAction - - // MARK: Initializers - - @objc - public init(thread: TSThread, - action: TypingIndicatorAction) { - self.action = action - - super.init(outgoingMessageWithTimestamp: NSDate.millisecondTimestamp(), - in: thread, - messageBody: nil, - attachmentIds: NSMutableArray(), - expiresInSeconds: 0, - expireStartedAt: 0, - isVoiceMessage: false, - groupMetaMessage: .unspecified, - quotedMessage: nil, - contactShare: nil, - linkPreview: nil) - } - - @objc - public required init!(coder: NSCoder) { - self.action = .started - super.init(coder: coder) - } - - @objc - public required init(dictionary dictionaryValue: [String: Any]!) throws { - self.action = .started - try super.init(dictionary: dictionaryValue) - } - - @objc - public override func shouldSyncTranscript() -> Bool { - return false - } - - @objc - public override var isSilent: Bool { - return true - } - - @objc - public override var isOnline: Bool { - return true - } - - private func protoAction(forAction action: TypingIndicatorAction) -> SSKProtoTypingMessage.SSKProtoTypingMessageAction { - switch action { - case .started: - return .started - case .stopped: - return .stopped - } - } - - @objc - public override func buildPlainTextData(_ recipient: SignalRecipient) -> Data? { - - let typingBuilder = SSKProtoTypingMessage.builder(timestamp: self.timestamp, - action: protoAction(forAction: action)) - - if let groupThread = self.thread as? TSGroupThread { - typingBuilder.setGroupID(groupThread.groupModel.groupId) - } - - let contentBuilder = SSKProtoContent.builder() - - do { - contentBuilder.setTypingMessage(try typingBuilder.build()) - - let data = try contentBuilder.buildSerializedData() - return data - } catch let error { - owsFailDebug("failed to build content: \(error)") - return nil - } - } - - // MARK: TSYapDatabaseObject overrides - - @objc - public override func shouldBeSaved() -> Bool { - return false - } - - @objc - public override var ttl: UInt32 { return UInt32(TTLUtilities.getTTL(for: .typingIndicator)) } - - @objc - public override var debugDescription: String { - return "typingIndicatorMessage" - } - - // MARK: - - @objc(stringForTypingIndicatorAction:) - public class func string(forTypingIndicatorAction action: TypingIndicatorAction) -> String { - switch action { - case .started: - return "started" - case .stopped: - return "stopped" - } - } -} diff --git a/SignalUtilitiesKit/TypingIndicators.swift b/SignalUtilitiesKit/TypingIndicators.swift index e05cb43ff..18b5325fb 100644 --- a/SignalUtilitiesKit/TypingIndicators.swift +++ b/SignalUtilitiesKit/TypingIndicators.swift @@ -73,10 +73,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { return SSKEnvironment.shared.primaryStorage } - private var syncManager: OWSSyncManagerProtocol { - return SSKEnvironment.shared.syncManager - } - // MARK: - @objc @@ -87,8 +83,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { primaryStorage.dbReadWriteConnection.setBool(value, forKey: kDatabaseKey_TypingIndicatorsEnabled, inCollection: kDatabaseCollection) - syncManager.sendConfigurationSyncMessage() - NotificationCenter.default.postNotificationNameAsync(TypingIndicatorsImpl.typingIndicatorStateDidChange, object: nil) } @@ -303,9 +297,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { sendPauseTimer = nil } - private func sendTypingMessageIfNecessary(forThread thread: TSThread, action: TypingIndicatorAction) { - Logger.verbose("\(TypingIndicatorMessage.string(forTypingIndicatorAction: action))") - + private func sendTypingMessageIfNecessary(forThread thread: TSThread, action: TypingIndicator.Kind) { guard let delegate = delegate else { owsFailDebug("Missing delegate.") return @@ -320,12 +312,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { if !SessionMetaProtocol.shouldSendTypingIndicator(in: thread) { return } let typingIndicator = TypingIndicator() - typingIndicator.kind = { - switch action { - case .started: return .started - case .stopped: return .stopped - } - }() + typingIndicator.kind = action typingIndicator.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) let job = MessageSendJob(message: typingIndicator, destination: destination) diff --git a/SignalUtilitiesKit/ApprovalRailCellView.swift b/SignalUtilitiesKit/UI/ApprovalRailCellView.swift similarity index 100% rename from SignalUtilitiesKit/ApprovalRailCellView.swift rename to SignalUtilitiesKit/UI/ApprovalRailCellView.swift diff --git a/SignalUtilitiesKit/AttachmentApprovalInputAccessoryView.swift b/SignalUtilitiesKit/UI/AttachmentApprovalInputAccessoryView.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentApprovalInputAccessoryView.swift rename to SignalUtilitiesKit/UI/AttachmentApprovalInputAccessoryView.swift diff --git a/SignalUtilitiesKit/AttachmentApprovalViewController.swift b/SignalUtilitiesKit/UI/AttachmentApprovalViewController.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentApprovalViewController.swift rename to SignalUtilitiesKit/UI/AttachmentApprovalViewController.swift diff --git a/SignalUtilitiesKit/AttachmentCaptionToolbar.swift b/SignalUtilitiesKit/UI/AttachmentCaptionToolbar.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentCaptionToolbar.swift rename to SignalUtilitiesKit/UI/AttachmentCaptionToolbar.swift diff --git a/SignalUtilitiesKit/AttachmentCaptionViewController.swift b/SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentCaptionViewController.swift rename to SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift diff --git a/SignalUtilitiesKit/AttachmentItemCollection.swift b/SignalUtilitiesKit/UI/AttachmentItemCollection.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentItemCollection.swift rename to SignalUtilitiesKit/UI/AttachmentItemCollection.swift diff --git a/SignalUtilitiesKit/AttachmentPrepViewController.swift b/SignalUtilitiesKit/UI/AttachmentPrepViewController.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentPrepViewController.swift rename to SignalUtilitiesKit/UI/AttachmentPrepViewController.swift diff --git a/SignalUtilitiesKit/AttachmentTextToolbar.swift b/SignalUtilitiesKit/UI/AttachmentTextToolbar.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentTextToolbar.swift rename to SignalUtilitiesKit/UI/AttachmentTextToolbar.swift diff --git a/SignalUtilitiesKit/AttachmentTextView.swift b/SignalUtilitiesKit/UI/AttachmentTextView.swift similarity index 100% rename from SignalUtilitiesKit/AttachmentTextView.swift rename to SignalUtilitiesKit/UI/AttachmentTextView.swift diff --git a/SignalUtilitiesKit/BlockListUIUtils.h b/SignalUtilitiesKit/UI/BlockListUIUtils.h similarity index 82% rename from SignalUtilitiesKit/BlockListUIUtils.h rename to SignalUtilitiesKit/UI/BlockListUIUtils.h index 77a7ec23a..c1dad0286 100644 --- a/SignalUtilitiesKit/BlockListUIUtils.h +++ b/SignalUtilitiesKit/UI/BlockListUIUtils.h @@ -8,8 +8,6 @@ NS_ASSUME_NONNULL_BEGIN @class Contact; @class OWSBlockingManager; -@class OWSContactsManager; -@class OWSMessageSender; @class SignalAccount; @class TSGroupModel; @class TSThread; @@ -25,20 +23,16 @@ typedef void (^BlockActionCompletionBlock)(BOOL isBlocked); + (void)showBlockThreadActionSheet:(TSThread *)thread fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager - messageSender:(OWSMessageSender *)messageSender completionBlock:(nullable BlockActionCompletionBlock)completionBlock; + (void)showBlockPhoneNumberActionSheet:(NSString *)phoneNumber fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock; + (void)showBlockSignalAccountActionSheet:(SignalAccount *)signalAccount fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock; #pragma mark - Unblock @@ -46,19 +40,16 @@ typedef void (^BlockActionCompletionBlock)(BOOL isBlocked); + (void)showUnblockThreadActionSheet:(TSThread *)thread fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock; + (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock; + (void)showUnblockSignalAccountActionSheet:(SignalAccount *)signalAccount fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock; + (void)showUnblockGroupActionSheet:(TSGroupModel *)groupModel diff --git a/SignalUtilitiesKit/BlockListUIUtils.m b/SignalUtilitiesKit/UI/BlockListUIUtils.m similarity index 95% rename from SignalUtilitiesKit/BlockListUIUtils.m rename to SignalUtilitiesKit/UI/BlockListUIUtils.m index ab6508375..179384411 100644 --- a/SignalUtilitiesKit/BlockListUIUtils.m +++ b/SignalUtilitiesKit/UI/BlockListUIUtils.m @@ -3,16 +3,12 @@ // #import "BlockListUIUtils.h" -#import "OWSContactsManager.h" -#import "PhoneNumber.h" #import "TSContactThread.h" -#import #import #import #import #import #import -#import #import #import "UIView+OWS.h" @@ -27,8 +23,6 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)showBlockThreadActionSheet:(TSThread *)thread fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager - messageSender:(OWSMessageSender *)messageSender completionBlock:(nullable BlockActionCompletionBlock)completionBlock { if ([thread isKindOfClass:[TSContactThread class]]) { @@ -36,14 +30,12 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); [self showBlockPhoneNumberActionSheet:contactThread.contactIdentifier fromViewController:fromViewController blockingManager:blockingManager - contactsManager:contactsManager completionBlock:completionBlock]; } else if ([thread isKindOfClass:[TSGroupThread class]]) { TSGroupThread *groupThread = (TSGroupThread *)thread; [self showBlockGroupActionSheet:groupThread fromViewController:fromViewController blockingManager:blockingManager - messageSender:messageSender completionBlock:completionBlock]; } else { OWSFailDebug(@"unexpected thread type: %@", thread.class); @@ -53,10 +45,9 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)showBlockPhoneNumberActionSheet:(NSString *)phoneNumber fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock { - NSString *displayName = [contactsManager displayNameForPhoneIdentifier:phoneNumber]; + NSString *displayName = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:phoneNumber avoidingWriteTransaction:YES]; [self showBlockPhoneNumbersActionSheet:@[ phoneNumber ] displayName:displayName fromViewController:fromViewController @@ -67,10 +58,9 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)showBlockSignalAccountActionSheet:(SignalAccount *)signalAccount fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock { - NSString *displayName = [contactsManager displayNameForSignalAccount:signalAccount]; + NSString *displayName = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:signalAccount.recipientId avoidingWriteTransaction:YES]; [self showBlockPhoneNumbersActionSheet:@[ signalAccount.recipientId ] displayName:displayName fromViewController:fromViewController @@ -152,7 +142,6 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)showBlockGroupActionSheet:(TSGroupThread *)groupThread fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - messageSender:(OWSMessageSender *)messageSender completionBlock:(nullable BlockActionCompletionBlock)completionBlock { OWSAssertDebug(groupThread); @@ -179,7 +168,6 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); [self blockGroup:groupThread fromViewController:fromViewController blockingManager:blockingManager - messageSender:messageSender completionBlock:^(UIAlertAction *ignore) { if (completionBlock) { completionBlock(YES); @@ -230,7 +218,6 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)blockGroup:(TSGroupThread *)groupThread fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - messageSender:(OWSMessageSender *)messageSender completionBlock:(BlockAlertCompletionBlock)completionBlock { OWSAssertDebug(groupThread); @@ -244,7 +231,9 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); // via params and instead have to create our own sneaky transaction here. [groupThread leaveGroupWithSneakyTransaction]; - [ThreadUtil enqueueLeaveGroupMessageInThread:groupThread]; + // TODO TODO TODO + +// [ThreadUtil enqueueLeaveGroupMessageInThread:groupThread]; NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName; @@ -266,7 +255,6 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)showUnblockThreadActionSheet:(TSThread *)thread fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock { if ([thread isKindOfClass:[TSContactThread class]]) { @@ -274,7 +262,6 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); [self showUnblockPhoneNumberActionSheet:contactThread.contactIdentifier fromViewController:fromViewController blockingManager:blockingManager - contactsManager:contactsManager completionBlock:completionBlock]; } else if ([thread isKindOfClass:[TSGroupThread class]]) { TSGroupThread *groupThread = (TSGroupThread *)thread; @@ -292,7 +279,6 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock { NSString *displayName = [LKUserDisplayNameUtilities getPrivateChatDisplayNameFor:phoneNumber] ?: phoneNumber; @@ -306,10 +292,9 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); + (void)showUnblockSignalAccountActionSheet:(SignalAccount *)signalAccount fromViewController:(UIViewController *)fromViewController blockingManager:(OWSBlockingManager *)blockingManager - contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock { - NSString *displayName = [contactsManager displayNameForSignalAccount:signalAccount]; + NSString *displayName = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:signalAccount.recipientId avoidingWriteTransaction:YES]; [self showUnblockPhoneNumbersActionSheet:@[ signalAccount.recipientId ] displayName:displayName fromViewController:fromViewController diff --git a/SignalUtilitiesKit/UI/CircleView.swift b/SignalUtilitiesKit/UI/CircleView.swift new file mode 100644 index 000000000..3cec26ba5 --- /dev/null +++ b/SignalUtilitiesKit/UI/CircleView.swift @@ -0,0 +1,82 @@ +// +// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// +import UIKit + +@objc (OWSCircleView) +public class CircleView: UIView { + + @available(*, unavailable, message:"use other constructor instead.") + required public init?(coder aDecoder: NSCoder) { + notImplemented() + } + + @objc + public required init() { + super.init(frame: .zero) + } + + @objc + public required init(diameter: CGFloat) { + super.init(frame: .zero) + + autoSetDimensions(to: CGSize(width: diameter, height: diameter)) + } + + @objc + override public var frame: CGRect { + didSet { + updateRadius() + } + } + + @objc + override public var bounds: CGRect { + didSet { + updateRadius() + } + } + + private func updateRadius() { + self.layer.cornerRadius = self.bounds.size.height / 2 + } +} + +@objc (OWSPillView) +public class PillView: UIView { + + public override init(frame: CGRect) { + super.init(frame: frame) + + // Constrain to be a pill that is at least a circle, and maybe wider. + autoPin(toAspectRatio: 1.0, relation: .greaterThanOrEqual) + + // low priority contstraint to ensure the pill + // is no taller than necessary + NSLayoutConstraint.autoSetPriority(.defaultLow) { + self.autoSetDimension(.height, toSize: 0) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc + override public var frame: CGRect { + didSet { + updateRadius() + } + } + + @objc + override public var bounds: CGRect { + didSet { + updateRadius() + } + } + + private func updateRadius() { + layer.cornerRadius = bounds.size.height / 2 + } +} diff --git a/SignalUtilitiesKit/ConversationStyle.swift b/SignalUtilitiesKit/UI/ConversationStyle.swift similarity index 92% rename from SignalUtilitiesKit/ConversationStyle.swift rename to SignalUtilitiesKit/UI/ConversationStyle.swift index c93742cbb..a24d00639 100644 --- a/SignalUtilitiesKit/ConversationStyle.swift +++ b/SignalUtilitiesKit/UI/ConversationStyle.swift @@ -65,7 +65,6 @@ public class ConversationStyle: NSObject { public required init(thread: TSThread) { self.thread = thread - self.conversationColor = ConversationStyle.conversationColor(thread: thread) super.init() @@ -92,7 +91,7 @@ public class ConversationStyle: NSObject { @objc public func updateProperties() { if thread.isGroupThread() { - if let thread = thread as? TSGroupThread, thread.isRSSFeed { + if thread is TSGroupThread { gutterLeading = 16 gutterTrailing = 16 } else { @@ -109,7 +108,7 @@ public class ConversationStyle: NSObject { headerGutterTrailing = 16 errorGutterTrailing = 16 - if let thread = thread as? TSGroupThread, thread.isRSSFeed { + if thread is TSGroupThread { maxMessageWidth = floor(contentWidth) } else { maxMessageWidth = floor(contentWidth - 32) @@ -130,21 +129,10 @@ public class ConversationStyle: NSObject { textInsetHorizontal = 12 lastTextLineAxis = CGFloat(round(baseFontOffset + messageTextFont.capHeight * 0.5)) - - self.conversationColor = ConversationStyle.conversationColor(thread: thread) } // MARK: Colors - @objc - public var conversationColor: OWSConversationColor - - private class func conversationColor(thread: TSThread) -> OWSConversationColor { - let colorName = thread.conversationColorName - - return OWSConversationColor.conversationColorOrDefault(colorName: colorName) - } - @objc private static var defaultBubbleColorIncoming: UIColor { return Colors.receivedMessageBackground diff --git a/SignalUtilitiesKit/DirectionalPanGestureRecognizer.swift b/SignalUtilitiesKit/UI/DirectionalPanGestureRecognizer.swift similarity index 100% rename from SignalUtilitiesKit/DirectionalPanGestureRecognizer.swift rename to SignalUtilitiesKit/UI/DirectionalPanGestureRecognizer.swift diff --git a/SignalUtilitiesKit/DisappearingTimerConfigurationView.swift b/SignalUtilitiesKit/UI/DisappearingTimerConfigurationView.swift similarity index 100% rename from SignalUtilitiesKit/DisappearingTimerConfigurationView.swift rename to SignalUtilitiesKit/UI/DisappearingTimerConfigurationView.swift diff --git a/SignalUtilitiesKit/DisplayableText.swift b/SignalUtilitiesKit/UI/DisplayableText.swift similarity index 100% rename from SignalUtilitiesKit/DisplayableText.swift rename to SignalUtilitiesKit/UI/DisplayableText.swift diff --git a/SignalUtilitiesKit/GalleryRailView.swift b/SignalUtilitiesKit/UI/GalleryRailView.swift similarity index 100% rename from SignalUtilitiesKit/GalleryRailView.swift rename to SignalUtilitiesKit/UI/GalleryRailView.swift diff --git a/SignalUtilitiesKit/GradientView.swift b/SignalUtilitiesKit/UI/GradientView.swift similarity index 100% rename from SignalUtilitiesKit/GradientView.swift rename to SignalUtilitiesKit/UI/GradientView.swift diff --git a/SignalUtilitiesKit/Identicon+ObjC.swift b/SignalUtilitiesKit/UI/Identicon+ObjC.swift similarity index 100% rename from SignalUtilitiesKit/Identicon+ObjC.swift rename to SignalUtilitiesKit/UI/Identicon+ObjC.swift diff --git a/SignalUtilitiesKit/ImageEditorBrushViewController.swift b/SignalUtilitiesKit/UI/ImageEditorBrushViewController.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorBrushViewController.swift rename to SignalUtilitiesKit/UI/ImageEditorBrushViewController.swift diff --git a/SignalUtilitiesKit/ImageEditorCanvasView.swift b/SignalUtilitiesKit/UI/ImageEditorCanvasView.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorCanvasView.swift rename to SignalUtilitiesKit/UI/ImageEditorCanvasView.swift diff --git a/SignalUtilitiesKit/ImageEditorContents.swift b/SignalUtilitiesKit/UI/ImageEditorContents.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorContents.swift rename to SignalUtilitiesKit/UI/ImageEditorContents.swift diff --git a/SignalUtilitiesKit/ImageEditorCropViewController.swift b/SignalUtilitiesKit/UI/ImageEditorCropViewController.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorCropViewController.swift rename to SignalUtilitiesKit/UI/ImageEditorCropViewController.swift diff --git a/SignalUtilitiesKit/ImageEditorItem.swift b/SignalUtilitiesKit/UI/ImageEditorItem.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorItem.swift rename to SignalUtilitiesKit/UI/ImageEditorItem.swift diff --git a/SignalUtilitiesKit/ImageEditorModel.swift b/SignalUtilitiesKit/UI/ImageEditorModel.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorModel.swift rename to SignalUtilitiesKit/UI/ImageEditorModel.swift diff --git a/SignalUtilitiesKit/ImageEditorPaletteView.swift b/SignalUtilitiesKit/UI/ImageEditorPaletteView.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorPaletteView.swift rename to SignalUtilitiesKit/UI/ImageEditorPaletteView.swift diff --git a/SignalUtilitiesKit/ImageEditorPanGestureRecognizer.swift b/SignalUtilitiesKit/UI/ImageEditorPanGestureRecognizer.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorPanGestureRecognizer.swift rename to SignalUtilitiesKit/UI/ImageEditorPanGestureRecognizer.swift diff --git a/SignalUtilitiesKit/ImageEditorPinchGestureRecognizer.swift b/SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorPinchGestureRecognizer.swift rename to SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift diff --git a/SignalUtilitiesKit/ImageEditorStrokeItem.swift b/SignalUtilitiesKit/UI/ImageEditorStrokeItem.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorStrokeItem.swift rename to SignalUtilitiesKit/UI/ImageEditorStrokeItem.swift diff --git a/SignalUtilitiesKit/ImageEditorTextItem.swift b/SignalUtilitiesKit/UI/ImageEditorTextItem.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorTextItem.swift rename to SignalUtilitiesKit/UI/ImageEditorTextItem.swift diff --git a/SignalUtilitiesKit/ImageEditorTextViewController.swift b/SignalUtilitiesKit/UI/ImageEditorTextViewController.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorTextViewController.swift rename to SignalUtilitiesKit/UI/ImageEditorTextViewController.swift diff --git a/SignalUtilitiesKit/ImageEditorTransform.swift b/SignalUtilitiesKit/UI/ImageEditorTransform.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorTransform.swift rename to SignalUtilitiesKit/UI/ImageEditorTransform.swift diff --git a/SignalUtilitiesKit/ImageEditorView.swift b/SignalUtilitiesKit/UI/ImageEditorView.swift similarity index 100% rename from SignalUtilitiesKit/ImageEditorView.swift rename to SignalUtilitiesKit/UI/ImageEditorView.swift diff --git a/SignalUtilitiesKit/MediaMessageView.swift b/SignalUtilitiesKit/UI/MediaMessageView.swift similarity index 100% rename from SignalUtilitiesKit/MediaMessageView.swift rename to SignalUtilitiesKit/UI/MediaMessageView.swift diff --git a/SignalUtilitiesKit/MessageApprovalViewController.swift b/SignalUtilitiesKit/UI/MessageApprovalViewController.swift similarity index 92% rename from SignalUtilitiesKit/MessageApprovalViewController.swift rename to SignalUtilitiesKit/UI/MessageApprovalViewController.swift index 1cdf49b71..a50083776 100644 --- a/SignalUtilitiesKit/MessageApprovalViewController.swift +++ b/SignalUtilitiesKit/UI/MessageApprovalViewController.swift @@ -19,7 +19,6 @@ public class MessageApprovalViewController: OWSViewController, UITextViewDelegat let thread: TSThread let initialMessageText: String - let contactsManager: OWSContactsManager private(set) var textView: UITextView! private var sendButton: UIBarButtonItem! @@ -32,10 +31,9 @@ public class MessageApprovalViewController: OWSViewController, UITextViewDelegat } @objc - required public init(messageText: String, thread: TSThread, contactsManager: OWSContactsManager, delegate: MessageApprovalViewControllerDelegate) { + required public init(messageText: String, thread: TSThread, delegate: MessageApprovalViewControllerDelegate) { self.initialMessageText = messageText self.thread = thread - self.contactsManager = contactsManager self.delegate = delegate super.init(nibName: nil, bundle: nil) @@ -164,7 +162,8 @@ public class MessageApprovalViewController: OWSViewController, UITextViewDelegat return recipientRow } - nameLabel.attributedText = contactsManager.formattedFullName(forRecipientId: contactThread.contactIdentifier(), font: font) + let publicKey = thread.contactIdentifier()! + nameLabel.text = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: publicKey, avoidingWriteTransaction: true) nameLabel.textColor = Theme.primaryColor if let profileName = self.profileName(contactThread: contactThread) { @@ -189,13 +188,8 @@ public class MessageApprovalViewController: OWSViewController, UITextViewDelegat } private func profileName(contactThread: TSContactThread) -> String? { - let recipientId = contactThread.contactIdentifier() - - if contactsManager.hasNameInSystemContacts(forRecipientId: recipientId) { - // Don't display profile name when we have a veritas name in system Contacts - return nil - } - return contactsManager.formattedProfileName(forRecipientId: recipientId) + let publicKey = contactThread.contactIdentifier() + return SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: publicKey, avoidingWriteTransaction: true) } // MARK: - Event Handlers diff --git a/SignalUtilitiesKit/ModalActivityIndicatorViewController.swift b/SignalUtilitiesKit/UI/ModalActivityIndicatorViewController.swift similarity index 100% rename from SignalUtilitiesKit/ModalActivityIndicatorViewController.swift rename to SignalUtilitiesKit/UI/ModalActivityIndicatorViewController.swift diff --git a/SignalUtilitiesKit/OWSAlerts.swift b/SignalUtilitiesKit/UI/OWSAlerts.swift similarity index 100% rename from SignalUtilitiesKit/OWSAlerts.swift rename to SignalUtilitiesKit/UI/OWSAlerts.swift diff --git a/SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.h b/SignalUtilitiesKit/UI/OWSAnyTouchGestureRecognizer.h similarity index 100% rename from SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.h rename to SignalUtilitiesKit/UI/OWSAnyTouchGestureRecognizer.h diff --git a/SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.m b/SignalUtilitiesKit/UI/OWSAnyTouchGestureRecognizer.m similarity index 100% rename from SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.m rename to SignalUtilitiesKit/UI/OWSAnyTouchGestureRecognizer.m diff --git a/SignalUtilitiesKit/OWSButton.swift b/SignalUtilitiesKit/UI/OWSButton.swift similarity index 100% rename from SignalUtilitiesKit/OWSButton.swift rename to SignalUtilitiesKit/UI/OWSButton.swift diff --git a/SignalUtilitiesKit/OWSFlatButton.swift b/SignalUtilitiesKit/UI/OWSFlatButton.swift similarity index 100% rename from SignalUtilitiesKit/OWSFlatButton.swift rename to SignalUtilitiesKit/UI/OWSFlatButton.swift diff --git a/SignalUtilitiesKit/OWSLayerView.swift b/SignalUtilitiesKit/UI/OWSLayerView.swift similarity index 100% rename from SignalUtilitiesKit/OWSLayerView.swift rename to SignalUtilitiesKit/UI/OWSLayerView.swift diff --git a/SignalUtilitiesKit/OWSNavigationBar.swift b/SignalUtilitiesKit/UI/OWSNavigationBar.swift similarity index 86% rename from SignalUtilitiesKit/OWSNavigationBar.swift rename to SignalUtilitiesKit/UI/OWSNavigationBar.swift index 7ba0c450d..707023a3b 100644 --- a/SignalUtilitiesKit/OWSNavigationBar.swift +++ b/SignalUtilitiesKit/UI/OWSNavigationBar.swift @@ -91,31 +91,6 @@ public class OWSNavigationBar: UINavigationBar { let color = Theme.navbarBackgroundColor let backgroundImage = UIImage(color: color) self.setBackgroundImage(backgroundImage, for: .default) - - /* - let blurEffect = Theme.barBlurEffect - - let blurEffectView: UIVisualEffectView = { - if let existingBlurEffectView = self.blurEffectView { - existingBlurEffectView.isHidden = false - return existingBlurEffectView - } - - let blurEffectView = UIVisualEffectView() - blurEffectView.isUserInteractionEnabled = false - - self.blurEffectView = blurEffectView - self.insertSubview(blurEffectView, at: 0) - - // navbar frame doesn't account for statusBar, so, same as the built-in navbar background, we need to exceed - // the navbar bounds to have the blur extend up and behind the status bar. - blurEffectView.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets(top: -statusBarHeight, left: 0, bottom: 0, right: 0)) - - return blurEffectView - }() - - blurEffectView.effect = blurEffect - */ // remove hairline below bar. self.shadowImage = UIImage() diff --git a/SignalUtilitiesKit/OWSNavigationController.h b/SignalUtilitiesKit/UI/OWSNavigationController.h similarity index 100% rename from SignalUtilitiesKit/OWSNavigationController.h rename to SignalUtilitiesKit/UI/OWSNavigationController.h diff --git a/SignalUtilitiesKit/OWSNavigationController.m b/SignalUtilitiesKit/UI/OWSNavigationController.m similarity index 100% rename from SignalUtilitiesKit/OWSNavigationController.m rename to SignalUtilitiesKit/UI/OWSNavigationController.m diff --git a/SignalUtilitiesKit/OWSSearchBar.h b/SignalUtilitiesKit/UI/OWSSearchBar.h similarity index 100% rename from SignalUtilitiesKit/OWSSearchBar.h rename to SignalUtilitiesKit/UI/OWSSearchBar.h diff --git a/SignalUtilitiesKit/OWSSearchBar.m b/SignalUtilitiesKit/UI/OWSSearchBar.m similarity index 100% rename from SignalUtilitiesKit/OWSSearchBar.m rename to SignalUtilitiesKit/UI/OWSSearchBar.m diff --git a/SignalUtilitiesKit/OWSTableViewController.h b/SignalUtilitiesKit/UI/OWSTableViewController.h similarity index 100% rename from SignalUtilitiesKit/OWSTableViewController.h rename to SignalUtilitiesKit/UI/OWSTableViewController.h diff --git a/SignalUtilitiesKit/OWSTableViewController.m b/SignalUtilitiesKit/UI/OWSTableViewController.m similarity index 100% rename from SignalUtilitiesKit/OWSTableViewController.m rename to SignalUtilitiesKit/UI/OWSTableViewController.m diff --git a/SignalUtilitiesKit/OWSTextField.h b/SignalUtilitiesKit/UI/OWSTextField.h similarity index 100% rename from SignalUtilitiesKit/OWSTextField.h rename to SignalUtilitiesKit/UI/OWSTextField.h diff --git a/SignalUtilitiesKit/OWSTextField.m b/SignalUtilitiesKit/UI/OWSTextField.m similarity index 100% rename from SignalUtilitiesKit/OWSTextField.m rename to SignalUtilitiesKit/UI/OWSTextField.m diff --git a/SignalUtilitiesKit/OWSTextView.h b/SignalUtilitiesKit/UI/OWSTextView.h similarity index 100% rename from SignalUtilitiesKit/OWSTextView.h rename to SignalUtilitiesKit/UI/OWSTextView.h diff --git a/SignalUtilitiesKit/OWSTextView.m b/SignalUtilitiesKit/UI/OWSTextView.m similarity index 100% rename from SignalUtilitiesKit/OWSTextView.m rename to SignalUtilitiesKit/UI/OWSTextView.m diff --git a/SignalUtilitiesKit/OWSViewController+ImageEditor.swift b/SignalUtilitiesKit/UI/OWSViewController+ImageEditor.swift similarity index 100% rename from SignalUtilitiesKit/OWSViewController+ImageEditor.swift rename to SignalUtilitiesKit/UI/OWSViewController+ImageEditor.swift diff --git a/SignalUtilitiesKit/OWSViewController.h b/SignalUtilitiesKit/UI/OWSViewController.h similarity index 100% rename from SignalUtilitiesKit/OWSViewController.h rename to SignalUtilitiesKit/UI/OWSViewController.h diff --git a/SignalUtilitiesKit/OWSViewController.m b/SignalUtilitiesKit/UI/OWSViewController.m similarity index 100% rename from SignalUtilitiesKit/OWSViewController.m rename to SignalUtilitiesKit/UI/OWSViewController.m diff --git a/SignalUtilitiesKit/OWSWindowManager.h b/SignalUtilitiesKit/UI/OWSWindowManager.h similarity index 100% rename from SignalUtilitiesKit/OWSWindowManager.h rename to SignalUtilitiesKit/UI/OWSWindowManager.h diff --git a/SignalUtilitiesKit/OWSWindowManager.m b/SignalUtilitiesKit/UI/OWSWindowManager.m similarity index 87% rename from SignalUtilitiesKit/OWSWindowManager.m rename to SignalUtilitiesKit/UI/OWSWindowManager.m index b4ee977e5..faf6a286e 100644 --- a/SignalUtilitiesKit/OWSWindowManager.m +++ b/SignalUtilitiesKit/UI/OWSWindowManager.m @@ -127,15 +127,11 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) #pragma mark - -@interface OWSWindowManager () +@interface OWSWindowManager () // UIWindowLevelNormal @property (nonatomic) UIWindow *rootWindow; -// UIWindowLevel_ReturnToCall -@property (nonatomic) UIWindow *returnToCallWindow; -@property (nonatomic) ReturnToCallViewController *returnToCallViewController; - // UIWindowLevel_CallView @property (nonatomic) UIWindow *callViewWindow; @property (nonatomic) UINavigationController *callNavigationController; @@ -190,7 +186,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) self.rootWindow = rootWindow; self.screenBlockingWindow = screenBlockingWindow; - self.returnToCallWindow = [self createReturnToCallWindow:rootWindow]; self.callViewWindow = [self createCallViewWindow:rootWindow]; self.menuActionsWindow = [self createMenuActionsWindowWithRoowWindow:rootWindow]; @@ -209,18 +204,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)didChangeStatusBarFrame:(NSNotification *)notification { - // Apple bug? Upon returning from landscape, this method *is* fired, but both the notification and [UIApplication - // sharedApplication].statusBarFrame still show a height of 0. So to work around we also call - // `ensureReturnToCallWindowFrame` before showing the call banner. - [self ensureReturnToCallWindowFrame]; -} - -- (void)ensureReturnToCallWindowFrame -{ - CGRect newFrame = self.returnToCallWindow.frame; - newFrame.size.height = OWSWindowManagerCallBannerHeight(); - OWSLogDebug(@"returnToCallWindowFrame: %@", NSStringFromCGRect(newFrame)); - self.returnToCallWindow.frame = newFrame; + } - (void)applicationWillResignActive:(NSNotification *)notification @@ -228,28 +212,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) [self hideMenuActionsWindow]; } -- (UIWindow *)createReturnToCallWindow:(UIWindow *)rootWindow -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(rootWindow); - - // "Return to call" should remain at the top of the screen. - CGRect windowFrame = UIScreen.mainScreen.bounds; - windowFrame.size.height = OWSWindowManagerCallBannerHeight(); - UIWindow *window = [[UIWindow alloc] initWithFrame:windowFrame]; - window.hidden = YES; - window.windowLevel = UIWindowLevel_ReturnToCall(); - window.opaque = YES; - - ReturnToCallViewController *viewController = [ReturnToCallViewController new]; - self.returnToCallViewController = viewController; - viewController.delegate = self; - - window.rootViewController = viewController; - - return window; -} - - (UIWindow *)createMenuActionsWindowWithRoowWindow:(UIWindow *)rootWindow { UIWindow *window; @@ -318,7 +280,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) { OWSAssertDebug(window); - return (window == self.rootWindow || window == self.returnToCallWindow || window == self.callViewWindow + return (window == self.rootWindow || window == self.callViewWindow || window == self.menuActionsWindow || window == self.screenBlockingWindow); } @@ -435,7 +397,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) { OWSAssertIsOnMainThread(); OWSAssertDebug(self.rootWindow); - OWSAssertDebug(self.returnToCallWindow); OWSAssertDebug(self.callViewWindow); OWSAssertDebug(self.screenBlockingWindow); @@ -448,7 +409,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) // Show Screen Block. [self ensureRootWindowHidden]; - [self ensureReturnToCallWindowHidden]; [self ensureCallViewWindowHidden]; [self ensureMessageActionsWindowHidden]; [self ensureScreenBlockWindowShown]; @@ -456,7 +416,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) // Show Call View. [self ensureRootWindowHidden]; - [self ensureReturnToCallWindowHidden]; [self ensureCallViewWindowShown]; [self ensureMessageActionsWindowHidden]; [self ensureScreenBlockWindowHidden]; @@ -467,14 +426,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) [self ensureCallViewWindowHidden]; [self ensureScreenBlockWindowHidden]; - if (self.callViewController) { - // Add "Return to Call" banner - - [self ensureReturnToCallWindowShown]; - } else { - [self ensureReturnToCallWindowHidden]; - } - if (self.menuActionsViewController) { // Add "Message Actions" action sheet @@ -515,33 +466,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) self.rootWindow.hidden = YES; } -- (void)ensureReturnToCallWindowShown -{ - OWSAssertIsOnMainThread(); - - if (!self.returnToCallWindow.hidden) { - return; - } - - [self ensureReturnToCallWindowFrame]; - OWSLogInfo(@"showing 'return to call' window."); - self.returnToCallWindow.hidden = NO; - [self.returnToCallViewController startAnimating]; -} - -- (void)ensureReturnToCallWindowHidden -{ - OWSAssertIsOnMainThread(); - - if (self.returnToCallWindow.hidden) { - return; - } - - OWSLogInfo(@"hiding 'return to call' window."); - self.returnToCallWindow.hidden = YES; - [self.returnToCallViewController stopAnimating]; -} - - (void)ensureCallViewWindowShown { OWSAssertIsOnMainThread(); @@ -613,13 +537,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) self.screenBlockingWindow.windowLevel = UIWindowLevel_Background; } -#pragma mark - ReturnToCallViewControllerDelegate - -- (void)returnToCallWasTapped:(ReturnToCallViewController *)viewController -{ - [self showCallView]; -} - #pragma mark - Fixit - (void)fixit_workAroundRotationIssue diff --git a/SignalUtilitiesKit/PlaceholderIcon.swift b/SignalUtilitiesKit/UI/PlaceholderIcon.swift similarity index 100% rename from SignalUtilitiesKit/PlaceholderIcon.swift rename to SignalUtilitiesKit/UI/PlaceholderIcon.swift diff --git a/SignalUtilitiesKit/ProfilePictureView.swift b/SignalUtilitiesKit/UI/ProfilePictureView.swift similarity index 97% rename from SignalUtilitiesKit/ProfilePictureView.swift rename to SignalUtilitiesKit/UI/ProfilePictureView.swift index 4b90a25d8..a53f34532 100644 --- a/SignalUtilitiesKit/ProfilePictureView.swift +++ b/SignalUtilitiesKit/UI/ProfilePictureView.swift @@ -68,8 +68,7 @@ public final class ProfilePictureView : UIView { self.openGroupProfilePicture = openGroupProfilePicture isRSSFeed = false hasTappableProfilePicture = true - } else if thread.groupModel.groupType == .openGroup - || thread.groupModel.groupType == .rssFeed { // An open group without a profile picture or an RSS feed + } else if thread.groupModel.groupType == .openGroup { // An open group without a profile picture or an RSS feed hexEncodedPublicKey = "" isRSSFeed = true } else { // A closed group diff --git a/SignalUtilitiesKit/ScreenLockViewController.h b/SignalUtilitiesKit/UI/ScreenLockViewController.h similarity index 100% rename from SignalUtilitiesKit/ScreenLockViewController.h rename to SignalUtilitiesKit/UI/ScreenLockViewController.h diff --git a/SignalUtilitiesKit/ScreenLockViewController.m b/SignalUtilitiesKit/UI/ScreenLockViewController.m similarity index 100% rename from SignalUtilitiesKit/ScreenLockViewController.m rename to SignalUtilitiesKit/UI/ScreenLockViewController.m diff --git a/SignalUtilitiesKit/SelectRecipientViewController.h b/SignalUtilitiesKit/UI/SelectRecipientViewController.h similarity index 100% rename from SignalUtilitiesKit/SelectRecipientViewController.h rename to SignalUtilitiesKit/UI/SelectRecipientViewController.h diff --git a/SignalUtilitiesKit/SelectRecipientViewController.m b/SignalUtilitiesKit/UI/SelectRecipientViewController.m similarity index 51% rename from SignalUtilitiesKit/SelectRecipientViewController.m rename to SignalUtilitiesKit/UI/SelectRecipientViewController.m index 4e7b96e5a..a592b7e1e 100644 --- a/SignalUtilitiesKit/SelectRecipientViewController.m +++ b/SignalUtilitiesKit/UI/SelectRecipientViewController.m @@ -3,18 +3,14 @@ // #import -#import "PhoneNumber.h" -#import "ViewControllerUtils.h" + #import -#import #import #import #import #import #import #import -#import -#import #import #import #import @@ -26,7 +22,6 @@ NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipien #pragma mark - @interface SelectRecipientViewController () @@ -54,12 +49,8 @@ NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipien self.view.backgroundColor = [Theme backgroundColor]; - _contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self]; - [self createViews]; - [self populateDefaultCountryNameAndCode]; - if (self.delegate.shouldHideContacts) { self.tableViewController.tableView.scrollEnabled = NO; } @@ -98,8 +89,6 @@ NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipien _tableViewController.view.backgroundColor = [Theme backgroundColor]; [self updateTableContents]; - - [self updatePhoneNumberButtonEnabling]; } - (UILabel *)countryCodeLabel @@ -209,225 +198,18 @@ NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipien return row; } -#pragma mark - Country - -- (void)populateDefaultCountryNameAndCode -{ - PhoneNumber *localNumber = [PhoneNumber phoneNumberFromE164:[TSAccountManager localNumber]]; - OWSAssertDebug(localNumber); - - NSString *countryCode; - NSNumber *callingCode; - if (localNumber) { - callingCode = [localNumber getCountryCode]; - OWSAssertDebug(callingCode); - if (callingCode) { - NSString *prefix = [NSString stringWithFormat:@"+%d", callingCode.intValue]; - countryCode = [[PhoneNumberUtil sharedThreadLocal] probableCountryCodeForCallingCode:prefix]; - } - } - - if (!countryCode || !callingCode) { - countryCode = [PhoneNumber defaultCountryCode]; - callingCode = [[PhoneNumberUtil sharedThreadLocal].nbPhoneNumberUtil getCountryCodeForRegion:countryCode]; - } - - NSString *countryName = [PhoneNumberUtil countryNameFromCountryCode:countryCode]; - - [self updateCountryWithName:countryName - callingCode:[NSString stringWithFormat:@"%@%@", COUNTRY_CODE_PREFIX, callingCode] - countryCode:countryCode]; -} - -- (void)updateCountryWithName:(NSString *)countryName - callingCode:(NSString *)callingCode - countryCode:(NSString *)countryCode -{ - _callingCode = callingCode; - - NSString *titleFormat = (CurrentAppContext().isRTL ? @"(%2$@) %1$@" : @"%1$@ (%2$@)"); - NSString *title = [NSString stringWithFormat:titleFormat, callingCode, countryCode.localizedUppercaseString]; - [self.countryCodeButton setTitle:title forState:UIControlStateNormal]; - [self.countryCodeButton layoutSubviews]; - - self.examplePhoneNumberLabel.text = - [ViewControllerUtils examplePhoneNumberForCountryCode:countryCode callingCode:callingCode]; - [self.examplePhoneNumberLabel.superview layoutSubviews]; -} - -- (void)setCallingCode:(NSString *)callingCode -{ - _callingCode = callingCode; - - [self updatePhoneNumberButtonEnabling]; -} - -#pragma mark - Actions - -- (void)showCountryCodeView:(nullable id)sender -{ - -} - -- (void)phoneNumberButtonPressed -{ - [self tryToSelectPhoneNumber]; -} - -- (void)tryToSelectPhoneNumber -{ - OWSAssertDebug(self.delegate); - - if (![self hasValidPhoneNumber]) { - OWSFailDebug(@"Invalid phone number was selected."); - return; - } - - NSString *rawPhoneNumber = [self.callingCode stringByAppendingString:self.phoneNumberTextField.text.digitsOnly]; - - NSMutableArray *possiblePhoneNumbers = [NSMutableArray new]; - for (PhoneNumber *phoneNumber in - [PhoneNumber tryParsePhoneNumbersFromsUserSpecifiedText:rawPhoneNumber - clientPhoneNumber:[TSAccountManager localNumber]]) { - [possiblePhoneNumbers addObject:phoneNumber.toE164]; - } - if ([possiblePhoneNumbers count] < 1) { - OWSFailDebug(@"Couldn't parse phone number."); - return; - } - - [self.phoneNumberTextField resignFirstResponder]; - - // There should only be one phone number, since we're explicitly specifying - // a country code and therefore parsing a number in e164 format. - OWSAssertDebug([possiblePhoneNumbers count] == 1); - - if ([self.delegate shouldValidatePhoneNumbers]) { - // Show an alert while validating the recipient. - - __weak SelectRecipientViewController *weakSelf = self; - [ModalActivityIndicatorViewController - presentFromViewController:self - canCancel:YES - backgroundBlock:^(ModalActivityIndicatorViewController *modalActivityIndicator) { - [[ContactsUpdater sharedUpdater] lookupIdentifiers:possiblePhoneNumbers - success:^(NSArray *recipients) { - OWSAssertIsOnMainThread(); - if (modalActivityIndicator.wasCancelled) { - return; - } - - if (recipients.count == 0) { - [modalActivityIndicator - dismissViewControllerAnimated:NO - completion:^{ - NSError *error - = OWSErrorMakeNoSuchSignalRecipientError(); - [OWSAlerts showErrorAlertWithMessage: - error.localizedDescription]; - }]; - return; - } - - NSString *recipientId = recipients[0].uniqueId; - [modalActivityIndicator - dismissViewControllerAnimated:NO - completion:^{ - [weakSelf.delegate phoneNumberWasSelected:recipientId]; - }]; - } - failure:^(NSError *error) { - OWSAssertIsOnMainThread(); - if (modalActivityIndicator.wasCancelled) { - return; - } - [modalActivityIndicator - dismissViewControllerAnimated:NO - completion:^{ - [OWSAlerts - showErrorAlertWithMessage:error.localizedDescription]; - }]; - }]; - }]; - } else { - NSString *recipientId = possiblePhoneNumbers[0]; - [self.delegate phoneNumberWasSelected:recipientId]; - } -} - -- (void)textFieldDidChange:(id)sender -{ - [self updatePhoneNumberButtonEnabling]; -} - -// TODO: We could also do this in registration view. -- (BOOL)hasValidPhoneNumber -{ - if (!self.callingCode) { - return NO; - } - NSString *possiblePhoneNumber = - [self.callingCode stringByAppendingString:self.phoneNumberTextField.text.digitsOnly]; - NSArray *parsePhoneNumbers = - [PhoneNumber tryParsePhoneNumbersFromsUserSpecifiedText:possiblePhoneNumber - clientPhoneNumber:[TSAccountManager localNumber]]; - if (parsePhoneNumbers.count < 1) { - return NO; - } - PhoneNumber *parsedPhoneNumber = parsePhoneNumbers[0]; - // It'd be nice to use [PhoneNumber isValid] but it always returns false for some countries - // (like afghanistan) and there doesn't seem to be a good way to determine beforehand - // which countries it can validate for without forking libPhoneNumber. - return parsedPhoneNumber.toE164.length > 1; -} - -- (void)updatePhoneNumberButtonEnabling -{ - BOOL isEnabled = [self hasValidPhoneNumber]; - self.phoneNumberButton.enabled = isEnabled; - [self.phoneNumberButton - setBackgroundColorsWithUpColor:(isEnabled ? [UIColor ows_signalBrandBlueColor] : [Theme secondaryColor])]; -} - -#pragma mark - CountryCodeViewControllerDelegate - -//- (void)countryCodeViewController:(CountryCodeViewController *)vc -// didSelectCountryCode:(NSString *)countryCode -// countryName:(NSString *)countryName -// callingCode:(NSString *)callingCode -//{ -// OWSAssertDebug(countryCode.length > 0); -// OWSAssertDebug(countryName.length > 0); -// OWSAssertDebug(callingCode.length > 0); -// -// [self updateCountryWithName:countryName callingCode:callingCode countryCode:countryCode]; -// -// // Trigger the formatting logic with a no-op edit. -// [self textField:self.phoneNumberTextField shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""]; -//} - #pragma mark - UITextFieldDelegate - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)insertionText { - [ViewControllerUtils phoneNumberTextField:textField - shouldChangeCharactersInRange:range - replacementString:insertionText - callingCode:_callingCode]; - - [self updatePhoneNumberButtonEnabling]; - return NO; // inform our caller that we took care of performing the change } - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; - if ([self hasValidPhoneNumber]) { - [self tryToSelectPhoneNumber]; - } return NO; } @@ -511,55 +293,6 @@ NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipien actionBlock:nil]]; [contents addSection:phoneNumberSection]; - if (![self.delegate shouldHideContacts]) { - OWSTableSection *contactsSection = [OWSTableSection new]; - contactsSection.headerTitle = [self.delegate contactsSectionTitle]; - NSArray *signalAccounts = helper.signalAccounts; - if (signalAccounts.count == 0) { - // No Contacts - [contactsSection - addItem:[OWSTableItem softCenterLabelItemWithText: - NSLocalizedString(@"SETTINGS_BLOCK_LIST_NO_CONTACTS", - @"A label that indicates the user has no Signal contacts.")]]; - } else { - // Contacts - - for (SignalAccount *signalAccount in signalAccounts) { - [contactsSection - addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - SelectRecipientViewController *strongSelf = weakSelf; - OWSCAssertDebug(strongSelf); - - ContactTableViewCell *cell = [ContactTableViewCell new]; - BOOL isBlocked = [helper isRecipientIdBlocked:signalAccount.recipientId]; - if (isBlocked) { - cell.accessoryMessage = NSLocalizedString(@"CONTACT_CELL_IS_BLOCKED", - @"An indicator that a contact has been blocked."); - } else { - cell.accessoryMessage = - [weakSelf.delegate accessoryMessageForSignalAccount:signalAccount]; - } - [cell configureWithRecipientId:signalAccount.recipientId]; - - if (![weakSelf.delegate canSignalAccountBeSelected:signalAccount]) { - cell.selectionStyle = UITableViewCellSelectionStyleNone; - } - - return cell; - } - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - if (![weakSelf.delegate canSignalAccountBeSelected:signalAccount]) { - return; - } - [weakSelf.delegate signalAccountWasSelected:signalAccount]; - }]]; - } - } - [contents addSection:contactsSection]; - } - self.tableViewController.contents = contents; } @@ -572,9 +305,7 @@ NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipien - (void)countryRowTouched:(UIGestureRecognizer *)sender { - if (sender.state == UIGestureRecognizerStateRecognized) { - [self showCountryCodeView:nil]; - } + } #pragma mark - OWSTableViewControllerDelegate diff --git a/SignalUtilitiesKit/SelectThreadViewController.h b/SignalUtilitiesKit/UI/SelectThreadViewController.h similarity index 100% rename from SignalUtilitiesKit/SelectThreadViewController.h rename to SignalUtilitiesKit/UI/SelectThreadViewController.h diff --git a/SignalUtilitiesKit/SelectThreadViewController.m b/SignalUtilitiesKit/UI/SelectThreadViewController.m similarity index 67% rename from SignalUtilitiesKit/SelectThreadViewController.m rename to SignalUtilitiesKit/UI/SelectThreadViewController.m index 149045246..c697301cf 100644 --- a/SignalUtilitiesKit/SelectThreadViewController.m +++ b/SignalUtilitiesKit/UI/SelectThreadViewController.m @@ -5,9 +5,6 @@ #import "SelectThreadViewController.h" #import "BlockListUIUtils.h" #import "ContactTableViewCell.h" -#import "ContactsViewHelper.h" -#import "NewNonContactConversationViewController.h" -#import "OWSContactsManager.h" #import "OWSSearchBar.h" #import "OWSTableViewController.h" #import "ThreadViewHelper.h" @@ -16,7 +13,6 @@ #import "UIView+OWS.h" #import #import -#import #import #import #import @@ -28,9 +24,7 @@ NS_ASSUME_NONNULL_BEGIN @interface SelectThreadViewController () + UISearchBarDelegate> @property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; @property (nonatomic, readonly) FullTextSearcher *fullTextSearcher; @@ -55,7 +49,6 @@ NS_ASSUME_NONNULL_BEGIN closeButton.tintColor = LKColors.text; self.navigationItem.leftBarButtonItem = closeButton; - _contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self]; _fullTextSearcher = FullTextSearcher.shared; _threadViewHelper = [ThreadViewHelper new]; _threadViewHelper.delegate = self; @@ -100,25 +93,6 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertDebug(self.selectThreadViewDelegate); - // Search - /* - UISearchBar *searchBar = [OWSSearchBar new]; - _searchBar = searchBar; - searchBar.delegate = self; - searchBar.placeholder = NSLocalizedString(@"Search by public key", @""); - [searchBar sizeToFit]; - - UIView *header = [self.selectThreadViewDelegate createHeaderWithSearchBar:searchBar]; - if (!header) { - header = searchBar; - } - [self.view addSubview:header]; - [header autoPinWidthToSuperview]; - [header autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:0.0f]; - [header setCompressionResistanceVerticalHigh]; - [header setContentHuggingVerticalHigh]; - */ - // Table _tableViewController = [OWSTableViewController new]; _tableViewController.delegate = self; @@ -187,27 +161,10 @@ NS_ASSUME_NONNULL_BEGIN ContactsViewHelper *helper = self.contactsViewHelper; OWSTableContents *contents = [OWSTableContents new]; - /* - OWSTableSection *findByPhoneSection = [OWSTableSection new]; - [findByPhoneSection - addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"NEW_CONVERSATION_FIND_BY_PHONE_NUMBER", - @"A label the cell that lets you add a new member to a group.") - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - NewNonContactConversationViewController *viewController = - [NewNonContactConversationViewController new]; - viewController.nonContactConversationDelegate = weakSelf; - viewController.isPresentedInNavigationController = YES; - [weakSelf.navigationController pushViewController:viewController - animated:YES]; - }]]; - [contents addSection:findByPhoneSection]; - */ - // Existing threads are listed first, ordered by most recently active OWSTableSection *recentChatsSection = [OWSTableSection new]; recentChatsSection.headerTitle = NSLocalizedString(@"SELECT_THREAD_TABLE_RECENT_CHATS_TITLE", @""); - for (TSThread *thread in [self filteredThreadsWithSearchText]) { + for (TSThread *thread in self.threadViewHelper.threads) { [recentChatsSection addItem:[OWSTableItem itemWithCustomCellBlock:^{ @@ -218,7 +175,7 @@ NS_ASSUME_NONNULL_BEGIN // instead of HomeViewCell to present contacts and threads. ContactTableViewCell *cell = [ContactTableViewCell new]; - BOOL isBlocked = [helper isThreadBlocked:thread]; + BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread]; if (isBlocked) { cell.accessoryMessage = NSLocalizedString( @"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked."); @@ -257,13 +214,12 @@ NS_ASSUME_NONNULL_BEGIN return; } - BOOL isBlocked = [helper isThreadBlocked:thread]; + BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread]; if (isBlocked && ![strongSelf.selectThreadViewDelegate canSelectBlockedContact]) { [BlockListUIUtils showUnblockThreadActionSheet:thread fromViewController:strongSelf - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager + blockingManager:SSKEnvironment.shared.blockingManager completionBlock:^(BOOL isStillBlocked) { if (!isStillBlocked) { [strongSelf.selectThreadViewDelegate threadWasSelected:thread]; @@ -280,37 +236,7 @@ NS_ASSUME_NONNULL_BEGIN [contents addSection:recentChatsSection]; } - // Contacts who don't yet have a thread are listed last - OWSTableSection *otherContactsSection = [OWSTableSection new]; - otherContactsSection.headerTitle = @"Other Chats"; - NSArray *filteredSignalAccounts = [self filteredSignalAccountsWithSearchText]; - for (SignalAccount *signalAccount in filteredSignalAccounts) { - [otherContactsSection - addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - SelectThreadViewController *strongSelf = weakSelf; - OWSCAssertDebug(strongSelf); - - ContactTableViewCell *cell = [ContactTableViewCell new]; - BOOL isBlocked = [helper isRecipientIdBlocked:signalAccount.recipientId]; - if (isBlocked) { - cell.accessoryMessage = NSLocalizedString( - @"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked."); - } - [cell configureWithRecipientId:signalAccount.recipientId]; - return cell; - } - customRowHeight:UITableViewAutomaticDimension - actionBlock:^{ - [weakSelf signalAccountWasSelected:signalAccount]; - }]]; - } - - if (otherContactsSection.itemCount > 0) { - [contents addSection:otherContactsSection]; - } - - if (recentChatsSection.itemCount + otherContactsSection.itemCount < 1) { + if (recentChatsSection.itemCount < 1) { OWSTableSection *emptySection = [OWSTableSection new]; [emptySection addItem:[OWSTableItem @@ -327,16 +253,13 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(signalAccount); OWSAssertDebug(self.selectThreadViewDelegate); - ContactsViewHelper *helper = self.contactsViewHelper; - - if ([helper isRecipientIdBlocked:signalAccount.recipientId] + if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId] && ![self.selectThreadViewDelegate canSelectBlockedContact]) { __weak SelectThreadViewController *weakSelf = self; [BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount fromViewController:self - blockingManager:helper.blockingManager - contactsManager:helper.contactsManager + blockingManager:SSKEnvironment.shared.blockingManager completionBlock:^(BOOL isBlocked) { if (!isBlocked) { [weakSelf signalAccountWasSelected:signalAccount]; @@ -354,37 +277,6 @@ NS_ASSUME_NONNULL_BEGIN [self.selectThreadViewDelegate threadWasSelected:thread]; } -#pragma mark - Filter - -- (NSArray *)filteredThreadsWithSearchText -{ - return self.threadViewHelper.threads; -} - -- (NSArray *)filteredSignalAccountsWithSearchText -{ - // We don't want to show a 1:1 thread with Alice and Alice's contact, - // so we de-duplicate by recipientId. - NSArray *threads = self.threadViewHelper.threads; - NSMutableSet *contactIdsToIgnore = [NSMutableSet new]; - for (TSThread *thread in threads) { - if ([thread isKindOfClass:[TSContactThread class]]) { - TSContactThread *contactThread = (TSContactThread *)thread; - [contactIdsToIgnore addObject:contactThread.contactIdentifier]; - } - } - - NSString *searchString = self.searchBar.text; - NSArray *matchingAccounts = - [self.contactsViewHelper signalAccountsMatchingSearchString:searchString]; - - return [matchingAccounts - filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(SignalAccount *signalAccount, - NSDictionary *_Nullable bindings) { - return ![contactIdsToIgnore containsObject:signalAccount.recipientId]; - }]]; -} - #pragma mark - Events - (void)dismissPressed:(id)sender @@ -419,14 +311,6 @@ NS_ASSUME_NONNULL_BEGIN return NO; } -#pragma mark - NewNonContactConversationViewControllerDelegate - -- (void)recipientIdWasSelected:(NSString *)recipientId -{ - SignalAccount *signalAccount = [self.contactsViewHelper fetchOrBuildSignalAccountForRecipientId:recipientId]; - [self signalAccountWasSelected:signalAccount]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/SharingThreadPickerViewController.h b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.h similarity index 100% rename from SignalUtilitiesKit/SharingThreadPickerViewController.h rename to SignalUtilitiesKit/UI/SharingThreadPickerViewController.h diff --git a/SignalUtilitiesKit/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m similarity index 65% rename from SignalUtilitiesKit/SharingThreadPickerViewController.m rename to SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index 9a85d0f96..50e9c85ae 100644 --- a/SignalUtilitiesKit/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -20,10 +20,8 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); @interface SharingThreadPickerViewController () + MessageApprovalViewControllerDelegate> -@property (nonatomic, readonly) OWSContactsManager *contactsManager; @property (nonatomic, readonly) OWSMessageSender *messageSender; @property (nonatomic) TSThread *thread; @property (nonatomic, readonly, weak) id shareViewDelegate; @@ -67,9 +65,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); { [super loadView]; - _contactsManager = Environment.shared.contactsManager; - _messageSender = SSKEnvironment.shared.messageSender; - _progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; self.title = NSLocalizedString(@"SHARE_EXTENSION_VIEW_TITLE", @"Title for the 'share extension' view."); } @@ -173,10 +168,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); return; } - if ([self tryToShareAsContactShare]) { - return; - } - OWSNavigationController *approvalModal = [AttachmentApprovalViewController wrappedInNavControllerWithAttachments:self.attachments approvalDelegate:self]; [self presentViewController:approvalModal animated:YES completion:nil]; @@ -194,69 +185,12 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); MessageApprovalViewController *approvalVC = [[MessageApprovalViewController alloc] initWithMessageText:messageText thread:self.thread - contactsManager:self.contactsManager delegate:self]; [self.navigationController pushViewController:approvalVC animated:YES]; return YES; } -- (BOOL)tryToShareAsContactShare -{ - OWSAssertDebug(self.attachments.count > 0); - - if (self.attachments.count > 1) { - return NO; - } - OWSAssertDebug(self.attachments.count == 1); - SignalAttachment *attachment = self.attachments.firstObject; - if (!attachment.isConvertibleToContactShare) { - return NO; - } - - [self showContactShareApproval:attachment]; - return YES; -} - -- (void)showContactShareApproval:(SignalAttachment *)attachment -{ - OWSAssertDebug(attachment); - OWSAssertDebug(self.thread); - OWSAssertDebug(attachment.isConvertibleToContactShare); - - NSData *data = attachment.data; - - CNContact *_Nullable cnContact = [Contact cnContactWithVCardData:data]; - Contact *_Nullable contact = [[Contact alloc] initWithSystemContact:cnContact]; - OWSContact *_Nullable contactShareRecord = [OWSContacts contactForSystemContact:cnContact]; - if (!contactShareRecord) { - OWSLogError(@"Could not convert system contact."); - return; - } - - BOOL isProfileAvatar = NO; - NSData *_Nullable avatarImageData = [self.contactsManager avatarDataForCNContactId:contact.cnContactId]; - for (NSString *recipientId in contact.textSecureIdentifiers) { - if (avatarImageData) { - break; - } - avatarImageData = [self.contactsManager profileImageDataForPhoneIdentifier:recipientId]; - if (avatarImageData) { - isProfileAvatar = YES; - } - } - contactShareRecord.isProfileAvatar = isProfileAvatar; - - ContactShareViewModel *contactShare = - [[ContactShareViewModel alloc] initWithContactShareRecord:contactShareRecord avatarImageData:avatarImageData]; - - ContactShareApprovalViewController *approvalVC = - [[ContactShareApprovalViewController alloc] initWithContactShare:contactShare - contactsManager:self.contactsManager - delegate:self]; - [self.navigationController pushViewController:approvalVC animated:YES]; -} - // override - (void)dismissPressed:(id)sender { @@ -281,7 +215,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); didApproveAttachments:(NSArray *_Nonnull)attachments messageText:(NSString *_Nullable)messageText { - [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; [self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) { OWSAssertIsOnMainThread(); @@ -293,15 +226,18 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); // TODO ALBUMS - send album via SAE [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText - mediaAttachments:attachments - inThread:self.thread - quotedReplyModel:nil - transaction:transaction - messageSender:self.messageSender - completion:^(NSError *_Nullable error) { - sendCompletion(error, outgoingMessage); - }]; + + // TODO TODO TODO + +// outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText +// mediaAttachments:attachments +// inThread:self.thread +// quotedReplyModel:nil +// transaction:transaction +// messageSender:self.messageSender +// completion:^(NSError *_Nullable error) { +// sendCompletion(error, outgoingMessage); +// }]; }]; // This is necessary to show progress. @@ -328,7 +264,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); { OWSAssertDebug(messageText.length > 0); - [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; [self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) { OWSAssertIsOnMainThread(); @@ -337,18 +272,21 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); // the sending operation. Alternatively, we could use a durable send, but do more to make sure the // SAE runs as long as it needs. [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText - inThread:self.thread - quotedReplyModel:nil - transaction:transaction - messageSender:self.messageSender - completion:^(NSError *_Nullable error) { - if (error) { - sendCompletion(error, outgoingMessage); - } else { - sendCompletion(nil, outgoingMessage); - } - }]; + + // TODO TODO TODO +// +// outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText +// inThread:self.thread +// quotedReplyModel:nil +// transaction:transaction +// messageSender:self.messageSender +// completion:^(NSError *_Nullable error) { +// if (error) { +// sendCompletion(error, outgoingMessage); +// } else { +// sendCompletion(nil, outgoingMessage); +// } +// }]; // This is necessary to show progress. self.outgoingMessage = outgoingMessage; }]; @@ -361,49 +299,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); [self cancelShareExperience]; } -#pragma mark - ContactShareApprovalViewControllerDelegate - -- (void)approveContactShare:(ContactShareApprovalViewController *)approvalViewController - didApproveContactShare:(ContactShareViewModel *)contactShare -{ - OWSLogInfo(@""); - - [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - [self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) { - OWSAssertIsOnMainThread(); - // TODO - in line with QuotedReply and other message attachments, saving should happen as part of sending - // preparation rather than duplicated here and in the SAE - - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - if (contactShare.avatarImage) { - [contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction]; - } - } - completion:^{ - __block TSOutgoingMessage *outgoingMessage = nil; - outgoingMessage = [ThreadUtil sendMessageNonDurablyWithContactShare:contactShare.dbRecord - inThread:self.thread - messageSender:self.messageSender - completion:^(NSError *_Nullable error) { - sendCompletion(error, outgoingMessage); - }]; - // This is necessary to show progress. - self.outgoingMessage = outgoingMessage; - }]; - - - } - fromViewController:approvalViewController]; -} - -- (void)approveContactShare:(ContactShareApprovalViewController *)approvalViewController - didCancelContactShare:(ContactShareViewModel *)contactShare -{ - OWSLogInfo(@""); - - [self cancelShareExperience]; -} - #pragma mark - Helpers - (void)tryToSendMessageWithBlock:(SendMessageBlock)sendMessageBlock @@ -475,7 +370,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); NSString *failureFormat = NSLocalizedString(@"SHARE_EXTENSION_FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_FORMAT", @"alert body when sharing file failed because of untrusted/changed identity keys"); - NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:untrustedRecipientId]; + NSString *displayName = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:untrustedRecipientId avoidingWriteTransaction:YES]; NSString *failureMessage = [NSString stringWithFormat:failureFormat, displayName]; UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle @@ -544,41 +439,9 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); OWSLogDebug(@"Confirming identity for recipient: %@", recipientId); - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSVerificationState verificationState = - [[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId transaction:transaction]; - switch (verificationState) { - case OWSVerificationStateVerified: { - OWSFailDebug(@"Shouldn't need to confirm identity if it was already verified"); - break; - } - case OWSVerificationStateDefault: { - // If we learned of a changed SN during send, then we've already recorded the new identity - // and there's nothing else we need to do for the resend to succeed. - // We don't want to redundantly set status to "default" because we would create a - // "You marked Alice as unverified" notice, which wouldn't make sense if Alice was never - // marked as "Verified". - OWSLogInfo(@"recipient has acceptable verification status. Next send will succeed."); - break; - } - case OWSVerificationStateNoLongerVerified: { - OWSLogInfo(@"marked recipient: %@ as default verification status.", recipientId); - NSData *identityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientId:recipientId - protocolContext:transaction]; - OWSAssertDebug(identityKey); - [[OWSIdentityManager sharedManager] setVerificationState:OWSVerificationStateDefault - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:YES - transaction:transaction]; - break; - } - } - - dispatch_async(dispatch_get_main_queue(), ^(void) { - [self resendMessage:message fromViewController:fromViewController]; - }); - }]; + dispatch_async(dispatch_get_main_queue(), ^(void) { + [self resendMessage:message fromViewController:fromViewController]; + }); } - (void)resendMessage:(TSOutgoingMessage *)message fromViewController:(UIViewController *)fromViewController @@ -602,25 +465,28 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); [fromViewController presentAlert:progressAlert completion:^{ - [self.messageSender sendMessage:message - success:^{ - OWSLogInfo(@"Resending attachment succeeded."); - dispatch_async(dispatch_get_main_queue(), ^{ - [self.shareViewDelegate shareViewWasCompleted]; - }); - } - failure:^(NSError *error) { - dispatch_async(dispatch_get_main_queue(), ^{ - [fromViewController - dismissViewControllerAnimated:YES - completion:^{ - OWSLogInfo(@"Sending attachment failed with error: %@", error); - [self showSendFailureAlertWithError:error - message:message - fromViewController:fromViewController]; - }]; - }); - }]; + + // TODO TODO TODO + +// [self.messageSender sendMessage:message +// success:^{ +// OWSLogInfo(@"Resending attachment succeeded."); +// dispatch_async(dispatch_get_main_queue(), ^{ +// [self.shareViewDelegate shareViewWasCompleted]; +// }); +// } +// failure:^(NSError *error) { +// dispatch_async(dispatch_get_main_queue(), ^{ +// [fromViewController +// dismissViewControllerAnimated:YES +// completion:^{ +// OWSLogInfo(@"Sending attachment failed with error: %@", error); +// [self showSendFailureAlertWithError:error +// message:message +// fromViewController:fromViewController]; +// }]; +// }); +// }]; }]; } diff --git a/SignalUtilitiesKit/SheetViewController.swift b/SignalUtilitiesKit/UI/SheetViewController.swift similarity index 100% rename from SignalUtilitiesKit/SheetViewController.swift rename to SignalUtilitiesKit/UI/SheetViewController.swift diff --git a/SignalUtilitiesKit/TappableStackView.swift b/SignalUtilitiesKit/UI/TappableStackView.swift similarity index 100% rename from SignalUtilitiesKit/TappableStackView.swift rename to SignalUtilitiesKit/UI/TappableStackView.swift diff --git a/SignalUtilitiesKit/TappableView.swift b/SignalUtilitiesKit/UI/TappableView.swift similarity index 100% rename from SignalUtilitiesKit/TappableView.swift rename to SignalUtilitiesKit/UI/TappableView.swift diff --git a/SignalUtilitiesKit/Theme.h b/SignalUtilitiesKit/UI/Theme.h similarity index 100% rename from SignalUtilitiesKit/Theme.h rename to SignalUtilitiesKit/UI/Theme.h diff --git a/SignalUtilitiesKit/Theme.m b/SignalUtilitiesKit/UI/Theme.m similarity index 100% rename from SignalUtilitiesKit/Theme.m rename to SignalUtilitiesKit/UI/Theme.m diff --git a/SignalUtilitiesKit/Toast.swift b/SignalUtilitiesKit/UI/Toast.swift similarity index 100% rename from SignalUtilitiesKit/Toast.swift rename to SignalUtilitiesKit/UI/Toast.swift diff --git a/SignalUtilitiesKit/UIColor+OWS.h b/SignalUtilitiesKit/UI/UIColor+OWS.h similarity index 100% rename from SignalUtilitiesKit/UIColor+OWS.h rename to SignalUtilitiesKit/UI/UIColor+OWS.h diff --git a/SignalUtilitiesKit/UIColor+OWS.m b/SignalUtilitiesKit/UI/UIColor+OWS.m similarity index 100% rename from SignalUtilitiesKit/UIColor+OWS.m rename to SignalUtilitiesKit/UI/UIColor+OWS.m diff --git a/SignalUtilitiesKit/UIFont+OWS.h b/SignalUtilitiesKit/UI/UIFont+OWS.h similarity index 100% rename from SignalUtilitiesKit/UIFont+OWS.h rename to SignalUtilitiesKit/UI/UIFont+OWS.h diff --git a/SignalUtilitiesKit/UIFont+OWS.m b/SignalUtilitiesKit/UI/UIFont+OWS.m similarity index 100% rename from SignalUtilitiesKit/UIFont+OWS.m rename to SignalUtilitiesKit/UI/UIFont+OWS.m diff --git a/SignalUtilitiesKit/UIGestureRecognizer+OWS.swift b/SignalUtilitiesKit/UI/UIGestureRecognizer+OWS.swift similarity index 100% rename from SignalUtilitiesKit/UIGestureRecognizer+OWS.swift rename to SignalUtilitiesKit/UI/UIGestureRecognizer+OWS.swift diff --git a/SignalUtilitiesKit/UIImage+OWS.swift b/SignalUtilitiesKit/UI/UIImage+OWS.swift similarity index 100% rename from SignalUtilitiesKit/UIImage+OWS.swift rename to SignalUtilitiesKit/UI/UIImage+OWS.swift diff --git a/SignalUtilitiesKit/UIUtil.h b/SignalUtilitiesKit/UI/UIUtil.h similarity index 100% rename from SignalUtilitiesKit/UIUtil.h rename to SignalUtilitiesKit/UI/UIUtil.h diff --git a/SignalUtilitiesKit/UIUtil.m b/SignalUtilitiesKit/UI/UIUtil.m similarity index 100% rename from SignalUtilitiesKit/UIUtil.m rename to SignalUtilitiesKit/UI/UIUtil.m diff --git a/SignalUtilitiesKit/UIView+OWS.h b/SignalUtilitiesKit/UI/UIView+OWS.h similarity index 100% rename from SignalUtilitiesKit/UIView+OWS.h rename to SignalUtilitiesKit/UI/UIView+OWS.h diff --git a/SignalUtilitiesKit/UIView+OWS.m b/SignalUtilitiesKit/UI/UIView+OWS.m similarity index 100% rename from SignalUtilitiesKit/UIView+OWS.m rename to SignalUtilitiesKit/UI/UIView+OWS.m diff --git a/SignalUtilitiesKit/UIView+OWS.swift b/SignalUtilitiesKit/UI/UIView+OWS.swift similarity index 100% rename from SignalUtilitiesKit/UIView+OWS.swift rename to SignalUtilitiesKit/UI/UIView+OWS.swift diff --git a/SignalUtilitiesKit/UIView+Utilities.swift b/SignalUtilitiesKit/UI/UIView+Utilities.swift similarity index 100% rename from SignalUtilitiesKit/UIView+Utilities.swift rename to SignalUtilitiesKit/UI/UIView+Utilities.swift diff --git a/SignalUtilitiesKit/UIViewController+OWS.h b/SignalUtilitiesKit/UI/UIViewController+OWS.h similarity index 100% rename from SignalUtilitiesKit/UIViewController+OWS.h rename to SignalUtilitiesKit/UI/UIViewController+OWS.h diff --git a/SignalUtilitiesKit/UIViewController+OWS.m b/SignalUtilitiesKit/UI/UIViewController+OWS.m similarity index 100% rename from SignalUtilitiesKit/UIViewController+OWS.m rename to SignalUtilitiesKit/UI/UIViewController+OWS.m diff --git a/SignalUtilitiesKit/UIViewController+Utilities.swift b/SignalUtilitiesKit/UI/UIViewController+Utilities.swift similarity index 100% rename from SignalUtilitiesKit/UIViewController+Utilities.swift rename to SignalUtilitiesKit/UI/UIViewController+Utilities.swift diff --git a/SignalUtilitiesKit/VideoPlayerView.swift b/SignalUtilitiesKit/UI/VideoPlayerView.swift similarity index 100% rename from SignalUtilitiesKit/VideoPlayerView.swift rename to SignalUtilitiesKit/UI/VideoPlayerView.swift diff --git a/SignalUtilitiesKit/AttachmentSharing.h b/SignalUtilitiesKit/Utilities/AttachmentSharing.h similarity index 100% rename from SignalUtilitiesKit/AttachmentSharing.h rename to SignalUtilitiesKit/Utilities/AttachmentSharing.h diff --git a/SignalUtilitiesKit/AttachmentSharing.m b/SignalUtilitiesKit/Utilities/AttachmentSharing.m similarity index 91% rename from SignalUtilitiesKit/AttachmentSharing.m rename to SignalUtilitiesKit/Utilities/AttachmentSharing.m index 264cdcd74..d1b883d9c 100644 --- a/SignalUtilitiesKit/AttachmentSharing.m +++ b/SignalUtilitiesKit/Utilities/AttachmentSharing.m @@ -4,7 +4,6 @@ #import "AttachmentSharing.h" #import "UIUtil.h" - #import #import @@ -41,9 +40,7 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertDebug(url); - [AttachmentSharing showShareUIForActivityItems:@[ - url, - ] + [AttachmentSharing showShareUIForActivityItems:@[ url ] completion:completion]; } @@ -64,9 +61,7 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertDebug(text); - [AttachmentSharing showShareUIForActivityItems:@[ - text, - ] + [AttachmentSharing showShareUIForActivityItems:@[ text, ] completion:completion]; } @@ -75,9 +70,7 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertDebug(image); - [AttachmentSharing showShareUIForActivityItems:@[ - image, - ] + [AttachmentSharing showShareUIForActivityItems:@[ image, ] completion:nil]; } #endif diff --git a/SignalUtilitiesKit/Bench.swift b/SignalUtilitiesKit/Utilities/Bench.swift similarity index 100% rename from SignalUtilitiesKit/Bench.swift rename to SignalUtilitiesKit/Utilities/Bench.swift diff --git a/SignalUtilitiesKit/BuildConfiguration.swift b/SignalUtilitiesKit/Utilities/BuildConfiguration.swift similarity index 100% rename from SignalUtilitiesKit/BuildConfiguration.swift rename to SignalUtilitiesKit/Utilities/BuildConfiguration.swift diff --git a/SignalUtilitiesKit/ByteParser.h b/SignalUtilitiesKit/Utilities/ByteParser.h similarity index 100% rename from SignalUtilitiesKit/ByteParser.h rename to SignalUtilitiesKit/Utilities/ByteParser.h diff --git a/SignalUtilitiesKit/ByteParser.m b/SignalUtilitiesKit/Utilities/ByteParser.m similarity index 100% rename from SignalUtilitiesKit/ByteParser.m rename to SignalUtilitiesKit/Utilities/ByteParser.m diff --git a/SignalUtilitiesKit/Collection+OWS.swift b/SignalUtilitiesKit/Utilities/Collection+OWS.swift similarity index 90% rename from SignalUtilitiesKit/Collection+OWS.swift rename to SignalUtilitiesKit/Utilities/Collection+OWS.swift index 5f1f1c8a8..c2e7959cb 100644 --- a/SignalUtilitiesKit/Collection+OWS.swift +++ b/SignalUtilitiesKit/Utilities/Collection+OWS.swift @@ -5,12 +5,13 @@ public extension Collection { /// Returns the element at the specified index iff it is within bounds, otherwise nil. - public subscript (safe index: Index) -> Element? { + subscript (safe index: Index) -> Element? { return indices.contains(index) ? self[index] : nil } } public extension Array { + func chunked(by chunkSize: Int) -> [[Element]] { return stride(from: 0, to: self.count, by: chunkSize).map { Array(self[$0.. Bool { + func hasMatch(input: String) -> Bool { return self.firstMatch(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count)) != nil } @objc - public class func parseFirstMatch(pattern: String, + class func parseFirstMatch(pattern: String, text: String, options: NSRegularExpression.Options = []) -> String? { do { @@ -37,7 +37,7 @@ public extension NSRegularExpression { } @objc - public func parseFirstMatch(inText text: String, + func parseFirstMatch(inText text: String, options: NSRegularExpression.Options = []) -> String? { guard let match = self.firstMatch(in: text, options: [], diff --git a/SignalUtilitiesKit/NSSet+Functional.h b/SignalUtilitiesKit/Utilities/NSSet+Functional.h similarity index 100% rename from SignalUtilitiesKit/NSSet+Functional.h rename to SignalUtilitiesKit/Utilities/NSSet+Functional.h diff --git a/SignalUtilitiesKit/NSSet+Functional.m b/SignalUtilitiesKit/Utilities/NSSet+Functional.m similarity index 100% rename from SignalUtilitiesKit/NSSet+Functional.m rename to SignalUtilitiesKit/Utilities/NSSet+Functional.m diff --git a/SignalUtilitiesKit/NSString+SSK.h b/SignalUtilitiesKit/Utilities/NSString+SSK.h similarity index 100% rename from SignalUtilitiesKit/NSString+SSK.h rename to SignalUtilitiesKit/Utilities/NSString+SSK.h diff --git a/SignalUtilitiesKit/NSString+SSK.m b/SignalUtilitiesKit/Utilities/NSString+SSK.m similarity index 100% rename from SignalUtilitiesKit/NSString+SSK.m rename to SignalUtilitiesKit/Utilities/NSString+SSK.m diff --git a/SignalUtilitiesKit/NSURLSessionDataTask+StatusCode.h b/SignalUtilitiesKit/Utilities/NSURLSessionDataTask+StatusCode.h similarity index 100% rename from SignalUtilitiesKit/NSURLSessionDataTask+StatusCode.h rename to SignalUtilitiesKit/Utilities/NSURLSessionDataTask+StatusCode.h diff --git a/SignalUtilitiesKit/NSURLSessionDataTask+StatusCode.m b/SignalUtilitiesKit/Utilities/NSURLSessionDataTask+StatusCode.m similarity index 100% rename from SignalUtilitiesKit/NSURLSessionDataTask+StatusCode.m rename to SignalUtilitiesKit/Utilities/NSURLSessionDataTask+StatusCode.m diff --git a/SignalUtilitiesKit/NSUserDefaults+OWS.h b/SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.h similarity index 100% rename from SignalUtilitiesKit/NSUserDefaults+OWS.h rename to SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.h diff --git a/SignalUtilitiesKit/NSUserDefaults+OWS.m b/SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.m similarity index 100% rename from SignalUtilitiesKit/NSUserDefaults+OWS.m rename to SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.m diff --git a/SignalUtilitiesKit/OWSAudioPlayer.h b/SignalUtilitiesKit/Utilities/OWSAudioPlayer.h similarity index 100% rename from SignalUtilitiesKit/OWSAudioPlayer.h rename to SignalUtilitiesKit/Utilities/OWSAudioPlayer.h diff --git a/SignalUtilitiesKit/OWSAudioPlayer.m b/SignalUtilitiesKit/Utilities/OWSAudioPlayer.m similarity index 100% rename from SignalUtilitiesKit/OWSAudioPlayer.m rename to SignalUtilitiesKit/Utilities/OWSAudioPlayer.m diff --git a/SignalUtilitiesKit/OWSAudioSession.swift b/SignalUtilitiesKit/Utilities/OWSAudioSession.swift similarity index 100% rename from SignalUtilitiesKit/OWSAudioSession.swift rename to SignalUtilitiesKit/Utilities/OWSAudioSession.swift diff --git a/SignalUtilitiesKit/OWSFormat.h b/SignalUtilitiesKit/Utilities/OWSFormat.h similarity index 100% rename from SignalUtilitiesKit/OWSFormat.h rename to SignalUtilitiesKit/Utilities/OWSFormat.h diff --git a/SignalUtilitiesKit/OWSFormat.m b/SignalUtilitiesKit/Utilities/OWSFormat.m similarity index 100% rename from SignalUtilitiesKit/OWSFormat.m rename to SignalUtilitiesKit/Utilities/OWSFormat.m diff --git a/SignalUtilitiesKit/OWSMath.h b/SignalUtilitiesKit/Utilities/OWSMath.h similarity index 100% rename from SignalUtilitiesKit/OWSMath.h rename to SignalUtilitiesKit/Utilities/OWSMath.h diff --git a/SignalUtilitiesKit/OWSMediaUtils.swift b/SignalUtilitiesKit/Utilities/OWSMediaUtils.swift similarity index 100% rename from SignalUtilitiesKit/OWSMediaUtils.swift rename to SignalUtilitiesKit/Utilities/OWSMediaUtils.swift diff --git a/SignalUtilitiesKit/OWSScrubbingLogFormatter.h b/SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.h similarity index 100% rename from SignalUtilitiesKit/OWSScrubbingLogFormatter.h rename to SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.h diff --git a/SignalUtilitiesKit/OWSScrubbingLogFormatter.m b/SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.m similarity index 100% rename from SignalUtilitiesKit/OWSScrubbingLogFormatter.m rename to SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.m diff --git a/SignalUtilitiesKit/OWSVideoPlayer.swift b/SignalUtilitiesKit/Utilities/OWSVideoPlayer.swift similarity index 100% rename from SignalUtilitiesKit/OWSVideoPlayer.swift rename to SignalUtilitiesKit/Utilities/OWSVideoPlayer.swift diff --git a/SignalUtilitiesKit/OrderedDictionary.swift b/SignalUtilitiesKit/Utilities/OrderedDictionary.swift similarity index 100% rename from SignalUtilitiesKit/OrderedDictionary.swift rename to SignalUtilitiesKit/Utilities/OrderedDictionary.swift diff --git a/SignalUtilitiesKit/ProtoUtils.h b/SignalUtilitiesKit/Utilities/ProtoUtils.h similarity index 100% rename from SignalUtilitiesKit/ProtoUtils.h rename to SignalUtilitiesKit/Utilities/ProtoUtils.h diff --git a/SignalUtilitiesKit/ProtoUtils.m b/SignalUtilitiesKit/Utilities/ProtoUtils.m similarity index 58% rename from SignalUtilitiesKit/ProtoUtils.m rename to SignalUtilitiesKit/Utilities/ProtoUtils.m index a48a0cd0c..9f330d66a 100644 --- a/SignalUtilitiesKit/ProtoUtils.m +++ b/SignalUtilitiesKit/Utilities/ProtoUtils.m @@ -29,19 +29,7 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)shouldMessageHaveLocalProfileKey:(TSThread *)thread recipientId:(NSString *_Nullable)recipientId { OWSAssertDebug(thread); - - // For 1:1 threads, we want to include the profile key IFF the - // contact is in the whitelist. - // - // For Group threads, we want to include the profile key IFF the - // recipient OR the group is in the whitelist. - if (recipientId.length > 0 && [self.profileManager isUserInProfileWhitelist:recipientId]) { - return YES; - } else if ([self.profileManager isThreadInProfileWhitelist:thread]) { - return YES; - } - - return NO; + return YES; } + (void)addLocalProfileKeyIfNecessary:(TSThread *)thread @@ -53,15 +41,6 @@ NS_ASSUME_NONNULL_BEGIN if ([self shouldMessageHaveLocalProfileKey:thread recipientId:recipientId]) { [dataMessageBuilder setProfileKey:self.localProfileKey.keyData]; - - if (recipientId.length > 0) { - // Once we've shared our profile key with a user (perhaps due to being - // a member of a whitelisted group), make sure they're whitelisted. - // FIXME PERF avoid this dispatch. It's going to happen for *each* recipient in a group message. - dispatch_async(dispatch_get_main_queue(), ^{ - [self.profileManager addUserToProfileWhitelist:recipientId]; - }); - } } } @@ -82,13 +61,6 @@ NS_ASSUME_NONNULL_BEGIN if ([self shouldMessageHaveLocalProfileKey:thread recipientId:recipientId]) { [callMessageBuilder setProfileKey:self.localProfileKey.keyData]; - - // Once we've shared our profile key with a user (perhaps due to being - // a member of a whitelisted group), make sure they're whitelisted. - // FIXME PERF avoid this dispatch. It's going to happen for *each* recipient in a group message. - dispatch_async(dispatch_get_main_queue(), ^{ - [self.profileManager addUserToProfileWhitelist:recipientId]; - }); } } diff --git a/SignalUtilitiesKit/ReverseDispatchQueue.swift b/SignalUtilitiesKit/Utilities/ReverseDispatchQueue.swift similarity index 100% rename from SignalUtilitiesKit/ReverseDispatchQueue.swift rename to SignalUtilitiesKit/Utilities/ReverseDispatchQueue.swift diff --git a/SignalUtilitiesKit/SSKProtoEnvelope+Conversion.swift b/SignalUtilitiesKit/Utilities/SNProtoEnvelope+Conversion.swift similarity index 82% rename from SignalUtilitiesKit/SSKProtoEnvelope+Conversion.swift rename to SignalUtilitiesKit/Utilities/SNProtoEnvelope+Conversion.swift index b5f6cb7c1..724b2698f 100644 --- a/SignalUtilitiesKit/SSKProtoEnvelope+Conversion.swift +++ b/SignalUtilitiesKit/Utilities/SNProtoEnvelope+Conversion.swift @@ -1,7 +1,7 @@ -public extension SSKProtoEnvelope { +public extension SNProtoEnvelope { - static func from(_ json: JSON) -> SSKProtoEnvelope? { + static func from(_ json: JSON) -> SNProtoEnvelope? { guard let base64EncodedData = json["data"] as? String, let data = Data(base64Encoded: base64EncodedData) else { print("[Loki] Failed to decode data for message: \(json).") return nil diff --git a/SignalUtilitiesKit/SSKAsserts.h b/SignalUtilitiesKit/Utilities/SSKAsserts.h similarity index 100% rename from SignalUtilitiesKit/SSKAsserts.h rename to SignalUtilitiesKit/Utilities/SSKAsserts.h diff --git a/SignalUtilitiesKit/ShareViewDelegate.swift b/SignalUtilitiesKit/Utilities/ShareViewDelegate.swift similarity index 100% rename from SignalUtilitiesKit/ShareViewDelegate.swift rename to SignalUtilitiesKit/Utilities/ShareViewDelegate.swift diff --git a/SignalUtilitiesKit/String+SSK.swift b/SignalUtilitiesKit/Utilities/String+SSK.swift similarity index 100% rename from SignalUtilitiesKit/String+SSK.swift rename to SignalUtilitiesKit/Utilities/String+SSK.swift diff --git a/SignalUtilitiesKit/String+Trimming.swift b/SignalUtilitiesKit/Utilities/String+Trimming.swift similarity index 100% rename from SignalUtilitiesKit/String+Trimming.swift rename to SignalUtilitiesKit/Utilities/String+Trimming.swift diff --git a/SignalUtilitiesKit/UIAlertController+OWS.swift b/SignalUtilitiesKit/Utilities/UIAlertController+OWS.swift similarity index 100% rename from SignalUtilitiesKit/UIAlertController+OWS.swift rename to SignalUtilitiesKit/Utilities/UIAlertController+OWS.swift diff --git a/SignalUtilitiesKit/UIDevice+featureSupport.swift b/SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift similarity index 100% rename from SignalUtilitiesKit/UIDevice+featureSupport.swift rename to SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift diff --git a/SignalUtilitiesKit/UIImage+OWS.h b/SignalUtilitiesKit/Utilities/UIImage+OWS.h similarity index 100% rename from SignalUtilitiesKit/UIImage+OWS.h rename to SignalUtilitiesKit/Utilities/UIImage+OWS.h diff --git a/SignalUtilitiesKit/UIImage+OWS.m b/SignalUtilitiesKit/Utilities/UIImage+OWS.m similarity index 100% rename from SignalUtilitiesKit/UIImage+OWS.m rename to SignalUtilitiesKit/Utilities/UIImage+OWS.m diff --git a/SignalUtilitiesKit/Weak.swift b/SignalUtilitiesKit/Utilities/Weak.swift similarity index 100% rename from SignalUtilitiesKit/Weak.swift rename to SignalUtilitiesKit/Utilities/Weak.swift diff --git a/SignalUtilitiesKit/WeakTimer.swift b/SignalUtilitiesKit/Utilities/WeakTimer.swift similarity index 100% rename from SignalUtilitiesKit/WeakTimer.swift rename to SignalUtilitiesKit/Utilities/WeakTimer.swift diff --git a/SignalUtilitiesKit/VersionMigrations.m b/SignalUtilitiesKit/VersionMigrations.m index af13af3d7..ceeced936 100644 --- a/SignalUtilitiesKit/VersionMigrations.m +++ b/SignalUtilitiesKit/VersionMigrations.m @@ -10,9 +10,9 @@ #import #import #import -#import + #import -#import + #import #import #import @@ -67,27 +67,6 @@ NS_ASSUME_NONNULL_BEGIN return; } - /* - if ([self isVersion:previousVersion atLeast:@"1.0.2" andLessThan:@"2.0"]) { - OWSLogError(@"Migrating from RedPhone no longer supported. Quitting."); - // Not translating these as so few are affected. - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:@"You must reinstall Signal" - message: - @"Sorry, your installation is too old for us to update. You'll have to start fresh." - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction *quitAction = [UIAlertAction actionWithTitle:@"Quit" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - OWSFail(@"Obsolete install."); - }]; - [alert addAction:quitAction]; - - [CurrentAppContext().frontmostViewController presentAlert:alert]; - } - */ - if ([self isVersion:previousVersion atLeast:@"2.0.0" andLessThan:@"2.1.70"] && [self.tsAccountManager isRegistered]) { [self clearVideoCache]; } diff --git a/SignalUtilitiesKit/ViewControllerUtils.h b/SignalUtilitiesKit/ViewControllerUtils.h deleted file mode 100644 index f027db313..000000000 --- a/SignalUtilitiesKit/ViewControllerUtils.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern const NSUInteger kMin2FAPinLength; -extern const NSUInteger kMax2FAPinLength; -extern NSString *const TappedStatusBarNotification; - -@interface ViewControllerUtils : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -// This convenience function can be used to reformat the contents of -// a phone number text field as the user modifies its text by typing, -// pasting, etc. -// -// "callingCode" should be of the form: "+1". -+ (void)phoneNumberTextField:(UITextField *)textField - shouldChangeCharactersInRange:(NSRange)range - replacementString:(NSString *)insertionText - callingCode:(NSString *)callingCode; - -+ (void)ows2FAPINTextField:(UITextField *)textField - shouldChangeCharactersInRange:(NSRange)range - replacementString:(NSString *)insertionText; - -+ (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode callingCode:(NSString *)callingCode; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ViewControllerUtils.m b/SignalUtilitiesKit/ViewControllerUtils.m deleted file mode 100644 index 5d26d87ee..000000000 --- a/SignalUtilitiesKit/ViewControllerUtils.m +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "ViewControllerUtils.h" -#import "PhoneNumber.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const TappedStatusBarNotification = @"TappedStatusBarNotification"; - -const NSUInteger kMin2FAPinLength = 4; -const NSUInteger kMax2FAPinLength = 16; - -@implementation ViewControllerUtils - -+ (void)phoneNumberTextField:(UITextField *)textField - shouldChangeCharactersInRange:(NSRange)range - replacementString:(NSString *)insertionText - callingCode:(NSString *)callingCode -{ - // Phone numbers takes many forms. - // - // * We only want to let the user enter decimal digits. - // * The user shouldn't have to enter hyphen, parentheses or whitespace; - // the phone number should be formatted automatically. - // * The user should be able to copy and paste freely. - // * Invalid input should be simply ignored. - // - // We accomplish this by being permissive and trying to "take as much of the user - // input as possible". - // - // * Always accept deletes. - // * Ignore invalid input. - // * Take partial input if possible. - - NSString *oldText = textField.text; - - // Construct the new contents of the text field by: - // 1. Determining the "left" substring: the contents of the old text _before_ the deletion range. - // Filtering will remove non-decimal digit characters like hyphen "-". - NSString *left = [oldText substringToIndex:range.location].digitsOnly; - // 2. Determining the "right" substring: the contents of the old text _after_ the deletion range. - NSString *right = [oldText substringFromIndex:range.location + range.length].digitsOnly; - // 3. Determining the "center" substring: the contents of the new insertion text. - NSString *center = insertionText.digitsOnly; - - // 3a. If user hits backspace, they should always delete a _digit_ to the - // left of the cursor, even if the text _immediately_ to the left of - // cursor is "formatting text" (e.g. whitespace, a hyphen or a - // parentheses). - bool isJustDeletion = insertionText.length == 0; - if (isJustDeletion) { - NSString *deletedText = [oldText substringWithRange:range]; - BOOL didDeleteFormatting = (deletedText.length == 1 && deletedText.digitsOnly.length < 1); - if (didDeleteFormatting && left.length > 0) { - left = [left substringToIndex:left.length - 1]; - } - } - - // 4. Construct the "raw" new text by concatenating left, center and right. - NSString *textAfterChange = [[left stringByAppendingString:center] stringByAppendingString:right]; - // 4a. Ensure we don't exceed the maximum length for a e164 phone number, - // 15 digits, per: https://en.wikipedia.org/wiki/E.164 - // - // NOTE: The actual limit is 18, not 15, because of certain invalid phone numbers in Germany. - // https://github.com/googlei18n/libphonenumber/blob/master/FALSEHOODS.md - const int kMaxPhoneNumberLength = 18; - if (textAfterChange.length > kMaxPhoneNumberLength) { - textAfterChange = [textAfterChange substringToIndex:kMaxPhoneNumberLength]; - } - // 5. Construct the "formatted" new text by inserting a hyphen if necessary. - // reformat the phone number, trying to keep the cursor beside the inserted or deleted digit - NSUInteger cursorPositionAfterChange = MIN(left.length + center.length, textAfterChange.length); - - NSString *textToFormat = textAfterChange; - NSString *formattedText = [PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:textToFormat - withSpecifiedCountryCodeString:callingCode]; - NSUInteger cursorPositionAfterReformat = [PhoneNumberUtil translateCursorPosition:cursorPositionAfterChange - from:textToFormat - to:formattedText - stickingRightward:isJustDeletion]; - - textField.text = formattedText; - UITextPosition *pos = - [textField positionFromPosition:textField.beginningOfDocument offset:(NSInteger)cursorPositionAfterReformat]; - [textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]]; -} - -+ (void)ows2FAPINTextField:(UITextField *)textField - shouldChangeCharactersInRange:(NSRange)range - replacementString:(NSString *)insertionText -{ - // * We only want to let the user enter decimal digits. - // * The user should be able to copy and paste freely. - // * Invalid input should be simply ignored. - // - // We accomplish this by being permissive and trying to "take as much of the user - // input as possible". - // - // * Always accept deletes. - // * Ignore invalid input. - // * Take partial input if possible. - - NSString *oldText = textField.text; - // Construct the new contents of the text field by: - // 1. Determining the "left" substring: the contents of the old text _before_ the deletion range. - // Filtering will remove non-decimal digit characters. - NSString *left = [oldText substringToIndex:range.location].digitsOnly; - // 2. Determining the "right" substring: the contents of the old text _after_ the deletion range. - NSString *right = [oldText substringFromIndex:range.location + range.length].digitsOnly; - // 3. Determining the "center" substring: the contents of the new insertion text. - NSString *center = insertionText.digitsOnly; - // 4. Construct the "raw" new text by concatenating left, center and right. - NSString *textAfterChange = [[left stringByAppendingString:center] stringByAppendingString:right]; - // 5. Ensure we don't exceed the maximum length for a PIN. - if (textAfterChange.length > kMax2FAPinLength) { - textAfterChange = [textAfterChange substringToIndex:kMax2FAPinLength]; - } - // 6. Construct the final text. - textField.text = textAfterChange; - NSUInteger cursorPositionAfterChange = MIN(left.length + center.length, textAfterChange.length); - UITextPosition *pos = - [textField positionFromPosition:textField.beginningOfDocument offset:(NSInteger)cursorPositionAfterChange]; - [textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]]; -} - -+ (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode callingCode:(NSString *)callingCode -{ - OWSAssertDebug(countryCode.length > 0); - OWSAssertDebug(callingCode.length > 0); - - NSString *examplePhoneNumber = [PhoneNumberUtil examplePhoneNumberForCountryCode:countryCode]; - OWSAssertDebug(!examplePhoneNumber || [examplePhoneNumber hasPrefix:callingCode]); - if (examplePhoneNumber && [examplePhoneNumber hasPrefix:callingCode]) { - NSString *formattedPhoneNumber = - [PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:examplePhoneNumber - withSpecifiedCountryCodeString:countryCode]; - if (formattedPhoneNumber.length > 0) { - examplePhoneNumber = formattedPhoneNumber; - } - - return [NSString - stringWithFormat: - NSLocalizedString(@"PHONE_NUMBER_EXAMPLE_FORMAT", - @"A format for a label showing an example phone number. Embeds {{the example phone number}}."), - [examplePhoneNumber substringFromIndex:callingCode.length]]; - } else { - return @""; - } -} - -@end - -NS_ASSUME_NONNULL_END From b030b5999bf6fd2e626ddf31878d04209aa6cd50 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 17 Nov 2020 16:23:13 +1100 Subject: [PATCH 004/177] Make messages show up again --- .../Storage+SessionMessagingKit.swift | 103 +- .../Database/Storage+SessionSnodeKit.swift | 23 +- Session/Meta/Signal-Bridging-Header.h | 10 - Session/Signal/AppDelegate.m | 7 +- Session/Signal/AppEnvironment.swift | 10 - Session/Signal/CallAudioService.swift | 549 -- Session/Signal/CallKitCallManager.swift | 133 - Session/Signal/CallKitCallUIAdaptee.swift | 414 - Session/Signal/CallService.swift | 1964 ----- Session/Signal/CallUIAdapter.swift | 307 - .../Cells/OWSSystemMessageCell.m | 3 - .../ConversationViewController.m | 5 +- .../ConversationView/ConversationViewItem.m | 4 - .../ConversationView/ConversationViewModel.m | 147 - Session/Signal/NonCallKitCallUIAdaptee.swift | 185 - Session/Signal/OWSBackupImportJob.m | 2 - .../OWSConversationSettingsViewController.m | 2 +- Session/Signal/OutboundCallInitiator.swift | 85 - Session/Signal/SignalCall.swift | 243 - Session/Signal/WebRTCCallMessageHandler.swift | 28 - Session/View Controllers/LinkDeviceVC.swift | 310 - .../LinkDeviceVCDelegate.swift | 5 - Session/View Controllers/QRCodeVC.swift | 4 - .../Jobs/AttachmentDownloadJob.swift | 3 +- .../Jobs/AttachmentUploadJob.swift | 3 +- SessionMessagingKit/Jobs/Job.swift | 3 +- SessionMessagingKit/Jobs/JobQueue.swift | 1 + .../Jobs/MessageReceiveJob.swift | 15 +- SessionMessagingKit/Jobs/MessageSendJob.swift | 10 +- .../Jobs/NotifyPNServerJob.swift | 6 +- .../Control Message/ClosedGroupUpdate.swift | 7 +- .../ExpirationTimerUpdate.swift | 5 +- .../Control Message/ReadReceipt.swift | 1 + .../Control Message/SessionRequest.swift | 5 +- .../Control Message/TypingIndicator.swift | 5 +- SessionMessagingKit/Messages/Message.swift | 7 +- .../Visible Message/VisibleMessage.swift | 1 + .../Sending & Receiving/MessageReceiver.swift | 42 +- .../Sending & Receiving/MessageSender.swift | 1 + SessionMessagingKit/Storage.swift | 6 + .../NotificationServiceExtension.swift | 9 +- .../ShareViewController.swift | 1 - Signal.xcodeproj/project.pbxproj | 136 +- SignalUtilitiesKit/AppSetup.m | 2 - .../Attachments/SignalAttachment.swift | 6 +- .../Attachments/TSAttachmentPointer.h | 6 +- .../Attachments/TSAttachmentPointer.m | 10 +- .../Attachments/TSAttachmentStream.h | 6 +- .../Attachments/TSAttachmentStream.m | 12 +- SignalUtilitiesKit/ClosedGroupsProtocol.swift | 16 +- SignalUtilitiesKit/ContentProxy.swift | 1 - .../Database/OWSDatabaseMigration.m | 2 - .../Database/OWSPrimaryStorage+Calling.h | 24 - .../Database/OWSPrimaryStorage+Calling.m | 35 - .../Database/OWSPrimaryStorage.m | 2 - .../Dictionary+Description.swift | 13 - SignalUtilitiesKit/Fingerprint.pb.swift | 164 - SignalUtilitiesKit/FingerprintProto.swift | 235 - SignalUtilitiesKit/FullTextSearchFinder.swift | 2 +- ...sappearingConfigurationUpdateInfoMessage.h | 0 ...sappearingConfigurationUpdateInfoMessage.m | 0 SignalUtilitiesKit/Messages/TSErrorMessage.h | 10 +- SignalUtilitiesKit/Messages/TSErrorMessage.m | 11 +- .../TSErrorMessage_privateConstructor.h | 2 +- .../Messages/TSIncomingMessage.h | 23 +- .../Messages/TSIncomingMessage.m | 24 +- SignalUtilitiesKit/Messages/TSInfoMessage.m | 1 - ...SInvalidIdentityKeyReceivingErrorMessage.h | 4 +- ...SInvalidIdentityKeyReceivingErrorMessage.m | 12 +- SignalUtilitiesKit/Messages/TSMessage.h | 2 - SignalUtilitiesKit/Messages/TSMessage.m | 2 - .../Messages/TSOutgoingMessage.h | 12 +- .../Messages/TSOutgoingMessage.m | 77 +- SignalUtilitiesKit/Messages/TSQuotedMessage.h | 4 +- SignalUtilitiesKit/Messages/TSQuotedMessage.m | 8 +- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 5 +- .../LokiDatabaseUtilities.swift | 0 .../NoopCallMessageHandler.swift | 29 - SignalUtilitiesKit/OWSAttachmentDownloads.h | 2 +- SignalUtilitiesKit/OWSCallMessageHandler.h | 30 - .../OWSContactOffersInteraction.h | 38 - .../OWSContactOffersInteraction.m | 73 - SignalUtilitiesKit/OWSContactsOutputStream.m | 6 +- .../OWSDisappearingMessagesConfiguration.m | 2 +- SignalUtilitiesKit/OWSGroupsOutputStream.m | 2 +- SignalUtilitiesKit/OWSIdentityManager.h | 4 +- SignalUtilitiesKit/OWSIdentityManager.m | 8 +- SignalUtilitiesKit/OWSIncompleteCallsJob.h | 31 - SignalUtilitiesKit/OWSIncompleteCallsJob.m | 160 - SignalUtilitiesKit/OWSLinkPreview.swift | 2 +- .../OWSOutgoingReceiptManager.h | 4 +- .../OWSOutgoingReceiptManager.m | 2 +- SignalUtilitiesKit/OWSReadReceiptManager.h | 4 +- SignalUtilitiesKit/OWSReadReceiptManager.m | 4 +- SignalUtilitiesKit/OWSRecipientIdentity.h | 4 +- SignalUtilitiesKit/OWSRecipientIdentity.m | 14 +- SignalUtilitiesKit/OWSRecordTranscriptJob.h | 2 +- .../ProximityMonitoringManager.swift | 2 +- SignalUtilitiesKit/PublicChatPoller.swift | 26 +- .../DisplayNameUtilities.swift | 0 .../DisplayNameUtilities2.swift | 0 .../Remove Later/OWSProfileManager.h | 2 - .../Remove Later/OWSProfileManager.m | 7 - .../SessionManagementProtocol.swift | 2 +- .../Remove Later/SessionMetaProtocol.swift | 4 +- SignalUtilitiesKit/SSKEnvironment.h | 2 - SignalUtilitiesKit/SSKEnvironment.m | 1 - SignalUtilitiesKit/SSKProto.swift | 7075 ----------------- SignalUtilitiesKit/SignalMessage.swift | 4 +- SignalUtilitiesKit/TSCall.h | 44 - SignalUtilitiesKit/TSCall.m | 178 - SignalUtilitiesKit/ThreadUtil.m | 1 - SignalUtilitiesKit/Threads/TSContactThread.m | 5 + SignalUtilitiesKit/Threads/TSGroupThread.h | 2 +- SignalUtilitiesKit/Threads/TSGroupThread.m | 19 +- SignalUtilitiesKit/Threads/TSThread.m | 2 +- .../ECKeyPair+Hexadecimal.swift | 2 +- .../{ => Utilities}/GeneralUtilities.swift | 0 .../{ => Utilities}/GroupUtilities.swift | 0 .../{ => Utilities}/LKGroupUtilities.h | 0 .../{ => Utilities}/LKGroupUtilities.m | 0 .../{ => Utilities}/LKUserDefaults.swift | 0 .../{ => Utilities}/NSAttributedString+OWS.h | 0 SignalUtilitiesKit/Utilities/ProtoUtils.h | 10 +- SignalUtilitiesKit/Utilities/ProtoUtils.m | 6 +- SignalUtilitiesKit/Utilities/String+SSK.swift | 16 +- .../TSIncomingMessage+Conversion.swift | 21 + .../Utilities/UIDevice+featureSupport.swift | 8 +- SignalUtilitiesKit/VersionMigrations.m | 3 - 129 files changed, 456 insertions(+), 12950 deletions(-) delete mode 100644 Session/Signal/CallAudioService.swift delete mode 100644 Session/Signal/CallKitCallManager.swift delete mode 100644 Session/Signal/CallKitCallUIAdaptee.swift delete mode 100644 Session/Signal/CallService.swift delete mode 100644 Session/Signal/CallUIAdapter.swift delete mode 100644 Session/Signal/NonCallKitCallUIAdaptee.swift delete mode 100644 Session/Signal/OutboundCallInitiator.swift delete mode 100644 Session/Signal/SignalCall.swift delete mode 100644 Session/Signal/WebRTCCallMessageHandler.swift delete mode 100644 Session/View Controllers/LinkDeviceVC.swift delete mode 100644 Session/View Controllers/LinkDeviceVCDelegate.swift delete mode 100644 SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.h delete mode 100644 SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.m delete mode 100644 SignalUtilitiesKit/Dictionary+Description.swift delete mode 100644 SignalUtilitiesKit/Fingerprint.pb.swift delete mode 100644 SignalUtilitiesKit/FingerprintProto.swift rename SignalUtilitiesKit/{ => Messages}/OWSDisappearingConfigurationUpdateInfoMessage.h (100%) rename SignalUtilitiesKit/{ => Messages}/OWSDisappearingConfigurationUpdateInfoMessage.m (100%) rename SignalUtilitiesKit/{ => Move to main app}/LokiDatabaseUtilities.swift (100%) delete mode 100644 SignalUtilitiesKit/NoopCallMessageHandler.swift delete mode 100644 SignalUtilitiesKit/OWSCallMessageHandler.h delete mode 100644 SignalUtilitiesKit/OWSContactOffersInteraction.h delete mode 100644 SignalUtilitiesKit/OWSContactOffersInteraction.m delete mode 100644 SignalUtilitiesKit/OWSIncompleteCallsJob.h delete mode 100644 SignalUtilitiesKit/OWSIncompleteCallsJob.m rename SignalUtilitiesKit/{ => Remove Later}/DisplayNameUtilities.swift (100%) rename SignalUtilitiesKit/{ => Remove Later}/DisplayNameUtilities2.swift (100%) delete mode 100644 SignalUtilitiesKit/SSKProto.swift delete mode 100644 SignalUtilitiesKit/TSCall.h delete mode 100644 SignalUtilitiesKit/TSCall.m rename SignalUtilitiesKit/{ => Utilities}/ECKeyPair+Hexadecimal.swift (91%) rename SignalUtilitiesKit/{ => Utilities}/GeneralUtilities.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/GroupUtilities.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/LKGroupUtilities.h (100%) rename SignalUtilitiesKit/{ => Utilities}/LKGroupUtilities.m (100%) rename SignalUtilitiesKit/{ => Utilities}/LKUserDefaults.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/NSAttributedString+OWS.h (100%) create mode 100644 SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift diff --git a/Session/Database/Storage+SessionMessagingKit.swift b/Session/Database/Storage+SessionMessagingKit.swift index 66156eee6..854cd09aa 100644 --- a/Session/Database/Storage+SessionMessagingKit.swift +++ b/Session/Database/Storage+SessionMessagingKit.swift @@ -3,7 +3,8 @@ import PromiseKit extension Storage : SessionMessagingKitStorageProtocol { - // MARK: Signal Protocol + // MARK: - Signal Protocol + public func getOrGenerateRegistrationID(using transaction: Any) -> UInt32 { SSKEnvironment.shared.tsAccountManager.getOrGenerateRegistrationId(transaction as! YapDatabaseReadWriteTransaction) } @@ -18,7 +19,10 @@ extension Storage : SessionMessagingKitStorageProtocol { return try! promise.wait() } - // MARK: Shared Sender Keys + + + // MARK: - Shared Sender Keys + private static let closedGroupPrivateKeyCollection = "LokiClosedGroupPrivateKeyCollection" public func getClosedGroupPrivateKey(for publicKey: String) -> String? { @@ -49,12 +53,28 @@ extension Storage : SessionMessagingKitStorageProtocol { getUserClosedGroupPublicKeys().contains(publicKey) } - // MARK: Jobs - public func persist(_ job: Job, using transaction: Any) { fatalError("Not implemented.") } - public func markJobAsSucceeded(_ job: Job, using transaction: Any) { fatalError("Not implemented.") } - public func markJobAsFailed(_ job: Job, using transaction: Any) { fatalError("Not implemented.") } - // MARK: Authorization + + // MARK: - Jobs + + private static let jobCollection = "SNJobCollection" + + public func persist(_ job: Job, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(job, forKey: job.id!, inCollection: Storage.jobCollection) + } + + public func markJobAsSucceeded(_ job: Job, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: Storage.jobCollection) + } + + public func markJobAsFailed(_ job: Job, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: Storage.jobCollection) + } + + + + // MARK: - Authorization + private static func getAuthTokenCollection(for server: String) -> String { return (server == FileServerAPI.server) ? "LokiStorageAuthTokenCollection" : "LokiGroupChatAuthTokenCollection" } @@ -78,7 +98,10 @@ extension Storage : SessionMessagingKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: server, inCollection: collection) } - // MARK: Open Group Public Keys + + + // MARK: - Open Group Public Keys + private static let openGroupPublicKeyCollection = "LokiOpenGroupPublicKeyCollection" public func getOpenGroupPublicKey(for server: String) -> String? { @@ -93,7 +116,10 @@ extension Storage : SessionMessagingKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: server, inCollection: Storage.openGroupPublicKeyCollection) } - // MARK: Last Message Server ID + + + // MARK: - Last Message Server ID + private static let lastMessageServerIDCollection = "LokiGroupChatLastMessageServerIDCollection" public func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64? { @@ -112,7 +138,10 @@ extension Storage : SessionMessagingKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: "\(server).\(group)", inCollection: Storage.lastMessageServerIDCollection) } - // MARK: Last Deletion Server ID + + + // MARK: - Last Deletion Server ID + private static let lastDeletionServerIDCollection = "LokiGroupChatLastDeletionServerIDCollection" public func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64? { @@ -131,7 +160,10 @@ extension Storage : SessionMessagingKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: "\(server).\(group)", inCollection: Storage.lastDeletionServerIDCollection) } - // MARK: Open Group Metadata + + + // MARK: - Open Group Metadata + private static let openGroupUserCountCollection = "LokiPublicChatUserCountCollection" private static let openGroupMessageIDCollection = "LKMessageIDCollection" @@ -155,4 +187,53 @@ extension Storage : SessionMessagingKitStorageProtocol { public func setLastProfilePictureUploadDate(_ date: Date) { UserDefaults.standard[.lastProfilePictureUpload] = date } + + + + // MARK: - Message Handling + + public func isBlocked(_ publicKey: String) -> Bool { + return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey) + } + + public func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) { +// let transaction = transaction as! YapDatabaseReadWriteTransaction +// let profileManager = SSKEnvironment.shared.profileManager +// if let displayName = profile.displayName { +// profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) +// } +// if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { +// profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) +// } + } + + /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. + public func persist(_ message: VisibleMessage, using transaction: Any) -> (String, Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + let thread = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) + let message = TSIncomingMessage.from(message, using: transaction) + message.save(with: transaction) + return (thread.uniqueId!, message) + } + + public func cancelTypingIndicatorsIfNeeded(for threadID: String, senderPublicKey: String) { + guard let thread = TSThread.fetch(uniqueId: threadID) else { return } + func cancelTypingIndicatorsIfNeeded() { + SSKEnvironment.shared.typingIndicators.didReceiveIncomingMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) + } + if Thread.current.isMainThread { + cancelTypingIndicatorsIfNeeded() + } else { + DispatchQueue.main.async { + cancelTypingIndicatorsIfNeeded() + } + } + } + + public func notifyUserIfNeeded(for message: Any, threadID: String) { + guard let thread = TSThread.fetch(uniqueId: threadID) else { return } + Storage.read { transaction in + SSKEnvironment.shared.notificationsManager!.notifyUser(for: (message as! TSIncomingMessage), in: thread, transaction: transaction) + } + } } diff --git a/Session/Database/Storage+SessionSnodeKit.swift b/Session/Database/Storage+SessionSnodeKit.swift index 032fcd439..76ff86907 100644 --- a/Session/Database/Storage+SessionSnodeKit.swift +++ b/Session/Database/Storage+SessionSnodeKit.swift @@ -1,7 +1,8 @@ extension Storage : SessionSnodeKitStorageProtocol { - // MARK: Onion Request Paths + // MARK: - Onion Request Paths + private static let onionRequestPathCollection = "LokiOnionRequestPathCollection" public func getOnionRequestPaths() -> [OnionRequestAPI.Path] { @@ -47,7 +48,10 @@ extension Storage : SessionSnodeKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.onionRequestPathCollection) } - // MARK: Snode Pool + + + // MARK: - Snode Pool + public func getSnodePool() -> Set { var result: Set = [] Storage.read { transaction in @@ -70,7 +74,10 @@ extension Storage : SessionSnodeKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.snodePoolCollection) } - // MARK: Swarm + + + // MARK: - Swarm + public func getSwarm(for publicKey: String) -> Set { var result: Set = [] let collection = Storage.getSwarmCollection(for: publicKey) @@ -96,7 +103,10 @@ extension Storage : SessionSnodeKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: collection) } - // MARK: Last Message Hash + + + // MARK: - Last Message Hash + private static let lastMessageHashCollection = "LokiLastMessageHashCollection" func getLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String) -> JSON? { @@ -136,7 +146,10 @@ extension Storage : SessionSnodeKitStorageProtocol { (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: Storage.lastMessageHashCollection) } - // MARK: Received Messages + + + // MARK: - Received Messages + private static let receivedMessagesCollection = "LokiReceivedMessagesCollection" public func getReceivedMessages(for publicKey: String) -> Set { diff --git a/Session/Meta/Signal-Bridging-Header.h b/Session/Meta/Signal-Bridging-Header.h index 860f774b2..54ffdc4b2 100644 --- a/Session/Meta/Signal-Bridging-Header.h +++ b/Session/Meta/Signal-Bridging-Header.h @@ -16,10 +16,8 @@ #import "ConversationViewCell.h" #import "ConversationViewItem.h" #import "DateUtil.h" - #import "MediaDetailViewController.h" #import "NotificationSettingsViewController.h" - #import "OWSAnyTouchGestureRecognizer.h" #import "OWSAudioPlayer.h" #import "OWSBackup.h" @@ -40,7 +38,6 @@ #import "OWSQRCodeScanningViewController.h" #import "SignalApp.h" #import "UIViewController+Permissions.h" - #import #import #import @@ -54,8 +51,6 @@ #import #import #import - - #import #import #import @@ -74,14 +69,12 @@ #import #import #import -#import #import #import #import #import #import #import -#import #import #import #import @@ -90,16 +83,13 @@ #import #import #import -#import #import #import #import #import #import - #import #import - #import #import #import diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 1b838dbf9..9d8454de5 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -23,17 +23,13 @@ #import #import #import -#import #import - -#import #import #import #import #import #import #import - #import #import @@ -558,8 +554,7 @@ static NSTimeInterval launchStartedAt; // TODO: or something like that in production. [OWSOrphanDataCleaner auditOnLaunchIfNecessary]; #endif - - [self.profileManager fetchLocalUsersProfile]; + [self.readReceiptManager prepareCachedValues]; // Disable the SAE until the main app has successfully completed launch process diff --git a/Session/Signal/AppEnvironment.swift b/Session/Signal/AppEnvironment.swift index 14a57265e..2df0f0dc8 100644 --- a/Session/Signal/AppEnvironment.swift +++ b/Session/Signal/AppEnvironment.swift @@ -25,15 +25,6 @@ import SignalUtilitiesKit } } - @objc - public var callMessageHandler: WebRTCCallMessageHandler - -// @objc -// public var callService: CallService - -// @objc -// public var outboundCallInitiator: OutboundCallInitiator - @objc public var accountManager: AccountManager @@ -77,7 +68,6 @@ import SignalUtilitiesKit public var backupLazyRestore: BackupLazyRestore private override init() { - self.callMessageHandler = WebRTCCallMessageHandler() self.accountManager = AccountManager() self.notificationPresenter = NotificationPresenter() self.pushRegistrationManager = PushRegistrationManager() diff --git a/Session/Signal/CallAudioService.swift b/Session/Signal/CallAudioService.swift deleted file mode 100644 index d890b4dcd..000000000 --- a/Session/Signal/CallAudioService.swift +++ /dev/null @@ -1,549 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import AVFoundation -//import SignalUtilitiesKit -//import SignalUtilitiesKit -// -//struct AudioSource: Hashable { -// -// let image: UIImage -// let localizedName: String -// let portDescription: AVAudioSessionPortDescription? -// -// // The built-in loud speaker / aka speakerphone -// let isBuiltInSpeaker: Bool -// -// // The built-in quiet speaker, aka the normal phone handset receiver earpiece -// let isBuiltInEarPiece: Bool -// -// init(localizedName: String, image: UIImage, isBuiltInSpeaker: Bool, isBuiltInEarPiece: Bool, portDescription: AVAudioSessionPortDescription? = nil) { -// self.localizedName = localizedName -// self.image = image -// self.isBuiltInSpeaker = isBuiltInSpeaker -// self.isBuiltInEarPiece = isBuiltInEarPiece -// self.portDescription = portDescription -// } -// -// init(portDescription: AVAudioSessionPortDescription) { -// -// let isBuiltInEarPiece = portDescription.portType == AVAudioSession.Port.builtInMic -// -// // portDescription.portName works well for BT linked devices, but if we are using -// // the built in mic, we have "iPhone Microphone" which is a little awkward. -// // In that case, instead we prefer just the model name e.g. "iPhone" or "iPad" -// let localizedName = isBuiltInEarPiece ? UIDevice.current.localizedModel : portDescription.portName -// -// self.init(localizedName: localizedName, -// image: #imageLiteral(resourceName: "button_phone_white"), // TODO -// isBuiltInSpeaker: false, -// isBuiltInEarPiece: isBuiltInEarPiece, -// portDescription: portDescription) -// } -// -// // Speakerphone is handled separately from the other audio routes as it doesn't appear as an "input" -// static var builtInSpeaker: AudioSource { -// return self.init(localizedName: NSLocalizedString("AUDIO_ROUTE_BUILT_IN_SPEAKER", comment: "action sheet button title to enable built in speaker during a call"), -// image: #imageLiteral(resourceName: "button_phone_white"), //TODO -// isBuiltInSpeaker: true, -// isBuiltInEarPiece: false) -// } -// -// // MARK: Hashable -// -// static func ==(lhs: AudioSource, rhs: AudioSource) -> Bool { -// // Simply comparing the `portDescription` vs the `portDescription.uid` -// // caused multiple instances of the built in mic to turn up in a set. -// if lhs.isBuiltInSpeaker && rhs.isBuiltInSpeaker { -// return true -// } -// -// if lhs.isBuiltInSpeaker || rhs.isBuiltInSpeaker { -// return false -// } -// -// guard let lhsPortDescription = lhs.portDescription else { -// owsFailDebug("only the built in speaker should lack a port description") -// return false -// } -// -// guard let rhsPortDescription = rhs.portDescription else { -// owsFailDebug("only the built in speaker should lack a port description") -// return false -// } -// -// return lhsPortDescription.uid == rhsPortDescription.uid -// } -// -// var hashValue: Int { -// guard let portDescription = self.portDescription else { -// assert(self.isBuiltInSpeaker) -// return "Built In Speaker".hashValue -// } -// return portDescription.uid.hash -// } -//} -// -//protocol CallAudioServiceDelegate: class { -// func callAudioService(_ callAudioService: CallAudioService, didUpdateIsSpeakerphoneEnabled isEnabled: Bool) -// func callAudioServiceDidChangeAudioSession(_ callAudioService: CallAudioService) -//} -// -//@objc class CallAudioService: NSObject, CallObserver { -// -// private var vibrateTimer: Timer? -// private let audioPlayer = AVAudioPlayer() -// private let handleRinging: Bool -// weak var delegate: CallAudioServiceDelegate? { -// willSet { -// assert(newValue == nil || delegate == nil) -// } -// } -// -// // MARK: Vibration config -// private let vibrateRepeatDuration = 1.6 -// -// // Our ring buzz is a pair of vibrations. -// // `pulseDuration` is the small pause between the two vibrations in the pair. -// private let pulseDuration = 0.2 -// -// var audioSession: OWSAudioSession { -// return Environment.shared.audioSession -// } -// -// var avAudioSession: AVAudioSession { -// return AVAudioSession.sharedInstance() -// } -// -// // MARK: - Initializers -// -// init(handleRinging: Bool) { -// self.handleRinging = handleRinging -// -// super.init() -// -// // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings -// -// // Configure audio session so we don't prompt user with Record permission until call is connected. -// -// audioSession.configureRTCAudio() -// NotificationCenter.default.addObserver(forName: AVAudioSession.routeChangeNotification, object: avAudioSession, queue: nil) { _ in -// assert(!Thread.isMainThread) -// self.updateIsSpeakerphoneEnabled() -// } -// } -// -// deinit { -// NotificationCenter.default.removeObserver(self) -// } -// -// // MARK: - CallObserver -// -// internal func stateDidChange(call: SignalCall, state: CallState) { -// AssertIsOnMainThread() -// self.handleState(call: call) -// } -// -// internal func muteDidChange(call: SignalCall, isMuted: Bool) { -// AssertIsOnMainThread() -// -// ensureProperAudioSession(call: call) -// } -// -// internal func holdDidChange(call: SignalCall, isOnHold: Bool) { -// AssertIsOnMainThread() -// -// ensureProperAudioSession(call: call) -// } -// -// internal func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) { -// AssertIsOnMainThread() -// -// ensureProperAudioSession(call: call) -// -// if let audioSource = audioSource, audioSource.isBuiltInSpeaker { -// self.isSpeakerphoneEnabled = true -// } else { -// self.isSpeakerphoneEnabled = false -// } -// } -// -// internal func hasLocalVideoDidChange(call: SignalCall, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// -// ensureProperAudioSession(call: call) -// } -// -// // Speakerphone can be manipulated by the in-app callscreen or via the system callscreen (CallKit). -// // Unlike other CallKit CallScreen buttons, enabling doesn't trigger a CXAction, so it's not as simple -// // to track state changes. Instead we never store the state and directly access the ground-truth in the -// // AVAudioSession. -// private(set) var isSpeakerphoneEnabled: Bool = false { -// didSet { -// self.delegate?.callAudioService(self, didUpdateIsSpeakerphoneEnabled: isSpeakerphoneEnabled) -// } -// } -// -// public func requestSpeakerphone(isEnabled: Bool) { -// // This is a little too slow to execute on the main thread and the results are not immediately available after execution -// // anyway, so we dispatch async. If you need to know the new value, you'll need to check isSpeakerphoneEnabled and take -// // advantage of the CallAudioServiceDelegate.callAudioService(_:didUpdateIsSpeakerphoneEnabled:) -// DispatchQueue.global().async { -// do { -// try self.avAudioSession.overrideOutputAudioPort( isEnabled ? .speaker : .none ) -// } catch { -// owsFailDebug("failed to set \(#function) = \(isEnabled) with error: \(error)") -// } -// } -// } -// -// private func updateIsSpeakerphoneEnabled() { -// let value = avAudioSession.currentRoute.outputs.contains { (portDescription: AVAudioSessionPortDescription) -> Bool in -// return portDescription.portType == .builtInSpeaker -// } -// DispatchQueue.main.async { -// self.isSpeakerphoneEnabled = value -// } -// } -// -// private func ensureProperAudioSession(call: SignalCall?) { -// AssertIsOnMainThread() -// -// guard let call = call, !call.isTerminated else { -// // Revert to default audio -// setAudioSession(category: .soloAmbient, -// mode: .default) -// return -// } -// -// // Disallow bluetooth while (and only while) the user has explicitly chosen the built in receiver. -// // -// // NOTE: I'm actually not sure why this is required - it seems like we should just be able -// // to setPreferredInput to call.audioSource.portDescription in this case, -// // but in practice I'm seeing the call revert to the bluetooth headset. -// // Presumably something else (in WebRTC?) is touching our shared AudioSession. - mjk -// let options: AVAudioSession.CategoryOptions = call.audioSource?.isBuiltInEarPiece == true ? [] : [.allowBluetooth] -// -// if call.state == .localRinging { -// // SoloAmbient plays through speaker, but respects silent switch -// setAudioSession(category: .soloAmbient, -// mode: .default) -// } else if call.hasLocalVideo { -// // Because ModeVideoChat affects gain, we don't want to apply it until the call is connected. -// // otherwise sounds like ringing will be extra loud for video vs. speakerphone -// -// // Apple Docs say that setting mode to AVAudioSessionModeVideoChat has the -// // side effect of setting options: .allowBluetooth, when I remove the (seemingly unnecessary) -// // option, and inspect AVAudioSession.sharedInstance.categoryOptions == 0. And availableInputs -// // does not include my linked bluetooth device -// setAudioSession(category: .playAndRecord, -// mode: .videoChat, -// options: options) -// } else { -// // Apple Docs say that setting mode to AVAudioSessionModeVoiceChat has the -// // side effect of setting options: .allowBluetooth, when I remove the (seemingly unnecessary) -// // option, and inspect AVAudioSession.sharedInstance.categoryOptions == 0. And availableInputs -// // does not include my linked bluetooth device -// setAudioSession(category: .playAndRecord, -// mode: .voiceChat, -// options: options) -// } -// -// do { -// // It's important to set preferred input *after* ensuring properAudioSession -// // because some sources are only valid for certain category/option combinations. -// let existingPreferredInput = avAudioSession.preferredInput -// if existingPreferredInput != call.audioSource?.portDescription { -// Logger.info("changing preferred input: \(String(describing: existingPreferredInput)) -> \(String(describing: call.audioSource?.portDescription))") -// try avAudioSession.setPreferredInput(call.audioSource?.portDescription) -// } -// -// } catch { -// owsFailDebug("failed setting audio source with error: \(error) isSpeakerPhoneEnabled: \(call.isSpeakerphoneEnabled)") -// } -// } -// -// // MARK: - Service action handlers -// -// public func didUpdateVideoTracks(call: SignalCall?) { -// Logger.verbose("") -// -// self.ensureProperAudioSession(call: call) -// } -// -// public func handleState(call: SignalCall) { -// assert(Thread.isMainThread) -// -// Logger.verbose("new state: \(call.state)") -// -// // Stop playing sounds while switching audio session so we don't -// // get any blips across a temporary unintended route. -// stopPlayingAnySounds() -// self.ensureProperAudioSession(call: call) -// -// switch call.state { -// case .idle: handleIdle(call: call) -// case .dialing: handleDialing(call: call) -// case .answering: handleAnswering(call: call) -// case .remoteRinging: handleRemoteRinging(call: call) -// case .localRinging: handleLocalRinging(call: call) -// case .connected: handleConnected(call: call) -// case .reconnecting: handleReconnecting(call: call) -// case .localFailure: handleLocalFailure(call: call) -// case .localHangup: handleLocalHangup(call: call) -// case .remoteHangup: handleRemoteHangup(call: call) -// case .remoteBusy: handleBusy(call: call) -// } -// } -// -// private func handleIdle(call: SignalCall) { -// Logger.debug("") -// } -// -// private func handleDialing(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// // HACK: Without this async, dialing sound only plays once. I don't really understand why. Does the audioSession -// // need some time to settle? Is somethign else interrupting our session? -// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { -// self.play(sound: OWSSound.callConnecting) -// } -// } -// -// private func handleAnswering(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// } -// -// private func handleRemoteRinging(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// self.play(sound: OWSSound.callOutboundRinging) -// } -// -// private func handleLocalRinging(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// startRinging(call: call) -// } -// -// private func handleConnected(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// } -// -// private func handleReconnecting(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// } -// -// private func handleLocalFailure(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// play(sound: OWSSound.callFailure) -// handleCallEnded(call: call) -// } -// -// private func handleLocalHangup(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// handleCallEnded(call: call) -// } -// -// private func handleRemoteHangup(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// vibrate() -// -// handleCallEnded(call: call) -// } -// -// private func handleBusy(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// play(sound: OWSSound.callBusy) -// -// // Let the busy sound play for 4 seconds. The full file is longer than necessary -// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 4.0) { -// self.handleCallEnded(call: call) -// } -// } -// -// private func handleCallEnded(call: SignalCall) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// // Stop solo audio, revert to default. -// isSpeakerphoneEnabled = false -// setAudioSession(category: .soloAmbient) -// } -// -// // MARK: Playing Sounds -// -// var currentPlayer: OWSAudioPlayer? -// -// private func stopPlayingAnySounds() { -// currentPlayer?.stop() -// stopAnyRingingVibration() -// } -// -// private func play(sound: OWSSound) { -// guard let newPlayer = OWSSounds.audioPlayer(for: sound, audioBehavior: .call) else { -// owsFailDebug("unable to build player for sound: \(OWSSounds.displayName(for: sound))") -// return -// } -// Logger.info("playing sound: \(OWSSounds.displayName(for: sound))") -// -// // It's important to stop the current player **before** starting the new player. In the case that -// // we're playing the same sound, since the player is memoized on the sound instance, we'd otherwise -// // stop the sound we just started. -// self.currentPlayer?.stop() -// newPlayer.play() -// self.currentPlayer = newPlayer -// } -// -// // MARK: - Ringing -// -// private func startRinging(call: SignalCall) { -// guard handleRinging else { -// Logger.debug("ignoring \(#function) since CallKit handles it's own ringing state") -// return -// } -// -// vibrateTimer = WeakTimer.scheduledTimer(timeInterval: vibrateRepeatDuration, target: self, userInfo: nil, repeats: true) {[weak self] _ in -// self?.ringVibration() -// } -// vibrateTimer?.fire() -// play(sound: .defaultiOSIncomingRingtone) -// } -// -// private func stopAnyRingingVibration() { -// guard handleRinging else { -// Logger.debug("ignoring \(#function) since CallKit handles it's own ringing state") -// return -// } -// Logger.debug("") -// -// // Stop vibrating -// vibrateTimer?.invalidate() -// vibrateTimer = nil -// } -// -// // public so it can be called by timer via selector -// public func ringVibration() { -// // Since a call notification is more urgent than a message notifaction, we -// // vibrate twice, like a pulse, to differentiate from a normal notification vibration. -// vibrate() -// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + pulseDuration) { -// self.vibrate() -// } -// } -// -// func vibrate() { -// // TODO implement HapticAdapter for iPhone7 and up -// AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) -// } -// -// // MARK: - AudioSession MGMT -// // TODO move this to CallAudioSession? -// -// // Note this method is sensitive to the current audio session configuration. -// // Specifically if you call it while speakerphone is enabled you won't see -// // any connected bluetooth routes. -// var availableInputs: [AudioSource] { -// guard let availableInputs = avAudioSession.availableInputs else { -// // I'm not sure why this would happen, but it may indicate an error. -// owsFailDebug("No available inputs or inputs not ready") -// return [AudioSource.builtInSpeaker] -// } -// -// Logger.info("availableInputs: \(availableInputs)") -// return [AudioSource.builtInSpeaker] + availableInputs.map { portDescription in -// return AudioSource(portDescription: portDescription) -// } -// } -// -// func currentAudioSource(call: SignalCall) -> AudioSource? { -// if let audioSource = call.audioSource { -// return audioSource -// } -// -// // Before the user has specified an audio source on the call, we rely on the existing -// // system state to determine the current audio source. -// // If a bluetooth is connected, this will be bluetooth, otherwise -// // this will be the receiver. -// guard let portDescription = avAudioSession.currentRoute.inputs.first else { -// return nil -// } -// -// return AudioSource(portDescription: portDescription) -// } -// -// private func setAudioSession(category: AVAudioSession.Category, -// mode: AVAudioSession.Mode? = nil, -// options: AVAudioSession.CategoryOptions = AVAudioSession.CategoryOptions(rawValue: 0)) { -// -// AssertIsOnMainThread() -// -// var audioSessionChanged = false -// do { -// if #available(iOS 10.0, *), let mode = mode { -// let oldCategory = avAudioSession.category -// let oldMode = avAudioSession.mode -// let oldOptions = avAudioSession.categoryOptions -// -// guard oldCategory != category || oldMode != mode || oldOptions != options else { -// return -// } -// -// audioSessionChanged = true -// -// if oldCategory != category { -// Logger.debug("audio session changed category: \(oldCategory) -> \(category) ") -// } -// if oldMode != mode { -// Logger.debug("audio session changed mode: \(oldMode) -> \(mode) ") -// } -// if oldOptions != options { -// Logger.debug("audio session changed options: \(oldOptions) -> \(options) ") -// } -// try avAudioSession.setCategory(category, mode: mode, options: options) -// -// } else { -// let oldCategory = avAudioSession.category -// let oldOptions = avAudioSession.categoryOptions -// -// guard avAudioSession.category != category || avAudioSession.categoryOptions != options else { -// return -// } -// -// audioSessionChanged = true -// -// if oldCategory != category { -// Logger.debug("audio session changed category: \(oldCategory) -> \(category) ") -// } -// if oldOptions != options { -// Logger.debug("audio session changed options: \(oldOptions) -> \(options) ") -// } -// try avAudioSession.ows_setCategory(category, with: options) -// } -// } catch { -// let message = "failed to set category: \(category) mode: \(String(describing: mode)), options: \(options) with error: \(error)" -// owsFailDebug(message) -// } -// -// if audioSessionChanged { -// Logger.info("") -// self.delegate?.callAudioServiceDidChangeAudioSession(self) -// } -// } -//} diff --git a/Session/Signal/CallKitCallManager.swift b/Session/Signal/CallKitCallManager.swift deleted file mode 100644 index 3d67d7fe5..000000000 --- a/Session/Signal/CallKitCallManager.swift +++ /dev/null @@ -1,133 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import UIKit -//import CallKit -//import SignalUtilitiesKit -// -///** -// * Requests actions from CallKit -// * -// * @Discussion: -// * Based on SpeakerboxCallManager, from the Apple CallKit Example app. Though, it's responsibilities are mostly -// * mirrored (and delegated from) CallKitCallUIAdaptee. -// * TODO: Would it simplify things to merge this into CallKitCallUIAdaptee? -// */ -//@available(iOS 10.0, *) -//final class CallKitCallManager: NSObject { -// -// let callController = CXCallController() -// let showNamesOnCallScreen: Bool -// -// @objc -// static let kAnonymousCallHandlePrefix = "Signal:" -// -// required init(showNamesOnCallScreen: Bool) { -// AssertIsOnMainThread() -// -// self.showNamesOnCallScreen = showNamesOnCallScreen -// super.init() -// -// // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings -// } -// -// // MARK: Actions -// -// func startCall(_ call: SignalCall) { -// var handle: CXHandle -// -// if showNamesOnCallScreen { -// handle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber) -// } else { -// let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString -// handle = CXHandle(type: .generic, value: callKitId) -// OWSPrimaryStorage.shared().setPhoneNumber(call.remotePhoneNumber, forCallKitId: callKitId) -// } -// -// let startCallAction = CXStartCallAction(call: call.localId, handle: handle) -// -// startCallAction.isVideo = call.hasLocalVideo -// -// let transaction = CXTransaction() -// transaction.addAction(startCallAction) -// -// requestTransaction(transaction) -// } -// -// func localHangup(call: SignalCall) { -// let endCallAction = CXEndCallAction(call: call.localId) -// let transaction = CXTransaction() -// transaction.addAction(endCallAction) -// -// requestTransaction(transaction) -// } -// -// func setHeld(call: SignalCall, onHold: Bool) { -// let setHeldCallAction = CXSetHeldCallAction(call: call.localId, onHold: onHold) -// let transaction = CXTransaction() -// transaction.addAction(setHeldCallAction) -// -// requestTransaction(transaction) -// } -// -// func setIsMuted(call: SignalCall, isMuted: Bool) { -// let muteCallAction = CXSetMutedCallAction(call: call.localId, muted: isMuted) -// let transaction = CXTransaction() -// transaction.addAction(muteCallAction) -// -// requestTransaction(transaction) -// } -// -// func answer(call: SignalCall) { -// let answerCallAction = CXAnswerCallAction(call: call.localId) -// let transaction = CXTransaction() -// transaction.addAction(answerCallAction) -// -// requestTransaction(transaction) -// } -// -// private func requestTransaction(_ transaction: CXTransaction) { -// callController.request(transaction) { error in -// if let error = error { -// Logger.error("Error requesting transaction: \(error)") -// } else { -// Logger.debug("Requested transaction successfully") -// } -// } -// } -// -// // MARK: Call Management -// -// private(set) var calls = [SignalCall]() -// -// func callWithLocalId(_ localId: UUID) -> SignalCall? { -// guard let index = calls.firstIndex(where: { $0.localId == localId }) else { -// return nil -// } -// return calls[index] -// } -// -// func addCall(_ call: SignalCall) { -// calls.append(call) -// } -// -// func removeCall(_ call: SignalCall) { -// calls.removeFirst(where: { $0 === call }) -// } -// -// func removeAllCalls() { -// calls.removeAll() -// } -//} -// -//fileprivate extension Array { -// -// mutating func removeFirst(where predicate: (Element) throws -> Bool) rethrows { -// guard let index = try firstIndex(where: predicate) else { -// return -// } -// -// remove(at: index) -// } -//} diff --git a/Session/Signal/CallKitCallUIAdaptee.swift b/Session/Signal/CallKitCallUIAdaptee.swift deleted file mode 100644 index 6de095ffb..000000000 --- a/Session/Signal/CallKitCallUIAdaptee.swift +++ /dev/null @@ -1,414 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import UIKit -//import CallKit -//import AVFoundation -//import SignalUtilitiesKit -//import SignalUtilitiesKit -// -///** -// * Connects user interface to the CallService using CallKit. -// * -// * User interface is routed to the CallManager which requests CXCallActions, and if the CXProvider accepts them, -// * their corresponding consequences are implmented in the CXProviderDelegate methods, e.g. using the CallService -// */ -//@available(iOS 10.0, *) -//final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { -// -// private let callManager: CallKitCallManager -// internal let callService: CallService -// internal let notificationPresenter: NotificationPresenter -// internal let contactsManager: OWSContactsManager -// private let showNamesOnCallScreen: Bool -// private let provider: CXProvider -// private let audioActivity: AudioActivity -// -// // CallKit handles incoming ringer stop/start for us. Yay! -// let hasManualRinger = false -// -// // Instantiating more than one CXProvider can cause us to miss call transactions, so -// // we maintain the provider across Adaptees using a singleton pattern -// private static var _sharedProvider: CXProvider? -// class func sharedProvider(useSystemCallLog: Bool) -> CXProvider { -// let configuration = buildProviderConfiguration(useSystemCallLog: useSystemCallLog) -// -// if let sharedProvider = self._sharedProvider { -// sharedProvider.configuration = configuration -// return sharedProvider -// } else { -// SwiftSingletons.register(self) -// let provider = CXProvider(configuration: configuration) -// _sharedProvider = provider -// return provider -// } -// } -// -// // The app's provider configuration, representing its CallKit capabilities -// class func buildProviderConfiguration(useSystemCallLog: Bool) -> CXProviderConfiguration { -// let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application") -// let providerConfiguration = CXProviderConfiguration(localizedName: localizedName) -// -// providerConfiguration.supportsVideo = true -// -// providerConfiguration.maximumCallGroups = 1 -// -// providerConfiguration.maximumCallsPerCallGroup = 1 -// -// providerConfiguration.supportedHandleTypes = [.phoneNumber, .generic] -// -// let iconMaskImage = #imageLiteral(resourceName: "logoSignal") -// providerConfiguration.iconTemplateImageData = iconMaskImage.pngData() -// -// // We don't set the ringtoneSound property, so that we use either the -// // default iOS ringtone OR the custom ringtone associated with this user's -// // system contact, if possible (iOS 11 or later). -// -// if #available(iOS 11.0, *) { -// providerConfiguration.includesCallsInRecents = useSystemCallLog -// } else { -// // not configurable for iOS10+ -// assert(useSystemCallLog) -// } -// -// return providerConfiguration -// } -// -// init(callService: CallService, contactsManager: OWSContactsManager, notificationPresenter: NotificationPresenter, showNamesOnCallScreen: Bool, useSystemCallLog: Bool) { -// AssertIsOnMainThread() -// -// Logger.debug("") -// -// self.callManager = CallKitCallManager(showNamesOnCallScreen: showNamesOnCallScreen) -// self.callService = callService -// self.contactsManager = contactsManager -// self.notificationPresenter = notificationPresenter -// -// self.provider = type(of: self).sharedProvider(useSystemCallLog: useSystemCallLog) -// -// self.audioActivity = AudioActivity(audioDescription: "[CallKitCallUIAdaptee]", behavior: .call) -// self.showNamesOnCallScreen = showNamesOnCallScreen -// -// super.init() -// -// // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings -// -// self.provider.setDelegate(self, queue: nil) -// } -// -// // MARK: Dependencies -// -// var audioSession: OWSAudioSession { -// return Environment.shared.audioSession -// } -// -// // MARK: CallUIAdaptee -// -// func startOutgoingCall(handle: String) -> SignalCall { -// AssertIsOnMainThread() -// Logger.info("") -// -// let call = SignalCall.outgoingCall(localId: UUID(), remotePhoneNumber: handle) -// -// // make sure we don't terminate audio session during call -// _ = self.audioSession.startAudioActivity(call.audioActivity) -// -// // Add the new outgoing call to the app's list of calls. -// // So we can find it in the provider delegate callbacks. -// callManager.addCall(call) -// callManager.startCall(call) -// -// return call -// } -// -// // Called from CallService after call has ended to clean up any remaining CallKit call state. -// func failCall(_ call: SignalCall, error: CallError) { -// AssertIsOnMainThread() -// Logger.info("") -// -// switch error { -// case .timeout(description: _): -// provider.reportCall(with: call.localId, endedAt: Date(), reason: CXCallEndedReason.unanswered) -// default: -// provider.reportCall(with: call.localId, endedAt: Date(), reason: CXCallEndedReason.failed) -// } -// -// self.callManager.removeCall(call) -// } -// -// func reportIncomingCall(_ call: SignalCall, callerName: String) { -// AssertIsOnMainThread() -// Logger.info("") -// -// // Construct a CXCallUpdate describing the incoming call, including the caller. -// let update = CXCallUpdate() -// -// if showNamesOnCallScreen { -// update.localizedCallerName = self.contactsManager.stringForConversationTitle(withPhoneIdentifier: call.remotePhoneNumber) -// update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber) -// } else { -// let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString -// update.remoteHandle = CXHandle(type: .generic, value: callKitId) -// OWSPrimaryStorage.shared().setPhoneNumber(call.remotePhoneNumber, forCallKitId: callKitId) -// update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled") -// } -// -// update.hasVideo = call.hasLocalVideo -// -// disableUnsupportedFeatures(callUpdate: update) -// -// // Report the incoming call to the system -// provider.reportNewIncomingCall(with: call.localId, update: update) { error in -// /* -// Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error) -// since calls may be "denied" for various legitimate reasons. See CXErrorCodeIncomingCallError. -// */ -// guard error == nil else { -// Logger.error("failed to report new incoming call") -// return -// } -// -// self.callManager.addCall(call) -// } -// } -// -// func answerCall(localId: UUID) { -// AssertIsOnMainThread() -// Logger.info("") -// -// owsFailDebug("CallKit should answer calls via system call screen, not via notifications.") -// } -// -// func answerCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// Logger.info("") -// -// callManager.answer(call: call) -// } -// -// func declineCall(localId: UUID) { -// AssertIsOnMainThread() -// -// owsFailDebug("CallKit should decline calls via system call screen, not via notifications.") -// } -// -// func declineCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// Logger.info("") -// -// callManager.localHangup(call: call) -// } -// -// func recipientAcceptedCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// Logger.info("") -// -// self.provider.reportOutgoingCall(with: call.localId, connectedAt: nil) -// -// let update = CXCallUpdate() -// disableUnsupportedFeatures(callUpdate: update) -// -// provider.reportCall(with: call.localId, updated: update) -// } -// -// func localHangupCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// Logger.info("") -// -// callManager.localHangup(call: call) -// } -// -// func remoteDidHangupCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// Logger.info("") -// -// provider.reportCall(with: call.localId, endedAt: nil, reason: CXCallEndedReason.remoteEnded) -// } -// -// func remoteBusy(_ call: SignalCall) { -// AssertIsOnMainThread() -// Logger.info("") -// -// provider.reportCall(with: call.localId, endedAt: nil, reason: CXCallEndedReason.unanswered) -// } -// -// func setIsMuted(call: SignalCall, isMuted: Bool) { -// AssertIsOnMainThread() -// Logger.info("") -// -// callManager.setIsMuted(call: call, isMuted: isMuted) -// } -// -// func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// let update = CXCallUpdate() -// update.hasVideo = hasLocalVideo -// -// // Update the CallKit UI. -// provider.reportCall(with: call.localId, updated: update) -// -// self.callService.setHasLocalVideo(hasLocalVideo: hasLocalVideo) -// } -// -// // MARK: CXProviderDelegate -// -// func providerDidReset(_ provider: CXProvider) { -// AssertIsOnMainThread() -// Logger.info("") -// -// // End any ongoing calls if the provider resets, and remove them from the app's list of calls, -// // since they are no longer valid. -// callService.handleFailedCurrentCall(error: .providerReset) -// -// // Remove all calls from the app's list of calls. -// callManager.removeAllCalls() -// } -// -// func provider(_ provider: CXProvider, perform action: CXStartCallAction) { -// AssertIsOnMainThread() -// -// Logger.info("CXStartCallAction") -// -// guard let call = callManager.callWithLocalId(action.callUUID) else { -// Logger.error("unable to find call") -// return -// } -// -// // We can't wait for long before fulfilling the CXAction, else CallKit will show a "Failed Call". We don't -// // actually need to wait for the outcome of the handleOutgoingCall promise, because it handles any errors by -// // manually failing the call. -// self.callService.handleOutgoingCall(call).retainUntilComplete() -// -// action.fulfill() -// self.provider.reportOutgoingCall(with: call.localId, startedConnectingAt: nil) -// -// // Update the name used in the CallKit UI for outgoing calls when the user prefers not to show names -// // in ther notifications -// if !showNamesOnCallScreen { -// let update = CXCallUpdate() -// update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", -// comment: "The generic name used for calls if CallKit privacy is enabled") -// provider.reportCall(with: call.localId, updated: update) -// } -// } -// -// func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { -// AssertIsOnMainThread() -// -// Logger.info("Received \(#function) CXAnswerCallAction") -// // Retrieve the instance corresponding to the action's call UUID -// guard let call = callManager.callWithLocalId(action.callUUID) else { -// action.fail() -// return -// } -// -// self.callService.handleAnswerCall(call) -// self.showCall(call) -// action.fulfill() -// } -// -// public func provider(_ provider: CXProvider, perform action: CXEndCallAction) { -// AssertIsOnMainThread() -// -// Logger.info("Received \(#function) CXEndCallAction") -// guard let call = callManager.callWithLocalId(action.callUUID) else { -// Logger.error("trying to end unknown call with localId: \(action.callUUID)") -// action.fail() -// return -// } -// -// self.callService.handleLocalHungupCall(call) -// -// // Signal to the system that the action has been successfully performed. -// action.fulfill() -// -// // Remove the ended call from the app's list of calls. -// self.callManager.removeCall(call) -// } -// -// public func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) { -// AssertIsOnMainThread() -// -// Logger.info("Received \(#function) CXSetHeldCallAction") -// guard let call = callManager.callWithLocalId(action.callUUID) else { -// action.fail() -// return -// } -// -// // Update the SignalCall's underlying hold state. -// self.callService.setIsOnHold(call: call, isOnHold: action.isOnHold) -// -// // Signal to the system that the action has been successfully performed. -// action.fulfill() -// } -// -// public func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) { -// AssertIsOnMainThread() -// -// Logger.info("Received \(#function) CXSetMutedCallAction") -// guard let call = callManager.callWithLocalId(action.callUUID) else { -// Logger.error("Failing CXSetMutedCallAction for unknown call: \(action.callUUID)") -// action.fail() -// return -// } -// -// self.callService.setIsMuted(call: call, isMuted: action.isMuted) -// action.fulfill() -// } -// -// public func provider(_ provider: CXProvider, perform action: CXSetGroupCallAction) { -// AssertIsOnMainThread() -// -// Logger.warn("unimplemented \(#function) for CXSetGroupCallAction") -// } -// -// public func provider(_ provider: CXProvider, perform action: CXPlayDTMFCallAction) { -// AssertIsOnMainThread() -// -// Logger.warn("unimplemented \(#function) for CXPlayDTMFCallAction") -// } -// -// func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) { -// AssertIsOnMainThread() -// -// owsFailDebug("Timed out while performing \(action)") -// -// // React to the action timeout if necessary, such as showing an error UI. -// } -// -// func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { -// AssertIsOnMainThread() -// -// Logger.debug("Received") -// -// _ = self.audioSession.startAudioActivity(self.audioActivity) -// self.audioSession.isRTCAudioEnabled = true -// } -// -// func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { -// AssertIsOnMainThread() -// -// Logger.debug("Received") -// self.audioSession.isRTCAudioEnabled = false -// self.audioSession.endAudioActivity(self.audioActivity) -// } -// -// // MARK: - Util -// -// private func disableUnsupportedFeatures(callUpdate: CXCallUpdate) { -// // Call Holding is failing to restart audio when "swapping" calls on the CallKit screen -// // until user returns to in-app call screen. -// callUpdate.supportsHolding = false -// -// // Not yet supported -// callUpdate.supportsGrouping = false -// callUpdate.supportsUngrouping = false -// -// // Is there any reason to support this? -// callUpdate.supportsDTMF = false -// } -//} diff --git a/Session/Signal/CallService.swift b/Session/Signal/CallService.swift deleted file mode 100644 index 3e8c0b903..000000000 --- a/Session/Signal/CallService.swift +++ /dev/null @@ -1,1964 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import PromiseKit -//import WebRTC -//import SignalUtilitiesKit -//import SignalUtilitiesKit -// -///** -// * `CallService` is a global singleton that manages the state of WebRTC-backed Signal Calls -// * (as opposed to legacy "RedPhone Calls"). -// * -// * It serves as a connection between the `CallUIAdapter` and the `PeerConnectionClient`. -// * -// * ## Signaling -// * -// * Signaling refers to the setup and tear down of the connection. Before the connection is established, this must happen -// * out of band (using Signal Service), but once the connection is established it's possible to publish updates -// * (like hangup) via the established channel. -// * -// * Signaling state is synchronized on the main thread and only mutated in the handleXXX family of methods. -// * -// * Following is a high level process of the exchange of messages that takes place during call signaling. -// * -// * ### Key -// * -// * --[SOMETHING]--> represents a message of type "Something" sent from the caller to the callee -// * <--[SOMETHING]-- represents a message of type "Something" sent from the callee to the caller -// * SS: Message sent via Signal Service -// * DC: Message sent via WebRTC Data Channel -// * -// * ### Message Exchange / State Flow Overview -// * -// * | Caller | Callee | -// * +----------------------------+-------------------------+ -// * Start outgoing call: `handleOutgoingCall`... -// --[SS.CallOffer]--> -// * ...and start generating ICE updates. -// * As ICE candidates are generated, `handleLocalAddedIceCandidate` is called. -// * and we *store* the ICE updates for later. -// * -// * Received call offer: `handleReceivedOffer` -// * Send call answer -// * <--[SS.CallAnswer]-- -// * Start generating ICE updates. -// * As they are generated `handleLocalAddedIceCandidate` is called -// which immediately sends the ICE updates to the Caller. -// * <--[SS.ICEUpdate]-- (sent multiple times) -// * -// * Received CallAnswer: `handleReceivedAnswer` -// * So send any stored ice updates (and send future ones immediately) -// * --[SS.ICEUpdates]--> -// * -// * Once compatible ICE updates have been exchanged... -// * both parties: `handleIceConnected` -// * -// * Show remote ringing UI -// * Connect to offered Data Channel -// * Show incoming call UI. -// * -// * If callee answers Call -// * send connected message -// * <--[DC.ConnectedMesage]-- -// * Received connected message -// * Show Call is connected. -// * -// * Hang up (this could equally be sent by the Callee) -// * --[DC.Hangup]--> -// * --[SS.Hangup]--> -// */ -// -//public enum CallError: Error { -// case providerReset -// case assertionError(description: String) -// case disconnected -// case externalError(underlyingError: Error) -// case timeout(description: String) -// case obsoleteCall(description: String) -// case fatalError(description: String) -// case messageSendFailure(underlyingError: Error) -//} -// -//// Should be roughly synced with Android client for consistency -//private let connectingTimeoutSeconds: TimeInterval = 120 -// -//// All Observer methods will be invoked from the main thread. -//protocol CallServiceObserver: class { -// /** -// * Fired whenever the call changes. -// */ -// func didUpdateCall(call: SignalCall?) -// -// /** -// * Fired whenever the local or remote video track become active or inactive. -// */ -// func didUpdateVideoTracks(call: SignalCall?, -// localCaptureSession: AVCaptureSession?, -// remoteVideoTrack: RTCVideoTrack?) -//} -// -//protocol SignalCallDataDelegate: class { -// func outgoingIceUpdateDidFail(call: SignalCall, error: Error) -//} -// -//// Gather all per-call state in one place. -//private class SignalCallData: NSObject { -// -// fileprivate weak var delegate: SignalCallDataDelegate? -// -// public let call: SignalCall -// -// // Used to coordinate promises across delegate methods -// let callConnectedPromise: Promise -// let callConnectedResolver: Resolver -// -// // Used to ensure any received ICE messages wait until the peer connection client is set up. -// let peerConnectionClientPromise: Promise -// let peerConnectionClientResolver: Resolver -// -// // Used to ensure CallOffer was sent before sending any ICE updates. -// let readyToSendIceUpdatesPromise: Promise -// let readyToSendIceUpdatesResolver: Resolver -// -// weak var localCaptureSession: AVCaptureSession? { -// didSet { -// AssertIsOnMainThread() -// -// Logger.info("") -// } -// } -// -// weak var remoteVideoTrack: RTCVideoTrack? { -// didSet { -// AssertIsOnMainThread() -// -// Logger.info("") -// } -// } -// -// var isRemoteVideoEnabled = false { -// didSet { -// AssertIsOnMainThread() -// -// Logger.info("\(isRemoteVideoEnabled)") -// } -// } -// -// var peerConnectionClient: PeerConnectionClient? { -// didSet { -// AssertIsOnMainThread() -// -// Logger.debug(".peerConnectionClient setter: \(oldValue != nil) -> \(peerConnectionClient != nil) \(String(describing: peerConnectionClient))") -// } -// } -// -// required init(call: SignalCall, delegate: SignalCallDataDelegate) { -// self.call = call -// self.delegate = delegate -// -// let (callConnectedPromise, callConnectedResolver) = Promise.pending() -// self.callConnectedPromise = callConnectedPromise -// self.callConnectedResolver = callConnectedResolver -// -// let (peerConnectionClientPromise, peerConnectionClientResolver) = Promise.pending() -// self.peerConnectionClientPromise = peerConnectionClientPromise -// self.peerConnectionClientResolver = peerConnectionClientResolver -// -// let (readyToSendIceUpdatesPromise, readyToSendIceUpdatesResolver) = Promise.pending() -// self.readyToSendIceUpdatesPromise = readyToSendIceUpdatesPromise -// self.readyToSendIceUpdatesResolver = readyToSendIceUpdatesResolver -// -// super.init() -// } -// -// deinit { -// Logger.debug("[SignalCallData] deinit") -// } -// -// // MARK: - -// -// public func terminate() { -// AssertIsOnMainThread() -// -// Logger.debug("") -// -// self.call.removeAllObservers() -// -// // In case we're still waiting on this promise somewhere, we need to reject it to avoid a memory leak. -// // There is no harm in rejecting a previously fulfilled promise. -// self.callConnectedResolver.reject(CallError.obsoleteCall(description: "Terminating call")) -// -// // In case we're still waiting on the peer connection setup somewhere, we need to reject it to avoid a memory leak. -// // There is no harm in rejecting a previously fulfilled promise. -// self.peerConnectionClientResolver.reject(CallError.obsoleteCall(description: "Terminating call")) -// -// // In case we're still waiting on this promise somewhere, we need to reject it to avoid a memory leak. -// // There is no harm in rejecting a previously fulfilled promise. -// self.readyToSendIceUpdatesResolver.reject(CallError.obsoleteCall(description: "Terminating call")) -// -// peerConnectionClient?.terminate() -// Logger.debug("setting peerConnectionClient") -// -// outgoingIceUpdateQueue.removeAll() -// } -// -// // MARK: - Dependencies -// -// private var messageSender: MessageSender { -// return SSKEnvironment.shared.messageSender -// } -// -// // MARK: - Outgoing ICE updates. -// -// // Setting up a call involves sending many (currently 20+) ICE updates. -// // We send messages serially in order to preserve outgoing message order. -// // There are so many ICE updates per call that the cost of sending all of -// // those messages becomes significant. So we batch outgoing ICE updates, -// // making sure that we only have one outgoing ICE update message at a time. -// // -// // This variable should only be accessed on the main thread. -// private var outgoingIceUpdateQueue = [SSKProtoCallMessageIceUpdate]() -// private var outgoingIceUpdatesInFlight = false -// -// func sendOrEnqueue(outgoingIceUpdate iceUpdateProto: SSKProtoCallMessageIceUpdate) { -// AssertIsOnMainThread() -// -// outgoingIceUpdateQueue.append(iceUpdateProto) -// -// tryToSendIceUpdates() -// } -// -// private func tryToSendIceUpdates() { -// AssertIsOnMainThread() -// -// guard !outgoingIceUpdatesInFlight else { -// Logger.verbose("Enqueued outgoing ice update") -// return -// } -// -// let iceUpdateProtos = outgoingIceUpdateQueue -// guard iceUpdateProtos.count > 0 else { -// // Nothing in the queue. -// return -// } -// -// outgoingIceUpdateQueue.removeAll() -// outgoingIceUpdatesInFlight = true -// -// /** -// * Sent by both parties out of band of the RTC calling channels, as part of setting up those channels. The messages -// * include network accessibility information from the perspective of each client. Once compatible ICEUpdates have been -// * exchanged, the clients can connect. -// */ -// let callMessage = OWSOutgoingCallMessage(thread: call.thread, iceUpdateMessages: iceUpdateProtos) -// let sendPromise = self.messageSender.sendPromise(message: callMessage) -// .done { [weak self] in -// AssertIsOnMainThread() -// -// guard let strongSelf = self else { -// return -// } -// -// strongSelf.outgoingIceUpdatesInFlight = false -// strongSelf.tryToSendIceUpdates() -// }.catch { [weak self] (error) in -// AssertIsOnMainThread() -// -// guard let strongSelf = self else { -// return -// } -// -// strongSelf.outgoingIceUpdatesInFlight = false -// strongSelf.delegate?.outgoingIceUpdateDidFail(call: strongSelf.call, error: error) -// } -// sendPromise.retainUntilComplete() -// } -//} -// -//// This class' state should only be accessed on the main queue. -//@objc public class CallService: NSObject, CallObserver, PeerConnectionClientDelegate, SignalCallDataDelegate { -// -// // MARK: - Properties -// -// var observers = [Weak]() -// -// // Exposed by environment.m -// -// @objc public var callUIAdapter: CallUIAdapter! -// -// // MARK: Class -// -// static let fallbackIceServer = RTCIceServer(urlStrings: ["stun:stun1.l.google.com:19302"]) -// -// // MARK: Ivars -// -// fileprivate var callData: SignalCallData? { -// didSet { -// AssertIsOnMainThread() -// -// oldValue?.delegate = nil -// oldValue?.call.removeObserver(self) -// callData?.call.addObserverAndSyncState(observer: self) -// -// updateIsVideoEnabled() -// -// // Prevent device from sleeping while we have an active call. -// if oldValue != callData { -// if let oldValue = oldValue { -// DeviceSleepManager.sharedInstance.removeBlock(blockObject: oldValue) -// } -// if let callData = callData { -// DeviceSleepManager.sharedInstance.addBlock(blockObject: callData) -// self.startCallTimer() -// } else { -// stopAnyCallTimer() -// } -// } -// -// Logger.debug(".callData setter: \(oldValue?.call.identifiersForLogs as Optional) -> \(callData?.call.identifiersForLogs as Optional)") -// -// for observer in observers { -// observer.value?.didUpdateCall(call: callData?.call) -// } -// } -// } -// -// @objc -// var call: SignalCall? { -// get { -// AssertIsOnMainThread() -// -// return callData?.call -// } -// } -// var peerConnectionClient: PeerConnectionClient? { -// get { -// AssertIsOnMainThread() -// -// return callData?.peerConnectionClient -// } -// } -// -// weak var localCaptureSession: AVCaptureSession? { -// get { -// AssertIsOnMainThread() -// -// return callData?.localCaptureSession -// } -// } -// -// var remoteVideoTrack: RTCVideoTrack? { -// get { -// AssertIsOnMainThread() -// -// return callData?.remoteVideoTrack -// } -// } -// var isRemoteVideoEnabled: Bool { -// get { -// AssertIsOnMainThread() -// -// guard let callData = callData else { -// return false -// } -// return callData.isRemoteVideoEnabled -// } -// } -// -// @objc public override init() { -// -// super.init() -// -// SwiftSingletons.register(self) -// -// NotificationCenter.default.addObserver(self, -// selector: #selector(didEnterBackground), -// name: NSNotification.Name.OWSApplicationDidEnterBackground, -// object: nil) -// NotificationCenter.default.addObserver(self, -// selector: #selector(didBecomeActive), -// name: NSNotification.Name.OWSApplicationDidBecomeActive, -// object: nil) -// } -// -// deinit { -// NotificationCenter.default.removeObserver(self) -// } -// -// // MARK: - Dependencies -// -// private var contactsManager: OWSContactsManager { -// return Environment.shared.contactsManager -// } -// -// private var messageSender: MessageSender { -// return SSKEnvironment.shared.messageSender -// } -// -// private var accountManager: AccountManager { -// return AppEnvironment.shared.accountManager -// } -// -// private var notificationPresenter: NotificationPresenter { -// return AppEnvironment.shared.notificationPresenter -// } -// -// // MARK: - Notifications -// -// @objc func didEnterBackground() { -// AssertIsOnMainThread() -// self.updateIsVideoEnabled() -// } -// -// @objc func didBecomeActive() { -// AssertIsOnMainThread() -// self.updateIsVideoEnabled() -// } -// -// /** -// * Choose whether to use CallKit or a Notification backed interface for calling. -// */ -// @objc public func createCallUIAdapter() { -// AssertIsOnMainThread() -// -// if self.call != nil { -// Logger.warn("ending current call in. Did user toggle callkit preference while in a call?") -// self.terminateCall() -// } -// self.callUIAdapter = CallUIAdapter(callService: self, contactsManager: self.contactsManager, notificationPresenter: self.notificationPresenter) -// } -// -// // MARK: - Service Actions -// -// /** -// * Initiate an outgoing call. -// */ -// func handleOutgoingCall(_ call: SignalCall) -> Promise { -// AssertIsOnMainThread() -// -// let callId = call.signalingId -// BenchEventStart(title: "Outgoing Call Connection", eventId: "call-\(callId)") -// -// guard self.call == nil else { -// let errorDescription = "call was unexpectedly already set." -// Logger.error(errorDescription) -// call.state = .localFailure -// OWSProdError(OWSAnalyticsEvents.callServiceCallAlreadySet(), file: #file, function: #function, line: #line) -// return Promise(error: CallError.assertionError(description: errorDescription)) -// } -// -// let callData = SignalCallData(call: call, delegate: self) -// self.callData = callData -// -// // MJK TODO remove this timestamp param -// let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeOutgoingIncomplete, in: call.thread) -// callRecord.save() -// call.callRecord = callRecord -// -// let promise = getIceServers() -// .then { iceServers -> Promise in -// Logger.debug("got ice servers:\(iceServers) for call: \(call.identifiersForLogs)") -// -// guard self.call == call else { -// throw CallError.obsoleteCall(description: "obsolete call") -// } -// -// guard callData.peerConnectionClient == nil else { -// let errorDescription = "peerconnection was unexpectedly already set." -// Logger.error(errorDescription) -// OWSProdError(OWSAnalyticsEvents.callServicePeerConnectionAlreadySet(), file: #file, function: #function, line: #line) -// throw CallError.assertionError(description: errorDescription) -// } -// -// let useTurnOnly = Environment.shared.preferences.doCallsHideIPAddress() -// -// let peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self, callDirection: .outgoing, useTurnOnly: useTurnOnly) -// Logger.debug("setting peerConnectionClient for call: \(call.identifiersForLogs)") -// callData.peerConnectionClient = peerConnectionClient -// callData.peerConnectionClientResolver.fulfill(()) -// -// return peerConnectionClient.createOffer() -// }.then { (sessionDescription: HardenedRTCSessionDescription) -> Promise in -// guard self.call == call else { -// throw CallError.obsoleteCall(description: "obsolete call") -// } -// guard let peerConnectionClient = self.peerConnectionClient else { -// owsFailDebug("Missing peerConnectionClient") -// throw CallError.obsoleteCall(description: "Missing peerConnectionClient") -// } -// -// Logger.info("session description for outgoing call: \(call.identifiersForLogs), sdp: \(sessionDescription.logSafeDescription).") -// -// return -// peerConnectionClient.setLocalSessionDescription(sessionDescription) -// .then { _ -> Promise in -// do { -// let offerBuilder = SSKProtoCallMessageOffer.builder(id: call.signalingId, -// sessionDescription: sessionDescription.sdp) -// let callMessage = OWSOutgoingCallMessage(thread: call.thread, offerMessage: try offerBuilder.build()) -// return self.messageSender.sendPromise(message: callMessage) -// } catch { -// owsFailDebug("Couldn't build proto") -// throw CallError.fatalError(description: "Couldn't build proto") -// } -// } -// }.then { () -> Promise in -// guard self.call == call else { -// throw CallError.obsoleteCall(description: "obsolete call") -// } -// -// // For outgoing calls, wait until call offer is sent before we send any ICE updates, to ensure message ordering for -// // clients that don't support receiving ICE updates before receiving the call offer. -// self.readyToSendIceUpdates(call: call) -// -// // Don't let the outgoing call ring forever. We don't support inbound ringing forever anyway. -// let timeout: Promise = after(seconds: connectingTimeoutSeconds).done { -// // This code will always be called, whether or not the call has timed out. -// // However, if the call has already connected, the `race` promise will have already been -// // fulfilled. Rejecting an already fulfilled promise is a no-op. -// throw CallError.timeout(description: "timed out waiting to receive call answer") -// } -// -// return race(timeout, callData.callConnectedPromise) -// }.done { -// Logger.info(self.call == call -// ? "outgoing call connected: \(call.identifiersForLogs)." -// : "obsolete outgoing call connected: \(call.identifiersForLogs).") -// } -// -// promise.catch { error in -// Logger.error("placing call \(call.identifiersForLogs) failed with error: \(error)") -// -// if let callError = error as? CallError { -// if case .timeout = callError { -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorTimeoutWhileConnectingOutgoing(), file: #file, function: #function, line: #line) -// } -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorOutgoingConnectionFailedInternal(), file: #file, function: #function, line: #line) -// self.handleFailedCall(failedCall: call, error: callError) -// } else { -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorOutgoingConnectionFailedExternal(), file: #file, function: #function, line: #line) -// let externalError = CallError.externalError(underlyingError: error) -// self.handleFailedCall(failedCall: call, error: externalError) -// } -// }.retainUntilComplete() -// -// return promise -// } -// -// func readyToSendIceUpdates(call: SignalCall) { -// AssertIsOnMainThread() -// -// guard let callData = self.callData else { -// self.handleFailedCall(failedCall: call, error: .obsoleteCall(description:"obsolete call")) -// return -// } -// guard callData.call == call else { -// Logger.warn("ignoring \(#function) for call other than current call") -// return -// } -// -// callData.readyToSendIceUpdatesResolver.fulfill(()) -// } -// -// /** -// * Called by the call initiator after receiving a CallAnswer from the callee. -// */ -// public func handleReceivedAnswer(thread: TSContactThread, callId: UInt64, sessionDescription: String) { -// AssertIsOnMainThread() -// Logger.info("received call answer for call: \(callId) thread: \(thread.contactIdentifier())") -// -// guard let call = self.call else { -// Logger.warn("ignoring obsolete call: \(callId)") -// return -// } -// -// guard call.signalingId == callId else { -// Logger.warn("ignoring mismatched call: \(callId) currentCall: \(call.signalingId)") -// return -// } -// -// guard let peerConnectionClient = self.peerConnectionClient else { -// OWSProdError(OWSAnalyticsEvents.callServicePeerConnectionMissing(), file: #file, function: #function, line: #line) -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "peerConnectionClient was unexpectedly nil")) -// return -// } -// -// let sessionDescription = RTCSessionDescription(type: .answer, sdp: sessionDescription) -// -// peerConnectionClient.setRemoteSessionDescription(sessionDescription) -// .done { -// Logger.debug("successfully set remote description") -// }.catch { error in -// if let callError = error as? CallError { -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorHandleReceivedErrorInternal(), file: #file, function: #function, line: #line) -// self.handleFailedCall(failedCall: call, error: callError) -// } else { -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorHandleReceivedErrorExternal(), file: #file, function: #function, line: #line) -// let externalError = CallError.externalError(underlyingError: error) -// self.handleFailedCall(failedCall: call, error: externalError) -// } -// }.retainUntilComplete() -// } -// -// /** -// * User didn't answer incoming call -// */ -// public func handleMissedCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// if call.callRecord == nil { -// // MJK TODO remove this timestamp param -// call.callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), -// withCallNumber: call.thread.contactIdentifier(), -// callType: RPRecentCallTypeIncomingMissed, -// in: call.thread) -// } -// -// guard let callRecord = call.callRecord else { -// handleFailedCall(failedCall: call, error: .assertionError(description: "callRecord was unexpectedly nil")) -// return -// } -// -// switch callRecord.callType { -// case RPRecentCallTypeIncomingMissed: -// callRecord.save() -// callUIAdapter.reportMissedCall(call) -// case RPRecentCallTypeIncomingIncomplete, RPRecentCallTypeIncoming: -// callRecord.updateCallType(RPRecentCallTypeIncomingMissed) -// callUIAdapter.reportMissedCall(call) -// case RPRecentCallTypeOutgoingIncomplete: -// callRecord.updateCallType(RPRecentCallTypeOutgoingMissed) -// case RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity, RPRecentCallTypeIncomingDeclined, RPRecentCallTypeOutgoingMissed, RPRecentCallTypeOutgoing: -// owsFailDebug("unexpected RPRecentCallType: \(callRecord.callType)") -// callRecord.save() -// default: -// callRecord.save() -// owsFailDebug("unknown RPRecentCallType: \(callRecord.callType)") -// } -// } -// -// /** -// * Received a call while already in another call. -// */ -// private func handleLocalBusyCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// Logger.info("for call: \(call.identifiersForLogs) thread: \(call.thread.contactIdentifier())") -// -// do { -// let busyBuilder = SSKProtoCallMessageBusy.builder(id: call.signalingId) -// let callMessage = OWSOutgoingCallMessage(thread: call.thread, busyMessage: try busyBuilder.build()) -// let sendPromise = messageSender.sendPromise(message: callMessage) -// sendPromise.retainUntilComplete() -// -// handleMissedCall(call) -// } catch { -// owsFailDebug("Couldn't build proto") -// } -// } -// -// /** -// * The callee was already in another call. -// */ -// public func handleRemoteBusy(thread: TSContactThread, callId: UInt64) { -// AssertIsOnMainThread() -// Logger.info("for thread: \(thread.contactIdentifier())") -// -// guard let call = self.call else { -// Logger.warn("ignoring obsolete call: \(callId)") -// return -// } -// -// guard call.signalingId == callId else { -// Logger.warn("ignoring mismatched call: \(callId) currentCall: \(call.signalingId)") -// return -// } -// -// guard thread.contactIdentifier() == call.remotePhoneNumber else { -// Logger.warn("ignoring obsolete call") -// return -// } -// -// call.state = .remoteBusy -// assert(call.callRecord != nil) -// call.callRecord?.updateCallType(RPRecentCallTypeOutgoingMissed) -// -// callUIAdapter.remoteBusy(call) -// terminateCall() -// } -// -// /** -// * Received an incoming call offer. We still have to complete setting up the Signaling channel before we notify -// * the user of an incoming call. -// */ -// public func handleReceivedOffer(thread: TSContactThread, callId: UInt64, sessionDescription callerSessionDescription: String) { -// AssertIsOnMainThread() -// -// BenchEventStart(title: "Incoming Call Connection", eventId: "call-\(callId)") -// -// let newCall = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: callId) -// -// Logger.info("receivedCallOffer: \(newCall.identifiersForLogs)") -// -// let untrustedIdentity = OWSIdentityManager.shared().untrustedIdentityForSending(toRecipientId: thread.contactIdentifier()) -// -// guard untrustedIdentity == nil else { -// Logger.warn("missed a call due to untrusted identity: \(newCall.identifiersForLogs)") -// -// let callerName = self.contactsManager.displayName(forPhoneIdentifier: thread.contactIdentifier()) -// -// switch untrustedIdentity!.verificationState { -// case .verified: -// owsFailDebug("shouldn't have missed a call due to untrusted identity if the identity is verified") -// self.notificationPresenter.presentMissedCall(newCall, callerName: callerName) -// case .default: -// self.notificationPresenter.presentMissedCallBecauseOfNewIdentity(call: newCall, callerName: callerName) -// case .noLongerVerified: -// self.notificationPresenter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: newCall, callerName: callerName) -// } -// -// // MJK TODO remove this timestamp param -// let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), -// withCallNumber: thread.contactIdentifier(), -// callType: RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity, -// in: thread) -// assert(newCall.callRecord == nil) -// newCall.callRecord = callRecord -// callRecord.save() -// -// terminateCall() -// -// return -// } -// -// guard self.call == nil else { -// let existingCall = self.call! -// -// // TODO on iOS10+ we can use CallKit to swap calls rather than just returning busy immediately. -// Logger.info("receivedCallOffer: \(newCall.identifiersForLogs) but we're already in call: \(existingCall.identifiersForLogs)") -// -// handleLocalBusyCall(newCall) -// -// if existingCall.remotePhoneNumber == newCall.remotePhoneNumber { -// Logger.info("handling call from current call user as remote busy.: \(newCall.identifiersForLogs) but we're already in call: \(existingCall.identifiersForLogs)") -// -// // If we're receiving a new call offer from the user we already think we have a call with, -// // terminate our current call to get back to a known good state. If they call back, we'll -// // be ready. -// // -// // TODO: Auto-accept this incoming call if our current call was either a) outgoing or -// // b) never connected. There will be a bit of complexity around making sure that two -// // parties that call each other at the same time end up connected. -// switch existingCall.state { -// case .idle, .dialing, .remoteRinging: -// // If both users are trying to call each other at the same time, -// // both should see busy. -// handleRemoteBusy(thread: existingCall.thread, callId: existingCall.signalingId) -// case .answering, .localRinging, .connected, .localFailure, .localHangup, .remoteHangup, .remoteBusy, .reconnecting: -// // If one user calls another while the other has a "vestigial" call with -// // that same user, fail the old call. -// terminateCall() -// } -// } -// -// return -// } -// -// Logger.info("starting new call: \(newCall.identifiersForLogs)") -// -// let callData = SignalCallData(call: newCall, delegate: self) -// self.callData = callData -// -// var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: "\(#function)", completionBlock: { [weak self] status in -// AssertIsOnMainThread() -// -// guard status == .expired else { -// return -// } -// -// guard let strongSelf = self else { -// return -// } -// let timeout = CallError.timeout(description: "background task time ran out before call connected.") -// -// guard strongSelf.call == newCall else { -// Logger.warn("ignoring obsolete call") -// return -// } -// strongSelf.handleFailedCall(failedCall: newCall, error: timeout) -// }) -// -// getIceServers() -// .then { (iceServers: [RTCIceServer]) -> Promise in -// // FIXME for first time call recipients I think we'll see mic/camera permission requests here, -// // even though, from the users perspective, no incoming call is yet visible. -// guard self.call == newCall else { -// throw CallError.obsoleteCall(description: "getIceServers() response for obsolete call") -// } -// assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance") -// -// // For contacts not stored in our system contacts, we assume they are an unknown caller, and we force -// // a TURN connection, so as not to reveal any connectivity information (IP/port) to the caller. -// let isUnknownCaller = !self.contactsManager.hasSignalAccount(forRecipientId: thread.contactIdentifier()) -// -// let useTurnOnly = isUnknownCaller || Environment.shared.preferences.doCallsHideIPAddress() -// -// Logger.debug("setting peerConnectionClient for: \(newCall.identifiersForLogs)") -// let peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self, callDirection: .incoming, useTurnOnly: useTurnOnly) -// callData.peerConnectionClient = peerConnectionClient -// callData.peerConnectionClientResolver.fulfill(()) -// -// let offerSessionDescription = RTCSessionDescription(type: .offer, sdp: callerSessionDescription) -// let constraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil) -// -// // Find a sessionDescription compatible with my constraints and the remote sessionDescription -// return peerConnectionClient.negotiateSessionDescription(remoteDescription: offerSessionDescription, constraints: constraints) -// }.then { (negotiatedSessionDescription: HardenedRTCSessionDescription) -> Promise in -// guard self.call == newCall else { -// throw CallError.obsoleteCall(description: "negotiateSessionDescription() response for obsolete call") -// } -// -// Logger.info("session description for incoming call: \(newCall.identifiersForLogs), sdp: \(negotiatedSessionDescription.logSafeDescription).") -// -// do { -// let answerBuilder = SSKProtoCallMessageAnswer.builder(id: newCall.signalingId, -// sessionDescription: negotiatedSessionDescription.sdp) -// let callAnswerMessage = OWSOutgoingCallMessage(thread: thread, answerMessage: try answerBuilder.build()) -// -// return self.messageSender.sendPromise(message: callAnswerMessage) -// } catch { -// owsFailDebug("Couldn't build proto") -// throw CallError.fatalError(description: "Couldn't build proto") -// } -// }.then { () -> Promise in -// guard self.call == newCall else { -// throw CallError.obsoleteCall(description: "sendPromise(message: ) response for obsolete call") -// } -// Logger.debug("successfully sent callAnswerMessage for: \(newCall.identifiersForLogs)") -// -// // There's nothing technically forbidding receiving ICE updates before receiving the CallAnswer, but this -// // a more intuitive ordering. -// self.readyToSendIceUpdates(call: newCall) -// -// let timeout: Promise = after(seconds: connectingTimeoutSeconds).done { -// // rejecting a promise by throwing is safely a no-op if the promise has already been fulfilled -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorTimeoutWhileConnectingIncoming(), file: #file, function: #function, line: #line) -// throw CallError.timeout(description: "timed out waiting for call to connect") -// } -// -// // This will be fulfilled (potentially) by the RTCDataChannel delegate method -// return race(callData.callConnectedPromise, timeout) -// }.done { -// Logger.info(self.call == newCall -// ? "incoming call connected: \(newCall.identifiersForLogs)." -// : "obsolete incoming call connected: \(newCall.identifiersForLogs).") -// }.recover { error in -// guard self.call == newCall else { -// Logger.debug("ignoring error: \(error) for obsolete call: \(newCall.identifiersForLogs).") -// return -// } -// if let callError = error as? CallError { -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorIncomingConnectionFailedInternal(), file: #file, function: #function, line: #line) -// self.handleFailedCall(failedCall: newCall, error: callError) -// } else { -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorIncomingConnectionFailedExternal(), file: #file, function: #function, line: #line) -// let externalError = CallError.externalError(underlyingError: error) -// self.handleFailedCall(failedCall: newCall, error: externalError) -// } -// }.ensure { -// Logger.debug("ending background task awaiting inbound call connection") -// -// assert(backgroundTask != nil) -// backgroundTask = nil -// }.retainUntilComplete() -// } -// -// /** -// * Remote client (could be caller or callee) sent us a connectivity update -// */ -// public func handleRemoteAddedIceCandidate(thread: TSContactThread, callId: UInt64, sdp: String, lineIndex: Int32, mid: String) { -// AssertIsOnMainThread() -// Logger.verbose("callId: \(callId)") -// -// guard let callData = self.callData else { -// Logger.info("ignoring remote ice update, since there is no current call.") -// return -// } -// -// callData.peerConnectionClientPromise.done { -// AssertIsOnMainThread() -// -// guard let call = self.call else { -// Logger.warn("ignoring remote ice update for thread: \(String(describing: thread.uniqueId)) since there is no current call. Call already ended?") -// return -// } -// -// guard call.signalingId == callId else { -// Logger.warn("ignoring mismatched call: \(callId) currentCall: \(call.signalingId)") -// return -// } -// -// guard thread.contactIdentifier() == call.thread.contactIdentifier() else { -// Logger.warn("ignoring remote ice update for thread: \(String(describing: thread.uniqueId)) due to thread mismatch. Call already ended?") -// return -// } -// -// guard let peerConnectionClient = self.peerConnectionClient else { -// Logger.warn("ignoring remote ice update for thread: \(String(describing: thread.uniqueId)) since there is no current peerConnectionClient. Call already ended?") -// return -// } -// -// Logger.verbose("addRemoteIceCandidate") -// peerConnectionClient.addRemoteIceCandidate(RTCIceCandidate(sdp: sdp, sdpMLineIndex: lineIndex, sdpMid: mid)) -// }.catch { error in -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorHandleRemoteAddedIceCandidate(), file: #file, function: #function, line: #line) -// Logger.error("peerConnectionClientPromise failed with error: \(error)") -// }.retainUntilComplete() -// } -// -// /** -// * Local client (could be caller or callee) generated some connectivity information that we should send to the -// * remote client. -// */ -// private func handleLocalAddedIceCandidate(_ iceCandidate: RTCIceCandidate) { -// AssertIsOnMainThread() -// -// guard let callData = self.callData else { -// OWSProdError(OWSAnalyticsEvents.callServiceCallMissing(), file: #file, function: #function, line: #line) -// self.handleFailedCurrentCall(error: CallError.assertionError(description: "ignoring local ice candidate, since there is no current call.")) -// return -// } -// let call = callData.call -// -// // Wait until we've sent the CallOffer before sending any ice updates for the call to ensure -// // intuitive message ordering for other clients. -// callData.readyToSendIceUpdatesPromise.done { -// guard call == self.call else { -// self.handleFailedCurrentCall(error: .obsoleteCall(description: "current call changed since we became ready to send ice updates")) -// return -// } -// -// guard call.state != .idle else { -// // This will only be called for the current peerConnectionClient, so -// // fail the current call. -// OWSProdError(OWSAnalyticsEvents.callServiceCallUnexpectedlyIdle(), file: #file, function: #function, line: #line) -// self.handleFailedCurrentCall(error: CallError.assertionError(description: "ignoring local ice candidate, since call is now idle.")) -// return -// } -// -// guard let sdpMid = iceCandidate.sdpMid else { -// owsFailDebug("Missing sdpMid") -// throw CallError.fatalError(description: "Missing sdpMid") -// } -// -// guard iceCandidate.sdpMLineIndex < UINT32_MAX else { -// owsFailDebug("Invalid sdpMLineIndex") -// throw CallError.fatalError(description: "Invalid sdpMLineIndex") -// } -// -// Logger.info("sending ICE Candidate \(call.identifiersForLogs).") -// -// let iceUpdateProto: SSKProtoCallMessageIceUpdate -// do { -// let iceUpdateBuilder = SSKProtoCallMessageIceUpdate.builder(id: call.signalingId, -// sdpMid: sdpMid, -// sdpMlineIndex: UInt32(iceCandidate.sdpMLineIndex), -// sdp: iceCandidate.sdp) -// iceUpdateProto = try iceUpdateBuilder.build() -// } catch { -// owsFailDebug("Couldn't build proto") -// throw CallError.fatalError(description: "Couldn't build proto") -// } -// -// /** -// * Sent by both parties out of band of the RTC calling channels, as part of setting up those channels. The messages -// * include network accessibility information from the perspective of each client. Once compatible ICEUpdates have been -// * exchanged, the clients can connect. -// */ -// callData.sendOrEnqueue(outgoingIceUpdate: iceUpdateProto) -// }.catch { error in -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorHandleLocalAddedIceCandidate(), file: #file, function: #function, line: #line) -// Logger.error("waitUntilReadyToSendIceUpdates failed with error: \(error)") -// }.retainUntilComplete() -// } -// -// /** -// * The clients can now communicate via WebRTC. -// * -// * Called by both caller and callee. Compatible ICE messages have been exchanged between the local and remote -// * client. -// */ -// private func handleIceConnected() { -// AssertIsOnMainThread() -// -// guard let callData = self.callData else { -// // This will only be called for the current peerConnectionClient, so -// // fail the current call. -// OWSProdError(OWSAnalyticsEvents.callServiceCallMissing(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "ignoring \(#function) since there is no current call.")) -// return -// } -// let call = callData.call -// let callId = call.signalingId -// -// Logger.info("\(call.identifiersForLogs)") -// -// switch call.state { -// case .dialing: -// if call.state != .remoteRinging { -// BenchEventComplete(eventId: "call-\(callId)") -// } -// call.state = .remoteRinging -// case .answering: -// if call.state != .localRinging { -// BenchEventComplete(eventId: "call-\(callId)") -// } -// call.state = .localRinging -// self.callUIAdapter.reportIncomingCall(call, thread: call.thread) -// case .remoteRinging: -// Logger.info("call already ringing. Ignoring \(#function): \(call.identifiersForLogs).") -// case .connected: -// Logger.info("Call reconnected \(#function): \(call.identifiersForLogs).") -// case .reconnecting: -// call.state = .connected -// case .idle, .localRinging, .localFailure, .localHangup, .remoteHangup, .remoteBusy: -// owsFailDebug("unexpected call state: \(call.state): \(call.identifiersForLogs).") -// } -// } -// -// private func handleIceDisconnected() { -// AssertIsOnMainThread() -// -// guard let call = self.call else { -// // This will only be called for the current peerConnectionClient, so -// // fail the current call. -// OWSProdError(OWSAnalyticsEvents.callServiceCallMissing(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "ignoring \(#function) since there is no current call.")) -// return -// } -// -// Logger.info("\(call.identifiersForLogs).") -// -// switch call.state { -// case .remoteRinging, .localRinging: -// Logger.debug("disconnect while ringing... we'll keep ringing") -// case .connected: -// call.state = .reconnecting -// default: -// owsFailDebug("unexpected call state: \(call.state): \(call.identifiersForLogs).") -// } -// } -// -// /** -// * The remote client (caller or callee) ended the call. -// */ -// public func handleRemoteHangup(thread: TSContactThread, callId: UInt64) { -// AssertIsOnMainThread() -// Logger.debug("") -// -// guard let call = self.call else { -// // This may happen if we hang up slightly before they hang up. -// handleFailedCurrentCall(error: .obsoleteCall(description:"call was unexpectedly nil")) -// return -// } -// -// guard call.signalingId == callId else { -// Logger.warn("ignoring mismatched call: \(callId) currentCall: \(call.signalingId)") -// return -// } -// -// guard thread.contactIdentifier() == call.thread.contactIdentifier() else { -// // This can safely be ignored. -// // We don't want to fail the current call because an old call was slow to send us the hangup message. -// Logger.warn("ignoring hangup for thread: \(thread.contactIdentifier()) which is not the current call: \(call.identifiersForLogs)") -// return -// } -// -// Logger.info("\(call.identifiersForLogs).") -// -// switch call.state { -// case .idle, .dialing, .answering, .localRinging, .localFailure, .remoteBusy, .remoteRinging: -// handleMissedCall(call) -// case .connected, .reconnecting, .localHangup, .remoteHangup: -// Logger.info("call is finished.") -// } -// -// call.state = .remoteHangup -// // Notify UI -// callUIAdapter.remoteDidHangupCall(call) -// -// // self.call is nil'd in `terminateCall`, so it's important we update it's state *before* calling `terminateCall` -// terminateCall() -// } -// -// /** -// * User chose to answer call referred to by call `localId`. Used by the Callee only. -// * -// * Used by notification actions which can't serialize a call object. -// */ -// @objc public func handleAnswerCall(localId: UUID) { -// AssertIsOnMainThread() -// -// guard let call = self.call else { -// // This should never happen; return to a known good state. -// owsFailDebug("call was unexpectedly nil") -// OWSProdError(OWSAnalyticsEvents.callServiceCallMissing(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "call was unexpectedly nil")) -// return -// } -// -// guard call.localId == localId else { -// // This should never happen; return to a known good state. -// owsFailDebug("callLocalId:\(localId) doesn't match current calls: \(call.localId)") -// OWSProdError(OWSAnalyticsEvents.callServiceCallIdMismatch(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "callLocalId:\(localId) doesn't match current calls: \(call.localId)")) -// return -// } -// -// self.handleAnswerCall(call) -// } -// -// /** -// * User chose to answer call referred to by call `localId`. Used by the Callee only. -// */ -// public func handleAnswerCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// Logger.debug("") -// -// guard let currentCallData = self.callData else { -// OWSProdError(OWSAnalyticsEvents.callServiceCallDataMissing(), file: #file, function: #function, line: #line) -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "callData unexpectedly nil")) -// return -// } -// -// guard call == currentCallData.call else { -// // This could conceivably happen if the other party of an old call was slow to send us their answer -// // and we've subsequently engaged in another call. Don't kill the current call, but just ignore it. -// Logger.warn("ignoring \(#function) for call other than current call") -// return -// } -// -// guard let peerConnectionClient = self.peerConnectionClient else { -// OWSProdError(OWSAnalyticsEvents.callServicePeerConnectionMissing(), file: #file, function: #function, line: #line) -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "missing peerconnection client")) -// return -// } -// -// Logger.info("\(call.identifiersForLogs).") -// -// // MJK TODO remove this timestamp param -// let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeIncomingIncomplete, in: call.thread) -// callRecord.save() -// call.callRecord = callRecord -// -// var messageData: Data -// do { -// let connectedBuilder = WebRTCProtoConnected.builder(id: call.signalingId) -// let dataBuilder = WebRTCProtoData.builder() -// dataBuilder.setConnected(try connectedBuilder.build()) -// messageData = try dataBuilder.buildSerializedData() -// } catch { -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "couldn't build proto")) -// return -// } -// -// peerConnectionClient.sendDataChannelMessage(data: messageData, description: "connected", isCritical: true) -// -// handleConnectedCall(currentCallData) -// } -// -// /** -// * For outgoing call, when the callee has chosen to accept the call. -// * For incoming call, when the local user has chosen to accept the call. -// */ -// private func handleConnectedCall(_ callData: SignalCallData) { -// AssertIsOnMainThread() -// Logger.info("") -// -// guard let peerConnectionClient = callData.peerConnectionClient else { -// OWSProdError(OWSAnalyticsEvents.callServicePeerConnectionMissing(), file: #file, function: #function, line: #line) -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "peerConnectionClient unexpectedly nil")) -// return -// } -// -// Logger.info("handleConnectedCall: \(callData.call.identifiersForLogs).") -// -// // cancel connection timeout -// callData.callConnectedResolver.fulfill(()) -// -// callData.call.state = .connected -// -// // We don't risk transmitting any media until the remote client has admitted to being connected. -// ensureAudioState(call: callData.call, peerConnectionClient: peerConnectionClient) -// peerConnectionClient.setLocalVideoEnabled(enabled: shouldHaveLocalVideoTrack()) -// } -// -// /** -// * Local user chose to decline the call vs. answering it. -// * -// * The call is referred to by call `localId`, which is included in Notification actions. -// * -// * Incoming call only. -// */ -// public func handleDeclineCall(localId: UUID) { -// AssertIsOnMainThread() -// -// guard let call = self.call else { -// // This should never happen; return to a known good state. -// owsFailDebug("call was unexpectedly nil") -// OWSProdError(OWSAnalyticsEvents.callServiceCallMissing(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "call was unexpectedly nil")) -// return -// } -// -// guard call.localId == localId else { -// // This should never happen; return to a known good state. -// owsFailDebug("callLocalId:\(localId) doesn't match current calls: \(call.localId)") -// OWSProdError(OWSAnalyticsEvents.callServiceCallIdMismatch(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "callLocalId:\(localId) doesn't match current calls: \(call.localId)")) -// return -// } -// -// self.handleDeclineCall(call) -// } -// -// /** -// * Local user chose to decline the call vs. answering it. -// * -// * Incoming call only. -// */ -// public func handleDeclineCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// Logger.info("\(call.identifiersForLogs).") -// -// if let callRecord = call.callRecord { -// owsFailDebug("Not expecting callrecord to already be set") -// callRecord.updateCallType(RPRecentCallTypeIncomingDeclined) -// } else { -// // MJK TODO remove this timestamp param -// let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeIncomingDeclined, in: call.thread) -// callRecord.save() -// call.callRecord = callRecord -// } -// -// // Currently we just handle this as a hangup. But we could offer more descriptive action. e.g. DataChannel message -// handleLocalHungupCall(call) -// } -// -// /** -// * Local user chose to end the call. -// * -// * Can be used for Incoming and Outgoing calls. -// */ -// func handleLocalHungupCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// guard let currentCall = self.call else { -// Logger.info("No current call. Other party hung up just before us.") -// -// // terminating the call might be redundant, but it shouldn't hurt. -// terminateCall() -// return -// } -// -// guard call == currentCall else { -// OWSProdError(OWSAnalyticsEvents.callServiceCallMismatch(), file: #file, function: #function, line: #line) -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "ignoring \(#function) for call other than current call")) -// return -// } -// -// Logger.info("\(call.identifiersForLogs).") -// -// call.state = .localHangup -// -// if let callRecord = call.callRecord { -// if callRecord.callType == RPRecentCallTypeOutgoingIncomplete { -// callRecord.updateCallType(RPRecentCallTypeOutgoingMissed) -// } -// } else { -// owsFailDebug("missing call record") -// } -// -// // TODO something like this lifted from Signal-Android. -// // this.accountManager.cancelInFlightRequests(); -// // this.messageSender.cancelInFlightRequests(); -// -// if let peerConnectionClient = self.peerConnectionClient { -// // Stop audio capture ASAP -// ensureAudioState(call: call, peerConnectionClient: peerConnectionClient) -// -// // If the call is connected, we can send the hangup via the data channel for faster hangup. -// -// var messageData: Data -// do { -// let hangupBuilder = WebRTCProtoHangup.builder(id: call.signalingId) -// let dataBuilder = WebRTCProtoData.builder() -// dataBuilder.setHangup(try hangupBuilder.build()) -// messageData = try dataBuilder.buildSerializedData() -// } catch { -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "couldn't build proto")) -// return -// } -// -// peerConnectionClient.sendDataChannelMessage(data: messageData, description: "hangup", isCritical: true) -// } else { -// Logger.info("ending call before peer connection created. Device offline or quick hangup.") -// } -// -// // If the call hasn't started yet, we don't have a data channel to communicate the hang up. Use Signal Service Message. -// do { -// let hangupBuilder = SSKProtoCallMessageHangup.builder(id: call.signalingId) -// let callMessage = OWSOutgoingCallMessage(thread: call.thread, hangupMessage: try hangupBuilder.build()) -// -// self.messageSender.sendPromise(message: callMessage) -// .done { -// Logger.debug("successfully sent hangup call message to \(call.thread.contactIdentifier())") -// }.catch { error in -// OWSProdInfo(OWSAnalyticsEvents.callServiceErrorHandleLocalHungupCall(), file: #file, function: #function, line: #line) -// Logger.error("failed to send hangup call message to \(call.thread.contactIdentifier()) with error: \(error)") -// }.retainUntilComplete() -// -// terminateCall() -// } catch { -// handleFailedCall(failedCall: call, error: CallError.assertionError(description: "couldn't build proto")) -// } -// } -// -// /** -// * Local user toggled to mute audio. -// * -// * Can be used for Incoming and Outgoing calls. -// */ -// func setIsMuted(call: SignalCall, isMuted: Bool) { -// AssertIsOnMainThread() -// -// guard call == self.call else { -// // This can happen after a call has ended. Reproducible on iOS11, when the other party ends the call. -// Logger.info("ignoring mute request for obsolete call") -// return -// } -// -// call.isMuted = isMuted -// -// guard let peerConnectionClient = self.peerConnectionClient else { -// // The peer connection might not be created yet. -// return -// } -// -// ensureAudioState(call: call, peerConnectionClient: peerConnectionClient) -// } -// -// /** -// * Local user toggled to hold call. Currently only possible via CallKit screen, -// * e.g. when another Call comes in. -// */ -// func setIsOnHold(call: SignalCall, isOnHold: Bool) { -// AssertIsOnMainThread() -// -// guard call == self.call else { -// Logger.info("ignoring held request for obsolete call") -// return -// } -// -// call.isOnHold = isOnHold -// -// guard let peerConnectionClient = self.peerConnectionClient else { -// // The peer connection might not be created yet. -// return -// } -// -// ensureAudioState(call: call, peerConnectionClient: peerConnectionClient) -// } -// -// func ensureAudioState(call: SignalCall, peerConnectionClient: PeerConnectionClient) { -// guard call.state == .connected else { -// peerConnectionClient.setAudioEnabled(enabled: false) -// return -// } -// guard !call.isMuted else { -// peerConnectionClient.setAudioEnabled(enabled: false) -// return -// } -// guard !call.isOnHold else { -// peerConnectionClient.setAudioEnabled(enabled: false) -// return -// } -// -// peerConnectionClient.setAudioEnabled(enabled: true) -// } -// -// /** -// * Local user toggled video. -// * -// * Can be used for Incoming and Outgoing calls. -// */ -// func setHasLocalVideo(hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// -// guard let frontmostViewController = UIApplication.shared.frontmostViewController else { -// owsFailDebug("could not identify frontmostViewController") -// return -// } -// -// frontmostViewController.ows_ask(forCameraPermissions: { [weak self] granted in -// guard let strongSelf = self else { -// return -// } -// -// if (granted) { -// // Success callback; camera permissions are granted. -// strongSelf.setHasLocalVideoWithCameraPermissions(hasLocalVideo: hasLocalVideo) -// } else { -// // Failed callback; camera permissions are _NOT_ granted. -// -// // We don't need to worry about the user granting or remoting this permission -// // during a call while the app is in the background, because changing this -// // permission kills the app. -// OWSAlerts.showAlert(title: NSLocalizedString("MISSING_CAMERA_PERMISSION_TITLE", comment: "Alert title when camera is not authorized"), -// message: NSLocalizedString("MISSING_CAMERA_PERMISSION_MESSAGE", comment: "Alert body when camera is not authorized")) -// } -// }) -// } -// -// private func setHasLocalVideoWithCameraPermissions(hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// -// guard let call = self.call else { -// // This can happen if you toggle local video right after -// // the other user ends the call. -// Logger.debug("Ignoring event from obsolete call") -// return -// } -// -// call.hasLocalVideo = hasLocalVideo -// -// guard let peerConnectionClient = self.peerConnectionClient else { -// // The peer connection might not be created yet. -// return -// } -// -// if call.state == .connected { -// peerConnectionClient.setLocalVideoEnabled(enabled: shouldHaveLocalVideoTrack()) -// } -// } -// -// @objc -// func handleCallKitStartVideo() { -// AssertIsOnMainThread() -// -// self.setHasLocalVideo(hasLocalVideo: true) -// } -// -// func setCameraSource(call: SignalCall, isUsingFrontCamera: Bool) { -// AssertIsOnMainThread() -// -// guard let peerConnectionClient = self.peerConnectionClient else { -// return -// } -// -// peerConnectionClient.setCameraSource(isUsingFrontCamera: isUsingFrontCamera) -// } -// -// /** -// * Local client received a message on the WebRTC data channel. -// * -// * The WebRTC data channel is a faster signaling channel than out of band Signal Service messages. Once it's -// * established we use it to communicate further signaling information. The one sort-of exception is that with -// * hangup messages we redundantly send a Signal Service hangup message, which is more reliable, and since the hangup -// * action is idemptotent, there's no harm done. -// * -// * Used by both Incoming and Outgoing calls. -// */ -// private func handleDataChannelMessage(_ message: WebRTCProtoData) { -// AssertIsOnMainThread() -// -// guard let callData = self.callData else { -// // This should never happen; return to a known good state. -// owsFailDebug("received data message, but there is no current call. Ignoring.") -// OWSProdError(OWSAnalyticsEvents.callServiceCallMissing(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "received data message, but there is no current call. Ignoring.")) -// return -// } -// let call = callData.call -// -// if let connected = message.connected { -// Logger.debug("remote participant sent Connected via data channel: \(call.identifiersForLogs).") -// -// guard connected.id == call.signalingId else { -// // This should never happen; return to a known good state. -// owsFailDebug("received connected message for call with id:\(connected.id) but current call has id:\(call.signalingId)") -// OWSProdError(OWSAnalyticsEvents.callServiceCallIdMismatch(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "received connected message for call with id:\(connected.id) but current call has id:\(call.signalingId)")) -// return -// } -// -// self.callUIAdapter.recipientAcceptedCall(call) -// handleConnectedCall(callData) -// -// } else if let hangup = message.hangup { -// Logger.debug("remote participant sent Hangup via data channel: \(call.identifiersForLogs).") -// -// guard hangup.id == call.signalingId else { -// // This should never happen; return to a known good state. -// owsFailDebug("received hangup message for call with id:\(hangup.id) but current call has id:\(call.signalingId)") -// OWSProdError(OWSAnalyticsEvents.callServiceCallIdMismatch(), file: #file, function: #function, line: #line) -// handleFailedCurrentCall(error: CallError.assertionError(description: "received hangup message for call with id:\(hangup.id) but current call has id:\(call.signalingId)")) -// return -// } -// -// handleRemoteHangup(thread: call.thread, callId: hangup.id) -// } else if let videoStreamingStatus = message.videoStreamingStatus { -// Logger.debug("remote participant sent VideoStreamingStatus via data channel: \(call.identifiersForLogs).") -// -// callData.isRemoteVideoEnabled = videoStreamingStatus.enabled -// self.fireDidUpdateVideoTracks() -// } else { -// Logger.info("received unknown or empty DataChannelMessage: \(call.identifiersForLogs).") -// } -// } -// -// // MARK: - PeerConnectionClientDelegate -// -// /** -// * The connection has been established. The clients can now communicate. -// */ -// internal func peerConnectionClientIceConnected(_ peerConnectionClient: PeerConnectionClient) { -// AssertIsOnMainThread() -// -// guard peerConnectionClient == self.peerConnectionClient else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// -// self.handleIceConnected() -// } -// -// func peerConnectionClientIceDisconnected(_ peerconnectionClient: PeerConnectionClient) { -// AssertIsOnMainThread() -// -// guard peerConnectionClient == self.peerConnectionClient else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// -// self.handleIceDisconnected() -// } -// -// /** -// * The connection failed to establish. The clients will not be able to communicate. -// */ -// internal func peerConnectionClientIceFailed(_ peerConnectionClient: PeerConnectionClient) { -// AssertIsOnMainThread() -// -// guard peerConnectionClient == self.peerConnectionClient else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// -// // Return to a known good state. -// self.handleFailedCurrentCall(error: CallError.disconnected) -// } -// -// /** -// * During the Signaling process each client generates IceCandidates locally, which contain information about how to -// * reach the local client via the internet. The delegate must shuttle these IceCandates to the other (remote) client -// * out of band, as part of establishing a connection over WebRTC. -// */ -// internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, addedLocalIceCandidate iceCandidate: RTCIceCandidate) { -// AssertIsOnMainThread() -// -// guard peerConnectionClient == self.peerConnectionClient else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// -// self.handleLocalAddedIceCandidate(iceCandidate) -// } -// -// /** -// * Once the peerconnection is established, we can receive messages via the data channel, and notify the delegate. -// */ -// internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, received dataChannelMessage: WebRTCProtoData) { -// AssertIsOnMainThread() -// -// guard peerConnectionClient == self.peerConnectionClient else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// -// self.handleDataChannelMessage(dataChannelMessage) -// } -// -// internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, didUpdateLocalVideoCaptureSession captureSession: AVCaptureSession?) { -// AssertIsOnMainThread() -// -// guard peerConnectionClient == self.peerConnectionClient else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// guard let callData = callData else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// -// callData.localCaptureSession = captureSession -// fireDidUpdateVideoTracks() -// } -// -// internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, didUpdateRemoteVideoTrack videoTrack: RTCVideoTrack?) { -// AssertIsOnMainThread() -// -// guard peerConnectionClient == self.peerConnectionClient else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// guard let callData = callData else { -// Logger.debug("Ignoring event from obsolete peerConnectionClient") -// return -// } -// -// callData.remoteVideoTrack = videoTrack -// fireDidUpdateVideoTracks() -// } -// -// // MARK: - -// -// /** -// * RTCIceServers are used when attempting to establish an optimal connection to the other party. SignalService supplies -// * a list of servers, plus we have fallback servers hardcoded in the app. -// */ -// private func getIceServers() -> Promise<[RTCIceServer]> { -// -// return self.accountManager.getTurnServerInfo() -// .map(on: DispatchQueue.global()) { turnServerInfo -> [RTCIceServer] in -// Logger.debug("got turn server urls: \(turnServerInfo.urls)") -// -// return turnServerInfo.urls.map { url in -// if url.hasPrefix("turn") { -// // Only "turn:" servers require authentication. Don't include the credentials to other ICE servers -// // as 1.) they aren't used, and 2.) the non-turn servers might not be under our control. -// // e.g. we use a public fallback STUN server. -// return RTCIceServer(urlStrings: [url], username: turnServerInfo.username, credential: turnServerInfo.password) -// } else { -// return RTCIceServer(urlStrings: [url]) -// } -// } + [CallService.fallbackIceServer] -// }.recover(on: DispatchQueue.global()) { (error: Error) -> Guarantee<[RTCIceServer]> in -// Logger.error("fetching ICE servers failed with error: \(error)") -// Logger.warn("using fallback ICE Servers") -// -// return Guarantee.value([CallService.fallbackIceServer]) -// } -// } -// -// // This method should be called when either: a) we know or assume that -// // the error is related to the current call. b) the error is so serious -// // that we want to terminate the current call (if any) in order to -// // return to a known good state. -// public func handleFailedCurrentCall(error: CallError) { -// Logger.debug("") -// -// // Return to a known good state by ending the current call, if any. -// handleFailedCall(failedCall: self.call, error: error) -// } -// -// // This method should be called when a fatal error occurred for a call. -// // -// // * If we know which call it was, we should update that call's state -// // to reflect the error. -// // * IFF that call is the current call, we want to terminate it. -// public func handleFailedCall(failedCall: SignalCall?, error: CallError) { -// AssertIsOnMainThread() -// -// if case CallError.assertionError(description: let description) = error { -// owsFailDebug(description) -// } -// -// if let failedCall = failedCall { -// -// switch failedCall.state { -// case .answering, .localRinging: -// assert(failedCall.callRecord == nil) -// // call failed before any call record could be created, make one now. -// handleMissedCall(failedCall) -// default: -// assert(failedCall.callRecord != nil) -// } -// -// // It's essential to set call.state before terminateCall, because terminateCall nils self.call -// failedCall.error = error -// failedCall.state = .localFailure -// self.callUIAdapter.failCall(failedCall, error: error) -// -// // Only terminate the current call if the error pertains to the current call. -// guard failedCall == self.call else { -// Logger.debug("ignoring obsolete call: \(failedCall.identifiersForLogs).") -// return -// } -// -// Logger.error("call: \(failedCall.identifiersForLogs) failed with error: \(error)") -// } else { -// Logger.error("unknown call failed with error: \(error)") -// } -// -// // Only terminate the call if it is the current call. -// terminateCall() -// } -// -// /** -// * Clean up any existing call state and get ready to receive a new call. -// */ -// private func terminateCall() { -// AssertIsOnMainThread() -// -// Logger.debug("") -// -// let currentCallData = self.callData -// self.callData = nil -// -// currentCallData?.terminate() -// -// self.callUIAdapter.didTerminateCall(currentCallData?.call) -// -// fireDidUpdateVideoTracks() -// -// // Apparently WebRTC will sometimes disable device orientation notifications. -// // After every call ends, we need to ensure they are enabled. -// UIDevice.current.beginGeneratingDeviceOrientationNotifications() -// } -// -// // MARK: - CallObserver -// -// internal func stateDidChange(call: SignalCall, state: CallState) { -// AssertIsOnMainThread() -// Logger.info("\(state)") -// -// updateIsVideoEnabled() -// } -// -// internal func hasLocalVideoDidChange(call: SignalCall, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// Logger.info("\(hasLocalVideo)") -// -// self.updateIsVideoEnabled() -// } -// -// internal func muteDidChange(call: SignalCall, isMuted: Bool) { -// AssertIsOnMainThread() -// // Do nothing -// } -// -// internal func holdDidChange(call: SignalCall, isOnHold: Bool) { -// AssertIsOnMainThread() -// // Do nothing -// } -// -// internal func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) { -// AssertIsOnMainThread() -// // Do nothing -// } -// -// // MARK: - Video -// -// private func shouldHaveLocalVideoTrack() -> Bool { -// AssertIsOnMainThread() -// -// guard let call = self.call else { -// return false -// } -// -// // The iOS simulator doesn't provide any sort of camera capture -// // support or emulation (http://goo.gl/rHAnC1) so don't bother -// // trying to open a local stream. -// return (!Platform.isSimulator && -// UIApplication.shared.applicationState != .background && -// call.state == .connected && -// call.hasLocalVideo) -// } -// -// //TODO only fire this when it's changed? as of right now it gets called whenever you e.g. lock the phone while it's incoming ringing. -// private func updateIsVideoEnabled() { -// AssertIsOnMainThread() -// -// guard let call = self.call else { -// return -// } -// guard let peerConnectionClient = self.peerConnectionClient else { -// return -// } -// -// let shouldHaveLocalVideoTrack = self.shouldHaveLocalVideoTrack() -// -// Logger.info("\(shouldHaveLocalVideoTrack)") -// -// self.peerConnectionClient?.setLocalVideoEnabled(enabled: shouldHaveLocalVideoTrack) -// -// var messageData: Data -// do { -// let videoStreamingStatusBuilder = WebRTCProtoVideoStreamingStatus.builder(id: call.signalingId) -// videoStreamingStatusBuilder.setEnabled(shouldHaveLocalVideoTrack) -// let dataBuilder = WebRTCProtoData.builder() -// dataBuilder.setVideoStreamingStatus(try videoStreamingStatusBuilder.build()) -// messageData = try dataBuilder.buildSerializedData() -// } catch { -// Logger.error("couldn't build proto") -// return -// } -// -// peerConnectionClient.sendDataChannelMessage(data: messageData, description: "videoStreamingStatus", isCritical: false) -// } -// -// // MARK: - Observers -// -// // The observer-related methods should be invoked on the main thread. -// func addObserverAndSyncState(observer: CallServiceObserver) { -// AssertIsOnMainThread() -// -// observers.append(Weak(value: observer)) -// -// // Synchronize observer with current call state -// let remoteVideoTrack = self.isRemoteVideoEnabled ? self.remoteVideoTrack : nil -// observer.didUpdateVideoTracks(call: self.call, -// localCaptureSession: self.localCaptureSession, -// remoteVideoTrack: remoteVideoTrack) -// } -// -// // The observer-related methods should be invoked on the main thread. -// func removeObserver(_ observer: CallServiceObserver) { -// AssertIsOnMainThread() -// -// while let index = observers.firstIndex(where: { $0.value === observer }) { -// observers.remove(at: index) -// } -// } -// -// // The observer-related methods should be invoked on the main thread. -// func removeAllObservers() { -// AssertIsOnMainThread() -// -// observers = [] -// } -// -// private func fireDidUpdateVideoTracks() { -// AssertIsOnMainThread() -// -// let remoteVideoTrack = self.isRemoteVideoEnabled ? self.remoteVideoTrack : nil -// for observer in observers { -// observer.value?.didUpdateVideoTracks(call: self.call, -// localCaptureSession: self.localCaptureSession, -// remoteVideoTrack: remoteVideoTrack) -// } -// } -// -// // MARK: CallViewController Timer -// -// var activeCallTimer: Timer? -// func startCallTimer() { -// AssertIsOnMainThread() -// -// stopAnyCallTimer() -// assert(self.activeCallTimer == nil) -// -// self.activeCallTimer = WeakTimer.scheduledTimer(timeInterval: 1, target: self, userInfo: nil, repeats: true) { [weak self] timer in -// guard let strongSelf = self else { -// return -// } -// -// guard let call = strongSelf.call else { -// owsFailDebug("call has since ended. Timer should have been invalidated.") -// timer.invalidate() -// return -// } -// -// strongSelf.ensureCallScreenPresented(call: call) -// } -// } -// -// func ensureCallScreenPresented(call: SignalCall) { -// guard let currentCall = self.call else { -// owsFailDebug("obsolete call: \(call.identifiersForLogs)") -// return -// } -// guard currentCall == call else { -// owsFailDebug("obsolete call: \(call.identifiersForLogs)") -// return -// } -// -// guard let connectedDate = call.connectedDate else { -// // Ignore; call hasn't connected yet. -// return -// } -// -// let kMaxViewPresentationDelay: Double = 5 -// guard fabs(connectedDate.timeIntervalSinceNow) > kMaxViewPresentationDelay else { -// // Ignore; call connected recently. -// return -// } -// -// guard !call.isTerminated else { -// // There's a brief window between when the callViewController is removed -// // and when this timer is terminated. -// // -// // We don't want to fail a call that's already terminated. -// Logger.debug("ignoring screen protection check for already terminated call.") -// return -// } -// -// if !OWSWindowManager.shared().hasCall() { -// OWSProdError(OWSAnalyticsEvents.callServiceCallViewCouldNotPresent(), file: #file, function: #function, line: #line) -// owsFailDebug("Call terminated due to missing call view.") -// self.handleFailedCall(failedCall: call, error: CallError.assertionError(description: "Call view didn't present after \(kMaxViewPresentationDelay) seconds")) -// return -// } -// } -// -// func stopAnyCallTimer() { -// AssertIsOnMainThread() -// -// self.activeCallTimer?.invalidate() -// self.activeCallTimer = nil -// } -// -// // MARK: - SignalCallDataDelegate -// -// func outgoingIceUpdateDidFail(call: SignalCall, error: Error) { -// AssertIsOnMainThread() -// -// guard self.call == call else { -// Logger.warn("obsolete call") -// return -// } -// -// handleFailedCall(failedCall: call, error: CallError.messageSendFailure(underlyingError: error)) -// } -//} -// -//extension RPRecentCallType: CustomStringConvertible { -// public var description: String { -// switch self { -// case RPRecentCallTypeIncoming: -// return "RPRecentCallTypeIncoming" -// case RPRecentCallTypeOutgoing: -// return "RPRecentCallTypeOutgoing" -// case RPRecentCallTypeIncomingMissed: -// return "RPRecentCallTypeIncomingMissed" -// case RPRecentCallTypeOutgoingIncomplete: -// return "RPRecentCallTypeOutgoingIncomplete" -// case RPRecentCallTypeIncomingIncomplete: -// return "RPRecentCallTypeIncomingIncomplete" -// case RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity: -// return "RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity" -// case RPRecentCallTypeIncomingDeclined: -// return "RPRecentCallTypeIncomingDeclined" -// case RPRecentCallTypeOutgoingMissed: -// return "RPRecentCallTypeOutgoingMissed" -// default: -// owsFailDebug("unexpected RPRecentCallType: \(self)") -// return "RPRecentCallTypeUnknown" -// } -// } -//} diff --git a/Session/Signal/CallUIAdapter.swift b/Session/Signal/CallUIAdapter.swift deleted file mode 100644 index 7710a6c0f..000000000 --- a/Session/Signal/CallUIAdapter.swift +++ /dev/null @@ -1,307 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import PromiseKit -//import CallKit -//import SignalUtilitiesKit -//import SignalUtilitiesKit -//import WebRTC -// -//protocol CallUIAdaptee { -// var notificationPresenter: NotificationPresenter { get } -// var callService: CallService { get } -// var hasManualRinger: Bool { get } -// -// func startOutgoingCall(handle: String) -> SignalCall -// func reportIncomingCall(_ call: SignalCall, callerName: String) -// func reportMissedCall(_ call: SignalCall, callerName: String) -// func answerCall(localId: UUID) -// func answerCall(_ call: SignalCall) -// func declineCall(localId: UUID) -// func declineCall(_ call: SignalCall) -// func recipientAcceptedCall(_ call: SignalCall) -// func localHangupCall(_ call: SignalCall) -// func remoteDidHangupCall(_ call: SignalCall) -// func remoteBusy(_ call: SignalCall) -// func failCall(_ call: SignalCall, error: CallError) -// func setIsMuted(call: SignalCall, isMuted: Bool) -// func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) -// func startAndShowOutgoingCall(recipientId: String, hasLocalVideo: Bool) -//} -// -//// Shared default implementations -//extension CallUIAdaptee { -// internal func showCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// let callViewController = CallViewController(call: call) -// callViewController.modalTransitionStyle = .crossDissolve -// -// if CallViewController.kShowCallViewOnSeparateWindow { -// OWSWindowManager.shared().startCall(callViewController) -// } else { -// guard let presentingViewController = UIApplication.shared.frontmostViewControllerIgnoringAlerts else { -// owsFailDebug("view controller unexpectedly nil") -// return -// } -// -// if let presentedViewController = presentingViewController.presentedViewController { -// presentedViewController.dismiss(animated: false) { -// presentingViewController.present(callViewController, animated: true) -// } -// } else { -// presentingViewController.present(callViewController, animated: true) -// } -// } -// } -// -// internal func reportMissedCall(_ call: SignalCall, callerName: String) { -// AssertIsOnMainThread() -// -// notificationPresenter.presentMissedCall(call, callerName: callerName) -// } -// -// internal func startAndShowOutgoingCall(recipientId: String, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// -// guard self.callService.call == nil else { -// owsFailDebug("unexpectedly found an existing call when trying to start outgoing call: \(recipientId)") -// return -// } -// -// let call = self.startOutgoingCall(handle: recipientId) -// call.hasLocalVideo = hasLocalVideo -// self.showCall(call) -// } -//} -// -///** -// * Notify the user of call related activities. -// * Driven by either a CallKit or System notifications adaptee -// */ -//@objc public class CallUIAdapter: NSObject, CallServiceObserver { -// -// private let adaptee: CallUIAdaptee -// private let contactsManager: OWSContactsManager -// internal let audioService: CallAudioService -// internal let callService: CallService -// -// public required init(callService: CallService, contactsManager: OWSContactsManager, notificationPresenter: NotificationPresenter) { -// AssertIsOnMainThread() -// -// self.contactsManager = contactsManager -// self.callService = callService -// -// if Platform.isSimulator { -// // CallKit doesn't seem entirely supported in simulator. -// // e.g. you can't receive calls in the call screen. -// // So we use the non-CallKit call UI. -// Logger.info("choosing non-callkit adaptee for simulator.") -// adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationPresenter: notificationPresenter) -// } else if CallUIAdapter.isCallkitDisabledForLocale { -// Logger.info("choosing non-callkit adaptee due to locale.") -// adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationPresenter: notificationPresenter) -// } else if #available(iOS 11, *) { -// Logger.info("choosing callkit adaptee for iOS11+") -// let showNames = Environment.shared.preferences.notificationPreviewType() != .noNameNoPreview -// let useSystemCallLog = Environment.shared.preferences.isSystemCallLogEnabled() -// -// adaptee = CallKitCallUIAdaptee(callService: callService, contactsManager: contactsManager, notificationPresenter: notificationPresenter, showNamesOnCallScreen: showNames, useSystemCallLog: useSystemCallLog) -// } else if #available(iOS 10.0, *), Environment.shared.preferences.isCallKitEnabled() { -// Logger.info("choosing callkit adaptee for iOS10") -// let hideNames = Environment.shared.preferences.isCallKitPrivacyEnabled() || Environment.shared.preferences.notificationPreviewType() == .noNameNoPreview -// let showNames = !hideNames -// -// // All CallKit calls use the system call log on iOS10 -// let useSystemCallLog = true -// -// adaptee = CallKitCallUIAdaptee(callService: callService, contactsManager: contactsManager, notificationPresenter: notificationPresenter, showNamesOnCallScreen: showNames, useSystemCallLog: useSystemCallLog) -// } else { -// Logger.info("choosing non-callkit adaptee") -// adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationPresenter: notificationPresenter) -// } -// -// audioService = CallAudioService(handleRinging: adaptee.hasManualRinger) -// -// super.init() -// -// // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings -// -// callService.addObserverAndSyncState(observer: self) -// } -// -// @objc -// public static var isCallkitDisabledForLocale: Bool { -// let locale = Locale.current -// guard let regionCode = locale.regionCode else { -// owsFailDebug("Missing region code.") -// return false -// } -// -// // Apple has stopped approving apps that use CallKit functionality in mainland China. -// // When the "CN" region is enabled, this check simply switches to the same pre-CallKit -// // interface that is still used by everyone on iOS 9. -// // -// // For further reference: https://forums.developer.apple.com/thread/103083 -// return regionCode == "CN" -// } -// -// // MARK: Dependencies -// -// var audioSession: OWSAudioSession { -// return Environment.shared.audioSession -// } -// -// // MARK: -// -// internal func reportIncomingCall(_ call: SignalCall, thread: TSContactThread) { -// AssertIsOnMainThread() -// -// // make sure we don't terminate audio session during call -// _ = audioSession.startAudioActivity(call.audioActivity) -// -// let callerName = self.contactsManager.displayName(forPhoneIdentifier: call.remotePhoneNumber) -// adaptee.reportIncomingCall(call, callerName: callerName) -// } -// -// internal func reportMissedCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// let callerName = self.contactsManager.displayName(forPhoneIdentifier: call.remotePhoneNumber) -// adaptee.reportMissedCall(call, callerName: callerName) -// } -// -// internal func startOutgoingCall(handle: String) -> SignalCall { -// AssertIsOnMainThread() -// -// let call = adaptee.startOutgoingCall(handle: handle) -// return call -// } -// -// @objc public func answerCall(localId: UUID) { -// AssertIsOnMainThread() -// -// adaptee.answerCall(localId: localId) -// } -// -// internal func answerCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// adaptee.answerCall(call) -// } -// -// @objc public func declineCall(localId: UUID) { -// AssertIsOnMainThread() -// -// adaptee.declineCall(localId: localId) -// } -// -// internal func declineCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// adaptee.declineCall(call) -// } -// -// internal func didTerminateCall(_ call: SignalCall?) { -// AssertIsOnMainThread() -// -// if let call = call { -// self.audioSession.endAudioActivity(call.audioActivity) -// } -// } -// -// @objc public func startAndShowOutgoingCall(recipientId: String, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// -// adaptee.startAndShowOutgoingCall(recipientId: recipientId, hasLocalVideo: hasLocalVideo) -// } -// -// internal func recipientAcceptedCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// adaptee.recipientAcceptedCall(call) -// } -// -// internal func remoteDidHangupCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// adaptee.remoteDidHangupCall(call) -// } -// -// internal func remoteBusy(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// adaptee.remoteBusy(call) -// } -// -// internal func localHangupCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// adaptee.localHangupCall(call) -// } -// -// internal func failCall(_ call: SignalCall, error: CallError) { -// AssertIsOnMainThread() -// -// adaptee.failCall(call, error: error) -// } -// -// internal func showCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// adaptee.showCall(call) -// } -// -// internal func setIsMuted(call: SignalCall, isMuted: Bool) { -// AssertIsOnMainThread() -// -// // With CallKit, muting is handled by a CXAction, so it must go through the adaptee -// adaptee.setIsMuted(call: call, isMuted: isMuted) -// } -// -// internal func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// -// adaptee.setHasLocalVideo(call: call, hasLocalVideo: hasLocalVideo) -// } -// -// internal func setAudioSource(call: SignalCall, audioSource: AudioSource?) { -// AssertIsOnMainThread() -// -// // AudioSource is not handled by CallKit (e.g. there is no CXAction), so we handle it w/o going through the -// // adaptee, relying on the AudioService CallObserver to put the system in a state consistent with the call's -// // assigned property. -// call.audioSource = audioSource -// } -// -// internal func setCameraSource(call: SignalCall, isUsingFrontCamera: Bool) { -// AssertIsOnMainThread() -// -// callService.setCameraSource(call: call, isUsingFrontCamera: isUsingFrontCamera) -// } -// -// // CallKit handles ringing state on it's own. But for non-call kit we trigger ringing start/stop manually. -// internal var hasManualRinger: Bool { -// AssertIsOnMainThread() -// -// return adaptee.hasManualRinger -// } -// -// // MARK: - CallServiceObserver -// -// internal func didUpdateCall(call: SignalCall?) { -// AssertIsOnMainThread() -// -// call?.addObserverAndSyncState(observer: audioService) -// } -// -// internal func didUpdateVideoTracks(call: SignalCall?, -// localCaptureSession: AVCaptureSession?, -// remoteVideoTrack: RTCVideoTrack?) { -// AssertIsOnMainThread() -// -// audioService.didUpdateVideoTracks(call: call) -// } -//} diff --git a/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m index d3c18cf51..7f12a6ae6 100644 --- a/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m +++ b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m @@ -11,7 +11,6 @@ #import "UIView+OWS.h" #import #import -#import #import #import @@ -290,8 +289,6 @@ typedef void (^SystemMessageActionBlock)(void); break; } } - } else if ([interaction isKindOfClass:[TSCall class]]) { - result = [UIImage imageNamed:@"system_message_call"]; } else { OWSFailDebug(@"Unknown interaction type: %@", [interaction class]); return nil; diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index d58e70587..f2a941323 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -16,7 +16,6 @@ #import "DateUtil.h" #import #import "OWSAudioPlayer.h" - #import "OWSConversationSettingsViewController.h" #import "OWSConversationSettingsViewDelegate.h" #import "OWSDisappearingMessagesJob.h" @@ -27,7 +26,6 @@ #import "Session-Swift.h" #import #import "TSAttachmentPointer.h" -#import #import "TSContactThread.h" #import "TSDatabaseView.h" #import "TSErrorMessage.h" @@ -45,7 +43,6 @@ #import #import #import -#import #import #import #import @@ -557,7 +554,7 @@ typedef enum : NSUInteger { } TSGroupThread *groupThread = (TSGroupThread *)self.thread; - return !groupThread.isCurrentUserInGroup; + return !groupThread.isCurrentUserMemberInGroup; } - (void)hideInputIfNeeded diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index 593cf28a7..529afe50f 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -760,10 +760,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) TSInfoMessage *infoMessage = (TSInfoMessage *)self.interaction; return [infoMessage previewTextWithTransaction:transaction]; } - case OWSInteractionType_Call: { - TSCall *call = (TSCall *)self.interaction; - return [call previewTextWithTransaction:transaction]; - } default: OWSFailDebug(@"not a system message."); return nil; diff --git a/Session/Signal/ConversationView/ConversationViewModel.m b/Session/Signal/ConversationView/ConversationViewModel.m index 12a2c5cae..c791e5474 100644 --- a/Session/Signal/ConversationView/ConversationViewModel.m +++ b/Session/Signal/ConversationView/ConversationViewModel.m @@ -9,11 +9,8 @@ #import "OWSQuotedReplyModel.h" #import "Session-Swift.h" #import -#import - #import #import - #import #import #import @@ -1041,133 +1038,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; return nil; } -- (nullable OWSContactOffersInteraction *) - tryToBuildContactOffersInteractionWithTransaction:(YapDatabaseReadTransaction *)transaction - loadedInteractions:(NSArray *)loadedInteractions - canLoadMoreItems:(BOOL)canLoadMoreItems -{ - OWSAssertDebug(transaction); - OWSAssertDebug(self.conversationProfileState); - - if (canLoadMoreItems) { - // Only show contact offers at the start of the conversation. - return nil; - } - - BOOL hasLocalProfile = self.conversationProfileState.hasLocalProfile; - BOOL isThreadInProfileWhitelist = self.conversationProfileState.isThreadInProfileWhitelist; - BOOL hasUnwhitelistedMember = self.conversationProfileState.hasUnwhitelistedMember; - - TSThread *thread = self.thread; - BOOL isContactThread = [thread isKindOfClass:[TSContactThread class]]; - if (!isContactThread) { - return nil; - } - TSContactThread *contactThread = (TSContactThread *)thread; - if (contactThread.hasDismissedOffers) { - return nil; - } - - NSString *localNumber = [self.tsAccountManager localNumber]; - OWSAssertDebug(localNumber.length > 0); - - TSInteraction *firstCallOrMessage = [self firstCallOrMessageForLoadedInteractions:loadedInteractions]; - if (!firstCallOrMessage) { - return nil; - } - - BOOL hasTooManyOutgoingMessagesToBlock; - if (self.hasTooManyOutgoingMessagesToBlockCached) { - hasTooManyOutgoingMessagesToBlock = YES; - } else { - NSUInteger outgoingMessageCount = - [[TSDatabaseView threadOutgoingMessageDatabaseView:transaction] numberOfItemsInGroup:thread.uniqueId]; - - const int kMaxBlockOfferOutgoingMessageCount = 10; - hasTooManyOutgoingMessagesToBlock = (outgoingMessageCount > kMaxBlockOfferOutgoingMessageCount); - self.hasTooManyOutgoingMessagesToBlockCached = hasTooManyOutgoingMessagesToBlock; - } - - BOOL shouldHaveBlockOffer = YES; - BOOL shouldHaveAddToContactsOffer = YES; - BOOL shouldHaveAddToProfileWhitelistOffer = YES; - - NSString *recipientId = ((TSContactThread *)thread).contactIdentifier; - - if ([recipientId isEqualToString:localNumber]) { - // Don't add self to contacts. - shouldHaveAddToContactsOffer = NO; - // Don't bother to block self. - shouldHaveBlockOffer = NO; - // Don't bother adding self to profile whitelist. - shouldHaveAddToProfileWhitelistOffer = NO; - } else { - if ([[self.blockingManager blockedPhoneNumbers] containsObject:recipientId]) { - // Only create "add to contacts" offers for users which are not already blocked. - shouldHaveAddToContactsOffer = NO; - // Only create block offers for users which are not already blocked. - shouldHaveBlockOffer = NO; - // Don't create profile whitelist offers for users which are not already blocked. - shouldHaveAddToProfileWhitelistOffer = NO; - } - } - - if (hasTooManyOutgoingMessagesToBlock) { - // If the user has sent more than N messages, don't show a block offer. - shouldHaveBlockOffer = NO; - } - - BOOL hasOutgoingBeforeIncomingInteraction = [firstCallOrMessage isKindOfClass:[TSOutgoingMessage class]]; - if ([firstCallOrMessage isKindOfClass:[TSCall class]]) { - TSCall *call = (TSCall *)firstCallOrMessage; - hasOutgoingBeforeIncomingInteraction - = (call.callType == RPRecentCallTypeOutgoing || call.callType == RPRecentCallTypeOutgoingIncomplete); - } - if (hasOutgoingBeforeIncomingInteraction) { - // If there is an outgoing message before an incoming message - // the local user initiated this conversation, don't show a block offer. - shouldHaveBlockOffer = NO; - } - - if (!hasLocalProfile || isThreadInProfileWhitelist) { - // Don't show offer if thread is local user hasn't configured their profile. - // Don't show offer if thread is already in profile whitelist. - shouldHaveAddToProfileWhitelistOffer = NO; - } else if (thread.isGroupThread && !hasUnwhitelistedMember) { - // Don't show offer in group thread if all members are already individually - // whitelisted. - shouldHaveAddToProfileWhitelistOffer = NO; - } - - BOOL shouldHaveContactOffers - = (shouldHaveBlockOffer || shouldHaveAddToContactsOffer || shouldHaveAddToProfileWhitelistOffer); - if (!shouldHaveContactOffers) { - return nil; - } - - // We want the offers to be the first interactions in their - // conversation's timeline, so we back-date them to slightly before - // the first message - or at an arbitrary old timestamp if the - // conversation has no messages. - uint64_t contactOffersTimestamp = firstCallOrMessage.timestamp - 1; - // This view model uses the "unique id" to identify this interaction, - // but the interaction is never saved in the database so the specific - // value doesn't matter. - NSString *uniqueId = @"contact-offers"; - OWSContactOffersInteraction *offersMessage = - [[OWSContactOffersInteraction alloc] initInteractionWithUniqueId:uniqueId - timestamp:contactOffersTimestamp - thread:thread - hasBlockOffer:shouldHaveBlockOffer - hasAddToContactsOffer:shouldHaveAddToContactsOffer - hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer - recipientId:recipientId - beforeInteractionId:firstCallOrMessage.uniqueId]; - - OWSLogInfo(@"Creating contact offers: %@ (%llu)", offersMessage.uniqueId, offersMessage.sortId); - return offersMessage; -} - // This is a key method. It builds or rebuilds the list of // cell view models. // @@ -1243,22 +1113,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; [interactionIds addObject:interaction.uniqueId]; } - OWSContactOffersInteraction *_Nullable offers = nil; - if (offers && [interactionIds containsObject:offers.beforeInteractionId]) { - id offersItem = tryToAddViewItem(offers, transaction); - if ([offersItem.interaction isKindOfClass:[OWSContactOffersInteraction class]]) { - OWSContactOffersInteraction *oldOffers = (OWSContactOffersInteraction *)offersItem.interaction; - BOOL didChange = (oldOffers.hasBlockOffer != offers.hasBlockOffer - || oldOffers.hasAddToContactsOffer != offers.hasAddToContactsOffer - || oldOffers.hasAddToProfileWhitelistOffer != offers.hasAddToProfileWhitelistOffer); - if (didChange) { - [offersItem clearCachedLayoutState]; - } - } else { - OWSFailDebug(@"Unexpected offers item: %@", offersItem.interaction.class); - } - } - for (TSInteraction *interaction in interactions) { tryToAddViewItem(interaction, transaction); } @@ -1548,7 +1402,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; // Because the message isn't yet saved, we don't have sufficient information to build // in-memory placeholder for message types more complex than plain text. OWSAssertDebug(outgoingMessage.attachmentIds.count == 0); - OWSAssertDebug(outgoingMessage.contactShare == nil); NSMutableArray *unsavedOutgoingMessages = [self.unsavedOutgoingMessages mutableCopy]; [unsavedOutgoingMessages addObject:outgoingMessage]; diff --git a/Session/Signal/NonCallKitCallUIAdaptee.swift b/Session/Signal/NonCallKitCallUIAdaptee.swift deleted file mode 100644 index 048e5796c..000000000 --- a/Session/Signal/NonCallKitCallUIAdaptee.swift +++ /dev/null @@ -1,185 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import SignalUtilitiesKit -//import SignalUtilitiesKit -// -///** -// * Manage call related UI in a pre-CallKit world. -// */ -//class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { -// -// let notificationPresenter: NotificationPresenter -// let callService: CallService -// -// // Starting/Stopping incoming call ringing is our apps responsibility for the non CallKit interface. -// let hasManualRinger = true -// -// required init(callService: CallService, notificationPresenter: NotificationPresenter) { -// AssertIsOnMainThread() -// -// self.callService = callService -// self.notificationPresenter = notificationPresenter -// -// super.init() -// } -// -// // MARK: Dependencies -// -// var audioSession: OWSAudioSession { -// return Environment.shared.audioSession -// } -// -// // MARK: -// -// func startOutgoingCall(handle: String) -> SignalCall { -// AssertIsOnMainThread() -// -// let call = SignalCall.outgoingCall(localId: UUID(), remotePhoneNumber: handle) -// -// // make sure we don't terminate audio session during call -// let success = self.audioSession.startAudioActivity(call.audioActivity) -// assert(success) -// -// self.callService.handleOutgoingCall(call).retainUntilComplete() -// -// return call -// } -// -// func reportIncomingCall(_ call: SignalCall, callerName: String) { -// AssertIsOnMainThread() -// -// Logger.debug("") -// -// self.showCall(call) -// -// // present lock screen notification -// if UIApplication.shared.applicationState == .active { -// Logger.debug("skipping notification since app is already active.") -// } else { -// notificationPresenter.presentIncomingCall(call, callerName: callerName) -// } -// } -// -// func reportMissedCall(_ call: SignalCall, callerName: String) { -// AssertIsOnMainThread() -// -// notificationPresenter.presentMissedCall(call, callerName: callerName) -// } -// -// func answerCall(localId: UUID) { -// AssertIsOnMainThread() -// -// guard let call = self.callService.call else { -// owsFailDebug("No current call.") -// return -// } -// -// guard call.localId == localId else { -// owsFailDebug("localId does not match current call") -// return -// } -// -// self.answerCall(call) -// } -// -// func answerCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// guard call.localId == self.callService.call?.localId else { -// owsFailDebug("localId does not match current call") -// return -// } -// -// self.audioSession.isRTCAudioEnabled = true -// self.callService.handleAnswerCall(call) -// } -// -// func declineCall(localId: UUID) { -// AssertIsOnMainThread() -// -// guard let call = self.callService.call else { -// owsFailDebug("No current call.") -// return -// } -// -// guard call.localId == localId else { -// owsFailDebug("localId does not match current call") -// return -// } -// -// self.declineCall(call) -// } -// -// func declineCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// guard call.localId == self.callService.call?.localId else { -// owsFailDebug("localId does not match current call") -// return -// } -// -// self.callService.handleDeclineCall(call) -// } -// -// func recipientAcceptedCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// self.audioSession.isRTCAudioEnabled = true -// } -// -// func localHangupCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// // If both parties hang up at the same moment, -// // call might already be nil. -// guard self.callService.call == nil || call.localId == self.callService.call?.localId else { -// owsFailDebug("localId does not match current call") -// return -// } -// -// self.callService.handleLocalHungupCall(call) -// } -// -// internal func remoteDidHangupCall(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// Logger.debug("is no-op") -// } -// -// internal func remoteBusy(_ call: SignalCall) { -// AssertIsOnMainThread() -// -// Logger.debug("is no-op") -// } -// -// internal func failCall(_ call: SignalCall, error: CallError) { -// AssertIsOnMainThread() -// -// Logger.debug("is no-op") -// } -// -// func setIsMuted(call: SignalCall, isMuted: Bool) { -// AssertIsOnMainThread() -// -// guard call.localId == self.callService.call?.localId else { -// owsFailDebug("localId does not match current call") -// return -// } -// -// self.callService.setIsMuted(call: call, isMuted: isMuted) -// } -// -// func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// -// guard call.localId == self.callService.call?.localId else { -// owsFailDebug("localId does not match current call") -// return -// } -// -// self.callService.setHasLocalVideo(hasLocalVideo: hasLocalVideo) -// } -//} diff --git a/Session/Signal/OWSBackupImportJob.m b/Session/Signal/OWSBackupImportJob.m index fb11e8e43..17c857fa5 100644 --- a/Session/Signal/OWSBackupImportJob.m +++ b/Session/Signal/OWSBackupImportJob.m @@ -180,8 +180,6 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe // Kick off lazy restore on main thread. [self.backupLazyRestore clearCompleteAndRunIfNecessary]; - [self.profileManager fetchLocalUsersProfile]; - // Make sure backup is enabled once we complete // a backup restore. [OWSBackup.sharedManager setIsBackupEnabled:YES]; diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index e10b9c7c6..d4ae93edd 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -937,7 +937,7 @@ static CGRect oldframe; { if (self.isGroupThread) { TSGroupThread *groupThread = (TSGroupThread *)self.thread; - return !groupThread.isCurrentUserInGroup; + return !groupThread.isCurrentUserMemberInGroup; } return NO; diff --git a/Session/Signal/OutboundCallInitiator.swift b/Session/Signal/OutboundCallInitiator.swift deleted file mode 100644 index 59bf3bcd6..000000000 --- a/Session/Signal/OutboundCallInitiator.swift +++ /dev/null @@ -1,85 +0,0 @@ -//// -//// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import SignalUtilitiesKit -//import SignalUtilitiesKit -// -///** -// * Creates an outbound call via WebRTC. -// */ -//@objc public class OutboundCallInitiator: NSObject { -// -// @objc public override init() { -// super.init() -// -// SwiftSingletons.register(self) -// } -// -// // MARK: - Dependencies -// -// private var contactsManager: OWSContactsManager { -// return Environment.shared.contactsManager -// } -// -// private var contactsUpdater: ContactsUpdater { -// return SSKEnvironment.shared.contactsUpdater -// } -// -// // MARK: - -// -// /** -// * |handle| is a user formatted phone number, e.g. from a system contacts entry -// */ -// @discardableResult @objc public func initiateCall(handle: String) -> Bool { -// Logger.info("with handle: \(handle)") -// -// guard let recipientId = PhoneNumber(fromE164: handle)?.toE164() else { -// Logger.warn("unable to parse signalId from phone number: \(handle)") -// return false -// } -// -// return initiateCall(recipientId: recipientId, isVideo: false) -// } -// -// /** -// * |recipientId| is a e164 formatted phone number. -// */ -// @discardableResult -// @objc -// public func initiateCall(recipientId: String, -// isVideo: Bool) -> Bool { -// guard let callUIAdapter = AppEnvironment.shared.callService.callUIAdapter else { -// owsFailDebug("missing callUIAdapter") -// return false -// } -// guard let frontmostViewController = UIApplication.shared.frontmostViewController else { -// owsFailDebug("could not identify frontmostViewController") -// return false -// } -// -// let showedAlert = SafetyNumberConfirmationAlert.presentAlertIfNecessary(recipientId: recipientId, -// confirmationText: CallStrings.confirmAndCallButtonTitle, -// contactsManager: self.contactsManager, -// completion: { didConfirmIdentity in -// if didConfirmIdentity { -// _ = self.initiateCall(recipientId: recipientId, isVideo: isVideo) -// } -// }) -// guard !showedAlert else { -// return false -// } -// -// frontmostViewController.ows_ask(forMicrophonePermissions: { granted in -// guard granted == true else { -// Logger.warn("aborting due to missing microphone permissions.") -// OWSAlerts.showNoMicrophonePermissionAlert() -// return -// } -// callUIAdapter.startAndShowOutgoingCall(recipientId: recipientId, hasLocalVideo: isVideo) -// }) -// -// return true -// } -//} diff --git a/Session/Signal/SignalCall.swift b/Session/Signal/SignalCall.swift deleted file mode 100644 index 814edbbb0..000000000 --- a/Session/Signal/SignalCall.swift +++ /dev/null @@ -1,243 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import SignalUtilitiesKit -// -//public enum CallState: String { -// case idle -// case dialing -// case answering -// case remoteRinging -// case localRinging -// case connected -// case reconnecting -// case localFailure // terminal -// case localHangup // terminal -// case remoteHangup // terminal -// case remoteBusy // terminal -//} -// -//enum CallDirection { -// case outgoing, incoming -//} -// -//// All Observer methods will be invoked from the main thread. -//protocol CallObserver: class { -// func stateDidChange(call: SignalCall, state: CallState) -// func hasLocalVideoDidChange(call: SignalCall, hasLocalVideo: Bool) -// func muteDidChange(call: SignalCall, isMuted: Bool) -// func holdDidChange(call: SignalCall, isOnHold: Bool) -// func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) -//} -// -///** -// * Data model for a WebRTC backed voice/video call. -// * -// * This class' state should only be accessed on the main queue. -// */ -//@objc public class SignalCall: NSObject { -// -// var observers = [Weak]() -// -// @objc -// let remotePhoneNumber: String -// -// var isTerminated: Bool { -// switch state { -// case .localFailure, .localHangup, .remoteHangup, .remoteBusy: -// return true -// case .idle, .dialing, .answering, .remoteRinging, .localRinging, .connected, .reconnecting: -// return false -// } -// } -// -// // Signal Service identifier for this Call. Used to coordinate the call across remote clients. -// let signalingId: UInt64 -// -// let direction: CallDirection -// -// // Distinguishes between calls locally, e.g. in CallKit -// @objc -// let localId: UUID -// -// let thread: TSContactThread -// -// var callRecord: TSCall? { -// didSet { -// AssertIsOnMainThread() -// assert(oldValue == nil) -// -// updateCallRecordType() -// } -// } -// -// var hasLocalVideo = false { -// didSet { -// AssertIsOnMainThread() -// -// for observer in observers { -// observer.value?.hasLocalVideoDidChange(call: self, hasLocalVideo: hasLocalVideo) -// } -// } -// } -// -// var state: CallState { -// didSet { -// AssertIsOnMainThread() -// Logger.debug("state changed: \(oldValue) -> \(self.state) for call: \(self.identifiersForLogs)") -// -// // Update connectedDate -// if case .connected = self.state { -// // if it's the first time we've connected (not a reconnect) -// if connectedDate == nil { -// connectedDate = NSDate() -// } -// } -// -// updateCallRecordType() -// -// for observer in observers { -// observer.value?.stateDidChange(call: self, state: state) -// } -// } -// } -// -// var isMuted = false { -// didSet { -// AssertIsOnMainThread() -// -// Logger.debug("muted changed: \(oldValue) -> \(self.isMuted)") -// -// for observer in observers { -// observer.value?.muteDidChange(call: self, isMuted: isMuted) -// } -// } -// } -// -// let audioActivity: AudioActivity -// -// var audioSource: AudioSource? = nil { -// didSet { -// AssertIsOnMainThread() -// Logger.debug("audioSource changed: \(String(describing: oldValue)) -> \(String(describing: audioSource))") -// -// for observer in observers { -// observer.value?.audioSourceDidChange(call: self, audioSource: audioSource) -// } -// } -// } -// -// var isSpeakerphoneEnabled: Bool { -// guard let audioSource = self.audioSource else { -// return false -// } -// -// return audioSource.isBuiltInSpeaker -// } -// -// var isOnHold = false { -// didSet { -// AssertIsOnMainThread() -// Logger.debug("isOnHold changed: \(oldValue) -> \(self.isOnHold)") -// -// for observer in observers { -// observer.value?.holdDidChange(call: self, isOnHold: isOnHold) -// } -// } -// } -// -// var connectedDate: NSDate? -// -// var error: CallError? -// -// // MARK: Initializers and Factory Methods -// -// init(direction: CallDirection, localId: UUID, signalingId: UInt64, state: CallState, remotePhoneNumber: String) { -// self.direction = direction -// self.localId = localId -// self.signalingId = signalingId -// self.state = state -// self.remotePhoneNumber = remotePhoneNumber -// self.thread = TSContactThread.getOrCreateThread(contactId: remotePhoneNumber) -// self.audioActivity = AudioActivity(audioDescription: "[SignalCall] with \(remotePhoneNumber)", behavior: .call) -// } -// -// // A string containing the three identifiers for this call. -// var identifiersForLogs: String { -// return "{\(remotePhoneNumber), \(localId), \(signalingId)}" -// } -// -// class func outgoingCall(localId: UUID, remotePhoneNumber: String) -> SignalCall { -// return SignalCall(direction: .outgoing, localId: localId, signalingId: newCallSignalingId(), state: .dialing, remotePhoneNumber: remotePhoneNumber) -// } -// -// class func incomingCall(localId: UUID, remotePhoneNumber: String, signalingId: UInt64) -> SignalCall { -// return SignalCall(direction: .incoming, localId: localId, signalingId: signalingId, state: .answering, remotePhoneNumber: remotePhoneNumber) -// } -// -// // - -// -// func addObserverAndSyncState(observer: CallObserver) { -// AssertIsOnMainThread() -// -// observers.append(Weak(value: observer)) -// -// // Synchronize observer with current call state -// observer.stateDidChange(call: self, state: state) -// } -// -// func removeObserver(_ observer: CallObserver) { -// AssertIsOnMainThread() -// -// while let index = observers.firstIndex(where: { $0.value === observer }) { -// observers.remove(at: index) -// } -// } -// -// func removeAllObservers() { -// AssertIsOnMainThread() -// -// observers = [] -// } -// -// private func updateCallRecordType() { -// AssertIsOnMainThread() -// -// guard let callRecord = self.callRecord else { -// return -// } -// -// // Mark incomplete calls as completed if call has connected. -// if state == .connected && -// callRecord.callType == RPRecentCallTypeOutgoingIncomplete { -// callRecord.updateCallType(RPRecentCallTypeOutgoing) -// } -// if state == .connected && -// callRecord.callType == RPRecentCallTypeIncomingIncomplete { -// callRecord.updateCallType(RPRecentCallTypeIncoming) -// } -// } -// -// // MARK: Equatable -// -// static func == (lhs: SignalCall, rhs: SignalCall) -> Bool { -// return lhs.localId == rhs.localId -// } -// -// static func newCallSignalingId() -> UInt64 { -// return UInt64.ows_random() -// } -// -// // This method should only be called when the call state is "connected". -// func connectionDuration() -> TimeInterval { -// return -connectedDate!.timeIntervalSinceNow -// } -//} -// -//fileprivate extension UInt64 { -// static func ows_random() -> UInt64 { -// return Cryptography.randomUInt64() -// } -//} diff --git a/Session/Signal/WebRTCCallMessageHandler.swift b/Session/Signal/WebRTCCallMessageHandler.swift deleted file mode 100644 index 3c037e0a1..000000000 --- a/Session/Signal/WebRTCCallMessageHandler.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit -import SignalUtilitiesKit - -@objc(OWSWebRTCCallMessageHandler) -public class WebRTCCallMessageHandler: NSObject/*, OWSCallMessageHandler*/ { - - // MARK: Initializers - - @objc - public override init() - { - super.init() - - SwiftSingletons.register(self) - } - - // MARK: - Dependencies - - private var accountManager : AccountManager - { - return AppEnvironment.shared.accountManager - } -} diff --git a/Session/View Controllers/LinkDeviceVC.swift b/Session/View Controllers/LinkDeviceVC.swift deleted file mode 100644 index 1d6bba838..000000000 --- a/Session/View Controllers/LinkDeviceVC.swift +++ /dev/null @@ -1,310 +0,0 @@ - -final class LinkDeviceVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate { - private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) - private var pages: [UIViewController] = [] - private var targetVCIndex: Int? - var delegate: LinkDeviceVCDelegate? - - // MARK: Components - private lazy var tabBar: TabBar = { - let tabs = [ - TabBar.Tab(title: NSLocalizedString("vc_link_device_enter_session_id_tab_title", comment: "")) { [weak self] in - guard let self = self else { return } - self.pageVC.setViewControllers([ self.pages[0] ], direction: .forward, animated: false, completion: nil) - }, - TabBar.Tab(title: NSLocalizedString("vc_link_device_scan_qr_code_tab_title", comment: "")) { [weak self] in - guard let self = self else { return } - self.pageVC.setViewControllers([ self.pages[1] ], direction: .forward, animated: false, completion: nil) - } - ] - return TabBar(tabs: tabs) - }() - - private lazy var enterPublicKeyVC: EnterPublicKeyVC = { - let result = EnterPublicKeyVC() - result.linkDeviceVC = self - return result - }() - - private lazy var scanQRCodePlaceholderVC: ScanQRCodePlaceholderVC = { - let result = ScanQRCodePlaceholderVC() - result.linkDeviceVC = self - return result - }() - - private lazy var scanQRCodeWrapperVC: ScanQRCodeWrapperVC = { - let message = NSLocalizedString("vc_link_device_scan_qr_code_explanation", comment: "") - let result = ScanQRCodeWrapperVC(message: message) - result.delegate = self - return result - }() - - // MARK: Lifecycle - override func viewDidLoad() { - super.viewDidLoad() - setUpGradientBackground() - setUpNavBarStyle() - setNavBarTitle(NSLocalizedString("vc_link_device_title", comment: "")) - let navigationBar = navigationController!.navigationBar - // Set up navigation bar buttons - let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) - closeButton.tintColor = Colors.text - navigationItem.leftBarButtonItem = closeButton - // Set up page VC - let hasCameraAccess = (AVCaptureDevice.authorizationStatus(for: .video) == .authorized) - pages = [ enterPublicKeyVC, (hasCameraAccess ? scanQRCodeWrapperVC : scanQRCodePlaceholderVC) ] - pageVC.dataSource = self - pageVC.delegate = self - pageVC.setViewControllers([ enterPublicKeyVC ], direction: .forward, animated: false, completion: nil) - // Set up tab bar - view.addSubview(tabBar) - tabBar.pin(.leading, to: .leading, of: view) - let tabBarInset: CGFloat - if #available(iOS 13, *) { - tabBarInset = navigationBar.height() - } else { - tabBarInset = 0 - } - tabBar.pin(.top, to: .top, of: view, withInset: tabBarInset) - view.pin(.trailing, to: .trailing, of: tabBar) - // Set up page VC constraints - let pageVCView = pageVC.view! - view.addSubview(pageVCView) - pageVCView.pin(.leading, to: .leading, of: view) - pageVCView.pin(.top, to: .bottom, of: tabBar) - view.pin(.trailing, to: .trailing, of: pageVCView) - view.pin(.bottom, to: .bottom, of: pageVCView) - let screen = UIScreen.main.bounds - pageVCView.set(.width, to: screen.width) - let height: CGFloat - if #available(iOS 13, *) { - height = navigationController!.view.bounds.height - navigationBar.height() - Values.tabBarHeight - } else { - let statusBarHeight = UIApplication.shared.statusBarFrame.height - height = navigationController!.view.bounds.height - navigationBar.height() - Values.tabBarHeight - statusBarHeight - } - pageVCView.set(.height, to: height) - enterPublicKeyVC.constrainHeight(to: height) - scanQRCodePlaceholderVC.constrainHeight(to: height) - } - - // MARK: General - func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { - guard let index = pages.firstIndex(of: viewController), index != 0 else { return nil } - return pages[index - 1] - } - - func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { - guard let index = pages.firstIndex(of: viewController), index != (pages.count - 1) else { return nil } - return pages[index + 1] - } - - fileprivate func handleCameraAccessGranted() { - pages[1] = scanQRCodeWrapperVC - pageVC.setViewControllers([ scanQRCodeWrapperVC ], direction: .forward, animated: false, completion: nil) - } - - // MARK: Updating - func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { - guard let targetVC = pendingViewControllers.first, let index = pages.firstIndex(of: targetVC) else { return } - targetVCIndex = index - } - - func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating isFinished: Bool, previousViewControllers: [UIViewController], transitionCompleted isCompleted: Bool) { - guard isCompleted, let index = targetVCIndex else { return } - tabBar.selectTab(at: index) - } - - // MARK: Interaction - @objc private func close() { - dismiss(animated: true, completion: nil) - } - - func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) { - let hexEncodedPublicKey = string - requestDeviceLink(with: hexEncodedPublicKey) - } - - fileprivate func requestDeviceLink(with hexEncodedPublicKey: String) { - dismiss(animated: true) { - self.delegate?.requestDeviceLink(with: hexEncodedPublicKey) - } - } -} - -private final class EnterPublicKeyVC : UIViewController { - weak var linkDeviceVC: LinkDeviceVC! - private var spacer1HeightConstraint: NSLayoutConstraint! - private var spacer2HeightConstraint: NSLayoutConstraint! - private var spacer3HeightConstraint: NSLayoutConstraint! - private var bottomConstraint: NSLayoutConstraint! - private var linkButtonBottomOffsetConstraint: NSLayoutConstraint! - - // MARK: Components - private lazy var publicKeyTextField: TextField = { - if isIPhone6OrSmaller { - return TextField(placeholder: NSLocalizedString("vc_enter_session_id_text_field_hint", comment: ""), customHeight: 56, customVerticalInset: 12) - } else { - return TextField(placeholder: NSLocalizedString("vc_enter_session_id_text_field_hint", comment: "")) - } - }() - - // MARK: Lifecycle - override func viewDidLoad() { - // Remove background color - view.backgroundColor = .clear - // Set up title label - let titleLabel = UILabel() - titleLabel.textColor = Colors.text - titleLabel.font = .boldSystemFont(ofSize: isIPhone6OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize) - titleLabel.text = NSLocalizedString("vc_enter_session_id_title", comment: "") - titleLabel.numberOfLines = 0 - titleLabel.lineBreakMode = .byWordWrapping - // Set up explanation label - let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text - explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) - explanationLabel.text = NSLocalizedString("vc_enter_session_id_explanation", comment: "") - explanationLabel.numberOfLines = 0 - explanationLabel.lineBreakMode = .byWordWrapping - // Link button - let linkButton = Button(style: .prominentOutline, size: .large) - linkButton.setTitle(NSLocalizedString("continue_2", comment: ""), for: UIControl.State.normal) - linkButton.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize) - linkButton.addTarget(self, action: #selector(requestDeviceLink), for: UIControl.Event.touchUpInside) - let linkButtonContainer = UIView() - linkButtonContainer.addSubview(linkButton) - linkButton.pin(.leading, to: .leading, of: linkButtonContainer, withInset: Values.massiveSpacing) - linkButton.pin(.top, to: .top, of: linkButtonContainer) - linkButtonContainer.pin(.trailing, to: .trailing, of: linkButton, withInset: Values.massiveSpacing) - linkButtonContainer.pin(.bottom, to: .bottom, of: linkButton) - // Set up spacers - let topSpacer = UIView.vStretchingSpacer() - let spacer1 = UIView() - spacer1HeightConstraint = spacer1.set(.height, to: isIPhone6OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing) - let spacer2 = UIView() - spacer2HeightConstraint = spacer2.set(.height, to: isIPhone6OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing) - let bottomSpacer = UIView.vStretchingSpacer() - let linkButtonBottomOffsetSpacer = UIView() - linkButtonBottomOffsetConstraint = linkButtonBottomOffsetSpacer.set(.height, to: Values.onboardingButtonBottomOffset) - // Set up top stack view - let topStackView = UIStackView(arrangedSubviews: [ titleLabel, spacer1, explanationLabel, spacer2, publicKeyTextField ]) - topStackView.axis = .vertical - // Set up top stack view container - let topStackViewContainer = UIView() - topStackViewContainer.addSubview(topStackView) - topStackView.pin(.leading, to: .leading, of: topStackViewContainer, withInset: Values.veryLargeSpacing) - topStackView.pin(.top, to: .top, of: topStackViewContainer) - topStackViewContainer.pin(.trailing, to: .trailing, of: topStackView, withInset: Values.veryLargeSpacing) - topStackViewContainer.pin(.bottom, to: .bottom, of: topStackView) - // Set up stack view - let stackView = UIStackView(arrangedSubviews: [ topSpacer, topStackViewContainer, bottomSpacer, linkButtonContainer, linkButtonBottomOffsetSpacer ]) - stackView.axis = .vertical - stackView.alignment = .fill - view.addSubview(stackView) - stackView.pin(.leading, to: .leading, of: view) - stackView.pin(.top, to: .top, of: view) - stackView.pin(.trailing, to: .trailing, of: view) - bottomConstraint = stackView.pin(.bottom, to: .bottom, of: view) - topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true - // Set up width constraint - view.set(.width, to: UIScreen.main.bounds.width) - // Dismiss keyboard on tap - let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) - view.addGestureRecognizer(tapGestureRecognizer) - // Listen to keyboard notifications - let notificationCenter = NotificationCenter.default - notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillChangeFrameNotification(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) - notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillHideNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - // MARK: General - func constrainHeight(to height: CGFloat) { - view.set(.height, to: height) - } - - @objc private func dismissKeyboard() { - publicKeyTextField.resignFirstResponder() - } - - // MARK: Updating - @objc private func handleKeyboardWillChangeFrameNotification(_ notification: Notification) { - guard let newHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height else { return } - bottomConstraint.constant = -newHeight - linkButtonBottomOffsetConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.largeSpacing - spacer1HeightConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.mediumSpacing - spacer2HeightConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.mediumSpacing - UIView.animate(withDuration: 0.25) { - self.view.layoutIfNeeded() - } - } - - @objc private func handleKeyboardWillHideNotification(_ notification: Notification) { - bottomConstraint.constant = 0 - linkButtonBottomOffsetConstraint.constant = Values.onboardingButtonBottomOffset - spacer1HeightConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing - spacer2HeightConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing - UIView.animate(withDuration: 0.25) { - self.view.layoutIfNeeded() - } - } - - // MARK: Interaction - @objc private func requestDeviceLink() { - let hexEncodedPublicKey = publicKeyTextField.text?.trimmingCharacters(in: .whitespaces) ?? "" - linkDeviceVC.requestDeviceLink(with: hexEncodedPublicKey) - } -} - -private final class ScanQRCodePlaceholderVC : UIViewController { - weak var linkDeviceVC: LinkDeviceVC! - - override func viewDidLoad() { - // Remove background color - view.backgroundColor = .clear - // Set up explanation label - let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text - explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) - explanationLabel.text = NSLocalizedString("vc_scan_qr_code_camera_access_explanation", comment: "") - explanationLabel.numberOfLines = 0 - explanationLabel.textAlignment = .center - explanationLabel.lineBreakMode = .byWordWrapping - // Set up call to action button - let callToActionButton = UIButton() - callToActionButton.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize) - callToActionButton.setTitleColor(Colors.accent, for: UIControl.State.normal) - callToActionButton.setTitle(NSLocalizedString("vc_scan_qr_code_grant_camera_access_button_title", comment: ""), for: UIControl.State.normal) - callToActionButton.addTarget(self, action: #selector(requestCameraAccess), for: UIControl.Event.touchUpInside) - // Set up stack view - let stackView = UIStackView(arrangedSubviews: [ explanationLabel, callToActionButton ]) - stackView.axis = .vertical - stackView.spacing = Values.mediumSpacing - stackView.alignment = .center - // Set up constraints - view.set(.width, to: UIScreen.main.bounds.width) - view.addSubview(stackView) - stackView.pin(.leading, to: .leading, of: view, withInset: Values.massiveSpacing) - view.pin(.trailing, to: .trailing, of: stackView, withInset: Values.massiveSpacing) - let verticalCenteringConstraint = stackView.center(.vertical, in: view) - verticalCenteringConstraint.constant = -16 // Makes things appear centered visually - } - - func constrainHeight(to height: CGFloat) { - view.set(.height, to: height) - } - - @objc private func requestCameraAccess() { - ows_ask(forCameraPermissions: { [weak self] hasCameraAccess in - if hasCameraAccess { - self?.linkDeviceVC.handleCameraAccessGranted() - } else { - // Do nothing - } - }) - } -} diff --git a/Session/View Controllers/LinkDeviceVCDelegate.swift b/Session/View Controllers/LinkDeviceVCDelegate.swift deleted file mode 100644 index db4536eb5..000000000 --- a/Session/View Controllers/LinkDeviceVCDelegate.swift +++ /dev/null @@ -1,5 +0,0 @@ - -protocol LinkDeviceVCDelegate { - - func requestDeviceLink(with hexEncodedPublicKey: String) -} diff --git a/Session/View Controllers/QRCodeVC.swift b/Session/View Controllers/QRCodeVC.swift index 3a24506bb..7d35f1725 100644 --- a/Session/View Controllers/QRCodeVC.swift +++ b/Session/View Controllers/QRCodeVC.swift @@ -167,10 +167,6 @@ private final class ViewMyQRCodeVC : UIViewController { let explanationLabel = UILabel() explanationLabel.textColor = Colors.text explanationLabel.font = .systemFont(ofSize: Values.mediumFontSize) -// let text = NSLocalizedString("This is your QR code. Other users can scan it to start a session with you.", comment: "") -// let attributedText = NSMutableAttributedString(string: text) -// attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.mediumFontSize), range: (text as NSString).range(of: "your unique public QR code")) -// explanationLabel.attributedText = attributedText explanationLabel.text = NSLocalizedString("vc_view_my_qr_code_explanation", comment: "") explanationLabel.numberOfLines = 0 explanationLabel.textAlignment = .center diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index a8332088a..27babc0f0 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -2,8 +2,9 @@ import SessionUtilitiesKit // TODO: Implementation -public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility +public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? + public var id: String? public var failureCount: UInt = 0 // MARK: Settings diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 4fb3ab4b1..0ae9dc76d 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -2,8 +2,9 @@ import SessionUtilitiesKit // TODO: Implementation -public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility +public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? + public var id: String? public var failureCount: UInt = 0 // MARK: Settings diff --git a/SessionMessagingKit/Jobs/Job.swift b/SessionMessagingKit/Jobs/Job.swift index 1abe7b996..87f82e2f5 100644 --- a/SessionMessagingKit/Jobs/Job.swift +++ b/SessionMessagingKit/Jobs/Job.swift @@ -1,7 +1,8 @@ @objc(SNJob) -public protocol Job : class { +public protocol Job : class, NSCoding { var delegate: JobDelegate? { get set } + var id: String? { get set } var failureCount: UInt { get set } static var maxFailureCount: UInt { get } diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 366a78502..fbfac1f10 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -6,6 +6,7 @@ public final class JobQueue : NSObject, JobDelegate { @objc public static let shared = JobQueue() @objc public func add(_ job: Job, using transaction: Any) { + job.id = UUID().uuidString Configuration.shared.storage.persist(job, using: transaction) job.delegate = self job.execute() diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 1c6f9503a..40b115304 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -1,8 +1,9 @@ import SessionUtilitiesKit -public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility +public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? private let data: Data + public var id: String? private let messageServerID: UInt64? public var failureCount: UInt = 0 @@ -17,31 +18,35 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NS // MARK: Coding public init?(coder: NSCoder) { - guard let data = coder.decodeObject(forKey: "data") as! Data? else { return nil } + guard let data = coder.decodeObject(forKey: "data") as! Data?, + let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.data = data + self.id = id self.messageServerID = coder.decodeObject(forKey: "messageServerUD") as! UInt64? self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(data, forKey: "data") + coder.encode(id, forKey: "id") coder.encode(messageServerID, forKey: "messageServerID") coder.encode(failureCount, forKey: "failureCount") } // MARK: Running public func execute() { - Configuration.shared.storage.with { transaction in // Intentionally capture self + Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self Threading.workQueue.async { do { - let _ = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) + let message = try MessageReceiver.parse(self.data, using: transaction) + MessageReceiver.handle(message, messageServerID: self.messageServerID, using: transaction) self.handleSuccess() } catch { SNLog("Couldn't parse message due to error: \(error).") self.handleFailure(error: error) } } - } + }, completion: { }) } private func handleSuccess() { diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index c0a2b5d33..ab1a74038 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -5,6 +5,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi public var delegate: JobDelegate? private let message: Message private let destination: Message.Destination + public var id: String? public var failureCount: UInt = 0 // MARK: Settings @@ -22,7 +23,8 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // MARK: Coding public init?(coder: NSCoder) { guard let message = coder.decodeObject(forKey: "message") as! Message?, - var rawDestination = coder.decodeObject(forKey: "destination") as! String? else { return nil } + var rawDestination = coder.decodeObject(forKey: "destination") as! String?, + let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.message = message if rawDestination.removePrefix("contact(") { guard rawDestination.removeSuffix(")") else { return nil } @@ -41,11 +43,13 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi } else { return nil } + self.id = id self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(message, forKey: "message") + coder.encode(id, forKey: "id") switch destination { case .contact(let publicKey): coder.encode("contact(\(publicKey))", forKey: "destination") case .closedGroup(let groupPublicKey): coder.encode("closedGroup(\(groupPublicKey))", forKey: "destination") @@ -56,7 +60,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // MARK: Running public func execute() { - Configuration.shared.storage.with { transaction in // Intentionally capture self + Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self Threading.workQueue.async { MessageSender.send(self.message, to: self.destination, using: transaction).done(on: Threading.workQueue) { self.handleSuccess() @@ -65,7 +69,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi self.handleFailure(error: error) } } - } + }, completion: { }) } private func handleSuccess() { diff --git a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift index b208c7ac8..a21bb2271 100644 --- a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift +++ b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift @@ -5,6 +5,7 @@ import SessionUtilitiesKit public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? private let message: SnodeMessage + public var id: String? public var failureCount: UInt = 0 // MARK: Settings @@ -17,13 +18,16 @@ public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSC // MARK: Coding public init?(coder: NSCoder) { - guard let message = coder.decodeObject(forKey: "message") as! SnodeMessage? else { return nil } + guard let message = coder.decodeObject(forKey: "message") as! SnodeMessage?, + let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.message = message + self.id = id self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(message, forKey: "message") + coder.encode(id, forKey: "id") coder.encode(failureCount, forKey: "failureCount") } diff --git a/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift index 0d525a271..1e012b060 100644 --- a/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift @@ -22,7 +22,10 @@ public final class ClosedGroupUpdate : ControlMessage { } // MARK: Validation - public override var isValid: Bool { kind != nil } + public override var isValid: Bool { + guard super.isValid else { return false } + return kind != nil + } // MARK: Coding public required init?(coder: NSCoder) { @@ -83,7 +86,7 @@ public final class ClosedGroupUpdate : ControlMessage { // MARK: Proto Conversion public override class func fromProto(_ proto: SNProtoContent) -> ClosedGroupUpdate? { - fatalError("Not implemented.") + return nil } public override func toProto() -> SNProtoContent? { diff --git a/SessionMessagingKit/Messages/Control Message/ExpirationTimerUpdate.swift b/SessionMessagingKit/Messages/Control Message/ExpirationTimerUpdate.swift index 3abe0b232..139e60430 100644 --- a/SessionMessagingKit/Messages/Control Message/ExpirationTimerUpdate.swift +++ b/SessionMessagingKit/Messages/Control Message/ExpirationTimerUpdate.swift @@ -11,7 +11,10 @@ public final class ExpirationTimerUpdate : ControlMessage { } // MARK: Validation - public override var isValid: Bool { duration != nil } + public override var isValid: Bool { + guard super.isValid else { return false } + return duration != nil + } // MARK: Coding public required init?(coder: NSCoder) { diff --git a/SessionMessagingKit/Messages/Control Message/ReadReceipt.swift b/SessionMessagingKit/Messages/Control Message/ReadReceipt.swift index 71cedf759..fc475c023 100644 --- a/SessionMessagingKit/Messages/Control Message/ReadReceipt.swift +++ b/SessionMessagingKit/Messages/Control Message/ReadReceipt.swift @@ -12,6 +12,7 @@ public final class ReadReceipt : ControlMessage { // MARK: Validation public override var isValid: Bool { + guard super.isValid else { return false } if let timestamps = timestamps, !timestamps.isEmpty { return true } return false } diff --git a/SessionMessagingKit/Messages/Control Message/SessionRequest.swift b/SessionMessagingKit/Messages/Control Message/SessionRequest.swift index 060ea1754..ac2e05046 100644 --- a/SessionMessagingKit/Messages/Control Message/SessionRequest.swift +++ b/SessionMessagingKit/Messages/Control Message/SessionRequest.swift @@ -14,7 +14,10 @@ public final class SessionRequest : ControlMessage { } // MARK: Validation - public override var isValid: Bool { preKeyBundle != nil } + public override var isValid: Bool { + guard super.isValid else { return false } + return preKeyBundle != nil + } // MARK: Coding public required init?(coder: NSCoder) { diff --git a/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift b/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift index e623868e0..a867d77b2 100644 --- a/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift +++ b/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift @@ -26,7 +26,10 @@ public final class TypingIndicator : ControlMessage { } // MARK: Validation - public override var isValid: Bool { kind != nil } + public override var isValid: Bool { + guard super.isValid else { return false } + return kind != nil + } // MARK: Initialization public override init() { super.init() } diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index 05d1981a9..496238a86 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -7,13 +7,18 @@ public class Message : NSObject, NSCoding { // NSObject/NSCoding conformance is public var sentTimestamp: UInt64? public var receivedTimestamp: UInt64? public var recipient: String? + public var sender: String? public class var ttl: UInt64 { 2 * 24 * 60 * 60 * 1000 } public override init() { } // MARK: Validation - public var isValid: Bool { true } + public var isValid: Bool { + if let sentTimestamp = sentTimestamp { guard sentTimestamp > 0 else { return false } } + if let receivedTimestamp = receivedTimestamp { guard receivedTimestamp > 0 else { return false } } + return sender != nil && recipient != nil + } // MARK: Coding public required init?(coder: NSCoder) { diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift index bd7f28b83..05f6839d4 100644 --- a/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift @@ -14,6 +14,7 @@ public final class VisibleMessage : Message { // MARK: Validation public override var isValid: Bool { + guard super.isValid else { return false } if !attachmentIDs.isEmpty { return true } if let text = text?.trimmingCharacters(in: .whitespacesAndNewlines), !text.isEmpty { return true } return false diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index a874a701f..c663548a4 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -8,6 +8,7 @@ internal enum MessageReceiver { case unknownEnvelopeType case noUserPublicKey case noData + case senderBlocked // Shared sender keys case invalidGroupPublicKey case noGroupPrivateKey @@ -21,6 +22,7 @@ internal enum MessageReceiver { case .unknownEnvelopeType: return "Unknown envelope type." case .noUserPublicKey: return "Couldn't find user key pair." case .noData: return "Received an empty envelope." + case .senderBlocked: return "Received a message from a blocked user." // Shared sender keys case .invalidGroupPublicKey: return "Invalid group public key." case .noGroupPrivateKey: return "Missing group private key." @@ -30,16 +32,19 @@ internal enum MessageReceiver { } } - internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> Message { + internal static func parse(_ data: Data, using transaction: Any) throws -> Message { // Parse the envelope - let envelope = try MessageWrapper.unwrap(data: data) + let envelope = try SNProtoEnvelope.parseData(data) // Decrypt the contents let plaintext: Data + let sender: String switch envelope.type { - case .unidentifiedSender: (plaintext, _) = try decryptWithSignalProtocol(envelope: envelope, using: transaction) - case .closedGroupCiphertext: (plaintext, _) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) + case .unidentifiedSender: (plaintext, sender) = try decryptWithSignalProtocol(envelope: envelope, using: transaction) + case .closedGroupCiphertext: (plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) default: throw Error.unknownEnvelopeType } + // Don't process the envelope any further if the sender is blocked + guard !Configuration.shared.storage.isBlocked(sender) else { throw Error.senderBlocked } // Parse the proto let proto: SNProtoContent do { @@ -59,6 +64,8 @@ internal enum MessageReceiver { return nil }() if let message = message { + message.sender = sender + message.recipient = Configuration.shared.storage.getUserPublicKey() message.receivedTimestamp = NSDate.millisecondTimestamp() guard message.isValid else { throw Error.invalidMessage } return message @@ -66,4 +73,31 @@ internal enum MessageReceiver { throw Error.unknownMessage } } + + internal static func handle(_ message: Message, messageServerID: UInt64?, using transaction: Any) { + switch message { + case is ReadReceipt: break + case is SessionRequest: break + case is TypingIndicator: break + case is ClosedGroupUpdate: break + case is ExpirationTimerUpdate: break + case let message as VisibleMessage: handleVisibleMessage(message, using: transaction) + default: fatalError() + } + } + + private static func handleVisibleMessage(_ message: VisibleMessage, using transaction: Any) { + let storage = Configuration.shared.storage + // Update profile if needed + if let profile = message.profile { + storage.updateProfile(for: message.sender!, from: profile, using: transaction) + } + // Persist the message + let (threadID, tsIncomingMessage) = storage.persist(message, using: transaction) + message.threadID = threadID + // Cancel any typing indicators + storage.cancelTypingIndicatorsIfNeeded(for: message.threadID!, senderPublicKey: message.sender!) + // Notify the user if needed + storage.notifyUserIfNeeded(for: tsIncomingMessage, threadID: threadID) + } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 203169e2a..1c2bf9dd0 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -29,6 +29,7 @@ public enum MessageSender { internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { message.sentTimestamp = NSDate.millisecondTimestamp() + message.sender = Configuration.shared.storage.getUserPublicKey() switch destination { case .contact(let publicKey): message.recipient = publicKey case .closedGroup(let groupPublicKey): message.recipient = groupPublicKey diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 2b3455892..c66e3c3c6 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -30,4 +30,10 @@ public protocol SessionMessagingKitStorageProtocol { func getIDForMessage(withServerID serverID: UInt64) -> UInt64? func setOpenGroupDisplayName(to displayName: String, for publicKey: String, on channel: UInt64, server: String, using transaction: Any) func setLastProfilePictureUploadDate(_ date: Date) // Stored in user defaults so no transaction is needed + func isBlocked(_ publicKey: String) -> Bool + func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) + /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. + func persist(_ message: VisibleMessage, using transaction: Any) -> (String, Any) + func cancelTypingIndicatorsIfNeeded(for threadID: String, senderPublicKey: String) + func notifyUserIfNeeded(for message: Any, threadID: String) } diff --git a/SessionPushNotificationExtension/NotificationServiceExtension.swift b/SessionPushNotificationExtension/NotificationServiceExtension.swift index 55ae73836..509e7adb7 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtension.swift +++ b/SessionPushNotificationExtension/NotificationServiceExtension.swift @@ -38,7 +38,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { decrypter.decryptEnvelope(envelope, envelopeData: data, successBlock: { result, transaction in - if let envelope = try? SSKProtoEnvelope.parseData(result.envelopeData) { + if let envelope = try? SNProtoEnvelope.parseData(result.envelopeData) { messageManager.throws_processEnvelope(envelope, plaintextData: result.plaintextData, wasReceivedByUD: wasReceivedByUD, transaction: transaction, serverID: 0) self.handleDecryptionResult(result: result, notificationContent: notificationContent, transaction: transaction) } else { @@ -59,7 +59,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { /* func handleDecryptionResult(result: OWSMessageDecryptResult, notificationContent: UNMutableNotificationContent, transaction: YapDatabaseReadWriteTransaction) { - let contentProto = try? SSKProtoContent.parseData(result.plaintextData!) + let contentProto = try? SNProtoContent.parseData(result.plaintextData!) var thread: TSThread var newNotificationBody = "" let masterPublicKey = OWSPrimaryStorage.shared().getMasterHexEncodedPublicKey(for: result.source, in: transaction) ?? result.source @@ -72,7 +72,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } let senderName = OWSUserProfile.fetch(uniqueId: masterPublicKey, transaction: transaction)?.profileName ?? SSKEnvironment.shared.contactsManager.displayName(forPhoneIdentifier: masterPublicKey) displayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderName, groupName) - let group: SSKProtoGroupContext = contentProto!.dataMessage!.group! + let group: SNProtoGroupContext = contentProto!.dataMessage!.group! let oldGroupModel = (thread as! TSGroupThread).groupModel let removedMembers = NSMutableSet(array: oldGroupModel.groupMemberIds) let newGroupModel = TSGroupModel.init(title: group.name, @@ -185,7 +185,6 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { AppSetup.setupEnvironment( appSpecificSingletonBlock: { - SSKEnvironment.shared.callMessageHandler = NoopCallMessageHandler() SSKEnvironment.shared.notificationsManager = NoopNotificationsManager() }, migrationCompletion: { [weak self] in @@ -208,7 +207,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } } - func wasReceivedByUD(envelope: SSKProtoEnvelope) -> Bool { + func wasReceivedByUD(envelope: SNProtoEnvelope) -> Bool { return (envelope.type == .unidentifiedSender && (!envelope.hasSource || envelope.source!.count < 1)) } diff --git a/SessionShareExtension/ShareViewController.swift b/SessionShareExtension/ShareViewController.swift index 675680472..556df6bc7 100644 --- a/SessionShareExtension/ShareViewController.swift +++ b/SessionShareExtension/ShareViewController.swift @@ -82,7 +82,6 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed // We shouldn't set up our environment until after we've consulted isReadyForAppExtensions. AppSetup.setupEnvironment(appSpecificSingletonBlock: { - SSKEnvironment.shared.callMessageHandler = NoopCallMessageHandler() SSKEnvironment.shared.notificationsManager = NoopNotificationsManager() }, migrationCompletion: { [weak self] in diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 419ee0233..b0fec9ae5 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -117,7 +117,6 @@ 451A13B11E13DED2000A50FD /* AppNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A13B01E13DED2000A50FD /* AppNotifications.swift */; }; 4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4520D8D41D417D8E00123472 /* Photos.framework */; }; 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */; }; - 452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; }; 452EC6DF205E9E30000E787C /* MediaGalleryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */; }; 4535186B1FC635DD00210559 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4535186A1FC635DD00210559 /* ShareViewController.swift */; }; 4535186E1FC635DD00210559 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4535186C1FC635DD00210559 /* MainInterface.storyboard */; }; @@ -127,8 +126,6 @@ 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 454A84032059C787008B8C75 /* MediaTileViewController.swift */; }; 455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DB1F1FEA0000F86704 /* Metal.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 4574A5D61DD6704700C6B692 /* CallService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4574A5D51DD6704700C6B692 /* CallService.swift */; }; - 45794E861E00620000066731 /* CallUIAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45794E851E00620000066731 /* CallUIAdapter.swift */; }; 457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457F671A20746193000EABCD /* QuotedReplyPreview.swift */; }; 45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */; }; @@ -165,20 +162,14 @@ 45BD60821DE9547E00A8F436 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45BD60811DE9547E00A8F436 /* Contacts.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 45C0DC1B1E68FE9000E04C47 /* UIApplication+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */; }; 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */; }; - 45C9DEB81DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45C9DEB71DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift */; }; 45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; }; 45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */; }; 45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */; }; 45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */; }; 45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; }; - 45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; }; 45F32C222057297A00A300D5 /* MediaDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 45B9EE9B200E91FB005D2F2D /* MediaDetailViewController.m */; }; 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */; }; 45F32C242057297A00A300D5 /* MessageDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */; }; - 45F659731E1BD99C00444429 /* CallKitCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */; }; - 45F659821E1BE77000444429 /* NonCallKitCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */; }; - 45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */; }; - 45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */; }; 4C04392A220A9EC800BAEA63 /* VoiceNoteLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C043929220A9EC800BAEA63 /* VoiceNoteLock.swift */; }; 4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; }; 4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */; }; @@ -256,8 +247,6 @@ B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; }; B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; }; - B85357C523A1F13800AAF6CD /* LinkDeviceVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C423A1F13800AAF6CD /* LinkDeviceVC.swift */; }; - B85357C723A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C623A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift */; }; B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; @@ -368,7 +357,6 @@ C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */; }; C33FDC5A255A582000E217F9 /* OWSRecipientIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC5B255A582000E217F9 /* TSYapDatabaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC5E255A582000E217F9 /* SSKProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA4255A57FF00E217F9 /* SSKProto.swift */; }; C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; @@ -387,7 +375,6 @@ C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC2255A580200E217F9 /* TSAttachment.m */; }; C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC3255A580200E217F9 /* OWSDispatch.m */; }; C33FDC7E255A582000E217F9 /* TSAttachmentStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */; }; - C33FDC80255A582000E217F9 /* Fingerprint.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC6255A580200E217F9 /* Fingerprint.pb.swift */; }; C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; }; C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC8D255A582000E217F9 /* TSThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD3255A580300E217F9 /* TSThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -423,7 +410,6 @@ C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */; }; C33FDCBB255A582000E217F9 /* AppReadiness.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB01255A580700E217F9 /* AppReadiness.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCBC255A582000E217F9 /* TSCall.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB02255A580700E217F9 /* TSCall.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; }; C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB09255A580700E217F9 /* NSError+MessageSending.m */; }; @@ -434,16 +420,13 @@ C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB17255A580800E217F9 /* FunctionalUtil.m */; }; C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB19255A580900E217F9 /* GroupUtilities.swift */; }; - C33FDCD4255A582000E217F9 /* OWSPrimaryStorage+Calling.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1A255A580900E217F9 /* OWSPrimaryStorage+Calling.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD6255A582000E217F9 /* UIImage+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1C255A580900E217F9 /* UIImage+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD7255A582000E217F9 /* OWSReadReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD8255A582000E217F9 /* OWSIncomingMessageFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */; }; C33FDCDA255A582000E217F9 /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; }; C33FDCDC255A582000E217F9 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; }; C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE0255A582000E217F9 /* FingerprintProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB26255A580A00E217F9 /* FingerprintProto.swift */; }; C33FDCE3255A582000E217F9 /* NSData+Image.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB29255A580A00E217F9 /* NSData+Image.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE4255A582000E217F9 /* OWSIncompleteCallsJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2A255A580A00E217F9 /* OWSIncompleteCallsJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE5255A582000E217F9 /* OWSProvisioningCipher.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */; }; C33FDCE6255A582000E217F9 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE9255A582000E217F9 /* ContactsManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -520,7 +503,6 @@ C33FDD4F255A582000E217F9 /* Storage+Collections.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB95255A581300E217F9 /* Storage+Collections.swift */; }; C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; }; C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD57255A582000E217F9 /* OWSCallMessageHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD58255A582000E217F9 /* TSAttachmentPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */; }; C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -553,7 +535,6 @@ C33FDD90255A582000E217F9 /* OWSUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */; }; C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */; }; - C33FDD94255A582000E217F9 /* Dictionary+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDA255A581900E217F9 /* Dictionary+Description.swift */; }; C33FDD97255A582000E217F9 /* OWSDisappearingMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */; }; C33FDD98255A582000E217F9 /* LokiPushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */; }; C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */; }; @@ -562,15 +543,12 @@ C33FDDA5255A582000E217F9 /* OWSBlockingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */; }; C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDAA255A582000E217F9 /* LokiDatabaseUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */; }; C33FDDAB255A582000E217F9 /* OWSIdentityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */; }; C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDB1255A582000E217F9 /* OWSIncompleteCallsJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF7255A581C00E217F9 /* OWSIncompleteCallsJob.m */; }; C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB3255A582000E217F9 /* OWSError.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF9255A581C00E217F9 /* OWSError.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB5255A582000E217F9 /* Storage+PublicChats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */; }; - C33FDDB7255A582000E217F9 /* OWSPrimaryStorage+Calling.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */; }; C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDBB255A582000E217F9 /* TSGroupThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC01255A581C00E217F9 /* TSGroupThread.m */; }; C33FDDBC255A582000E217F9 /* OWSPrimaryStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */; }; @@ -588,7 +566,6 @@ C33FDDD2255A582000E217F9 /* TSAttachmentPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC19255A581F00E217F9 /* OWSQueues.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */; }; - C33FDDD6255A582000E217F9 /* TSCall.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1C255A581F00E217F9 /* TSCall.m */; }; C33FDDD8255A582000E217F9 /* OWSUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */; }; C33FDDD9255A582000E217F9 /* LokiSessionRestorationImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */; }; C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */; }; @@ -669,7 +646,6 @@ C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF286255B6D85007E1867 /* VersionMigrations.m */; }; C38EF293255B6D86007E1867 /* AppSetup.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF287255B6D85007E1867 /* AppSetup.m */; }; C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF288255B6D85007E1867 /* OWSSounds.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF295255B6D86007E1867 /* NoopCallMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF289255B6D85007E1867 /* NoopCallMessageHandler.swift */; }; C38EF297255B6D86007E1867 /* OWSSounds.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF28B255B6D86007E1867 /* OWSSounds.m */; }; C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */; }; C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */; }; @@ -677,8 +653,6 @@ C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */; }; C38EF2B4255B6D9C007E1867 /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */; }; C38EF2C2255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF2C3255B6DA6007E1867 /* OWSContactOffersInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2BF255B6DA6007E1867 /* OWSContactOffersInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF2C4255B6DA6007E1867 /* OWSContactOffersInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2C0255B6DA6007E1867 /* OWSContactOffersInteraction.m */; }; C38EF2C5255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */; }; C38EF2D4255B6DAF007E1867 /* OWSProfileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */; }; C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; @@ -829,6 +803,7 @@ C3A722922558C8940043A11F /* OpenGroupAPIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */; }; C3A7229C2558E4310043A11F /* OpenGroupMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */; }; C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Description.swift */; }; + C3B7845D25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */; }; C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; }; C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE07F2554CDD70050F1E3 /* Storage.swift */; }; C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */; }; @@ -951,6 +926,7 @@ C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; + C3EEA017256487B300C338BC /* LokiDatabaseUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3EEA016256487B300C338BC /* LokiDatabaseUtilities.swift */; }; C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; }; C3F0A5EC255C970D007BE2A3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5EB255C970D007BE2A3 /* Configuration.swift */; }; C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; }; @@ -1232,7 +1208,6 @@ 451A13B01E13DED2000A50FD /* AppNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppNotifications.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldHelper.swift; sourceTree = ""; }; - 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutboundCallInitiator.swift; sourceTree = ""; }; 452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryViewController.swift; sourceTree = ""; }; 453518681FC635DD00210559 /* SessionShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 4535186A1FC635DD00210559 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; @@ -1243,8 +1218,6 @@ 454A84032059C787008B8C75 /* MediaTileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaTileViewController.swift; sourceTree = ""; }; 455A16DB1F1FEA0000F86704 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; 455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; - 4574A5D51DD6704700C6B692 /* CallService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CallService.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 45794E851E00620000066731 /* CallUIAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallUIAdapter.swift; sourceTree = ""; }; 457F671A20746193000EABCD /* QuotedReplyPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuotedReplyPreview.swift; sourceTree = ""; }; 45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerConnectionClient.swift; sourceTree = ""; }; @@ -1285,18 +1258,12 @@ 45BD60811DE9547E00A8F436 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+OWS.swift"; sourceTree = ""; }; 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard+OWS.swift"; sourceTree = ""; }; - 45C9DEB71DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebRTCCallMessageHandler.swift; sourceTree = ""; }; 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Session/Signal/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; }; 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncPushTokensJob.swift; sourceTree = ""; }; 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionResetJob.swift; sourceTree = ""; }; 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompareSafetyNumbersActivity.swift; sourceTree = ""; }; 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabel.swift; sourceTree = ""; }; - 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = ""; }; 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaPageViewController.swift; path = Session/Signal/MediaPageViewController.swift; sourceTree = SOURCE_ROOT; }; - 45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallUIAdaptee.swift; sourceTree = ""; }; - 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NonCallKitCallUIAdaptee.swift; sourceTree = ""; }; - 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallManager.swift; sourceTree = ""; }; - 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalCall.swift; sourceTree = ""; }; 4C043929220A9EC800BAEA63 /* VoiceNoteLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceNoteLock.swift; sourceTree = ""; }; 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = ""; }; 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoGridViewCell.swift; sourceTree = ""; }; @@ -1403,8 +1370,6 @@ B847570023D568EB00759540 /* SignalServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SignalServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedReminderView.swift; sourceTree = ""; }; B85357C223A1BD1200AAF6CD /* SeedVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedVC.swift; sourceTree = ""; }; - B85357C423A1F13800AAF6CD /* LinkDeviceVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkDeviceVC.swift; sourceTree = ""; }; - B85357C623A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkDeviceVCDelegate.swift; sourceTree = ""; }; B8544E3023D16CA500299F14 /* DeviceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceUtilities.swift; sourceTree = ""; }; B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceUtilities.swift; sourceTree = ""; }; B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; @@ -1509,7 +1474,6 @@ C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseDispatchQueue.swift; sourceTree = ""; }; C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSRecipientIdentity.h; sourceTree = ""; }; C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSYapDatabaseObject.h; sourceTree = ""; }; - C33FDAA4255A57FF00E217F9 /* SSKProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKProto.swift; sourceTree = ""; }; C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+SignedPreKeyStore.h"; sourceTree = ""; }; C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = ""; }; C33FDAAA255A580000E217F9 /* NSObject+Casting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Casting.m"; sourceTree = ""; }; @@ -1528,7 +1492,6 @@ C33FDAC2255A580200E217F9 /* TSAttachment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachment.m; sourceTree = ""; }; C33FDAC3255A580200E217F9 /* OWSDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDispatch.m; sourceTree = ""; }; C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentStream.m; sourceTree = ""; }; - C33FDAC6255A580200E217F9 /* Fingerprint.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fingerprint.pb.swift; sourceTree = ""; }; C33FDACD255A580200E217F9 /* SSKJobRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKJobRecord.m; sourceTree = ""; }; C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAttachmentDownloads.h; sourceTree = ""; }; C33FDAD3255A580300E217F9 /* TSThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSThread.h; sourceTree = ""; }; @@ -1564,7 +1527,6 @@ C33FDAFE255A580600E217F9 /* OWSStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSStorage.h; sourceTree = ""; }; C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayNameUtilities.swift; sourceTree = ""; }; C33FDB01255A580700E217F9 /* AppReadiness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppReadiness.h; sourceTree = ""; }; - C33FDB02255A580700E217F9 /* TSCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSCall.h; sourceTree = ""; }; C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+SessionStore.h"; sourceTree = ""; }; C33FDB07255A580700E217F9 /* OWSBackupFragment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupFragment.m; sourceTree = ""; }; C33FDB09255A580700E217F9 /* NSError+MessageSending.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+MessageSending.m"; sourceTree = ""; }; @@ -1575,16 +1537,13 @@ C33FDB14255A580800E217F9 /* OWSMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMath.h; sourceTree = ""; }; C33FDB17255A580800E217F9 /* FunctionalUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FunctionalUtil.m; sourceTree = ""; }; C33FDB19255A580900E217F9 /* GroupUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupUtilities.swift; sourceTree = ""; }; - C33FDB1A255A580900E217F9 /* OWSPrimaryStorage+Calling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+Calling.h"; sourceTree = ""; }; C33FDB1C255A580900E217F9 /* UIImage+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+OWS.h"; sourceTree = ""; }; C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSReadReceiptManager.h; sourceTree = ""; }; C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIncomingMessageFinder.m; sourceTree = ""; }; C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseSecondaryIndexes.m; sourceTree = ""; }; C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMediaUtils.swift; sourceTree = ""; }; C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseSecondaryIndexes.h; sourceTree = ""; }; - C33FDB26255A580A00E217F9 /* FingerprintProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FingerprintProto.swift; sourceTree = ""; }; C33FDB29255A580A00E217F9 /* NSData+Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Image.h"; sourceTree = ""; }; - C33FDB2A255A580A00E217F9 /* OWSIncompleteCallsJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIncompleteCallsJob.h; sourceTree = ""; }; C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProvisioningCipher.m; sourceTree = ""; }; C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseView.h; sourceTree = ""; }; C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsManagerProtocol.h; sourceTree = ""; }; @@ -1661,7 +1620,6 @@ C33FDB95255A581300E217F9 /* Storage+Collections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+Collections.swift"; sourceTree = ""; }; C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+keyFromIntLong.m"; sourceTree = ""; }; C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSIncomingMessage.h; sourceTree = ""; }; - C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCallMessageHandler.h; sourceTree = ""; }; C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentPointer.m; sourceTree = ""; }; C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageHeaders.h; sourceTree = ""; }; C33FDBA1255A581400E217F9 /* OWSOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOperation.h; sourceTree = ""; }; @@ -1694,7 +1652,6 @@ C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSUploadOperation.h; sourceTree = ""; }; C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageUtils.m; sourceTree = ""; }; C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOS.pb.swift; sourceTree = ""; }; - C33FDBDA255A581900E217F9 /* Dictionary+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Description.swift"; sourceTree = ""; }; C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesJob.m; sourceTree = ""; }; C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiPushNotificationManager.swift; sourceTree = ""; }; C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = ""; }; @@ -1703,15 +1660,12 @@ C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockingManager.h; sourceTree = ""; }; C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecipientIdentity.m; sourceTree = ""; }; C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageKeys.h; sourceTree = ""; }; - C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiDatabaseUtilities.swift; sourceTree = ""; }; C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIdentityManager.h; sourceTree = ""; }; C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayNameUtilities2.swift; sourceTree = ""; }; C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLSessionDataTask+StatusCode.h"; sourceTree = ""; }; - C33FDBF7255A581C00E217F9 /* OWSIncompleteCallsJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIncompleteCallsJob.m; sourceTree = ""; }; C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+OWS.h"; sourceTree = ""; }; C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = ""; }; C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+PublicChats.swift"; sourceTree = ""; }; - C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+Calling.m"; sourceTree = ""; }; C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+Functional.h"; sourceTree = ""; }; C33FDC01255A581C00E217F9 /* TSGroupThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSGroupThread.m; sourceTree = ""; }; C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSPrimaryStorage.m; sourceTree = ""; }; @@ -1729,7 +1683,6 @@ C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAttachmentPointer.h; sourceTree = ""; }; C33FDC19255A581F00E217F9 /* OWSQueues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQueues.h; sourceTree = ""; }; C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackgroundTask.m; sourceTree = ""; }; - C33FDC1C255A581F00E217F9 /* TSCall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSCall.m; sourceTree = ""; }; C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUploadOperation.m; sourceTree = ""; }; C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiSessionRestorationImplementation.swift; sourceTree = ""; }; C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Encryption.swift"; sourceTree = ""; }; @@ -1781,7 +1734,7 @@ C38EF23C255B6D66007E1867 /* UIColor+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIColor+OWS.h"; path = "SignalUtilitiesKit/UI/UIColor+OWS.h"; sourceTree = SOURCE_ROOT; }; C38EF23D255B6D66007E1867 /* UIView+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+OWS.h"; path = "SignalUtilitiesKit/UI/UIView+OWS.h"; sourceTree = SOURCE_ROOT; }; C38EF23E255B6D66007E1867 /* UIView+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+OWS.m"; path = "SignalUtilitiesKit/UI/UIView+OWS.m"; sourceTree = SOURCE_ROOT; }; - C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSAttributedString+OWS.h"; path = "SignalUtilitiesKit/NSAttributedString+OWS.h"; sourceTree = SOURCE_ROOT; }; + C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSAttributedString+OWS.h"; path = "SignalUtilitiesKit/Utilities/NSAttributedString+OWS.h"; sourceTree = SOURCE_ROOT; }; C38EF240255B6D67007E1867 /* UIView+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+OWS.swift"; path = "SignalUtilitiesKit/UI/UIView+OWS.swift"; sourceTree = SOURCE_ROOT; }; C38EF241255B6D67007E1867 /* Collection+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Collection+OWS.swift"; path = "SignalUtilitiesKit/Utilities/Collection+OWS.swift"; sourceTree = SOURCE_ROOT; }; C38EF242255B6D67007E1867 /* UIColor+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIColor+OWS.m"; path = "SignalUtilitiesKit/UI/UIColor+OWS.m"; sourceTree = SOURCE_ROOT; }; @@ -1799,7 +1752,6 @@ C38EF286255B6D85007E1867 /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VersionMigrations.m; path = SignalUtilitiesKit/VersionMigrations.m; sourceTree = SOURCE_ROOT; }; C38EF287255B6D85007E1867 /* AppSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppSetup.m; path = SignalUtilitiesKit/AppSetup.m; sourceTree = SOURCE_ROOT; }; C38EF288255B6D85007E1867 /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSounds.h; path = SignalUtilitiesKit/OWSSounds.h; sourceTree = SOURCE_ROOT; }; - C38EF289255B6D85007E1867 /* NoopCallMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NoopCallMessageHandler.swift; path = SignalUtilitiesKit/NoopCallMessageHandler.swift; sourceTree = SOURCE_ROOT; }; C38EF28B255B6D86007E1867 /* OWSSounds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSounds.m; path = SignalUtilitiesKit/OWSSounds.m; sourceTree = SOURCE_ROOT; }; C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Identicon+ObjC.swift"; path = "SignalUtilitiesKit/UI/Identicon+ObjC.swift"; sourceTree = SOURCE_ROOT; }; C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = SignalUtilitiesKit/UI/PlaceholderIcon.swift; sourceTree = SOURCE_ROOT; }; @@ -1807,8 +1759,6 @@ C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIView+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = SignalUtilitiesKit/TSUnreadIndicatorInteraction.h; sourceTree = SOURCE_ROOT; }; - C38EF2BF255B6DA6007E1867 /* OWSContactOffersInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSContactOffersInteraction.h; path = SignalUtilitiesKit/OWSContactOffersInteraction.h; sourceTree = SOURCE_ROOT; }; - C38EF2C0255B6DA6007E1867 /* OWSContactOffersInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSContactOffersInteraction.m; path = SignalUtilitiesKit/OWSContactOffersInteraction.m; sourceTree = SOURCE_ROOT; }; C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = SignalUtilitiesKit/TSUnreadIndicatorInteraction.m; sourceTree = SOURCE_ROOT; }; C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = "SignalUtilitiesKit/Remove Later/OWSProfileManager.m"; sourceTree = SOURCE_ROOT; }; C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SignalUtilitiesKit/Remove Later/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; @@ -1968,6 +1918,7 @@ C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupMessage+Conversion.swift"; sourceTree = ""; }; C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = "Migrating Translations from Android.md"; path = "Meta/Translations/Migrating Translations from Android.md"; sourceTree = ""; }; C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Localizable.strings; sourceTree = ""; }; + C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSIncomingMessage+Conversion.swift"; sourceTree = ""; }; C3BBE0752554CDA60050F1E3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; C3BBE07F2554CDD70050F1E3 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProofOfWork.swift; sourceTree = ""; }; @@ -2095,6 +2046,7 @@ C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = ""; }; + C3EEA016256487B300C338BC /* LokiDatabaseUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiDatabaseUtilities.swift; sourceTree = ""; }; C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = ""; }; C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; C3F0A5EB255C970D007BE2A3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; @@ -2416,17 +2368,8 @@ children = ( 76EB03C218170B33006006FC /* AppDelegate.h */, 76EB03C318170B33006006FC /* AppDelegate.m */, - 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */, - 45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */, - 45794E851E00620000066731 /* CallUIAdapter.swift */, - 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */, - 45C9DEB71DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift */, 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */, - 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */, 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */, - 4574A5D51DD6704700C6B692 /* CallService.swift */, - 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */, - 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */, 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */, 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */, 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */, @@ -2698,8 +2641,6 @@ B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */, B82B40872399EB0E00A248E7 /* LandingVC.swift */, C329FEEB24F7277900B1C64C /* LightModeSheet.swift */, - B85357C423A1F13800AAF6CD /* LinkDeviceVC.swift */, - B85357C623A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift */, B86BD08323399ACF000F5AE3 /* Modal.swift */, B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */, B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */, @@ -2884,7 +2825,6 @@ C33FDB01255A580700E217F9 /* AppReadiness.h */, C33FDB75255A581000E217F9 /* AppReadiness.m */, C33FDB4C255A580D00E217F9 /* AppVersion.h */, - C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */, C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */, C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, @@ -2903,13 +2843,10 @@ C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */, C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */, - C38EF2BF255B6DA6007E1867 /* OWSContactOffersInteraction.h */, - C38EF2C0255B6DA6007E1867 /* OWSContactOffersInteraction.m */, C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, C38EF284255B6D84007E1867 /* AppSetup.h */, C38EF287255B6D85007E1867 /* AppSetup.m */, - C38EF289255B6D85007E1867 /* NoopCallMessageHandler.swift */, C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */, C38EF288255B6D85007E1867 /* OWSSounds.h */, C38EF28B255B6D86007E1867 /* OWSSounds.m */, @@ -2926,23 +2863,11 @@ C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */, C33FDB54255A580D00E217F9 /* DataSource.h */, C33FDBB6255A581600E217F9 /* DataSource.m */, - C33FDBDA255A581900E217F9 /* Dictionary+Description.swift */, - C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, - C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, - C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, - C33FDAC6255A580200E217F9 /* Fingerprint.pb.swift */, - C33FDB26255A580A00E217F9 /* FingerprintProto.swift */, C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, C33FDC16255A581E00E217F9 /* FunctionalUtil.h */, C33FDB17255A580800E217F9 /* FunctionalUtil.m */, - C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, - C33FDB19255A580900E217F9 /* GroupUtilities.swift */, C33FDB87255A581100E217F9 /* JobQueue.swift */, - C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, - C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, - C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, - C33FDBF0255A581B00E217F9 /* LokiDatabaseUtilities.swift */, C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */, C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */, C33FDA7E255A57FB00E217F9 /* Mention.swift */, @@ -2962,13 +2887,10 @@ C33FDB07255A580700E217F9 /* OWSBackupFragment.m */, C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, - C33FDB9D255A581300E217F9 /* OWSCallMessageHandler.h */, C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */, C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */, C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */, C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */, - C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, - C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, @@ -2993,8 +2915,6 @@ C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */, C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, - C33FDB2A255A580A00E217F9 /* OWSIncompleteCallsJob.h */, - C33FDBF7255A581C00E217F9 /* OWSIncompleteCallsJob.m */, C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */, C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */, @@ -3052,12 +2972,9 @@ C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */, C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */, C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, - C33FDAA4255A57FF00E217F9 /* SSKProto.swift */, C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, C33FDB94255A581300E217F9 /* TSAccountManager.h */, C33FDB88255A581200E217F9 /* TSAccountManager.m */, - C33FDB02255A580700E217F9 /* TSCall.h */, - C33FDC1C255A581F00E217F9 /* TSCall.m */, C33FDC12255A581E00E217F9 /* TSConstants.h */, C33FDABE255A580100E217F9 /* TSConstants.m */, C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, @@ -3211,6 +3128,8 @@ C3851CE3256250FA0061EEB0 /* Remove Later */ = { isa = PBXGroup; children = ( + C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, + C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */, C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */, @@ -3258,6 +3177,8 @@ C38BBA0D255E321C0041B9A3 /* Messages */ = { isa = PBXGroup; children = ( + C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, + C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, C33FDBB0255A581500E217F9 /* TSErrorMessage.h */, C33FDAE7255A580500E217F9 /* TSErrorMessage.m */, @@ -3295,8 +3216,6 @@ C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */, C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, - C33FDB1A255A580900E217F9 /* OWSPrimaryStorage+Calling.h */, - C33FDBFD255A581C00E217F9 /* OWSPrimaryStorage+Calling.m */, C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */, C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */, C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */, @@ -3321,6 +3240,7 @@ C38BBA17255E327A0041B9A3 /* Move to main app */ = { isa = PBXGroup; children = ( + C3EEA016256487B300C338BC /* LokiDatabaseUtilities.swift */, C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */, C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */, C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */, @@ -3705,6 +3625,12 @@ C3CA3B11255CF17200F4C6D4 /* Utilities */ = { isa = PBXGroup; children = ( + C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, + C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, + C33FDB19255A580900E217F9 /* GroupUtilities.swift */, + C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, + C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, + C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, C33FDB81255A581100E217F9 /* UIImage+OWS.m */, C33FDB49255A580C00E217F9 /* WeakTimer.swift */, @@ -3761,8 +3687,10 @@ C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */, C38EF2EF255B6DBB007E1867 /* Weak.swift */, C38EF2FA255B6DBD007E1867 /* Bench.swift */, + C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */, C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */, C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */, + C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, ); path = Utilities; sourceTree = ""; @@ -3957,10 +3885,7 @@ C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */, C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */, C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */, - C33FDCBC255A582000E217F9 /* TSCall.h in Headers */, - C38EF2C3255B6DA6007E1867 /* OWSContactOffersInteraction.h in Headers */, C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */, - C33FDCD4255A582000E217F9 /* OWSPrimaryStorage+Calling.h in Headers */, C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */, C33FDC5B255A582000E217F9 /* TSYapDatabaseObject.h in Headers */, C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */, @@ -4001,12 +3926,10 @@ C33FDD16255A582000E217F9 /* NSArray+Functional.h in Headers */, C38EF35B255B6DCC007E1867 /* SelectThreadViewController.h in Headers */, C33FDCE9255A582000E217F9 /* ContactsManagerProtocol.h in Headers */, - C33FDCE4255A582000E217F9 /* OWSIncompleteCallsJob.h in Headers */, C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */, C33FDC96255A582000E217F9 /* NSObject+Casting.h in Headers */, C33FDC75255A582000E217F9 /* OWSGroupsOutputStream.h in Headers */, C33FDDB3255A582000E217F9 /* OWSError.h in Headers */, - C33FDD57255A582000E217F9 /* OWSCallMessageHandler.h in Headers */, C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */, C38EF403255B6DF7007E1867 /* ContactCellView.h in Headers */, C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */, @@ -4952,7 +4875,6 @@ C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */, C38EF330255B6DBF007E1867 /* OWSWindowManager.m in Sources */, C33FDD79255A582000E217F9 /* OWSHTTPSecurityPolicy.m in Sources */, - C33FDDB7255A582000E217F9 /* OWSPrimaryStorage+Calling.m in Sources */, C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */, C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */, C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */, @@ -4972,14 +4894,12 @@ C33FDD0A255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.m in Sources */, C33FDC4E255A582000E217F9 /* Data+Streaming.swift in Sources */, C33FDCE5255A582000E217F9 /* OWSProvisioningCipher.m in Sources */, - C33FDDD6255A582000E217F9 /* TSCall.m in Sources */, C33FDD1A255A582000E217F9 /* TSMessage.m in Sources */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */, C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */, C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */, - C33FDC80255A582000E217F9 /* Fingerprint.pb.swift in Sources */, C33FDD42255A582000E217F9 /* TSAccountManager.m in Sources */, C38EF3FB255B6DF7007E1867 /* UIAlertController+OWS.swift in Sources */, C33FDC53255A582000E217F9 /* OutageDetection.swift in Sources */, @@ -4987,6 +4907,7 @@ C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */, C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */, C33FDD00255A582000E217F9 /* TSDatabaseView.m in Sources */, + C3EEA017256487B300C338BC /* LokiDatabaseUtilities.swift in Sources */, C33FDD3B255A582000E217F9 /* UIImage+OWS.m in Sources */, C33FDD5F255A582000E217F9 /* SignalServiceProfile.swift in Sources */, C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */, @@ -5010,12 +4931,10 @@ C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */, C38EF2C5255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m in Sources */, C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */, - C38EF2C4255B6DA6007E1867 /* OWSContactOffersInteraction.m in Sources */, C38EF388255B6DD2007E1867 /* AttachmentApprovalViewController.swift in Sources */, C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */, C33FDC72255A582000E217F9 /* NSArray+Functional.m in Sources */, C33FDD38255A582000E217F9 /* TSPreKeyManager.m in Sources */, - C33FDD94255A582000E217F9 /* Dictionary+Description.swift in Sources */, C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */, C38EF22C255B6D5D007E1867 /* OWSVideoPlayer.swift in Sources */, C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */, @@ -5093,7 +5012,6 @@ C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */, C33FDC69255A582000E217F9 /* String+Trimming.swift in Sources */, C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */, - C33FDDB1255A582000E217F9 /* OWSIncompleteCallsJob.m in Sources */, C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */, C38EF3C4255B6DE7007E1867 /* ImageEditorContents.swift in Sources */, C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */, @@ -5112,11 +5030,11 @@ C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */, C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */, C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */, + C3B7845D25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift in Sources */, C33FDCF4255A582000E217F9 /* Poller.swift in Sources */, C38EF332255B6DBF007E1867 /* OWSPreferences.m in Sources */, C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */, C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */, - C33FDC5E255A582000E217F9 /* SSKProto.swift in Sources */, C38EF39E255B6DDA007E1867 /* OWSQuotedReplyModel.m in Sources */, C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, @@ -5139,7 +5057,6 @@ C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */, C38EF3BB255B6DE7007E1867 /* ImageEditorStrokeItem.swift in Sources */, C33FDCA1255A582000E217F9 /* TSErrorMessage.m in Sources */, - C38EF295255B6D86007E1867 /* NoopCallMessageHandler.swift in Sources */, C38EF3C0255B6DE7007E1867 /* ImageEditorCropViewController.swift in Sources */, C38EF401255B6DF7007E1867 /* VideoPlayerView.swift in Sources */, C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */, @@ -5156,7 +5073,6 @@ C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */, C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */, C33FDC78255A582000E217F9 /* TSConstants.m in Sources */, - C33FDCE0255A582000E217F9 /* FingerprintProto.swift in Sources */, C38EF324255B6DBF007E1867 /* Bench.swift in Sources */, C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */, C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */, @@ -5173,7 +5089,6 @@ C33FDCFE255A582000E217F9 /* OWSContactsOutputStream.m in Sources */, C33FDDBC255A582000E217F9 /* OWSPrimaryStorage.m in Sources */, C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */, - C33FDDAA255A582000E217F9 /* LokiDatabaseUtilities.swift in Sources */, C33FDC2B255A581F00E217F9 /* OWSReadReceiptManager.m in Sources */, C38EF326255B6DBF007E1867 /* ConversationStyle.swift in Sources */, C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */, @@ -5375,7 +5290,6 @@ 4C04392A220A9EC800BAEA63 /* VoiceNoteLock.swift in Sources */, 3496956E21A301A100DCFE74 /* OWSBackupExportJob.m in Sources */, 4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */, - 45C9DEB81DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift in Sources */, 34D1F0501F7D45A60066283D /* GifPickerCell.swift in Sources */, 3496957421A301A100DCFE74 /* OWSBackupAPI.swift in Sources */, C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */, @@ -5403,7 +5317,6 @@ EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */, 45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */, 4CEB78C92178EBAB00F315D2 /* OWSSessionResetJobRecord.m in Sources */, - 45794E861E00620000066731 /* CallUIAdapter.swift in Sources */, C396DAF32518408B00FF6DC5 /* Description.swift in Sources */, 450D19131F85236600970622 /* RemoteVideoView.m in Sources */, 34129B8621EF877A005457A8 /* LinkPreviewView.swift in Sources */, @@ -5459,7 +5372,6 @@ 34D1F0B71F87F8850066283D /* OWSGenericAttachmentView.m in Sources */, 34D920E720E179C200D51158 /* OWSMessageFooterView.m in Sources */, 341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */, - B85357C523A1F13800AAF6CD /* LinkDeviceVC.swift in Sources */, 4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */, C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */, 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */, @@ -5491,24 +5403,18 @@ B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */, C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */, 3441FD9F21A3604F00BB9542 /* BackupRestoreViewController.swift in Sources */, - 45F659821E1BE77000444429 /* NonCallKitCallUIAdaptee.swift in Sources */, 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */, 45C0DC1B1E68FE9000E04C47 /* UIApplication+OWS.swift in Sources */, - 45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */, 4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */, - 45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */, C396DAF22518408B00FF6DC5 /* NamedView.swift in Sources */, 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */, - 452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */, B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */, 34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */, - 45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */, 4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */, 340FC8B7204DAC8D007AEB0F /* OWSConversationSettingsViewController.m in Sources */, 34BECE2E1F7ABCE000D7438D /* GifPickerViewController.swift in Sources */, B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */, 34D1F0C01F8EC1760066283D /* MessageRecipientStatusUtils.swift in Sources */, - 45F659731E1BD99C00444429 /* CallKitCallUIAdaptee.swift in Sources */, 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */, 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */, C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */, @@ -5539,13 +5445,11 @@ C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */, C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */, 3448E1662215B313004B052E /* OnboardingCaptchaViewController.swift in Sources */, - 4574A5D61DD6704700C6B692 /* CallService.swift in Sources */, 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */, 340FC8AC204DAC8D007AEB0F /* PrivacySettingsTableViewController.m in Sources */, B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */, B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */, C31F812625258FB000DD9FD9 /* Storage+VolumeSamples.swift in Sources */, - B85357C723A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift in Sources */, C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */, 340FC8AE204DAC8D007AEB0F /* OWSSoundSettingsViewController.m in Sources */, 340FC8B0204DAC8D007AEB0F /* AddToBlockListViewController.m in Sources */, diff --git a/SignalUtilitiesKit/AppSetup.m b/SignalUtilitiesKit/AppSetup.m index ee84e9235..189933e35 100644 --- a/SignalUtilitiesKit/AppSetup.m +++ b/SignalUtilitiesKit/AppSetup.m @@ -8,8 +8,6 @@ #import #import #import - - #import #import #import diff --git a/SignalUtilitiesKit/Attachments/SignalAttachment.swift b/SignalUtilitiesKit/Attachments/SignalAttachment.swift index d5eadc9e4..3547fa2f5 100644 --- a/SignalUtilitiesKit/Attachments/SignalAttachment.swift +++ b/SignalUtilitiesKit/Attachments/SignalAttachment.swift @@ -586,11 +586,7 @@ public class SignalAttachment: NSObject { owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") return nil } - guard let data = datas[0] as? Data else { - owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") - return nil - } - return data + return datas[0] } // MARK: Image Attachments diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentPointer.h b/SignalUtilitiesKit/Attachments/TSAttachmentPointer.h index 55a94f5c0..8820b2c70 100644 --- a/SignalUtilitiesKit/Attachments/TSAttachmentPointer.h +++ b/SignalUtilitiesKit/Attachments/TSAttachmentPointer.h @@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWSBackupFragment; -@class SSKProtoAttachmentPointer; +@class SNProtoAttachmentPointer; @class TSAttachmentStream; @class TSMessage; @@ -57,11 +57,11 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { - (instancetype)initForRestoreWithAttachmentStream:(TSAttachmentStream *)attachmentStream NS_DESIGNATED_INITIALIZER; -+ (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto ++ (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SNProtoAttachmentPointer *)attachmentProto albumMessage:(nullable TSMessage *)message; + (NSArray *)attachmentPointersFromProtos: - (NSArray *)attachmentProtos + (NSArray *)attachmentProtos albumMessage:(TSMessage *)message; #pragma mark - Update With... Methods diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentPointer.m b/SignalUtilitiesKit/Attachments/TSAttachmentPointer.m index fe2b1fb4a..88f9f9788 100644 --- a/SignalUtilitiesKit/Attachments/TSAttachmentPointer.m +++ b/SignalUtilitiesKit/Attachments/TSAttachmentPointer.m @@ -105,7 +105,7 @@ NS_ASSUME_NONNULL_BEGIN return self; } -+ (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto ++ (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SNProtoAttachmentPointer *)attachmentProto albumMessage:(nullable TSMessage *)albumMessage { if (attachmentProto.id < 1) { @@ -139,7 +139,7 @@ NS_ASSUME_NONNULL_BEGIN TSAttachmentType attachmentType = TSAttachmentTypeDefault; if ([attachmentProto hasFlags]) { UInt32 flags = attachmentProto.flags; - if ((flags & (UInt32)SSKProtoAttachmentPointerFlagsVoiceMessage) > 0) { + if ((flags & (UInt32)SNProtoAttachmentPointerFlagsVoiceMessage) > 0) { attachmentType = TSAttachmentTypeVoiceMessage; } } @@ -176,14 +176,14 @@ NS_ASSUME_NONNULL_BEGIN } + (NSArray *)attachmentPointersFromProtos: - (NSArray *)attachmentProtos + (NSArray *)attachmentProtos albumMessage:(TSMessage *)albumMessage { OWSAssertDebug(attachmentProtos); OWSAssertDebug(albumMessage); NSMutableArray *attachmentPointers = [NSMutableArray new]; - for (SSKProtoAttachmentPointer *attachmentProto in attachmentProtos) { + for (SNProtoAttachmentPointer *attachmentProto in attachmentProtos) { TSAttachmentPointer *_Nullable attachmentPointer = [self attachmentPointerFromProto:attachmentProto albumMessage:albumMessage]; if (attachmentPointer) { @@ -206,7 +206,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug([self isDecimalNumberText:self.uniqueId]); if ([self isDecimalNumberText:self.uniqueId]) { // For legacy instances, try to parse the serverId from the uniqueId. - self.serverId = [self.uniqueId integerValue]; + self.serverId = (UInt64)[self.uniqueId integerValue]; } else { OWSLogError(@"invalid legacy attachment uniqueId: %@.", self.uniqueId); } diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentStream.h b/SignalUtilitiesKit/Attachments/TSAttachmentStream.h index ce6125ee9..76496107b 100644 --- a/SignalUtilitiesKit/Attachments/TSAttachmentStream.h +++ b/SignalUtilitiesKit/Attachments/TSAttachmentStream.h @@ -12,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN -@class SSKProtoAttachmentPointer; +@class SNProtoAttachmentPointer; @class TSAttachmentPointer; @class YapDatabaseReadWriteTransaction; @@ -99,9 +99,9 @@ typedef void (^OWSThumbnailFailure)(void); #pragma mark - Protobuf -+ (nullable SSKProtoAttachmentPointer *)buildProtoForAttachmentId:(nullable NSString *)attachmentId; ++ (nullable SNProtoAttachmentPointer *)buildProtoForAttachmentId:(nullable NSString *)attachmentId; -- (nullable SSKProtoAttachmentPointer *)buildProto; +- (nullable SNProtoAttachmentPointer *)buildProto; @end diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentStream.m b/SignalUtilitiesKit/Attachments/TSAttachmentStream.m index cd0a4ff1f..e5a6037b0 100644 --- a/SignalUtilitiesKit/Attachments/TSAttachmentStream.m +++ b/SignalUtilitiesKit/Attachments/TSAttachmentStream.m @@ -21,7 +21,7 @@ const NSUInteger ThumbnailDimensionPointsLarge() { CGSize screenSizePoints = UIScreen.mainScreen.bounds.size; const CGFloat kMinZoomFactor = 2.f; - return MAX(screenSizePoints.width, screenSizePoints.height) * kMinZoomFactor; + return (NSUInteger)MAX(screenSizePoints.width, screenSizePoints.height) * kMinZoomFactor; } typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); @@ -821,7 +821,7 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); // MARK: Protobuf serialization -+ (nullable SSKProtoAttachmentPointer *)buildProtoForAttachmentId:(nullable NSString *)attachmentId ++ (nullable SNProtoAttachmentPointer *)buildProtoForAttachmentId:(nullable NSString *)attachmentId { OWSAssertDebug(attachmentId.length > 0); @@ -839,9 +839,9 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); } -- (nullable SSKProtoAttachmentPointer *)buildProto +- (nullable SNProtoAttachmentPointer *)buildProto { - SSKProtoAttachmentPointerBuilder *builder = [SSKProtoAttachmentPointer builderWithId:self.serverId]; + SNProtoAttachmentPointerBuilder *builder = [SNProtoAttachmentPointer builderWithId:self.serverId]; OWSAssertDebug(self.contentType.length > 0); builder.contentType = self.contentType; @@ -857,7 +857,7 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); builder.size = self.byteCount; builder.key = self.encryptionKey; builder.digest = self.digest; - builder.flags = self.isVoiceMessage ? SSKProtoAttachmentPointerFlagsVoiceMessage : 0; + builder.flags = self.isVoiceMessage ? SNProtoAttachmentPointerFlagsVoiceMessage : 0; if (self.shouldHaveImageSize) { CGSize imageSize = self.imageSize; @@ -874,7 +874,7 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); builder.url = self.downloadURL; NSError *error; - SSKProtoAttachmentPointer *_Nullable attachmentProto = [builder buildAndReturnError:&error]; + SNProtoAttachmentPointer *_Nullable attachmentProto = [builder buildAndReturnError:&error]; if (error || !attachmentProto) { OWSFailDebug(@"could not build protobuf: %@", error); return nil; diff --git a/SignalUtilitiesKit/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/ClosedGroupsProtocol.swift index 7a458ae86..43d76609d 100644 --- a/SignalUtilitiesKit/ClosedGroupsProtocol.swift +++ b/SignalUtilitiesKit/ClosedGroupsProtocol.swift @@ -248,7 +248,7 @@ public final class ClosedGroupsProtocol : NSObject { // MARK: - Receiving @objc(handleSharedSenderKeysUpdateIfNeeded:from:transaction:) - public static func handleSharedSenderKeysUpdateIfNeeded(_ dataMessage: SSKProtoDataMessage, from publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { + public static func handleSharedSenderKeysUpdateIfNeeded(_ dataMessage: SNProtoDataMessage, from publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { // Note that `publicKey` is either the public key of the group or the public key of the // sender, depending on how the message was sent guard let closedGroupUpdate = dataMessage.closedGroupUpdate, isValid(closedGroupUpdate) else { return } @@ -260,7 +260,7 @@ public final class ClosedGroupsProtocol : NSObject { } } - private static func isValid(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate) -> Bool { + private static func isValid(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate) -> Bool { guard !closedGroupUpdate.groupPublicKey.isEmpty else { return false } switch closedGroupUpdate.type { case .new: return !(closedGroupUpdate.name ?? "").isEmpty && !(closedGroupUpdate.groupPrivateKey ?? Data()).isEmpty && !closedGroupUpdate.members.isEmpty @@ -271,7 +271,7 @@ public final class ClosedGroupsProtocol : NSObject { } } - private static func handleNewGroupMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, using transaction: YapDatabaseReadWriteTransaction) { + private static func handleNewGroupMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, using transaction: YapDatabaseReadWriteTransaction) { // Unwrap the message let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let name = closedGroupUpdate.name @@ -330,7 +330,7 @@ public final class ClosedGroupsProtocol : NSObject { /// Invoked upon receiving a group update. A group update is sent out when a group's name is changed, when new users are added, when users leave or are /// kicked, or if the group admins are changed. - private static func handleInfoMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, + private static func handleInfoMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { // Unwrap the message let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() @@ -397,7 +397,7 @@ public final class ClosedGroupsProtocol : NSObject { } } - private static func handleSenderKeyRequestMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { + private static func handleSenderKeyRequestMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { // Prepare let userPublicKey = getUserHexEncodedPublicKey() let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() @@ -426,7 +426,7 @@ public final class ClosedGroupsProtocol : NSObject { } /// Invoked upon receiving a sender key from another user. - private static func handleSenderKeyMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { + private static func handleSenderKeyMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { // Prepare let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() guard let senderKey = closedGroupUpdate.senderKeys.first else { @@ -451,7 +451,7 @@ public final class ClosedGroupsProtocol : NSObject { } @objc(shouldIgnoreClosedGroupMessage:inThread:wrappedIn:) - public static func shouldIgnoreClosedGroupMessage(_ dataMessage: SSKProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SSKProtoEnvelope) -> Bool { + public static func shouldIgnoreClosedGroupMessage(_ dataMessage: SNProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SNProtoEnvelope) -> Bool { guard thread.groupModel.groupType == .closedGroup else { return true } let publicKey = envelope.source! // Set during UD decryption return !thread.isUserMember(inGroup: publicKey) @@ -459,7 +459,7 @@ public final class ClosedGroupsProtocol : NSObject { /// - Note: Deprecated. @objc(shouldIgnoreClosedGroupUpdateMessage:inThread:wrappedIn:) - public static func shouldIgnoreClosedGroupUpdateMessage(_ dataMessage: SSKProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SSKProtoEnvelope) -> Bool { + public static func shouldIgnoreClosedGroupUpdateMessage(_ dataMessage: SNProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SNProtoEnvelope) -> Bool { guard thread.groupModel.groupType == .closedGroup else { return true } let publicKey = envelope.source! // Set during UD decryption return !thread.isUserAdmin(inGroup: publicKey) diff --git a/SignalUtilitiesKit/ContentProxy.swift b/SignalUtilitiesKit/ContentProxy.swift index 2efb7765f..12cf3eb2a 100644 --- a/SignalUtilitiesKit/ContentProxy.swift +++ b/SignalUtilitiesKit/ContentProxy.swift @@ -4,7 +4,6 @@ import Foundation - @objc public class ContentProxy: NSObject { diff --git a/SignalUtilitiesKit/Database/OWSDatabaseMigration.m b/SignalUtilitiesKit/Database/OWSDatabaseMigration.m index ca97b49f5..edd205151 100644 --- a/SignalUtilitiesKit/Database/OWSDatabaseMigration.m +++ b/SignalUtilitiesKit/Database/OWSDatabaseMigration.m @@ -69,8 +69,6 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertDebug(completion); - OWSDatabaseConnection *dbConnection = (OWSDatabaseConnection *)self.primaryStorage.newDatabaseConnection; - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self runUpWithTransaction:transaction]; } diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.h deleted file mode 100644 index 2ca3331f4..000000000 --- a/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSPrimaryStorage (Calling) - -// phoneNumber is an e164 formatted phone number. -// -// callKitId is expected to have CallKitCallManager.kAnonymousCallHandlePrefix. -- (void)setPhoneNumber:(NSString *)phoneNumber forCallKitId:(NSString *)callKitId; - -// returns an e164 formatted phone number or nil if no -// record can be found. -// -// callKitId is expected to have CallKitCallManager.kAnonymousCallHandlePrefix. -- (NSString *)phoneNumberForCallKitId:(NSString *)callKitId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.m deleted file mode 100644 index fd96acd7f..000000000 --- a/SignalUtilitiesKit/Database/OWSPrimaryStorage+Calling.m +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSPrimaryStorage+Calling.h" -#import "YapDatabaseConnection+OWS.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const OWSPrimaryStorageCallKitIdToPhoneNumberCollection = @"TSStorageManagerCallKitIdToPhoneNumberCollection"; - -@implementation OWSPrimaryStorage (Calling) - -- (void)setPhoneNumber:(NSString *)phoneNumber forCallKitId:(NSString *)callKitId -{ - OWSAssertDebug(phoneNumber.length > 0); - OWSAssertDebug(callKitId.length > 0); - - [self.dbReadWriteConnection setObject:phoneNumber - forKey:callKitId - inCollection:OWSPrimaryStorageCallKitIdToPhoneNumberCollection]; -} - -- (NSString *)phoneNumberForCallKitId:(NSString *)callKitId -{ - OWSAssertDebug(callKitId.length > 0); - - return - [self.dbReadConnection objectForKey:callKitId inCollection:OWSPrimaryStorageCallKitIdToPhoneNumberCollection]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage.m index 965eb093e..edd029b88 100644 --- a/SignalUtilitiesKit/Database/OWSPrimaryStorage.m +++ b/SignalUtilitiesKit/Database/OWSPrimaryStorage.m @@ -9,7 +9,6 @@ #import "OWSFailedMessagesJob.h" #import "OWSFileSystem.h" #import "OWSIncomingMessageFinder.h" -#import "OWSIncompleteCallsJob.h" #import "OWSMediaGalleryFinder.h" #import "OWSStorage+Subclass.h" #import "SSKEnvironment.h" @@ -203,7 +202,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) [OWSIncomingMessageFinder asyncRegisterExtensionWithPrimaryStorage:self]; [OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self]; [OWSFailedMessagesJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; - [OWSIncompleteCallsJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; [OWSFailedAttachmentDownloadsJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; [OWSMediaGalleryFinder asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self]; diff --git a/SignalUtilitiesKit/Dictionary+Description.swift b/SignalUtilitiesKit/Dictionary+Description.swift deleted file mode 100644 index c7aedbfe6..000000000 --- a/SignalUtilitiesKit/Dictionary+Description.swift +++ /dev/null @@ -1,13 +0,0 @@ - -public extension Dictionary { - - public var prettifiedDescription: String { - return "[ " + map { key, value in - let keyDescription = String(describing: key) - let valueDescription = String(describing: value) - let maxLength = 20 - let truncatedValueDescription = valueDescription.count > maxLength ? valueDescription.prefix(maxLength) + "..." : valueDescription - return keyDescription + " : " + truncatedValueDescription - }.joined(separator: ", ") + " ]" - } -} diff --git a/SignalUtilitiesKit/Fingerprint.pb.swift b/SignalUtilitiesKit/Fingerprint.pb.swift deleted file mode 100644 index 7ebca2ef2..000000000 --- a/SignalUtilitiesKit/Fingerprint.pb.swift +++ /dev/null @@ -1,164 +0,0 @@ -// DO NOT EDIT. -// swift-format-ignore-file -// -// Generated by the Swift generator plugin for the protocol buffer compiler. -// Source: Fingerprint.proto -// -// For information on using the generated types, please see the documentation: -// https://github.com/apple/swift-protobuf/ - -/// iOS - since we use a modern proto-compiler, we must specify -/// the legacy proto format. - -import Foundation -import SwiftProtobuf - -// If the compiler emits an error on this type, it is because this file -// was generated by a version of the `protoc` Swift plug-in that is -// incompatible with the version of SwiftProtobuf to which you are linking. -// Please ensure that you are building against the same version of the API -// that was used to generate this file. -fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { - struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} - typealias Version = _2 -} - -struct FingerprintProtos_LogicalFingerprint { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var identityData: Data { - get {return _identityData ?? SwiftProtobuf.Internal.emptyData} - set {_identityData = newValue} - } - /// Returns true if `identityData` has been explicitly set. - var hasIdentityData: Bool {return self._identityData != nil} - /// Clears the value of `identityData`. Subsequent reads from it will return its default value. - mutating func clearIdentityData() {self._identityData = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _identityData: Data? = nil -} - -struct FingerprintProtos_LogicalFingerprints { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var version: UInt32 { - get {return _version ?? 0} - set {_version = newValue} - } - /// Returns true if `version` has been explicitly set. - var hasVersion: Bool {return self._version != nil} - /// Clears the value of `version`. Subsequent reads from it will return its default value. - mutating func clearVersion() {self._version = nil} - - /// @required - var localFingerprint: FingerprintProtos_LogicalFingerprint { - get {return _localFingerprint ?? FingerprintProtos_LogicalFingerprint()} - set {_localFingerprint = newValue} - } - /// Returns true if `localFingerprint` has been explicitly set. - var hasLocalFingerprint: Bool {return self._localFingerprint != nil} - /// Clears the value of `localFingerprint`. Subsequent reads from it will return its default value. - mutating func clearLocalFingerprint() {self._localFingerprint = nil} - - /// @required - var remoteFingerprint: FingerprintProtos_LogicalFingerprint { - get {return _remoteFingerprint ?? FingerprintProtos_LogicalFingerprint()} - set {_remoteFingerprint = newValue} - } - /// Returns true if `remoteFingerprint` has been explicitly set. - var hasRemoteFingerprint: Bool {return self._remoteFingerprint != nil} - /// Clears the value of `remoteFingerprint`. Subsequent reads from it will return its default value. - mutating func clearRemoteFingerprint() {self._remoteFingerprint = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _version: UInt32? = nil - fileprivate var _localFingerprint: FingerprintProtos_LogicalFingerprint? = nil - fileprivate var _remoteFingerprint: FingerprintProtos_LogicalFingerprint? = nil -} - -// MARK: - Code below here is support for the SwiftProtobuf runtime. - -fileprivate let _protobuf_package = "FingerprintProtos" - -extension FingerprintProtos_LogicalFingerprint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".LogicalFingerprint" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "identityData"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._identityData) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._identityData { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: FingerprintProtos_LogicalFingerprint, rhs: FingerprintProtos_LogicalFingerprint) -> Bool { - if lhs._identityData != rhs._identityData {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension FingerprintProtos_LogicalFingerprints: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".LogicalFingerprints" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "version"), - 2: .same(proto: "localFingerprint"), - 3: .same(proto: "remoteFingerprint"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt32Field(value: &self._version) - case 2: try decoder.decodeSingularMessageField(value: &self._localFingerprint) - case 3: try decoder.decodeSingularMessageField(value: &self._remoteFingerprint) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._version { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 1) - } - if let v = self._localFingerprint { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } - if let v = self._remoteFingerprint { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: FingerprintProtos_LogicalFingerprints, rhs: FingerprintProtos_LogicalFingerprints) -> Bool { - if lhs._version != rhs._version {return false} - if lhs._localFingerprint != rhs._localFingerprint {return false} - if lhs._remoteFingerprint != rhs._remoteFingerprint {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} diff --git a/SignalUtilitiesKit/FingerprintProto.swift b/SignalUtilitiesKit/FingerprintProto.swift deleted file mode 100644 index b841ce062..000000000 --- a/SignalUtilitiesKit/FingerprintProto.swift +++ /dev/null @@ -1,235 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -// WARNING: This code is generated. Only edit within the markers. - -public enum FingerprintProtoError: Error { - case invalidProtobuf(description: String) -} - -// MARK: - FingerprintProtoLogicalFingerprint - -@objc public class FingerprintProtoLogicalFingerprint: NSObject { - - // MARK: - FingerprintProtoLogicalFingerprintBuilder - - @objc public class func builder(identityData: Data) -> FingerprintProtoLogicalFingerprintBuilder { - return FingerprintProtoLogicalFingerprintBuilder(identityData: identityData) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> FingerprintProtoLogicalFingerprintBuilder { - let builder = FingerprintProtoLogicalFingerprintBuilder(identityData: identityData) - return builder - } - - @objc public class FingerprintProtoLogicalFingerprintBuilder: NSObject { - - private var proto = FingerprintProtos_LogicalFingerprint() - - @objc fileprivate override init() {} - - @objc fileprivate init(identityData: Data) { - super.init() - - setIdentityData(identityData) - } - - @objc public func setIdentityData(_ valueParam: Data) { - proto.identityData = valueParam - } - - @objc public func build() throws -> FingerprintProtoLogicalFingerprint { - return try FingerprintProtoLogicalFingerprint.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try FingerprintProtoLogicalFingerprint.parseProto(proto).serializedData() - } - } - - fileprivate let proto: FingerprintProtos_LogicalFingerprint - - @objc public let identityData: Data - - private init(proto: FingerprintProtos_LogicalFingerprint, - identityData: Data) { - self.proto = proto - self.identityData = identityData - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> FingerprintProtoLogicalFingerprint { - let proto = try FingerprintProtos_LogicalFingerprint(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: FingerprintProtos_LogicalFingerprint) throws -> FingerprintProtoLogicalFingerprint { - guard proto.hasIdentityData else { - throw FingerprintProtoError.invalidProtobuf(description: "\(logTag) missing required field: identityData") - } - let identityData = proto.identityData - - // MARK: - Begin Validation Logic for FingerprintProtoLogicalFingerprint - - - // MARK: - End Validation Logic for FingerprintProtoLogicalFingerprint - - - let result = FingerprintProtoLogicalFingerprint(proto: proto, - identityData: identityData) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension FingerprintProtoLogicalFingerprint { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension FingerprintProtoLogicalFingerprint.FingerprintProtoLogicalFingerprintBuilder { - @objc public func buildIgnoringErrors() -> FingerprintProtoLogicalFingerprint? { - return try! self.build() - } -} - -#endif - -// MARK: - FingerprintProtoLogicalFingerprints - -@objc public class FingerprintProtoLogicalFingerprints: NSObject { - - // MARK: - FingerprintProtoLogicalFingerprintsBuilder - - @objc public class func builder(version: UInt32, localFingerprint: FingerprintProtoLogicalFingerprint, remoteFingerprint: FingerprintProtoLogicalFingerprint) -> FingerprintProtoLogicalFingerprintsBuilder { - return FingerprintProtoLogicalFingerprintsBuilder(version: version, localFingerprint: localFingerprint, remoteFingerprint: remoteFingerprint) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> FingerprintProtoLogicalFingerprintsBuilder { - let builder = FingerprintProtoLogicalFingerprintsBuilder(version: version, localFingerprint: localFingerprint, remoteFingerprint: remoteFingerprint) - return builder - } - - @objc public class FingerprintProtoLogicalFingerprintsBuilder: NSObject { - - private var proto = FingerprintProtos_LogicalFingerprints() - - @objc fileprivate override init() {} - - @objc fileprivate init(version: UInt32, localFingerprint: FingerprintProtoLogicalFingerprint, remoteFingerprint: FingerprintProtoLogicalFingerprint) { - super.init() - - setVersion(version) - setLocalFingerprint(localFingerprint) - setRemoteFingerprint(remoteFingerprint) - } - - @objc public func setVersion(_ valueParam: UInt32) { - proto.version = valueParam - } - - @objc public func setLocalFingerprint(_ valueParam: FingerprintProtoLogicalFingerprint) { - proto.localFingerprint = valueParam.proto - } - - @objc public func setRemoteFingerprint(_ valueParam: FingerprintProtoLogicalFingerprint) { - proto.remoteFingerprint = valueParam.proto - } - - @objc public func build() throws -> FingerprintProtoLogicalFingerprints { - return try FingerprintProtoLogicalFingerprints.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try FingerprintProtoLogicalFingerprints.parseProto(proto).serializedData() - } - } - - fileprivate let proto: FingerprintProtos_LogicalFingerprints - - @objc public let version: UInt32 - - @objc public let localFingerprint: FingerprintProtoLogicalFingerprint - - @objc public let remoteFingerprint: FingerprintProtoLogicalFingerprint - - private init(proto: FingerprintProtos_LogicalFingerprints, - version: UInt32, - localFingerprint: FingerprintProtoLogicalFingerprint, - remoteFingerprint: FingerprintProtoLogicalFingerprint) { - self.proto = proto - self.version = version - self.localFingerprint = localFingerprint - self.remoteFingerprint = remoteFingerprint - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> FingerprintProtoLogicalFingerprints { - let proto = try FingerprintProtos_LogicalFingerprints(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: FingerprintProtos_LogicalFingerprints) throws -> FingerprintProtoLogicalFingerprints { - guard proto.hasVersion else { - throw FingerprintProtoError.invalidProtobuf(description: "\(logTag) missing required field: version") - } - let version = proto.version - - guard proto.hasLocalFingerprint else { - throw FingerprintProtoError.invalidProtobuf(description: "\(logTag) missing required field: localFingerprint") - } - let localFingerprint = try FingerprintProtoLogicalFingerprint.parseProto(proto.localFingerprint) - - guard proto.hasRemoteFingerprint else { - throw FingerprintProtoError.invalidProtobuf(description: "\(logTag) missing required field: remoteFingerprint") - } - let remoteFingerprint = try FingerprintProtoLogicalFingerprint.parseProto(proto.remoteFingerprint) - - // MARK: - Begin Validation Logic for FingerprintProtoLogicalFingerprints - - - // MARK: - End Validation Logic for FingerprintProtoLogicalFingerprints - - - let result = FingerprintProtoLogicalFingerprints(proto: proto, - version: version, - localFingerprint: localFingerprint, - remoteFingerprint: remoteFingerprint) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension FingerprintProtoLogicalFingerprints { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension FingerprintProtoLogicalFingerprints.FingerprintProtoLogicalFingerprintsBuilder { - @objc public func buildIgnoringErrors() -> FingerprintProtoLogicalFingerprints? { - return try! self.build() - } -} - -#endif diff --git a/SignalUtilitiesKit/FullTextSearchFinder.swift b/SignalUtilitiesKit/FullTextSearchFinder.swift index d6a3913b1..3584ace3c 100644 --- a/SignalUtilitiesKit/FullTextSearchFinder.swift +++ b/SignalUtilitiesKit/FullTextSearchFinder.swift @@ -181,7 +181,7 @@ public class FullTextSearchFinder: NSObject { } private static let recipientIndexer: SearchIndexer = SearchIndexer { (recipientId: String, transaction: YapDatabaseReadTransaction) in - let displayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true) + let displayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true)! return "\(recipientId) \(displayName)" } diff --git a/SignalUtilitiesKit/OWSDisappearingConfigurationUpdateInfoMessage.h b/SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.h similarity index 100% rename from SignalUtilitiesKit/OWSDisappearingConfigurationUpdateInfoMessage.h rename to SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.h diff --git a/SignalUtilitiesKit/OWSDisappearingConfigurationUpdateInfoMessage.m b/SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.m similarity index 100% rename from SignalUtilitiesKit/OWSDisappearingConfigurationUpdateInfoMessage.m rename to SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.m diff --git a/SignalUtilitiesKit/Messages/TSErrorMessage.h b/SignalUtilitiesKit/Messages/TSErrorMessage.h index 0831a4f71..bb04ed25f 100644 --- a/SignalUtilitiesKit/Messages/TSErrorMessage.h +++ b/SignalUtilitiesKit/Messages/TSErrorMessage.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN -@class SSKProtoEnvelope; +@class SNProtoEnvelope; typedef NS_ENUM(int32_t, TSErrorMessageType) { TSErrorMessageNoSession, @@ -52,18 +52,18 @@ typedef NS_ENUM(int32_t, TSErrorMessageType) { failedMessageType:(TSErrorMessageType)errorMessageType recipientId:(nullable NSString *)recipientId NS_DESIGNATED_INITIALIZER; -+ (instancetype)corruptedMessageWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)corruptedMessageWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction; + (instancetype)corruptedMessageInUnknownThread; -+ (instancetype)invalidVersionWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)invalidVersionWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction; -+ (instancetype)invalidKeyExceptionWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)invalidKeyExceptionWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction; -+ (instancetype)missingSessionWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)missingSessionWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction; + (instancetype)nonblockingIdentityChangeInThread:(TSThread *)thread recipientId:(NSString *)recipientId; diff --git a/SignalUtilitiesKit/Messages/TSErrorMessage.m b/SignalUtilitiesKit/Messages/TSErrorMessage.m index 90f30198e..62464701d 100644 --- a/SignalUtilitiesKit/Messages/TSErrorMessage.m +++ b/SignalUtilitiesKit/Messages/TSErrorMessage.m @@ -59,7 +59,6 @@ NSUInteger TSErrorMessageSchemaVersion = 1; expiresInSeconds:0 expireStartedAt:0 quotedMessage:nil - contactShare:nil linkPreview:nil]; if (!self) { @@ -84,7 +83,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1; return [self initWithTimestamp:timestamp inThread:thread failedMessageType:errorMessageType recipientId:nil]; } -- (instancetype)initWithEnvelope:(SSKProtoEnvelope *)envelope +- (instancetype)initWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction failedMessageType:(TSErrorMessageType)errorMessageType { @@ -143,7 +142,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1; } } -+ (instancetype)corruptedMessageWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)corruptedMessageWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction { return [[self alloc] initWithEnvelope:envelope @@ -159,7 +158,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1; failedMessageType:TSErrorMessageInvalidMessage]; } -+ (instancetype)invalidVersionWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)invalidVersionWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction { return [[self alloc] initWithEnvelope:envelope @@ -167,7 +166,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1; failedMessageType:TSErrorMessageInvalidVersion]; } -+ (instancetype)invalidKeyExceptionWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)invalidKeyExceptionWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction { return [[self alloc] initWithEnvelope:envelope @@ -175,7 +174,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1; failedMessageType:TSErrorMessageInvalidKeyException]; } -+ (instancetype)missingSessionWithEnvelope:(SSKProtoEnvelope *)envelope ++ (instancetype)missingSessionWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction { return diff --git a/SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h b/SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h index 77e5a39f4..08de35a44 100644 --- a/SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h +++ b/SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "TSErrorMessage.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messages/TSIncomingMessage.h b/SignalUtilitiesKit/Messages/TSIncomingMessage.h index 5e806a6b6..84c3f1cf2 100644 --- a/SignalUtilitiesKit/Messages/TSIncomingMessage.h +++ b/SignalUtilitiesKit/Messages/TSIncomingMessage.h @@ -48,18 +48,17 @@ NS_ASSUME_NONNULL_BEGIN * * @return initiated incoming group message */ -- (instancetype)initIncomingMessageWithTimestamp:(uint64_t)timestamp - inThread:(TSThread *)thread - authorId:(NSString *)authorId - sourceDeviceId:(uint32_t)sourceDeviceId - messageBody:(nullable NSString *)body - attachmentIds:(NSArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview - serverTimestamp:(nullable NSNumber *)serverTimestamp - wasReceivedByUD:(BOOL)wasReceivedByUD NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithTimestamp:(uint64_t)timestamp + inThread:(TSThread *)thread + authorId:(NSString *)authorId + sourceDeviceId:(uint32_t)sourceDeviceId + messageBody:(nullable NSString *)body + attachmentIds:(NSArray *)attachmentIds + expiresInSeconds:(uint32_t)expiresInSeconds + quotedMessage:(nullable TSQuotedMessage *)quotedMessage + linkPreview:(nullable OWSLinkPreview *)linkPreview + serverTimestamp:(nullable NSNumber *)serverTimestamp + wasReceivedByUD:(BOOL)wasReceivedByUD NS_DESIGNATED_INITIALIZER; - (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; diff --git a/SignalUtilitiesKit/Messages/TSIncomingMessage.m b/SignalUtilitiesKit/Messages/TSIncomingMessage.m index b8a8b31b3..a2d30d92a 100644 --- a/SignalUtilitiesKit/Messages/TSIncomingMessage.m +++ b/SignalUtilitiesKit/Messages/TSIncomingMessage.m @@ -43,18 +43,17 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (instancetype)initIncomingMessageWithTimestamp:(uint64_t)timestamp - inThread:(TSThread *)thread - authorId:(NSString *)authorId - sourceDeviceId:(uint32_t)sourceDeviceId - messageBody:(nullable NSString *)body - attachmentIds:(NSArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview - serverTimestamp:(nullable NSNumber *)serverTimestamp - wasReceivedByUD:(BOOL)wasReceivedByUD +- (instancetype)initWithTimestamp:(uint64_t)timestamp + inThread:(TSThread *)thread + authorId:(NSString *)authorId + sourceDeviceId:(uint32_t)sourceDeviceId + messageBody:(nullable NSString *)body + attachmentIds:(NSArray *)attachmentIds + expiresInSeconds:(uint32_t)expiresInSeconds + quotedMessage:(nullable TSQuotedMessage *)quotedMessage + linkPreview:(nullable OWSLinkPreview *)linkPreview + serverTimestamp:(nullable NSNumber *)serverTimestamp + wasReceivedByUD:(BOOL)wasReceivedByUD { self = [super initMessageWithTimestamp:timestamp inThread:thread @@ -63,7 +62,6 @@ NS_ASSUME_NONNULL_BEGIN expiresInSeconds:expiresInSeconds expireStartedAt:0 quotedMessage:quotedMessage - contactShare:contactShare linkPreview:linkPreview]; if (!self) { diff --git a/SignalUtilitiesKit/Messages/TSInfoMessage.m b/SignalUtilitiesKit/Messages/TSInfoMessage.m index fb9cd0dc7..d47a01044 100644 --- a/SignalUtilitiesKit/Messages/TSInfoMessage.m +++ b/SignalUtilitiesKit/Messages/TSInfoMessage.m @@ -56,7 +56,6 @@ NSUInteger TSInfoMessageSchemaVersion = 1; expiresInSeconds:0 expireStartedAt:0 quotedMessage:nil - contactShare:nil linkPreview:nil]; if (!self) { diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h index 9ff43a951..a59fe3bbb 100644 --- a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h +++ b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h @@ -6,14 +6,14 @@ NS_ASSUME_NONNULL_BEGIN -@class SSKProtoEnvelope; +@class SNProtoEnvelope; // DEPRECATED - we no longer create new instances of this class (as of mid-2017); However, existing instances may // exist, so we should keep this class around to honor their old behavior. __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage : TSInvalidIdentityKeyErrorMessage #ifdef DEBUG -+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope ++ (nullable instancetype)untrustedKeyWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction; #endif diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m index 8b745f029..168db6d70 100644 --- a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -25,7 +25,7 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage @implementation TSInvalidIdentityKeyReceivingErrorMessage { // Not using a property declaration in order to exclude from DB serialization - SSKProtoEnvelope *_Nullable _envelope; + SNProtoEnvelope *_Nullable _envelope; } @synthesize envelopeData = _envelopeData; @@ -33,7 +33,7 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage #ifdef DEBUG // We no longer create these messages, but they might exist on legacy clients so it's useful to be able to // create them with the debug UI -+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope ++ (nullable instancetype)untrustedKeyWithEnvelope:(SNProtoEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction { TSContactThread *contactThread = @@ -49,7 +49,7 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage - (nullable instancetype)initForUnknownIdentityKeyWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread - incomingEnvelope:(SSKProtoEnvelope *)envelope + incomingEnvelope:(SNProtoEnvelope *)envelope { self = [self initWithTimestamp:timestamp inThread:thread failedMessageType:TSErrorMessageWrongTrustedIdentityKey]; if (!self) { @@ -69,11 +69,11 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage } #endif -- (nullable SSKProtoEnvelope *)envelope +- (nullable SNProtoEnvelope *)envelope { if (!_envelope) { NSError *error; - SSKProtoEnvelope *_Nullable envelope = [SSKProtoEnvelope parseData:self.envelopeData error:&error]; + SNProtoEnvelope *_Nullable envelope = [SNProtoEnvelope parseData:self.envelopeData error:&error]; if (error || envelope == nil) { OWSFailDebug(@"Could not parse proto: %@", error); } else { @@ -120,7 +120,7 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage return nil; } - if (self.envelope.type != SSKProtoEnvelopeTypePrekeyBundle) { + if (self.envelope.type != SNProtoEnvelopeTypePrekeyBundle) { OWSLogError(@"Refusing to attempt key extraction from an envelope which isn't a prekey bundle"); return nil; } diff --git a/SignalUtilitiesKit/Messages/TSMessage.h b/SignalUtilitiesKit/Messages/TSMessage.h index 7702f8655..d7abfd6e3 100644 --- a/SignalUtilitiesKit/Messages/TSMessage.h +++ b/SignalUtilitiesKit/Messages/TSMessage.h @@ -26,7 +26,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) uint64_t expiresAt; @property (nonatomic, readonly) BOOL isExpiringMessage; @property (nonatomic, readonly, nullable) TSQuotedMessage *quotedMessage; -@property (nonatomic, readonly, nullable) OWSContact *contactShare; @property (nonatomic, nullable) OWSLinkPreview *linkPreview; @property BOOL skipSave; // Open groups @@ -44,7 +43,6 @@ NS_ASSUME_NONNULL_BEGIN expiresInSeconds:(uint32_t)expiresInSeconds expireStartedAt:(uint64_t)expireStartedAt quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare linkPreview:(nullable OWSLinkPreview *)linkPreview NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; diff --git a/SignalUtilitiesKit/Messages/TSMessage.m b/SignalUtilitiesKit/Messages/TSMessage.m index 0003614aa..6d7c2575c 100644 --- a/SignalUtilitiesKit/Messages/TSMessage.m +++ b/SignalUtilitiesKit/Messages/TSMessage.m @@ -63,7 +63,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4; expiresInSeconds:(uint32_t)expiresInSeconds expireStartedAt:(uint64_t)expireStartedAt quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare linkPreview:(nullable OWSLinkPreview *)linkPreview { self = [super initInteractionWithTimestamp:timestamp inThread:thread]; @@ -80,7 +79,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4; _expireStartedAt = expireStartedAt; [self updateExpiresAt]; _quotedMessage = quotedMessage; - _contactShare = contactShare; _linkPreview = linkPreview; _openGroupServerMessageID = -1; diff --git a/SignalUtilitiesKit/Messages/TSOutgoingMessage.h b/SignalUtilitiesKit/Messages/TSOutgoingMessage.h index 0d33b756a..f5d9e340b 100644 --- a/SignalUtilitiesKit/Messages/TSOutgoingMessage.h +++ b/SignalUtilitiesKit/Messages/TSOutgoingMessage.h @@ -54,10 +54,10 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { TSGroupMetaMessageRequestInfo, }; -@class SSKProtoAttachmentPointer; -@class SSKProtoContentBuilder; -@class SSKProtoDataMessage; -@class SSKProtoDataMessageBuilder; +@class SNProtoAttachmentPointer; +@class SNProtoContentBuilder; +@class SNProtoDataMessage; +@class SNProtoDataMessageBuilder; @class SignalRecipient; @interface TSOutgoingMessageRecipientState : MTLModel @@ -83,7 +83,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { expiresInSeconds:(uint32_t)expiresInSeconds expireStartedAt:(uint64_t)expireStartedAt quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare linkPreview:(nullable OWSLinkPreview *)linkPreview NS_UNAVAILABLE; // MJK TODO - Can we remove the sender timestamp param? @@ -96,7 +95,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { isVoiceMessage:(BOOL)isVoiceMessage groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare linkPreview:(nullable OWSLinkPreview *)linkPreview NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; @@ -156,7 +154,7 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { */ - (nullable id)dataMessageBuilder; -- (nullable SSKProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId; +- (nullable SNProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId; /** * Allows subclasses to supply a custom content builder that has already prepared part of the message. diff --git a/SignalUtilitiesKit/Messages/TSOutgoingMessage.m b/SignalUtilitiesKit/Messages/TSOutgoingMessage.m index cff531a5b..58a0bdb64 100644 --- a/SignalUtilitiesKit/Messages/TSOutgoingMessage.m +++ b/SignalUtilitiesKit/Messages/TSOutgoingMessage.m @@ -276,7 +276,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:quotedMessage - contactShare:nil linkPreview:linkPreview]; } @@ -294,7 +293,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt isVoiceMessage:NO groupMetaMessage:groupMetaMessage quotedMessage:nil - contactShare:nil linkPreview:nil]; } @@ -307,7 +305,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt isVoiceMessage:(BOOL)isVoiceMessage groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare linkPreview:(nullable OWSLinkPreview *)linkPreview { self = [super initMessageWithTimestamp:timestamp @@ -317,7 +314,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt expiresInSeconds:expiresInSeconds expireStartedAt:expireStartedAt quotedMessage:quotedMessage - contactShare:contactShare linkPreview:linkPreview]; if (!self) { return self; @@ -345,16 +341,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt // New outgoing messages should immediately determine their // recipient list from current thread state. NSMutableDictionary *recipientStateMap = [NSMutableDictionary new]; - NSArray *recipientIds; -// if ([self isKindOfClass:[OWSOutgoingSyncMessage class]]) { -// NSString *_Nullable localNumber = [TSAccountManager localNumber]; -// OWSAssertDebug(localNumber); -// recipientIds = @[ -// localNumber, -// ]; -// } else { -// recipientIds = [thread recipientIdentifiers]; -// } + NSArray *recipientIds = [thread recipientIdentifiers]; for (NSString *recipientId in recipientIds) { TSOutgoingMessageRecipientState *recipientState = [TSOutgoingMessageRecipientState new]; recipientState.state = OWSOutgoingMessageRecipientStateSending; @@ -884,7 +871,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt TSThread *thread = self.thread; OWSAssertDebug(thread); - SSKProtoDataMessageBuilder *builder = [SSKProtoDataMessage builder]; + SNProtoDataMessageBuilder *builder = [SNProtoDataMessage builder]; [builder setTimestamp:self.timestamp]; if ([self.body lengthOfBytesUsingEncoding:NSUTF8StringEncoding] <= kOversizeTextMessageSizeThreshold) { @@ -905,25 +892,25 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt BOOL attachmentWasGroupAvatar = NO; if ([thread isKindOfClass:[TSGroupThread class]]) { TSGroupThread *gThread = (TSGroupThread *)thread; - SSKProtoGroupContextType groupMessageType; + SNProtoGroupContextType groupMessageType; switch (self.groupMetaMessage) { case TSGroupMetaMessageQuit: - groupMessageType = SSKProtoGroupContextTypeQuit; + groupMessageType = SNProtoGroupContextTypeQuit; break; case TSGroupMetaMessageUpdate: case TSGroupMetaMessageNew: - groupMessageType = SSKProtoGroupContextTypeUpdate; + groupMessageType = SNProtoGroupContextTypeUpdate; break; default: - groupMessageType = SSKProtoGroupContextTypeDeliver; + groupMessageType = SNProtoGroupContextTypeDeliver; break; } - SSKProtoGroupContextBuilder *groupBuilder = - [SSKProtoGroupContext builderWithId:gThread.groupModel.groupId type:groupMessageType]; - if (groupMessageType == SSKProtoGroupContextTypeUpdate) { + SNProtoGroupContextBuilder *groupBuilder = + [SNProtoGroupContext builderWithId:gThread.groupModel.groupId type:groupMessageType]; + if (groupMessageType == SNProtoGroupContextTypeUpdate) { if (gThread.groupModel.groupImage != nil && self.attachmentIds.count == 1) { attachmentWasGroupAvatar = YES; - SSKProtoAttachmentPointer *_Nullable attachmentProto = + SNProtoAttachmentPointer *_Nullable attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; if (!attachmentProto) { OWSFailDebug(@"could not build protobuf."); @@ -937,7 +924,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt [groupBuilder setAdmins:gThread.groupModel.groupAdminIds]; } NSError *error; - SSKProtoGroupContext *_Nullable groupContextProto = [groupBuilder buildAndReturnError:&error]; + SNProtoGroupContext *_Nullable groupContextProto = [groupBuilder buildAndReturnError:&error]; if (error || !groupContextProto) { OWSFailDebug(@"could not build protobuf: %@.", error); return nil; @@ -949,7 +936,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt if (!attachmentWasGroupAvatar) { NSMutableArray *attachments = [NSMutableArray new]; for (NSString *attachmentId in self.attachmentIds) { - SSKProtoAttachmentPointer *_Nullable attachmentProto = + SNProtoAttachmentPointer *_Nullable attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:attachmentId]; if (!attachmentProto) { OWSFailDebug(@"could not build protobuf."); @@ -961,10 +948,10 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } // Quoted Reply - SSKProtoDataMessageQuoteBuilder *_Nullable quotedMessageBuilder = self.quotedMessageBuilder; + SNProtoDataMessageQuoteBuilder *_Nullable quotedMessageBuilder = self.quotedMessageBuilder; if (quotedMessageBuilder) { NSError *error; - SSKProtoDataMessageQuote *_Nullable quoteProto = [quotedMessageBuilder buildAndReturnError:&error]; + SNProtoDataMessageQuote *_Nullable quoteProto = [quotedMessageBuilder buildAndReturnError:&error]; if (error || !quoteProto) { OWSFailDebug(@"could not build protobuf: %@.", error); return nil; @@ -974,13 +961,13 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt // Link Preview if (self.linkPreview) { - SSKProtoDataMessagePreviewBuilder *previewBuilder = - [SSKProtoDataMessagePreview builderWithUrl:self.linkPreview.urlString]; + SNProtoDataMessagePreviewBuilder *previewBuilder = + [SNProtoDataMessagePreview builderWithUrl:self.linkPreview.urlString]; if (self.linkPreview.title.length > 0) { [previewBuilder setTitle:self.linkPreview.title]; } if (self.linkPreview.imageAttachmentId) { - SSKProtoAttachmentPointer *_Nullable attachmentProto = + SNProtoAttachmentPointer *_Nullable attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:self.linkPreview.imageAttachmentId]; if (!attachmentProto) { OWSFailDebug(@"Could not build link preview image protobuf."); @@ -990,7 +977,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } NSError *error; - SSKProtoDataMessagePreview *_Nullable previewProto = [previewBuilder buildAndReturnError:&error]; + SNProtoDataMessagePreview *_Nullable previewProto = [previewBuilder buildAndReturnError:&error]; if (error || !previewProto) { OWSFailDebug(@"Could not build link preview protobuf: %@.", error); } else { @@ -1001,15 +988,15 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt return builder; } -- (nullable SSKProtoDataMessageQuoteBuilder *)quotedMessageBuilder +- (nullable SNProtoDataMessageQuoteBuilder *)quotedMessageBuilder { if (!self.quotedMessage) { return nil; } TSQuotedMessage *quotedMessage = self.quotedMessage; - SSKProtoDataMessageQuoteBuilder *quoteBuilder = - [SSKProtoDataMessageQuote builderWithId:quotedMessage.timestamp author:quotedMessage.authorId]; + SNProtoDataMessageQuoteBuilder *quoteBuilder = + [SNProtoDataMessageQuote builderWithId:quotedMessage.timestamp author:quotedMessage.authorId]; BOOL hasQuotedText = NO; BOOL hasQuotedAttachment = NO; @@ -1022,8 +1009,8 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt for (OWSAttachmentInfo *attachment in quotedMessage.quotedAttachments) { hasQuotedAttachment = YES; - SSKProtoDataMessageQuoteQuotedAttachmentBuilder *quotedAttachmentBuilder = - [SSKProtoDataMessageQuoteQuotedAttachment builder]; + SNProtoDataMessageQuoteQuotedAttachmentBuilder *quotedAttachmentBuilder = + [SNProtoDataMessageQuoteQuotedAttachment builder]; quotedAttachmentBuilder.contentType = attachment.contentType; quotedAttachmentBuilder.fileName = attachment.sourceFilename; @@ -1033,7 +1020,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } NSError *error; - SSKProtoDataMessageQuoteQuotedAttachment *_Nullable quotedAttachmentMessage = + SNProtoDataMessageQuoteQuotedAttachment *_Nullable quotedAttachmentMessage = [quotedAttachmentBuilder buildAndReturnError:&error]; if (error || !quotedAttachmentMessage) { OWSFailDebug(@"could not build protobuf: %@", error); @@ -1053,10 +1040,10 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } // recipientId is nil when building "sent" sync messages for messages sent to groups. -- (nullable SSKProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId +- (nullable SNProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId { OWSAssertDebug(self.thread); - SSKProtoDataMessageBuilder *_Nullable builder = [self dataMessageBuilder]; + SNProtoDataMessageBuilder *_Nullable builder = [self dataMessageBuilder]; if (builder == nil) { OWSFailDebug(@"Couldn't build protobuf."); return nil; @@ -1073,14 +1060,14 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt displayName = profileManager.localProfileName; } NSString *profilePictureURL = profileManager.profilePictureURL; - SSKProtoDataMessageLokiProfileBuilder *profileBuilder = [SSKProtoDataMessageLokiProfile builder]; + SNProtoDataMessageLokiProfileBuilder *profileBuilder = [SNProtoDataMessageLokiProfile builder]; [profileBuilder setDisplayName:displayName]; [profileBuilder setProfilePicture:profilePictureURL ?: @""]; - SSKProtoDataMessageLokiProfile *profile = [profileBuilder buildAndReturnError:nil]; + SNProtoDataMessageLokiProfile *profile = [profileBuilder buildAndReturnError:nil]; [builder setProfile:profile]; NSError *error; - SSKProtoDataMessage *_Nullable dataProto = [builder buildAndReturnError:&error]; + SNProtoDataMessage *_Nullable dataProto = [builder buildAndReturnError:&error]; if (error != nil || dataProto == nil) { OWSFailDebug(@"Couldn't build protobuf due to error: %@.", error); return nil; @@ -1089,14 +1076,14 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } - (nullable id)prepareCustomContentBuilder:(SignalRecipient *)recipient { - SSKProtoDataMessage *_Nullable dataMessage = [self buildDataMessage:recipient.recipientId]; + SNProtoDataMessage *_Nullable dataMessage = [self buildDataMessage:recipient.recipientId]; if (dataMessage == nil) { OWSFailDebug(@"Couldn't build protobuf."); return nil; } - SSKProtoContentBuilder *contentBuilder = SSKProtoContent.builder; + SNProtoContentBuilder *contentBuilder = SNProtoContent.builder; [contentBuilder setDataMessage:dataMessage]; return contentBuilder; @@ -1104,7 +1091,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient { - SSKProtoContentBuilder *contentBuilder = [self prepareCustomContentBuilder:recipient]; + SNProtoContentBuilder *contentBuilder = [self prepareCustomContentBuilder:recipient]; NSError *error; NSData *_Nullable contentData = [contentBuilder buildSerializedDataAndReturnError:&error]; diff --git a/SignalUtilitiesKit/Messages/TSQuotedMessage.h b/SignalUtilitiesKit/Messages/TSQuotedMessage.h index 62befe9bf..ecfb822ce 100644 --- a/SignalUtilitiesKit/Messages/TSQuotedMessage.h +++ b/SignalUtilitiesKit/Messages/TSQuotedMessage.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN -@class SSKProtoDataMessage; +@class SNProtoDataMessage; @class TSAttachment; @class TSAttachmentStream; @class TSQuotedMessage; @@ -97,7 +97,7 @@ typedef NS_ENUM(NSUInteger, TSQuotedMessageContentSource) { quotedAttachmentsForSending:(NSArray *)attachments; -+ (nullable instancetype)quotedMessageForDataMessage:(SSKProtoDataMessage *)dataMessage ++ (nullable instancetype)quotedMessageForDataMessage:(SNProtoDataMessage *)dataMessage thread:(TSThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalUtilitiesKit/Messages/TSQuotedMessage.m b/SignalUtilitiesKit/Messages/TSQuotedMessage.m index d5a4068f7..8af86dafb 100644 --- a/SignalUtilitiesKit/Messages/TSQuotedMessage.m +++ b/SignalUtilitiesKit/Messages/TSQuotedMessage.m @@ -106,7 +106,7 @@ NS_ASSUME_NONNULL_BEGIN return self; } -+ (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(SSKProtoDataMessage *)dataMessage ++ (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(SNProtoDataMessage *)dataMessage thread:(TSThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction { @@ -116,7 +116,7 @@ NS_ASSUME_NONNULL_BEGIN return nil; } - SSKProtoDataMessageQuote *quoteProto = [dataMessage quote]; + SNProtoDataMessageQuote *quoteProto = [dataMessage quote]; if (quoteProto.id == 0) { OWSFailDebug(@"quoted message missing id"); @@ -158,7 +158,7 @@ NS_ASSUME_NONNULL_BEGIN } NSMutableArray *attachmentInfos = [NSMutableArray new]; - for (SSKProtoDataMessageQuoteQuotedAttachment *quotedAttachment in quoteProto.attachments) { + for (SNProtoDataMessageQuoteQuotedAttachment *quotedAttachment in quoteProto.attachments) { hasAttachment = YES; OWSAttachmentInfo *attachmentInfo = [[OWSAttachmentInfo alloc] initWithAttachmentId:nil contentType:quotedAttachment.contentType @@ -185,7 +185,7 @@ NS_ASSUME_NONNULL_BEGIN thread.uniqueId, (unsigned long)timestamp); - SSKProtoAttachmentPointer *thumbnailAttachmentProto = quotedAttachment.thumbnail; + SNProtoAttachmentPointer *thumbnailAttachmentProto = quotedAttachment.thumbnail; TSAttachmentPointer *_Nullable thumbnailPointer = [TSAttachmentPointer attachmentPointerFromProto:thumbnailAttachmentProto albumMessage:nil]; if (thumbnailPointer) { diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 085cc69ad..710dd8d5e 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -33,8 +33,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import -#import #import #import #import @@ -77,7 +75,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import @@ -85,6 +82,8 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import +#import +#import #import #import #import diff --git a/SignalUtilitiesKit/LokiDatabaseUtilities.swift b/SignalUtilitiesKit/Move to main app/LokiDatabaseUtilities.swift similarity index 100% rename from SignalUtilitiesKit/LokiDatabaseUtilities.swift rename to SignalUtilitiesKit/Move to main app/LokiDatabaseUtilities.swift diff --git a/SignalUtilitiesKit/NoopCallMessageHandler.swift b/SignalUtilitiesKit/NoopCallMessageHandler.swift deleted file mode 100644 index 7ef576d77..000000000 --- a/SignalUtilitiesKit/NoopCallMessageHandler.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - - - -@objc -public class NoopCallMessageHandler: NSObject, OWSCallMessageHandler { - - public func receivedOffer(_ offer: SSKProtoCallMessageOffer, from callerId: String) { - owsFailDebug("") - } - - public func receivedAnswer(_ answer: SSKProtoCallMessageAnswer, from callerId: String) { - owsFailDebug("") - } - - public func receivedIceUpdate(_ iceUpdate: SSKProtoCallMessageIceUpdate, from callerId: String) { - owsFailDebug("") - } - - public func receivedHangup(_ hangup: SSKProtoCallMessageHangup, from callerId: String) { - owsFailDebug("") - } - - public func receivedBusy(_ busy: SSKProtoCallMessageBusy, from callerId: String) { - owsFailDebug("") - } -} diff --git a/SignalUtilitiesKit/OWSAttachmentDownloads.h b/SignalUtilitiesKit/OWSAttachmentDownloads.h index 4840d3ae2..9f619b34b 100644 --- a/SignalUtilitiesKit/OWSAttachmentDownloads.h +++ b/SignalUtilitiesKit/OWSAttachmentDownloads.h @@ -10,7 +10,7 @@ extern NSString *const kAttachmentDownloadProgressNotification; extern NSString *const kAttachmentDownloadProgressKey; extern NSString *const kAttachmentDownloadAttachmentIDKey; -@class SSKProtoAttachmentPointer; +@class SNProtoAttachmentPointer; @class TSAttachment; @class TSAttachmentPointer; @class TSAttachmentStream; diff --git a/SignalUtilitiesKit/OWSCallMessageHandler.h b/SignalUtilitiesKit/OWSCallMessageHandler.h deleted file mode 100644 index 13b471857..000000000 --- a/SignalUtilitiesKit/OWSCallMessageHandler.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class SSKProtoCallMessageAnswer; -@class SSKProtoCallMessageBusy; -@class SSKProtoCallMessageHangup; -@class SSKProtoCallMessageIceUpdate; -@class SSKProtoCallMessageOffer; - -@protocol OWSCallMessageHandler - -- (void)receivedOffer:(SSKProtoCallMessageOffer *)offer - fromCallerId:(NSString *)callerId NS_SWIFT_NAME(receivedOffer(_:from:)); -- (void)receivedAnswer:(SSKProtoCallMessageAnswer *)answer - fromCallerId:(NSString *)callerId NS_SWIFT_NAME(receivedAnswer(_:from:)); -- (void)receivedIceUpdate:(SSKProtoCallMessageIceUpdate *)iceUpdate - fromCallerId:(NSString *)callerId NS_SWIFT_NAME(receivedIceUpdate(_:from:)); -- (void)receivedHangup:(SSKProtoCallMessageHangup *)hangup - fromCallerId:(NSString *)callerId NS_SWIFT_NAME(receivedHangup(_:from:)); -- (void)receivedBusy:(SSKProtoCallMessageBusy *)busy - fromCallerId:(NSString *)callerId NS_SWIFT_NAME(receivedBusy(_:from:)); - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContactOffersInteraction.h b/SignalUtilitiesKit/OWSContactOffersInteraction.h deleted file mode 100644 index bbe4635d9..000000000 --- a/SignalUtilitiesKit/OWSContactOffersInteraction.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -@class YapDatabaseReadWriteTransaction; - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSContactOffersInteraction : TSInteraction - -@property (nonatomic, readonly) BOOL hasBlockOffer; -@property (nonatomic, readonly) BOOL hasAddToContactsOffer; -@property (nonatomic, readonly) BOOL hasAddToProfileWhitelistOffer; - -// TODO - remove this recipientId param -// it's redundant with the interaction's TSContactThread -@property (nonatomic, readonly) NSString *recipientId; -@property (nonatomic, readonly) NSString *beforeInteractionId; - -- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; - -- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -// MJK TODO should be safe to remove this timestamp param -- (instancetype)initInteractionWithUniqueId:(NSString *)uniqueId - timestamp:(uint64_t)timestamp - thread:(TSThread *)thread - hasBlockOffer:(BOOL)hasBlockOffer - hasAddToContactsOffer:(BOOL)hasAddToContactsOffer - hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer - recipientId:(NSString *)recipientId - beforeInteractionId:(NSString *)beforeInteractionId NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContactOffersInteraction.m b/SignalUtilitiesKit/OWSContactOffersInteraction.m deleted file mode 100644 index f9bcbd150..000000000 --- a/SignalUtilitiesKit/OWSContactOffersInteraction.m +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSContactOffersInteraction.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSContactOffersInteraction () - -@property (nonatomic) BOOL hasBlockOffer; -@property (nonatomic) BOOL hasAddToContactsOffer; -@property (nonatomic) BOOL hasAddToProfileWhitelistOffer; - -@end - -@implementation OWSContactOffersInteraction - -- (instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -- (instancetype)initInteractionWithUniqueId:(NSString *)uniqueId - timestamp:(uint64_t)timestamp - thread:(TSThread *)thread - hasBlockOffer:(BOOL)hasBlockOffer - hasAddToContactsOffer:(BOOL)hasAddToContactsOffer - hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer - recipientId:(NSString *)recipientId - beforeInteractionId:(NSString *)beforeInteractionId -{ - self = [super initInteractionWithUniqueId:uniqueId timestamp:timestamp inThread:thread]; - - if (!self) { - return self; - } - - _hasBlockOffer = hasBlockOffer; - _hasAddToContactsOffer = hasAddToContactsOffer; - _hasAddToProfileWhitelistOffer = hasAddToProfileWhitelistOffer; - OWSAssertDebug(recipientId.length > 0); - _recipientId = recipientId; - _beforeInteractionId = beforeInteractionId; - - return self; -} - -- (BOOL)shouldUseReceiptDateForSorting -{ - // Use the timestamp, not the "received at" timestamp to sort, - // since we're creating these interactions after the fact and back-dating them. - return NO; -} - -- (BOOL)isDynamicInteraction -{ - return YES; -} - -- (OWSInteractionType)interactionType -{ - return OWSInteractionType_Offer; -} - -- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSFailDebug(@"This interaction should never be saved to the database."); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSContactsOutputStream.m b/SignalUtilitiesKit/OWSContactsOutputStream.m index 9162b76e0..cd0a85223 100644 --- a/SignalUtilitiesKit/OWSContactsOutputStream.m +++ b/SignalUtilitiesKit/OWSContactsOutputStream.m @@ -30,13 +30,13 @@ disappearingMessagesConfiguration:(nullable OWSDisappearingMessagesConfiguration OWSAssertDebug(signalAccount); OWSAssertDebug(contactsManager); - SSKProtoContactDetailsBuilder *contactBuilder = - [SSKProtoContactDetails builderWithNumber:signalAccount.recipientId]; + SNProtoContactDetailsBuilder *contactBuilder = + [SNProtoContactDetails builderWithNumber:signalAccount.recipientId]; [contactBuilder setName:[LKUserDisplayNameUtilities getPrivateChatDisplayNameFor:signalAccount.recipientId] ?: signalAccount.recipientId]; [contactBuilder setColor:conversationColorName]; if (recipientIdentity != nil) { - SSKProtoVerified *_Nullable verified = BuildVerifiedProtoWithRecipientId(recipientIdentity.recipientId, + SNProtoVerified *_Nullable verified = BuildVerifiedProtoWithRecipientId(recipientIdentity.recipientId, [recipientIdentity.identityKey prependKeyType], recipientIdentity.verificationState, 0); diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.m b/SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.m index a993ad808..4422da013 100644 --- a/SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.m +++ b/SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.m @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN { return [self initWithThreadId:threadId enabled:NO - durationSeconds:OWSDisappearingMessagesConfigurationDefaultExpirationDuration]; + durationSeconds:(NSTimeInterval)OWSDisappearingMessagesConfigurationDefaultExpirationDuration]; } - (nullable instancetype)initWithCoder:(NSCoder *)coder diff --git a/SignalUtilitiesKit/OWSGroupsOutputStream.m b/SignalUtilitiesKit/OWSGroupsOutputStream.m index cd6941758..2cd2877b6 100644 --- a/SignalUtilitiesKit/OWSGroupsOutputStream.m +++ b/SignalUtilitiesKit/OWSGroupsOutputStream.m @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN TSGroupModel *group = groupThread.groupModel; OWSAssertDebug(group); - SSKProtoGroupDetailsBuilder *groupBuilder = [SSKProtoGroupDetails builderWithId:group.groupId]; + SNProtoGroupDetailsBuilder *groupBuilder = [SNProtoGroupDetails builderWithId:group.groupId]; [groupBuilder setName:group.groupName]; [groupBuilder setMembers:group.groupMemberIds]; [groupBuilder setAdmins:group.groupAdminIds]; diff --git a/SignalUtilitiesKit/OWSIdentityManager.h b/SignalUtilitiesKit/OWSIdentityManager.h index c2e4e61a9..149362b9a 100644 --- a/SignalUtilitiesKit/OWSIdentityManager.h +++ b/SignalUtilitiesKit/OWSIdentityManager.h @@ -28,7 +28,7 @@ extern const NSUInteger kStoredIdentityKeyLength; @class OWSRecipientIdentity; @class OWSStorage; -@class SSKProtoVerified; +@class SNProtoVerified; @class YapDatabaseReadWriteTransaction; // This class can be safely accessed and used from any thread. @@ -54,7 +54,7 @@ extern const NSUInteger kStoredIdentityKeyLength; - (nullable OWSRecipientIdentity *)untrustedIdentityForSendingToRecipientId:(NSString *)recipientId; // This method can be called from any thread. -- (void)throws_processIncomingSyncMessage:(SSKProtoVerified *)verified +- (void)throws_processIncomingSyncMessage:(SNProtoVerified *)verified transaction:(YapDatabaseReadWriteTransaction *)transaction; - (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId; diff --git a/SignalUtilitiesKit/OWSIdentityManager.m b/SignalUtilitiesKit/OWSIdentityManager.m index 9da61ac84..46651537e 100644 --- a/SignalUtilitiesKit/OWSIdentityManager.m +++ b/SignalUtilitiesKit/OWSIdentityManager.m @@ -527,7 +527,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa [transaction removeObjectForKey:recipientId inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages]; } -- (void)throws_processIncomingSyncMessage:(SSKProtoVerified *)verified +- (void)throws_processIncomingSyncMessage:(SNProtoVerified *)verified transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssertDebug(verified); @@ -548,21 +548,21 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa NSData *identityKey = [rawIdentityKey throws_removeKeyType]; switch (verified.state) { - case SSKProtoVerifiedStateDefault: + case SNProtoVerifiedStateDefault: [self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault recipientId:recipientId identityKey:identityKey overwriteOnConflict:NO transaction:transaction]; break; - case SSKProtoVerifiedStateVerified: + case SNProtoVerifiedStateVerified: [self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified recipientId:recipientId identityKey:identityKey overwriteOnConflict:YES transaction:transaction]; break; - case SSKProtoVerifiedStateUnverified: + case SNProtoVerifiedStateUnverified: OWSFailDebug(@"Verification state sync message for recipientId: %@ has unexpected value: %@.", recipientId, OWSVerificationStateToString(OWSVerificationStateNoLongerVerified)); diff --git a/SignalUtilitiesKit/OWSIncompleteCallsJob.h b/SignalUtilitiesKit/OWSIncompleteCallsJob.h deleted file mode 100644 index 2b2e1f311..000000000 --- a/SignalUtilitiesKit/OWSIncompleteCallsJob.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSPrimaryStorage; -@class OWSStorage; - -@interface OWSIncompleteCallsJob : NSObject - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; - -- (void)run; - -+ (NSString *)databaseExtensionName; -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage; - -#ifdef DEBUG -/** - * Only use the sync version for testing, generally we'll want to register extensions async - */ -- (void)blockingRegisterDatabaseExtensions; -#endif - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSIncompleteCallsJob.m b/SignalUtilitiesKit/OWSIncompleteCallsJob.m deleted file mode 100644 index 9a4e1755d..000000000 --- a/SignalUtilitiesKit/OWSIncompleteCallsJob.m +++ /dev/null @@ -1,160 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSIncompleteCallsJob.h" -#import "AppContext.h" -#import "OWSPrimaryStorage.h" -#import "TSCall.h" -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -static NSString *const OWSIncompleteCallsJobCallTypeColumn = @"call_type"; -static NSString *const OWSIncompleteCallsJobCallTypeIndex = @"index_calls_on_call_type"; - -@interface OWSIncompleteCallsJob () - -@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage; - -@end - -#pragma mark - - -@implementation OWSIncompleteCallsJob - -- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage -{ - self = [super init]; - if (!self) { - return self; - } - - _primaryStorage = primaryStorage; - - return self; -} - -- (NSArray *)fetchIncompleteCallIdsWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *messageIds = [NSMutableArray new]; - - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ == %d OR %@ == %d", - OWSIncompleteCallsJobCallTypeColumn, - (int)RPRecentCallTypeOutgoingIncomplete, - OWSIncompleteCallsJobCallTypeColumn, - (int)RPRecentCallTypeIncomingIncomplete]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - [[transaction ext:OWSIncompleteCallsJobCallTypeIndex] - enumerateKeysMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) { - [messageIds addObject:key]; - }]; - - return [messageIds copy]; -} - -- (void)enumerateIncompleteCallsWithBlock:(void (^)(TSCall *call))block - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - // Since we can't directly mutate the enumerated "incomplete" calls, we store only their ids in hopes - // of saving a little memory and then enumerate the (larger) TSCall objects one at a time. - for (NSString *callId in [self fetchIncompleteCallIdsWithTransaction:transaction]) { - TSCall *_Nullable call = [TSCall fetchObjectWithUniqueID:callId transaction:transaction]; - if ([call isKindOfClass:[TSCall class]]) { - block(call); - } else { - OWSLogError(@"unexpected object: %@", call); - } - } -} - -- (void)run -{ - __block uint count = 0; - - OWSAssertDebug(CurrentAppContext().appLaunchTime); - uint64_t cutoffTimestamp = [NSDate ows_millisecondsSince1970ForDate:CurrentAppContext().appLaunchTime]; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self - enumerateIncompleteCallsWithBlock:^(TSCall *call) { - if (call.timestamp <= cutoffTimestamp) { - OWSLogInfo(@"ignoring new call: %@", call.uniqueId); - return; - } - - if (call.callType == RPRecentCallTypeOutgoingIncomplete) { - OWSLogDebug(@"marking call as missed: %@", call.uniqueId); - [call updateCallType:RPRecentCallTypeOutgoingMissed transaction:transaction]; - OWSAssertDebug(call.callType == RPRecentCallTypeOutgoingMissed); - } else if (call.callType == RPRecentCallTypeIncomingIncomplete) { - OWSLogDebug(@"marking call as missed: %@", call.uniqueId); - [call updateCallType:RPRecentCallTypeIncomingMissed transaction:transaction]; - OWSAssertDebug(call.callType == RPRecentCallTypeIncomingMissed); - } else { - OWSFailDebug(@"call has unexpected call type: %@", NSStringFromCallType(call.callType)); - return; - } - count++; - } - transaction:transaction]; - }]; - - OWSLogInfo(@"Marked %u calls as missed", count); -} - -#pragma mark - YapDatabaseExtension - -+ (YapDatabaseSecondaryIndex *)indexDatabaseExtension -{ - YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new]; - [setup addColumn:OWSIncompleteCallsJobCallTypeColumn withType:YapDatabaseSecondaryIndexTypeInteger]; - - YapDatabaseSecondaryIndexHandler *handler = - [YapDatabaseSecondaryIndexHandler withObjectBlock:^(YapDatabaseReadTransaction *transaction, - NSMutableDictionary *dict, - NSString *collection, - NSString *key, - id object) { - if (![object isKindOfClass:[TSCall class]]) { - return; - } - TSCall *call = (TSCall *)object; - - dict[OWSIncompleteCallsJobCallTypeColumn] = @(call.callType); - }]; - - return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:nil]; -} - -#ifdef DEBUG -// Useful for tests, don't use in app startup path because it's slow. -- (void)blockingRegisterDatabaseExtensions -{ - [self.primaryStorage registerExtension:[self.class indexDatabaseExtension] - withName:OWSIncompleteCallsJobCallTypeIndex]; -} -#endif - -+ (NSString *)databaseExtensionName -{ - return OWSIncompleteCallsJobCallTypeIndex; -} - -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage -{ - [storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSIncompleteCallsJobCallTypeIndex]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSLinkPreview.swift b/SignalUtilitiesKit/OWSLinkPreview.swift index 656f43657..a5e6260b8 100644 --- a/SignalUtilitiesKit/OWSLinkPreview.swift +++ b/SignalUtilitiesKit/OWSLinkPreview.swift @@ -128,7 +128,7 @@ public class OWSLinkPreview: MTLModel { } @objc - public class func buildValidatedLinkPreview(dataMessage: SSKProtoDataMessage, + public class func buildValidatedLinkPreview(dataMessage: SNProtoDataMessage, body: String?, transaction: YapDatabaseReadWriteTransaction) throws -> OWSLinkPreview { guard OWSLinkPreview.featureEnabled else { diff --git a/SignalUtilitiesKit/OWSOutgoingReceiptManager.h b/SignalUtilitiesKit/OWSOutgoingReceiptManager.h index fe5be23e2..f6784ee0b 100644 --- a/SignalUtilitiesKit/OWSOutgoingReceiptManager.h +++ b/SignalUtilitiesKit/OWSOutgoingReceiptManager.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWSPrimaryStorage; -@class SSKProtoEnvelope; +@class SNProtoEnvelope; @interface OWSOutgoingReceiptManager : NSObject @@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER; + (instancetype)sharedManager; -- (void)enqueueDeliveryReceiptForEnvelope:(SSKProtoEnvelope *)envelope; +- (void)enqueueDeliveryReceiptForEnvelope:(SNProtoEnvelope *)envelope; - (void)enqueueReadReceiptForEnvelope:(NSString *)messageAuthorId timestamp:(uint64_t)timestamp; diff --git a/SignalUtilitiesKit/OWSOutgoingReceiptManager.m b/SignalUtilitiesKit/OWSOutgoingReceiptManager.m index c66e7419a..07e8e7708 100644 --- a/SignalUtilitiesKit/OWSOutgoingReceiptManager.m +++ b/SignalUtilitiesKit/OWSOutgoingReceiptManager.m @@ -217,7 +217,7 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa return [sendPromises copy]; } -- (void)enqueueDeliveryReceiptForEnvelope:(SSKProtoEnvelope *)envelope +- (void)enqueueDeliveryReceiptForEnvelope:(SNProtoEnvelope *)envelope { [self enqueueReceiptWithRecipientId:envelope.source timestamp:envelope.timestamp diff --git a/SignalUtilitiesKit/OWSReadReceiptManager.h b/SignalUtilitiesKit/OWSReadReceiptManager.h index a01f46e29..aeacacee3 100644 --- a/SignalUtilitiesKit/OWSReadReceiptManager.h +++ b/SignalUtilitiesKit/OWSReadReceiptManager.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWSPrimaryStorage; -@class SSKProtoSyncMessageRead; +@class SNProtoSyncMessageRead; @class TSIncomingMessage; @class TSOutgoingMessage; @class TSThread; @@ -53,7 +53,7 @@ extern NSString *const kIncomingMessageMarkedAsReadNotification; #pragma mark - Linked Device Read Receipts -- (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos +- (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos readTimestamp:(uint64_t)readTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalUtilitiesKit/OWSReadReceiptManager.m b/SignalUtilitiesKit/OWSReadReceiptManager.m index 161637226..4ec0df35f 100644 --- a/SignalUtilitiesKit/OWSReadReceiptManager.m +++ b/SignalUtilitiesKit/OWSReadReceiptManager.m @@ -396,7 +396,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE */ } -- (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos +- (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos readTimestamp:(uint64_t)readTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { @@ -406,7 +406,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE OWSAssertDebug(readReceiptProtos); OWSAssertDebug(transaction); - for (SSKProtoSyncMessageRead *readReceiptProto in readReceiptProtos) { + for (SNProtoSyncMessageRead *readReceiptProto in readReceiptProtos) { NSString *_Nullable senderId = readReceiptProto.sender; uint64_t messageIdTimestamp = readReceiptProto.timestamp; diff --git a/SignalUtilitiesKit/OWSRecipientIdentity.h b/SignalUtilitiesKit/OWSRecipientIdentity.h index da8c1a913..f1486c656 100644 --- a/SignalUtilitiesKit/OWSRecipientIdentity.h +++ b/SignalUtilitiesKit/OWSRecipientIdentity.h @@ -12,10 +12,10 @@ typedef NS_ENUM(NSUInteger, OWSVerificationState) { OWSVerificationStateNoLongerVerified, }; -@class SSKProtoVerified; +@class SNProtoVerified; NSString *OWSVerificationStateToString(OWSVerificationState verificationState); -SSKProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinationRecipientId, +SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinationRecipientId, NSData *identityKey, OWSVerificationState verificationState, NSUInteger paddingBytesLength); diff --git a/SignalUtilitiesKit/OWSRecipientIdentity.m b/SignalUtilitiesKit/OWSRecipientIdentity.m index eaabf61b6..55bd13414 100644 --- a/SignalUtilitiesKit/OWSRecipientIdentity.m +++ b/SignalUtilitiesKit/OWSRecipientIdentity.m @@ -24,19 +24,19 @@ NSString *OWSVerificationStateToString(OWSVerificationState verificationState) } } -SSKProtoVerifiedState OWSVerificationStateToProtoState(OWSVerificationState verificationState) +SNProtoVerifiedState OWSVerificationStateToProtoState(OWSVerificationState verificationState) { switch (verificationState) { case OWSVerificationStateDefault: - return SSKProtoVerifiedStateDefault; + return SNProtoVerifiedStateDefault; case OWSVerificationStateVerified: - return SSKProtoVerifiedStateVerified; + return SNProtoVerifiedStateVerified; case OWSVerificationStateNoLongerVerified: - return SSKProtoVerifiedStateUnverified; + return SNProtoVerifiedStateUnverified; } } -SSKProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinationRecipientId, +SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinationRecipientId, NSData *identityKey, OWSVerificationState verificationState, NSUInteger paddingBytesLength) @@ -47,7 +47,7 @@ SSKProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinat // will figure that out on it's own. OWSCAssertDebug(verificationState != OWSVerificationStateNoLongerVerified); - SSKProtoVerifiedBuilder *verifiedBuilder = [SSKProtoVerified builderWithDestination:destinationRecipientId]; + SNProtoVerifiedBuilder *verifiedBuilder = [SNProtoVerified builderWithDestination:destinationRecipientId]; verifiedBuilder.identityKey = identityKey; verifiedBuilder.state = OWSVerificationStateToProtoState(verificationState); @@ -61,7 +61,7 @@ SSKProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinat } NSError *error; - SSKProtoVerified *_Nullable verifiedProto = [verifiedBuilder buildAndReturnError:&error]; + SNProtoVerified *_Nullable verifiedProto = [verifiedBuilder buildAndReturnError:&error]; if (error || !verifiedProto) { OWSCFailDebug(@"%@ could not build protobuf: %@", @"[BuildVerifiedProtoWithRecipientId]", error); return nil; diff --git a/SignalUtilitiesKit/OWSRecordTranscriptJob.h b/SignalUtilitiesKit/OWSRecordTranscriptJob.h index 11e5df9b0..d9e345a4c 100644 --- a/SignalUtilitiesKit/OWSRecordTranscriptJob.h +++ b/SignalUtilitiesKit/OWSRecordTranscriptJob.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWSIncomingSentMessageTranscript; -@class SSKProtoSyncMessageSentUpdate; +@class SNProtoSyncMessageSentUpdate; @class TSAttachmentStream; @class YapDatabaseReadWriteTransaction; diff --git a/SignalUtilitiesKit/ProximityMonitoringManager.swift b/SignalUtilitiesKit/ProximityMonitoringManager.swift index 8c8ec9aef..3b74af82d 100644 --- a/SignalUtilitiesKit/ProximityMonitoringManager.swift +++ b/SignalUtilitiesKit/ProximityMonitoringManager.swift @@ -32,7 +32,7 @@ public class OWSProximityMonitoringManagerImpl: NSObject, OWSProximityMonitoring public func add(lifetime: AnyObject) { objc_sync_enter(self) - if !lifetimes.contains { $0.value === lifetime } { + if !lifetimes.contains(where: { $0.value === lifetime }) { lifetimes.append(Weak(value: lifetime)) } reconcile() diff --git a/SignalUtilitiesKit/PublicChatPoller.swift b/SignalUtilitiesKit/PublicChatPoller.swift index 27ca5dc4d..95e3aac9e 100644 --- a/SignalUtilitiesKit/PublicChatPoller.swift +++ b/SignalUtilitiesKit/PublicChatPoller.swift @@ -73,12 +73,12 @@ public final class PublicChatPoller : NSObject { } let senderDisplayName = UserDisplayNameUtilities.getPublicChatDisplayName(for: senderPublicKey, in: publicChat.channel, on: publicChat.server) ?? generateDisplayName(from: NSLocalizedString("Anonymous", comment: "")) let id = LKGroupUtilities.getEncodedOpenGroupIDAsData(publicChat.id) - let groupContext = SSKProtoGroupContext.builder(id: id, type: .deliver) + let groupContext = SNProtoGroupContext.builder(id: id, type: .deliver) groupContext.setName(publicChat.displayName) - let dataMessage = SSKProtoDataMessage.builder() - let attachments: [SSKProtoAttachmentPointer] = message.attachments.compactMap { attachment in + let dataMessage = SNProtoDataMessage.builder() + let attachments: [SNProtoAttachmentPointer] = message.attachments.compactMap { attachment in guard attachment.kind == .attachment else { return nil } - let result = SSKProtoAttachmentPointer.builder(id: attachment.serverID) + let result = SNProtoAttachmentPointer.builder(id: attachment.serverID) result.setContentType(attachment.contentType) result.setSize(UInt32(attachment.size)) result.setFileName(attachment.fileName) @@ -93,9 +93,9 @@ public final class PublicChatPoller : NSObject { } dataMessage.setAttachments(attachments) if let linkPreview = message.attachments.first(where: { $0.kind == .linkPreview }) { - let signalLinkPreview = SSKProtoDataMessagePreview.builder(url: linkPreview.linkPreviewURL!) + let signalLinkPreview = SNProtoDataMessagePreview.builder(url: linkPreview.linkPreviewURL!) signalLinkPreview.setTitle(linkPreview.linkPreviewTitle!) - let attachment = SSKProtoAttachmentPointer.builder(id: linkPreview.serverID) + let attachment = SNProtoAttachmentPointer.builder(id: linkPreview.serverID) attachment.setContentType(linkPreview.contentType) attachment.setSize(UInt32(linkPreview.size)) attachment.setFileName(linkPreview.fileName) @@ -109,7 +109,7 @@ public final class PublicChatPoller : NSObject { signalLinkPreview.setImage(try! attachment.build()) dataMessage.setPreview([ try! signalLinkPreview.build() ]) } - let profile = SSKProtoDataMessageLokiProfile.builder() + let profile = SNProtoDataMessageLokiProfile.builder() profile.setDisplayName(message.displayName) if let profilePicture = message.profilePicture { profile.setProfilePicture(profilePicture.url) @@ -119,31 +119,31 @@ public final class PublicChatPoller : NSObject { dataMessage.setTimestamp(message.timestamp) dataMessage.setGroup(try! groupContext.build()) if let quote = message.quote { - let signalQuote = SSKProtoDataMessageQuote.builder(id: quote.quotedMessageTimestamp, author: quote.quoteePublicKey) + let signalQuote = SNProtoDataMessageQuote.builder(id: quote.quotedMessageTimestamp, author: quote.quoteePublicKey) signalQuote.setText(quote.quotedMessageBody) dataMessage.setQuote(try! signalQuote.build()) } let body = (message.body == message.timestamp.description) ? "" : message.body // Workaround for the fact that the back-end doesn't accept messages without a body dataMessage.setBody(body) if let messageServerID = message.serverID { - let publicChatInfo = SSKProtoPublicChatInfo.builder() + let publicChatInfo = SNProtoPublicChatInfo.builder() publicChatInfo.setServerID(messageServerID) dataMessage.setPublicChatInfo(try! publicChatInfo.build()) } - let content = SSKProtoContent.builder() + let content = SNProtoContent.builder() if !wasSentByCurrentUser { content.setDataMessage(try! dataMessage.build()) } else { - let syncMessageSentBuilder = SSKProtoSyncMessageSent.builder() + let syncMessageSentBuilder = SNProtoSyncMessageSent.builder() syncMessageSentBuilder.setMessage(try! dataMessage.build()) syncMessageSentBuilder.setDestination(userPublicKey) syncMessageSentBuilder.setTimestamp(message.timestamp) let syncMessageSent = try! syncMessageSentBuilder.build() - let syncMessageBuilder = SSKProtoSyncMessage.builder() + let syncMessageBuilder = SNProtoSyncMessage.builder() syncMessageBuilder.setSent(syncMessageSent) content.setSyncMessage(try! syncMessageBuilder.build()) } - let envelope = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp) + let envelope = SNProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp) envelope.setSource(senderPublicKey) envelope.setSourceDevice(1) envelope.setContent(try! content.build().serializedData()) diff --git a/SignalUtilitiesKit/DisplayNameUtilities.swift b/SignalUtilitiesKit/Remove Later/DisplayNameUtilities.swift similarity index 100% rename from SignalUtilitiesKit/DisplayNameUtilities.swift rename to SignalUtilitiesKit/Remove Later/DisplayNameUtilities.swift diff --git a/SignalUtilitiesKit/DisplayNameUtilities2.swift b/SignalUtilitiesKit/Remove Later/DisplayNameUtilities2.swift similarity index 100% rename from SignalUtilitiesKit/DisplayNameUtilities2.swift rename to SignalUtilitiesKit/Remove Later/DisplayNameUtilities2.swift diff --git a/SignalUtilitiesKit/Remove Later/OWSProfileManager.h b/SignalUtilitiesKit/Remove Later/OWSProfileManager.h index 2631674be..5741620aa 100644 --- a/SignalUtilitiesKit/Remove Later/OWSProfileManager.h +++ b/SignalUtilitiesKit/Remove Later/OWSProfileManager.h @@ -54,8 +54,6 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; - (BOOL)isProfileNameTooLong:(nullable NSString *)profileName; -- (void)fetchLocalUsersProfile; - #pragma mark - Profile Whitelist // These methods are for debugging. diff --git a/SignalUtilitiesKit/Remove Later/OWSProfileManager.m b/SignalUtilitiesKit/Remove Later/OWSProfileManager.m index c503fffce..67ef370bd 100644 --- a/SignalUtilitiesKit/Remove Later/OWSProfileManager.m +++ b/SignalUtilitiesKit/Remove Later/OWSProfileManager.m @@ -654,13 +654,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); return [self.tsAccountManager updateAccountAttributes]; }); - // Fetch local profile. - promise = promise.then(^(id value) { - [self fetchLocalUsersProfile]; - - return @(1); - }); - promise = promise.then(^(id value) { [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_ProfileKeyDidChange object:nil diff --git a/SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift b/SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift index 1455a715d..315c3f511 100644 --- a/SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift +++ b/SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift @@ -192,7 +192,7 @@ public final class SessionManagementProtocol : NSObject { } @objc(handlePreKeyBundleMessageIfNeeded:wrappedIn:transaction:) - public static func handlePreKeyBundleMessageIfNeeded(_ protoContent: SSKProtoContent, wrappedIn envelope: SSKProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { + public static func handlePreKeyBundleMessageIfNeeded(_ protoContent: SNProtoContent, wrappedIn envelope: SNProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { // let publicKey = envelope.source! // Set during UD decryption // guard let preKeyBundleMessage = protoContent.prekeyBundleMessage else { return } // print("[Loki] Received a pre key bundle message from: \(publicKey).") diff --git a/SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift b/SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift index bcbc2ee13..a89cc17f7 100644 --- a/SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift +++ b/SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift @@ -102,14 +102,14 @@ public final class SessionMetaProtocol : NSObject { } @objc(updateDisplayNameIfNeededForPublicKey:using:transaction:) - public static func updateDisplayNameIfNeeded(for publicKey: String, using dataMessage: SSKProtoDataMessage, in transaction: YapDatabaseReadWriteTransaction) { + public static func updateDisplayNameIfNeeded(for publicKey: String, using dataMessage: SNProtoDataMessage, in transaction: YapDatabaseReadWriteTransaction) { guard let profile = dataMessage.profile, let displayName = profile.displayName, !displayName.isEmpty else { return } let profileManager = SSKEnvironment.shared.profileManager profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) } @objc(updateProfileKeyIfNeededForPublicKey:using:) - public static func updateProfileKeyIfNeeded(for publicKey: String, using dataMessage: SSKProtoDataMessage) { + public static func updateProfileKeyIfNeeded(for publicKey: String, using dataMessage: SNProtoDataMessage) { guard dataMessage.hasProfileKey, let profileKey = dataMessage.profileKey else { return } guard profileKey.count == kAES256_KeyByteLength else { return print("[Loki] Unexpected profile key size: \(profileKey.count).") diff --git a/SignalUtilitiesKit/SSKEnvironment.h b/SignalUtilitiesKit/SSKEnvironment.h index 4ac8cae53..09f9262d9 100644 --- a/SignalUtilitiesKit/SSKEnvironment.h +++ b/SignalUtilitiesKit/SSKEnvironment.h @@ -74,8 +74,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) id typingIndicators; @property (nonatomic, readonly) OWSAttachmentDownloads *attachmentDownloads; -// This property is configured after Environment is created. -@property (atomic, nullable) id callMessageHandler; // This property is configured after Environment is created. @property (atomic, nullable) id notificationsManager; diff --git a/SignalUtilitiesKit/SSKEnvironment.m b/SignalUtilitiesKit/SSKEnvironment.m index b0e233b16..2430e125d 100644 --- a/SignalUtilitiesKit/SSKEnvironment.m +++ b/SignalUtilitiesKit/SSKEnvironment.m @@ -32,7 +32,6 @@ static SSKEnvironment *sharedSSKEnvironment; @implementation SSKEnvironment -@synthesize callMessageHandler = _callMessageHandler; @synthesize notificationsManager = _notificationsManager; @synthesize objectReadWriteConnection = _objectReadWriteConnection; @synthesize sessionStoreDBConnection = _sessionStoreDBConnection; diff --git a/SignalUtilitiesKit/SSKProto.swift b/SignalUtilitiesKit/SSKProto.swift deleted file mode 100644 index 6b7e07e7f..000000000 --- a/SignalUtilitiesKit/SSKProto.swift +++ /dev/null @@ -1,7075 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -// WARNING: This code is generated. Only edit within the markers. - -public enum SSKProtoError: Error { - case invalidProtobuf(description: String) -} - -// MARK: - SSKProtoEnvelope - -@objc public class SSKProtoEnvelope: NSObject { - - // MARK: - SSKProtoEnvelopeType - - @objc public enum SSKProtoEnvelopeType: Int32 { - case unknown = 0 - case ciphertext = 1 - case keyExchange = 2 - case prekeyBundle = 3 - case receipt = 5 - case unidentifiedSender = 6 - case closedGroupCiphertext = 7 - case fallbackMessage = 101 - } - - private class func SSKProtoEnvelopeTypeWrap(_ value: SignalServiceProtos_Envelope.TypeEnum) -> SSKProtoEnvelopeType { - switch value { - case .unknown: return .unknown - case .ciphertext: return .ciphertext - case .keyExchange: return .keyExchange - case .prekeyBundle: return .prekeyBundle - case .receipt: return .receipt - case .unidentifiedSender: return .unidentifiedSender - case .closedGroupCiphertext: return .closedGroupCiphertext - case .fallbackMessage: return .fallbackMessage - } - } - - private class func SSKProtoEnvelopeTypeUnwrap(_ value: SSKProtoEnvelopeType) -> SignalServiceProtos_Envelope.TypeEnum { - switch value { - case .unknown: return .unknown - case .ciphertext: return .ciphertext - case .keyExchange: return .keyExchange - case .prekeyBundle: return .prekeyBundle - case .receipt: return .receipt - case .unidentifiedSender: return .unidentifiedSender - case .closedGroupCiphertext: return .closedGroupCiphertext - case .fallbackMessage: return .fallbackMessage - } - } - - // MARK: - SSKProtoEnvelopeBuilder - - @objc public class func builder(type: SSKProtoEnvelopeType, timestamp: UInt64) -> SSKProtoEnvelopeBuilder { - return SSKProtoEnvelopeBuilder(type: type, timestamp: timestamp) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoEnvelopeBuilder { - let builder = SSKProtoEnvelopeBuilder(type: type, timestamp: timestamp) - if let _value = source { - builder.setSource(_value) - } - if hasSourceDevice { - builder.setSourceDevice(sourceDevice) - } - if let _value = relay { - builder.setRelay(_value) - } - if let _value = legacyMessage { - builder.setLegacyMessage(_value) - } - if let _value = content { - builder.setContent(_value) - } - if let _value = serverGuid { - builder.setServerGuid(_value) - } - if hasServerTimestamp { - builder.setServerTimestamp(serverTimestamp) - } - return builder - } - - @objc public class SSKProtoEnvelopeBuilder: NSObject { - - private var proto = SignalServiceProtos_Envelope() - - @objc fileprivate override init() {} - - @objc fileprivate init(type: SSKProtoEnvelopeType, timestamp: UInt64) { - super.init() - - setType(type) - setTimestamp(timestamp) - } - - @objc public func setType(_ valueParam: SSKProtoEnvelopeType) { - proto.type = SSKProtoEnvelopeTypeUnwrap(valueParam) - } - - @objc public func setSource(_ valueParam: String) { - proto.source = valueParam - } - - @objc public func setSourceDevice(_ valueParam: UInt32) { - proto.sourceDevice = valueParam - } - - @objc public func setRelay(_ valueParam: String) { - proto.relay = valueParam - } - - @objc public func setTimestamp(_ valueParam: UInt64) { - proto.timestamp = valueParam - } - - @objc public func setLegacyMessage(_ valueParam: Data) { - proto.legacyMessage = valueParam - } - - @objc public func setContent(_ valueParam: Data) { - proto.content = valueParam - } - - @objc public func setServerGuid(_ valueParam: String) { - proto.serverGuid = valueParam - } - - @objc public func setServerTimestamp(_ valueParam: UInt64) { - proto.serverTimestamp = valueParam - } - - @objc public func build() throws -> SSKProtoEnvelope { - return try SSKProtoEnvelope.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoEnvelope.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_Envelope - - @objc public let type: SSKProtoEnvelopeType - - @objc public let timestamp: UInt64 - - @objc public var source: String? { - guard proto.hasSource else { - return nil - } - return proto.source - } - @objc public var hasSource: Bool { - return proto.hasSource - } - - @objc public var sourceDevice: UInt32 { - return proto.sourceDevice - } - @objc public var hasSourceDevice: Bool { - return proto.hasSourceDevice - } - - @objc public var relay: String? { - guard proto.hasRelay else { - return nil - } - return proto.relay - } - @objc public var hasRelay: Bool { - return proto.hasRelay - } - - @objc public var legacyMessage: Data? { - guard proto.hasLegacyMessage else { - return nil - } - return proto.legacyMessage - } - @objc public var hasLegacyMessage: Bool { - return proto.hasLegacyMessage - } - - @objc public var content: Data? { - guard proto.hasContent else { - return nil - } - return proto.content - } - @objc public var hasContent: Bool { - return proto.hasContent - } - - @objc public var serverGuid: String? { - guard proto.hasServerGuid else { - return nil - } - return proto.serverGuid - } - @objc public var hasServerGuid: Bool { - return proto.hasServerGuid - } - - @objc public var serverTimestamp: UInt64 { - return proto.serverTimestamp - } - @objc public var hasServerTimestamp: Bool { - return proto.hasServerTimestamp - } - - private init(proto: SignalServiceProtos_Envelope, - type: SSKProtoEnvelopeType, - timestamp: UInt64) { - self.proto = proto - self.type = type - self.timestamp = timestamp - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoEnvelope { - let proto = try SignalServiceProtos_Envelope(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_Envelope) throws -> SSKProtoEnvelope { - guard proto.hasType else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: type") - } - let type = SSKProtoEnvelopeTypeWrap(proto.type) - - guard proto.hasTimestamp else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: timestamp") - } - let timestamp = proto.timestamp - - // MARK: - Begin Validation Logic for SSKProtoEnvelope - - - // MARK: - End Validation Logic for SSKProtoEnvelope - - - let result = SSKProtoEnvelope(proto: proto, - type: type, - timestamp: timestamp) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoEnvelope { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoEnvelope.SSKProtoEnvelopeBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoEnvelope? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoTypingMessage - -@objc public class SSKProtoTypingMessage: NSObject { - - // MARK: - SSKProtoTypingMessageAction - - @objc public enum SSKProtoTypingMessageAction: Int32 { - case started = 0 - case stopped = 1 - } - - private class func SSKProtoTypingMessageActionWrap(_ value: SignalServiceProtos_TypingMessage.Action) -> SSKProtoTypingMessageAction { - switch value { - case .started: return .started - case .stopped: return .stopped - } - } - - private class func SSKProtoTypingMessageActionUnwrap(_ value: SSKProtoTypingMessageAction) -> SignalServiceProtos_TypingMessage.Action { - switch value { - case .started: return .started - case .stopped: return .stopped - } - } - - // MARK: - SSKProtoTypingMessageBuilder - - @objc public class func builder(timestamp: UInt64, action: SSKProtoTypingMessageAction) -> SSKProtoTypingMessageBuilder { - return SSKProtoTypingMessageBuilder(timestamp: timestamp, action: action) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoTypingMessageBuilder { - let builder = SSKProtoTypingMessageBuilder(timestamp: timestamp, action: action) - if let _value = groupID { - builder.setGroupID(_value) - } - return builder - } - - @objc public class SSKProtoTypingMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_TypingMessage() - - @objc fileprivate override init() {} - - @objc fileprivate init(timestamp: UInt64, action: SSKProtoTypingMessageAction) { - super.init() - - setTimestamp(timestamp) - setAction(action) - } - - @objc public func setTimestamp(_ valueParam: UInt64) { - proto.timestamp = valueParam - } - - @objc public func setAction(_ valueParam: SSKProtoTypingMessageAction) { - proto.action = SSKProtoTypingMessageActionUnwrap(valueParam) - } - - @objc public func setGroupID(_ valueParam: Data) { - proto.groupID = valueParam - } - - @objc public func build() throws -> SSKProtoTypingMessage { - return try SSKProtoTypingMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoTypingMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_TypingMessage - - @objc public let timestamp: UInt64 - - @objc public let action: SSKProtoTypingMessageAction - - @objc public var groupID: Data? { - guard proto.hasGroupID else { - return nil - } - return proto.groupID - } - @objc public var hasGroupID: Bool { - return proto.hasGroupID - } - - private init(proto: SignalServiceProtos_TypingMessage, - timestamp: UInt64, - action: SSKProtoTypingMessageAction) { - self.proto = proto - self.timestamp = timestamp - self.action = action - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoTypingMessage { - let proto = try SignalServiceProtos_TypingMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_TypingMessage) throws -> SSKProtoTypingMessage { - guard proto.hasTimestamp else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: timestamp") - } - let timestamp = proto.timestamp - - guard proto.hasAction else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: action") - } - let action = SSKProtoTypingMessageActionWrap(proto.action) - - // MARK: - Begin Validation Logic for SSKProtoTypingMessage - - - // MARK: - End Validation Logic for SSKProtoTypingMessage - - - let result = SSKProtoTypingMessage(proto: proto, - timestamp: timestamp, - action: action) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoTypingMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoTypingMessage.SSKProtoTypingMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoTypingMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoContent - -@objc public class SSKProtoContent: NSObject { - - // MARK: - SSKProtoContentBuilder - - @objc public class func builder() -> SSKProtoContentBuilder { - return SSKProtoContentBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoContentBuilder { - let builder = SSKProtoContentBuilder() - if let _value = dataMessage { - builder.setDataMessage(_value) - } - if let _value = syncMessage { - builder.setSyncMessage(_value) - } - if let _value = callMessage { - builder.setCallMessage(_value) - } - if let _value = nullMessage { - builder.setNullMessage(_value) - } - if let _value = receiptMessage { - builder.setReceiptMessage(_value) - } - if let _value = typingMessage { - builder.setTypingMessage(_value) - } - if let _value = prekeyBundleMessage { - builder.setPrekeyBundleMessage(_value) - } - if let _value = lokiDeviceLinkMessage { - builder.setLokiDeviceLinkMessage(_value) - } - return builder - } - - @objc public class SSKProtoContentBuilder: NSObject { - - private var proto = SignalServiceProtos_Content() - - @objc fileprivate override init() {} - - @objc public func setDataMessage(_ valueParam: SSKProtoDataMessage) { - proto.dataMessage = valueParam.proto - } - - @objc public func setSyncMessage(_ valueParam: SSKProtoSyncMessage) { - proto.syncMessage = valueParam.proto - } - - @objc public func setCallMessage(_ valueParam: SSKProtoCallMessage) { - proto.callMessage = valueParam.proto - } - - @objc public func setNullMessage(_ valueParam: SSKProtoNullMessage) { - proto.nullMessage = valueParam.proto - } - - @objc public func setReceiptMessage(_ valueParam: SSKProtoReceiptMessage) { - proto.receiptMessage = valueParam.proto - } - - @objc public func setTypingMessage(_ valueParam: SSKProtoTypingMessage) { - proto.typingMessage = valueParam.proto - } - - @objc public func setPrekeyBundleMessage(_ valueParam: SSKProtoPrekeyBundleMessage) { - proto.prekeyBundleMessage = valueParam.proto - } - - @objc public func setLokiDeviceLinkMessage(_ valueParam: SSKProtoLokiDeviceLinkMessage) { - proto.lokiDeviceLinkMessage = valueParam.proto - } - - @objc public func build() throws -> SSKProtoContent { - return try SSKProtoContent.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoContent.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_Content - - @objc public let dataMessage: SSKProtoDataMessage? - - @objc public let syncMessage: SSKProtoSyncMessage? - - @objc public let callMessage: SSKProtoCallMessage? - - @objc public let nullMessage: SSKProtoNullMessage? - - @objc public let receiptMessage: SSKProtoReceiptMessage? - - @objc public let typingMessage: SSKProtoTypingMessage? - - @objc public let prekeyBundleMessage: SSKProtoPrekeyBundleMessage? - - @objc public let lokiDeviceLinkMessage: SSKProtoLokiDeviceLinkMessage? - - private init(proto: SignalServiceProtos_Content, - dataMessage: SSKProtoDataMessage?, - syncMessage: SSKProtoSyncMessage?, - callMessage: SSKProtoCallMessage?, - nullMessage: SSKProtoNullMessage?, - receiptMessage: SSKProtoReceiptMessage?, - typingMessage: SSKProtoTypingMessage?, - prekeyBundleMessage: SSKProtoPrekeyBundleMessage?, - lokiDeviceLinkMessage: SSKProtoLokiDeviceLinkMessage?) { - self.proto = proto - self.dataMessage = dataMessage - self.syncMessage = syncMessage - self.callMessage = callMessage - self.nullMessage = nullMessage - self.receiptMessage = receiptMessage - self.typingMessage = typingMessage - self.prekeyBundleMessage = prekeyBundleMessage - self.lokiDeviceLinkMessage = lokiDeviceLinkMessage - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoContent { - let proto = try SignalServiceProtos_Content(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_Content) throws -> SSKProtoContent { - var dataMessage: SSKProtoDataMessage? = nil - if proto.hasDataMessage { - dataMessage = try SSKProtoDataMessage.parseProto(proto.dataMessage) - } - - var syncMessage: SSKProtoSyncMessage? = nil - if proto.hasSyncMessage { - syncMessage = try SSKProtoSyncMessage.parseProto(proto.syncMessage) - } - - var callMessage: SSKProtoCallMessage? = nil - if proto.hasCallMessage { - callMessage = try SSKProtoCallMessage.parseProto(proto.callMessage) - } - - var nullMessage: SSKProtoNullMessage? = nil - if proto.hasNullMessage { - nullMessage = try SSKProtoNullMessage.parseProto(proto.nullMessage) - } - - var receiptMessage: SSKProtoReceiptMessage? = nil - if proto.hasReceiptMessage { - receiptMessage = try SSKProtoReceiptMessage.parseProto(proto.receiptMessage) - } - - var typingMessage: SSKProtoTypingMessage? = nil - if proto.hasTypingMessage { - typingMessage = try SSKProtoTypingMessage.parseProto(proto.typingMessage) - } - - var prekeyBundleMessage: SSKProtoPrekeyBundleMessage? = nil - if proto.hasPrekeyBundleMessage { - prekeyBundleMessage = try SSKProtoPrekeyBundleMessage.parseProto(proto.prekeyBundleMessage) - } - - var lokiDeviceLinkMessage: SSKProtoLokiDeviceLinkMessage? = nil - if proto.hasLokiDeviceLinkMessage { - lokiDeviceLinkMessage = try SSKProtoLokiDeviceLinkMessage.parseProto(proto.lokiDeviceLinkMessage) - } - - // MARK: - Begin Validation Logic for SSKProtoContent - - - // MARK: - End Validation Logic for SSKProtoContent - - - let result = SSKProtoContent(proto: proto, - dataMessage: dataMessage, - syncMessage: syncMessage, - callMessage: callMessage, - nullMessage: nullMessage, - receiptMessage: receiptMessage, - typingMessage: typingMessage, - prekeyBundleMessage: prekeyBundleMessage, - lokiDeviceLinkMessage: lokiDeviceLinkMessage) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoContent { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoContent.SSKProtoContentBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoContent? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoPrekeyBundleMessage - -@objc public class SSKProtoPrekeyBundleMessage: NSObject { - - // MARK: - SSKProtoPrekeyBundleMessageBuilder - - @objc public class func builder() -> SSKProtoPrekeyBundleMessageBuilder { - return SSKProtoPrekeyBundleMessageBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoPrekeyBundleMessageBuilder { - let builder = SSKProtoPrekeyBundleMessageBuilder() - if let _value = identityKey { - builder.setIdentityKey(_value) - } - if hasDeviceID { - builder.setDeviceID(deviceID) - } - if hasPrekeyID { - builder.setPrekeyID(prekeyID) - } - if hasSignedKeyID { - builder.setSignedKeyID(signedKeyID) - } - if let _value = prekey { - builder.setPrekey(_value) - } - if let _value = signedKey { - builder.setSignedKey(_value) - } - if let _value = signature { - builder.setSignature(_value) - } - return builder - } - - @objc public class SSKProtoPrekeyBundleMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_PrekeyBundleMessage() - - @objc fileprivate override init() {} - - @objc public func setIdentityKey(_ valueParam: Data) { - proto.identityKey = valueParam - } - - @objc public func setDeviceID(_ valueParam: UInt32) { - proto.deviceID = valueParam - } - - @objc public func setPrekeyID(_ valueParam: UInt32) { - proto.prekeyID = valueParam - } - - @objc public func setSignedKeyID(_ valueParam: UInt32) { - proto.signedKeyID = valueParam - } - - @objc public func setPrekey(_ valueParam: Data) { - proto.prekey = valueParam - } - - @objc public func setSignedKey(_ valueParam: Data) { - proto.signedKey = valueParam - } - - @objc public func setSignature(_ valueParam: Data) { - proto.signature = valueParam - } - - @objc public func build() throws -> SSKProtoPrekeyBundleMessage { - return try SSKProtoPrekeyBundleMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoPrekeyBundleMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_PrekeyBundleMessage - - @objc public var identityKey: Data? { - guard proto.hasIdentityKey else { - return nil - } - return proto.identityKey - } - @objc public var hasIdentityKey: Bool { - return proto.hasIdentityKey - } - - @objc public var deviceID: UInt32 { - return proto.deviceID - } - @objc public var hasDeviceID: Bool { - return proto.hasDeviceID - } - - @objc public var prekeyID: UInt32 { - return proto.prekeyID - } - @objc public var hasPrekeyID: Bool { - return proto.hasPrekeyID - } - - @objc public var signedKeyID: UInt32 { - return proto.signedKeyID - } - @objc public var hasSignedKeyID: Bool { - return proto.hasSignedKeyID - } - - @objc public var prekey: Data? { - guard proto.hasPrekey else { - return nil - } - return proto.prekey - } - @objc public var hasPrekey: Bool { - return proto.hasPrekey - } - - @objc public var signedKey: Data? { - guard proto.hasSignedKey else { - return nil - } - return proto.signedKey - } - @objc public var hasSignedKey: Bool { - return proto.hasSignedKey - } - - @objc public var signature: Data? { - guard proto.hasSignature else { - return nil - } - return proto.signature - } - @objc public var hasSignature: Bool { - return proto.hasSignature - } - - private init(proto: SignalServiceProtos_PrekeyBundleMessage) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoPrekeyBundleMessage { - let proto = try SignalServiceProtos_PrekeyBundleMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_PrekeyBundleMessage) throws -> SSKProtoPrekeyBundleMessage { - // MARK: - Begin Validation Logic for SSKProtoPrekeyBundleMessage - - - // MARK: - End Validation Logic for SSKProtoPrekeyBundleMessage - - - let result = SSKProtoPrekeyBundleMessage(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoPrekeyBundleMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoPrekeyBundleMessage.SSKProtoPrekeyBundleMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoPrekeyBundleMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoLokiDeviceLinkMessage - -@objc public class SSKProtoLokiDeviceLinkMessage: NSObject { - - // MARK: - SSKProtoLokiDeviceLinkMessageBuilder - - @objc public class func builder() -> SSKProtoLokiDeviceLinkMessageBuilder { - return SSKProtoLokiDeviceLinkMessageBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoLokiDeviceLinkMessageBuilder { - let builder = SSKProtoLokiDeviceLinkMessageBuilder() - if let _value = masterPublicKey { - builder.setMasterPublicKey(_value) - } - if let _value = slavePublicKey { - builder.setSlavePublicKey(_value) - } - if let _value = slaveSignature { - builder.setSlaveSignature(_value) - } - if let _value = masterSignature { - builder.setMasterSignature(_value) - } - return builder - } - - @objc public class SSKProtoLokiDeviceLinkMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_LokiDeviceLinkMessage() - - @objc fileprivate override init() {} - - @objc public func setMasterPublicKey(_ valueParam: String) { - proto.masterPublicKey = valueParam - } - - @objc public func setSlavePublicKey(_ valueParam: String) { - proto.slavePublicKey = valueParam - } - - @objc public func setSlaveSignature(_ valueParam: Data) { - proto.slaveSignature = valueParam - } - - @objc public func setMasterSignature(_ valueParam: Data) { - proto.masterSignature = valueParam - } - - @objc public func build() throws -> SSKProtoLokiDeviceLinkMessage { - return try SSKProtoLokiDeviceLinkMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoLokiDeviceLinkMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_LokiDeviceLinkMessage - - @objc public var masterPublicKey: String? { - guard proto.hasMasterPublicKey else { - return nil - } - return proto.masterPublicKey - } - @objc public var hasMasterPublicKey: Bool { - return proto.hasMasterPublicKey - } - - @objc public var slavePublicKey: String? { - guard proto.hasSlavePublicKey else { - return nil - } - return proto.slavePublicKey - } - @objc public var hasSlavePublicKey: Bool { - return proto.hasSlavePublicKey - } - - @objc public var slaveSignature: Data? { - guard proto.hasSlaveSignature else { - return nil - } - return proto.slaveSignature - } - @objc public var hasSlaveSignature: Bool { - return proto.hasSlaveSignature - } - - @objc public var masterSignature: Data? { - guard proto.hasMasterSignature else { - return nil - } - return proto.masterSignature - } - @objc public var hasMasterSignature: Bool { - return proto.hasMasterSignature - } - - private init(proto: SignalServiceProtos_LokiDeviceLinkMessage) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoLokiDeviceLinkMessage { - let proto = try SignalServiceProtos_LokiDeviceLinkMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_LokiDeviceLinkMessage) throws -> SSKProtoLokiDeviceLinkMessage { - // MARK: - Begin Validation Logic for SSKProtoLokiDeviceLinkMessage - - - // MARK: - End Validation Logic for SSKProtoLokiDeviceLinkMessage - - - let result = SSKProtoLokiDeviceLinkMessage(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoLokiDeviceLinkMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoLokiDeviceLinkMessage.SSKProtoLokiDeviceLinkMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoLokiDeviceLinkMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoCallMessageOffer - -@objc public class SSKProtoCallMessageOffer: NSObject { - - // MARK: - SSKProtoCallMessageOfferBuilder - - @objc public class func builder(id: UInt64, sessionDescription: String) -> SSKProtoCallMessageOfferBuilder { - return SSKProtoCallMessageOfferBuilder(id: id, sessionDescription: sessionDescription) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoCallMessageOfferBuilder { - let builder = SSKProtoCallMessageOfferBuilder(id: id, sessionDescription: sessionDescription) - return builder - } - - @objc public class SSKProtoCallMessageOfferBuilder: NSObject { - - private var proto = SignalServiceProtos_CallMessage.Offer() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: UInt64, sessionDescription: String) { - super.init() - - setId(id) - setSessionDescription(sessionDescription) - } - - @objc public func setId(_ valueParam: UInt64) { - proto.id = valueParam - } - - @objc public func setSessionDescription(_ valueParam: String) { - proto.sessionDescription = valueParam - } - - @objc public func build() throws -> SSKProtoCallMessageOffer { - return try SSKProtoCallMessageOffer.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoCallMessageOffer.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_CallMessage.Offer - - @objc public let id: UInt64 - - @objc public let sessionDescription: String - - private init(proto: SignalServiceProtos_CallMessage.Offer, - id: UInt64, - sessionDescription: String) { - self.proto = proto - self.id = id - self.sessionDescription = sessionDescription - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoCallMessageOffer { - let proto = try SignalServiceProtos_CallMessage.Offer(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_CallMessage.Offer) throws -> SSKProtoCallMessageOffer { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - guard proto.hasSessionDescription else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sessionDescription") - } - let sessionDescription = proto.sessionDescription - - // MARK: - Begin Validation Logic for SSKProtoCallMessageOffer - - - // MARK: - End Validation Logic for SSKProtoCallMessageOffer - - - let result = SSKProtoCallMessageOffer(proto: proto, - id: id, - sessionDescription: sessionDescription) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoCallMessageOffer { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoCallMessageOffer.SSKProtoCallMessageOfferBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoCallMessageOffer? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoCallMessageAnswer - -@objc public class SSKProtoCallMessageAnswer: NSObject { - - // MARK: - SSKProtoCallMessageAnswerBuilder - - @objc public class func builder(id: UInt64, sessionDescription: String) -> SSKProtoCallMessageAnswerBuilder { - return SSKProtoCallMessageAnswerBuilder(id: id, sessionDescription: sessionDescription) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoCallMessageAnswerBuilder { - let builder = SSKProtoCallMessageAnswerBuilder(id: id, sessionDescription: sessionDescription) - return builder - } - - @objc public class SSKProtoCallMessageAnswerBuilder: NSObject { - - private var proto = SignalServiceProtos_CallMessage.Answer() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: UInt64, sessionDescription: String) { - super.init() - - setId(id) - setSessionDescription(sessionDescription) - } - - @objc public func setId(_ valueParam: UInt64) { - proto.id = valueParam - } - - @objc public func setSessionDescription(_ valueParam: String) { - proto.sessionDescription = valueParam - } - - @objc public func build() throws -> SSKProtoCallMessageAnswer { - return try SSKProtoCallMessageAnswer.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoCallMessageAnswer.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_CallMessage.Answer - - @objc public let id: UInt64 - - @objc public let sessionDescription: String - - private init(proto: SignalServiceProtos_CallMessage.Answer, - id: UInt64, - sessionDescription: String) { - self.proto = proto - self.id = id - self.sessionDescription = sessionDescription - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoCallMessageAnswer { - let proto = try SignalServiceProtos_CallMessage.Answer(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_CallMessage.Answer) throws -> SSKProtoCallMessageAnswer { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - guard proto.hasSessionDescription else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sessionDescription") - } - let sessionDescription = proto.sessionDescription - - // MARK: - Begin Validation Logic for SSKProtoCallMessageAnswer - - - // MARK: - End Validation Logic for SSKProtoCallMessageAnswer - - - let result = SSKProtoCallMessageAnswer(proto: proto, - id: id, - sessionDescription: sessionDescription) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoCallMessageAnswer { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoCallMessageAnswer.SSKProtoCallMessageAnswerBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoCallMessageAnswer? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoCallMessageIceUpdate - -@objc public class SSKProtoCallMessageIceUpdate: NSObject { - - // MARK: - SSKProtoCallMessageIceUpdateBuilder - - @objc public class func builder(id: UInt64, sdpMid: String, sdpMlineIndex: UInt32, sdp: String) -> SSKProtoCallMessageIceUpdateBuilder { - return SSKProtoCallMessageIceUpdateBuilder(id: id, sdpMid: sdpMid, sdpMlineIndex: sdpMlineIndex, sdp: sdp) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoCallMessageIceUpdateBuilder { - let builder = SSKProtoCallMessageIceUpdateBuilder(id: id, sdpMid: sdpMid, sdpMlineIndex: sdpMlineIndex, sdp: sdp) - return builder - } - - @objc public class SSKProtoCallMessageIceUpdateBuilder: NSObject { - - private var proto = SignalServiceProtos_CallMessage.IceUpdate() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: UInt64, sdpMid: String, sdpMlineIndex: UInt32, sdp: String) { - super.init() - - setId(id) - setSdpMid(sdpMid) - setSdpMlineIndex(sdpMlineIndex) - setSdp(sdp) - } - - @objc public func setId(_ valueParam: UInt64) { - proto.id = valueParam - } - - @objc public func setSdpMid(_ valueParam: String) { - proto.sdpMid = valueParam - } - - @objc public func setSdpMlineIndex(_ valueParam: UInt32) { - proto.sdpMlineIndex = valueParam - } - - @objc public func setSdp(_ valueParam: String) { - proto.sdp = valueParam - } - - @objc public func build() throws -> SSKProtoCallMessageIceUpdate { - return try SSKProtoCallMessageIceUpdate.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoCallMessageIceUpdate.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_CallMessage.IceUpdate - - @objc public let id: UInt64 - - @objc public let sdpMid: String - - @objc public let sdpMlineIndex: UInt32 - - @objc public let sdp: String - - private init(proto: SignalServiceProtos_CallMessage.IceUpdate, - id: UInt64, - sdpMid: String, - sdpMlineIndex: UInt32, - sdp: String) { - self.proto = proto - self.id = id - self.sdpMid = sdpMid - self.sdpMlineIndex = sdpMlineIndex - self.sdp = sdp - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoCallMessageIceUpdate { - let proto = try SignalServiceProtos_CallMessage.IceUpdate(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_CallMessage.IceUpdate) throws -> SSKProtoCallMessageIceUpdate { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - guard proto.hasSdpMid else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sdpMid") - } - let sdpMid = proto.sdpMid - - guard proto.hasSdpMlineIndex else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sdpMlineIndex") - } - let sdpMlineIndex = proto.sdpMlineIndex - - guard proto.hasSdp else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sdp") - } - let sdp = proto.sdp - - // MARK: - Begin Validation Logic for SSKProtoCallMessageIceUpdate - - - // MARK: - End Validation Logic for SSKProtoCallMessageIceUpdate - - - let result = SSKProtoCallMessageIceUpdate(proto: proto, - id: id, - sdpMid: sdpMid, - sdpMlineIndex: sdpMlineIndex, - sdp: sdp) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoCallMessageIceUpdate { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoCallMessageIceUpdate.SSKProtoCallMessageIceUpdateBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoCallMessageIceUpdate? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoCallMessageBusy - -@objc public class SSKProtoCallMessageBusy: NSObject { - - // MARK: - SSKProtoCallMessageBusyBuilder - - @objc public class func builder(id: UInt64) -> SSKProtoCallMessageBusyBuilder { - return SSKProtoCallMessageBusyBuilder(id: id) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoCallMessageBusyBuilder { - let builder = SSKProtoCallMessageBusyBuilder(id: id) - return builder - } - - @objc public class SSKProtoCallMessageBusyBuilder: NSObject { - - private var proto = SignalServiceProtos_CallMessage.Busy() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: UInt64) { - super.init() - - setId(id) - } - - @objc public func setId(_ valueParam: UInt64) { - proto.id = valueParam - } - - @objc public func build() throws -> SSKProtoCallMessageBusy { - return try SSKProtoCallMessageBusy.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoCallMessageBusy.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_CallMessage.Busy - - @objc public let id: UInt64 - - private init(proto: SignalServiceProtos_CallMessage.Busy, - id: UInt64) { - self.proto = proto - self.id = id - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoCallMessageBusy { - let proto = try SignalServiceProtos_CallMessage.Busy(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_CallMessage.Busy) throws -> SSKProtoCallMessageBusy { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - // MARK: - Begin Validation Logic for SSKProtoCallMessageBusy - - - // MARK: - End Validation Logic for SSKProtoCallMessageBusy - - - let result = SSKProtoCallMessageBusy(proto: proto, - id: id) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoCallMessageBusy { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoCallMessageBusy.SSKProtoCallMessageBusyBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoCallMessageBusy? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoCallMessageHangup - -@objc public class SSKProtoCallMessageHangup: NSObject { - - // MARK: - SSKProtoCallMessageHangupBuilder - - @objc public class func builder(id: UInt64) -> SSKProtoCallMessageHangupBuilder { - return SSKProtoCallMessageHangupBuilder(id: id) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoCallMessageHangupBuilder { - let builder = SSKProtoCallMessageHangupBuilder(id: id) - return builder - } - - @objc public class SSKProtoCallMessageHangupBuilder: NSObject { - - private var proto = SignalServiceProtos_CallMessage.Hangup() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: UInt64) { - super.init() - - setId(id) - } - - @objc public func setId(_ valueParam: UInt64) { - proto.id = valueParam - } - - @objc public func build() throws -> SSKProtoCallMessageHangup { - return try SSKProtoCallMessageHangup.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoCallMessageHangup.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_CallMessage.Hangup - - @objc public let id: UInt64 - - private init(proto: SignalServiceProtos_CallMessage.Hangup, - id: UInt64) { - self.proto = proto - self.id = id - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoCallMessageHangup { - let proto = try SignalServiceProtos_CallMessage.Hangup(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_CallMessage.Hangup) throws -> SSKProtoCallMessageHangup { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - // MARK: - Begin Validation Logic for SSKProtoCallMessageHangup - - - // MARK: - End Validation Logic for SSKProtoCallMessageHangup - - - let result = SSKProtoCallMessageHangup(proto: proto, - id: id) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoCallMessageHangup { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoCallMessageHangup.SSKProtoCallMessageHangupBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoCallMessageHangup? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoCallMessage - -@objc public class SSKProtoCallMessage: NSObject { - - // MARK: - SSKProtoCallMessageBuilder - - @objc public class func builder() -> SSKProtoCallMessageBuilder { - return SSKProtoCallMessageBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoCallMessageBuilder { - let builder = SSKProtoCallMessageBuilder() - if let _value = offer { - builder.setOffer(_value) - } - if let _value = answer { - builder.setAnswer(_value) - } - builder.setIceUpdate(iceUpdate) - if let _value = hangup { - builder.setHangup(_value) - } - if let _value = busy { - builder.setBusy(_value) - } - if let _value = profileKey { - builder.setProfileKey(_value) - } - return builder - } - - @objc public class SSKProtoCallMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_CallMessage() - - @objc fileprivate override init() {} - - @objc public func setOffer(_ valueParam: SSKProtoCallMessageOffer) { - proto.offer = valueParam.proto - } - - @objc public func setAnswer(_ valueParam: SSKProtoCallMessageAnswer) { - proto.answer = valueParam.proto - } - - @objc public func addIceUpdate(_ valueParam: SSKProtoCallMessageIceUpdate) { - var items = proto.iceUpdate - items.append(valueParam.proto) - proto.iceUpdate = items - } - - @objc public func setIceUpdate(_ wrappedItems: [SSKProtoCallMessageIceUpdate]) { - proto.iceUpdate = wrappedItems.map { $0.proto } - } - - @objc public func setHangup(_ valueParam: SSKProtoCallMessageHangup) { - proto.hangup = valueParam.proto - } - - @objc public func setBusy(_ valueParam: SSKProtoCallMessageBusy) { - proto.busy = valueParam.proto - } - - @objc public func setProfileKey(_ valueParam: Data) { - proto.profileKey = valueParam - } - - @objc public func build() throws -> SSKProtoCallMessage { - return try SSKProtoCallMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoCallMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_CallMessage - - @objc public let offer: SSKProtoCallMessageOffer? - - @objc public let answer: SSKProtoCallMessageAnswer? - - @objc public let iceUpdate: [SSKProtoCallMessageIceUpdate] - - @objc public let hangup: SSKProtoCallMessageHangup? - - @objc public let busy: SSKProtoCallMessageBusy? - - @objc public var profileKey: Data? { - guard proto.hasProfileKey else { - return nil - } - return proto.profileKey - } - @objc public var hasProfileKey: Bool { - return proto.hasProfileKey - } - - private init(proto: SignalServiceProtos_CallMessage, - offer: SSKProtoCallMessageOffer?, - answer: SSKProtoCallMessageAnswer?, - iceUpdate: [SSKProtoCallMessageIceUpdate], - hangup: SSKProtoCallMessageHangup?, - busy: SSKProtoCallMessageBusy?) { - self.proto = proto - self.offer = offer - self.answer = answer - self.iceUpdate = iceUpdate - self.hangup = hangup - self.busy = busy - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoCallMessage { - let proto = try SignalServiceProtos_CallMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_CallMessage) throws -> SSKProtoCallMessage { - var offer: SSKProtoCallMessageOffer? = nil - if proto.hasOffer { - offer = try SSKProtoCallMessageOffer.parseProto(proto.offer) - } - - var answer: SSKProtoCallMessageAnswer? = nil - if proto.hasAnswer { - answer = try SSKProtoCallMessageAnswer.parseProto(proto.answer) - } - - var iceUpdate: [SSKProtoCallMessageIceUpdate] = [] - iceUpdate = try proto.iceUpdate.map { try SSKProtoCallMessageIceUpdate.parseProto($0) } - - var hangup: SSKProtoCallMessageHangup? = nil - if proto.hasHangup { - hangup = try SSKProtoCallMessageHangup.parseProto(proto.hangup) - } - - var busy: SSKProtoCallMessageBusy? = nil - if proto.hasBusy { - busy = try SSKProtoCallMessageBusy.parseProto(proto.busy) - } - - // MARK: - Begin Validation Logic for SSKProtoCallMessage - - - // MARK: - End Validation Logic for SSKProtoCallMessage - - - let result = SSKProtoCallMessage(proto: proto, - offer: offer, - answer: answer, - iceUpdate: iceUpdate, - hangup: hangup, - busy: busy) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoCallMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoCallMessage.SSKProtoCallMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoCallMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoClosedGroupCiphertextMessageWrapper - -@objc public class SSKProtoClosedGroupCiphertextMessageWrapper: NSObject { - - // MARK: - SSKProtoClosedGroupCiphertextMessageWrapperBuilder - - @objc public class func builder(ciphertext: Data, ephemeralPublicKey: Data) -> SSKProtoClosedGroupCiphertextMessageWrapperBuilder { - return SSKProtoClosedGroupCiphertextMessageWrapperBuilder(ciphertext: ciphertext, ephemeralPublicKey: ephemeralPublicKey) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoClosedGroupCiphertextMessageWrapperBuilder { - let builder = SSKProtoClosedGroupCiphertextMessageWrapperBuilder(ciphertext: ciphertext, ephemeralPublicKey: ephemeralPublicKey) - return builder - } - - @objc public class SSKProtoClosedGroupCiphertextMessageWrapperBuilder: NSObject { - - private var proto = SignalServiceProtos_ClosedGroupCiphertextMessageWrapper() - - @objc fileprivate override init() {} - - @objc fileprivate init(ciphertext: Data, ephemeralPublicKey: Data) { - super.init() - - setCiphertext(ciphertext) - setEphemeralPublicKey(ephemeralPublicKey) - } - - @objc public func setCiphertext(_ valueParam: Data) { - proto.ciphertext = valueParam - } - - @objc public func setEphemeralPublicKey(_ valueParam: Data) { - proto.ephemeralPublicKey = valueParam - } - - @objc public func build() throws -> SSKProtoClosedGroupCiphertextMessageWrapper { - return try SSKProtoClosedGroupCiphertextMessageWrapper.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoClosedGroupCiphertextMessageWrapper.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_ClosedGroupCiphertextMessageWrapper - - @objc public let ciphertext: Data - - @objc public let ephemeralPublicKey: Data - - private init(proto: SignalServiceProtos_ClosedGroupCiphertextMessageWrapper, - ciphertext: Data, - ephemeralPublicKey: Data) { - self.proto = proto - self.ciphertext = ciphertext - self.ephemeralPublicKey = ephemeralPublicKey - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoClosedGroupCiphertextMessageWrapper { - let proto = try SignalServiceProtos_ClosedGroupCiphertextMessageWrapper(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_ClosedGroupCiphertextMessageWrapper) throws -> SSKProtoClosedGroupCiphertextMessageWrapper { - guard proto.hasCiphertext else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: ciphertext") - } - let ciphertext = proto.ciphertext - - guard proto.hasEphemeralPublicKey else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: ephemeralPublicKey") - } - let ephemeralPublicKey = proto.ephemeralPublicKey - - // MARK: - Begin Validation Logic for SSKProtoClosedGroupCiphertextMessageWrapper - - - // MARK: - End Validation Logic for SSKProtoClosedGroupCiphertextMessageWrapper - - - let result = SSKProtoClosedGroupCiphertextMessageWrapper(proto: proto, - ciphertext: ciphertext, - ephemeralPublicKey: ephemeralPublicKey) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoClosedGroupCiphertextMessageWrapper { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoClosedGroupCiphertextMessageWrapper.SSKProtoClosedGroupCiphertextMessageWrapperBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoClosedGroupCiphertextMessageWrapper? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageQuoteQuotedAttachment - -@objc public class SSKProtoDataMessageQuoteQuotedAttachment: NSObject { - - // MARK: - SSKProtoDataMessageQuoteQuotedAttachmentFlags - - @objc public enum SSKProtoDataMessageQuoteQuotedAttachmentFlags: Int32 { - case voiceMessage = 1 - } - - private class func SSKProtoDataMessageQuoteQuotedAttachmentFlagsWrap(_ value: SignalServiceProtos_DataMessage.Quote.QuotedAttachment.Flags) -> SSKProtoDataMessageQuoteQuotedAttachmentFlags { - switch value { - case .voiceMessage: return .voiceMessage - } - } - - private class func SSKProtoDataMessageQuoteQuotedAttachmentFlagsUnwrap(_ value: SSKProtoDataMessageQuoteQuotedAttachmentFlags) -> SignalServiceProtos_DataMessage.Quote.QuotedAttachment.Flags { - switch value { - case .voiceMessage: return .voiceMessage - } - } - - // MARK: - SSKProtoDataMessageQuoteQuotedAttachmentBuilder - - @objc public class func builder() -> SSKProtoDataMessageQuoteQuotedAttachmentBuilder { - return SSKProtoDataMessageQuoteQuotedAttachmentBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageQuoteQuotedAttachmentBuilder { - let builder = SSKProtoDataMessageQuoteQuotedAttachmentBuilder() - if let _value = contentType { - builder.setContentType(_value) - } - if let _value = fileName { - builder.setFileName(_value) - } - if let _value = thumbnail { - builder.setThumbnail(_value) - } - if hasFlags { - builder.setFlags(flags) - } - return builder - } - - @objc public class SSKProtoDataMessageQuoteQuotedAttachmentBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Quote.QuotedAttachment() - - @objc fileprivate override init() {} - - @objc public func setContentType(_ valueParam: String) { - proto.contentType = valueParam - } - - @objc public func setFileName(_ valueParam: String) { - proto.fileName = valueParam - } - - @objc public func setThumbnail(_ valueParam: SSKProtoAttachmentPointer) { - proto.thumbnail = valueParam.proto - } - - @objc public func setFlags(_ valueParam: UInt32) { - proto.flags = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageQuoteQuotedAttachment { - return try SSKProtoDataMessageQuoteQuotedAttachment.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageQuoteQuotedAttachment.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Quote.QuotedAttachment - - @objc public let thumbnail: SSKProtoAttachmentPointer? - - @objc public var contentType: String? { - guard proto.hasContentType else { - return nil - } - return proto.contentType - } - @objc public var hasContentType: Bool { - return proto.hasContentType - } - - @objc public var fileName: String? { - guard proto.hasFileName else { - return nil - } - return proto.fileName - } - @objc public var hasFileName: Bool { - return proto.hasFileName - } - - @objc public var flags: UInt32 { - return proto.flags - } - @objc public var hasFlags: Bool { - return proto.hasFlags - } - - private init(proto: SignalServiceProtos_DataMessage.Quote.QuotedAttachment, - thumbnail: SSKProtoAttachmentPointer?) { - self.proto = proto - self.thumbnail = thumbnail - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageQuoteQuotedAttachment { - let proto = try SignalServiceProtos_DataMessage.Quote.QuotedAttachment(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Quote.QuotedAttachment) throws -> SSKProtoDataMessageQuoteQuotedAttachment { - var thumbnail: SSKProtoAttachmentPointer? = nil - if proto.hasThumbnail { - thumbnail = try SSKProtoAttachmentPointer.parseProto(proto.thumbnail) - } - - // MARK: - Begin Validation Logic for SSKProtoDataMessageQuoteQuotedAttachment - - - // MARK: - End Validation Logic for SSKProtoDataMessageQuoteQuotedAttachment - - - let result = SSKProtoDataMessageQuoteQuotedAttachment(proto: proto, - thumbnail: thumbnail) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageQuoteQuotedAttachment { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageQuoteQuotedAttachment.SSKProtoDataMessageQuoteQuotedAttachmentBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageQuoteQuotedAttachment? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageQuote - -@objc public class SSKProtoDataMessageQuote: NSObject { - - // MARK: - SSKProtoDataMessageQuoteBuilder - - @objc public class func builder(id: UInt64, author: String) -> SSKProtoDataMessageQuoteBuilder { - return SSKProtoDataMessageQuoteBuilder(id: id, author: author) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageQuoteBuilder { - let builder = SSKProtoDataMessageQuoteBuilder(id: id, author: author) - if let _value = text { - builder.setText(_value) - } - builder.setAttachments(attachments) - return builder - } - - @objc public class SSKProtoDataMessageQuoteBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Quote() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: UInt64, author: String) { - super.init() - - setId(id) - setAuthor(author) - } - - @objc public func setId(_ valueParam: UInt64) { - proto.id = valueParam - } - - @objc public func setAuthor(_ valueParam: String) { - proto.author = valueParam - } - - @objc public func setText(_ valueParam: String) { - proto.text = valueParam - } - - @objc public func addAttachments(_ valueParam: SSKProtoDataMessageQuoteQuotedAttachment) { - var items = proto.attachments - items.append(valueParam.proto) - proto.attachments = items - } - - @objc public func setAttachments(_ wrappedItems: [SSKProtoDataMessageQuoteQuotedAttachment]) { - proto.attachments = wrappedItems.map { $0.proto } - } - - @objc public func build() throws -> SSKProtoDataMessageQuote { - return try SSKProtoDataMessageQuote.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageQuote.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Quote - - @objc public let id: UInt64 - - @objc public let author: String - - @objc public let attachments: [SSKProtoDataMessageQuoteQuotedAttachment] - - @objc public var text: String? { - guard proto.hasText else { - return nil - } - return proto.text - } - @objc public var hasText: Bool { - return proto.hasText - } - - private init(proto: SignalServiceProtos_DataMessage.Quote, - id: UInt64, - author: String, - attachments: [SSKProtoDataMessageQuoteQuotedAttachment]) { - self.proto = proto - self.id = id - self.author = author - self.attachments = attachments - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageQuote { - let proto = try SignalServiceProtos_DataMessage.Quote(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Quote) throws -> SSKProtoDataMessageQuote { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - guard proto.hasAuthor else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: author") - } - let author = proto.author - - var attachments: [SSKProtoDataMessageQuoteQuotedAttachment] = [] - attachments = try proto.attachments.map { try SSKProtoDataMessageQuoteQuotedAttachment.parseProto($0) } - - // MARK: - Begin Validation Logic for SSKProtoDataMessageQuote - - - // MARK: - End Validation Logic for SSKProtoDataMessageQuote - - - let result = SSKProtoDataMessageQuote(proto: proto, - id: id, - author: author, - attachments: attachments) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageQuote { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageQuote.SSKProtoDataMessageQuoteBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageQuote? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageContactName - -@objc public class SSKProtoDataMessageContactName: NSObject { - - // MARK: - SSKProtoDataMessageContactNameBuilder - - @objc public class func builder() -> SSKProtoDataMessageContactNameBuilder { - return SSKProtoDataMessageContactNameBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageContactNameBuilder { - let builder = SSKProtoDataMessageContactNameBuilder() - if let _value = givenName { - builder.setGivenName(_value) - } - if let _value = familyName { - builder.setFamilyName(_value) - } - if let _value = prefix { - builder.setPrefix(_value) - } - if let _value = suffix { - builder.setSuffix(_value) - } - if let _value = middleName { - builder.setMiddleName(_value) - } - if let _value = displayName { - builder.setDisplayName(_value) - } - return builder - } - - @objc public class SSKProtoDataMessageContactNameBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Contact.Name() - - @objc fileprivate override init() {} - - @objc public func setGivenName(_ valueParam: String) { - proto.givenName = valueParam - } - - @objc public func setFamilyName(_ valueParam: String) { - proto.familyName = valueParam - } - - @objc public func setPrefix(_ valueParam: String) { - proto.prefix = valueParam - } - - @objc public func setSuffix(_ valueParam: String) { - proto.suffix = valueParam - } - - @objc public func setMiddleName(_ valueParam: String) { - proto.middleName = valueParam - } - - @objc public func setDisplayName(_ valueParam: String) { - proto.displayName = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageContactName { - return try SSKProtoDataMessageContactName.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageContactName.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Contact.Name - - @objc public var givenName: String? { - guard proto.hasGivenName else { - return nil - } - return proto.givenName - } - @objc public var hasGivenName: Bool { - return proto.hasGivenName - } - - @objc public var familyName: String? { - guard proto.hasFamilyName else { - return nil - } - return proto.familyName - } - @objc public var hasFamilyName: Bool { - return proto.hasFamilyName - } - - @objc public var prefix: String? { - guard proto.hasPrefix else { - return nil - } - return proto.prefix - } - @objc public var hasPrefix: Bool { - return proto.hasPrefix - } - - @objc public var suffix: String? { - guard proto.hasSuffix else { - return nil - } - return proto.suffix - } - @objc public var hasSuffix: Bool { - return proto.hasSuffix - } - - @objc public var middleName: String? { - guard proto.hasMiddleName else { - return nil - } - return proto.middleName - } - @objc public var hasMiddleName: Bool { - return proto.hasMiddleName - } - - @objc public var displayName: String? { - guard proto.hasDisplayName else { - return nil - } - return proto.displayName - } - @objc public var hasDisplayName: Bool { - return proto.hasDisplayName - } - - private init(proto: SignalServiceProtos_DataMessage.Contact.Name) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageContactName { - let proto = try SignalServiceProtos_DataMessage.Contact.Name(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Contact.Name) throws -> SSKProtoDataMessageContactName { - // MARK: - Begin Validation Logic for SSKProtoDataMessageContactName - - - // MARK: - End Validation Logic for SSKProtoDataMessageContactName - - - let result = SSKProtoDataMessageContactName(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageContactName { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageContactName.SSKProtoDataMessageContactNameBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageContactName? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageContactPhone - -@objc public class SSKProtoDataMessageContactPhone: NSObject { - - // MARK: - SSKProtoDataMessageContactPhoneType - - @objc public enum SSKProtoDataMessageContactPhoneType: Int32 { - case home = 1 - case mobile = 2 - case work = 3 - case custom = 4 - } - - private class func SSKProtoDataMessageContactPhoneTypeWrap(_ value: SignalServiceProtos_DataMessage.Contact.Phone.TypeEnum) -> SSKProtoDataMessageContactPhoneType { - switch value { - case .home: return .home - case .mobile: return .mobile - case .work: return .work - case .custom: return .custom - } - } - - private class func SSKProtoDataMessageContactPhoneTypeUnwrap(_ value: SSKProtoDataMessageContactPhoneType) -> SignalServiceProtos_DataMessage.Contact.Phone.TypeEnum { - switch value { - case .home: return .home - case .mobile: return .mobile - case .work: return .work - case .custom: return .custom - } - } - - // MARK: - SSKProtoDataMessageContactPhoneBuilder - - @objc public class func builder() -> SSKProtoDataMessageContactPhoneBuilder { - return SSKProtoDataMessageContactPhoneBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageContactPhoneBuilder { - let builder = SSKProtoDataMessageContactPhoneBuilder() - if let _value = value { - builder.setValue(_value) - } - if hasType { - builder.setType(type) - } - if let _value = label { - builder.setLabel(_value) - } - return builder - } - - @objc public class SSKProtoDataMessageContactPhoneBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Contact.Phone() - - @objc fileprivate override init() {} - - @objc public func setValue(_ valueParam: String) { - proto.value = valueParam - } - - @objc public func setType(_ valueParam: SSKProtoDataMessageContactPhoneType) { - proto.type = SSKProtoDataMessageContactPhoneTypeUnwrap(valueParam) - } - - @objc public func setLabel(_ valueParam: String) { - proto.label = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageContactPhone { - return try SSKProtoDataMessageContactPhone.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageContactPhone.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Contact.Phone - - @objc public var value: String? { - guard proto.hasValue else { - return nil - } - return proto.value - } - @objc public var hasValue: Bool { - return proto.hasValue - } - - @objc public var type: SSKProtoDataMessageContactPhoneType { - return SSKProtoDataMessageContactPhone.SSKProtoDataMessageContactPhoneTypeWrap(proto.type) - } - @objc public var hasType: Bool { - return proto.hasType - } - - @objc public var label: String? { - guard proto.hasLabel else { - return nil - } - return proto.label - } - @objc public var hasLabel: Bool { - return proto.hasLabel - } - - private init(proto: SignalServiceProtos_DataMessage.Contact.Phone) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageContactPhone { - let proto = try SignalServiceProtos_DataMessage.Contact.Phone(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Contact.Phone) throws -> SSKProtoDataMessageContactPhone { - // MARK: - Begin Validation Logic for SSKProtoDataMessageContactPhone - - - // MARK: - End Validation Logic for SSKProtoDataMessageContactPhone - - - let result = SSKProtoDataMessageContactPhone(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageContactPhone { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageContactPhone.SSKProtoDataMessageContactPhoneBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageContactPhone? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageContactEmail - -@objc public class SSKProtoDataMessageContactEmail: NSObject { - - // MARK: - SSKProtoDataMessageContactEmailType - - @objc public enum SSKProtoDataMessageContactEmailType: Int32 { - case home = 1 - case mobile = 2 - case work = 3 - case custom = 4 - } - - private class func SSKProtoDataMessageContactEmailTypeWrap(_ value: SignalServiceProtos_DataMessage.Contact.Email.TypeEnum) -> SSKProtoDataMessageContactEmailType { - switch value { - case .home: return .home - case .mobile: return .mobile - case .work: return .work - case .custom: return .custom - } - } - - private class func SSKProtoDataMessageContactEmailTypeUnwrap(_ value: SSKProtoDataMessageContactEmailType) -> SignalServiceProtos_DataMessage.Contact.Email.TypeEnum { - switch value { - case .home: return .home - case .mobile: return .mobile - case .work: return .work - case .custom: return .custom - } - } - - // MARK: - SSKProtoDataMessageContactEmailBuilder - - @objc public class func builder() -> SSKProtoDataMessageContactEmailBuilder { - return SSKProtoDataMessageContactEmailBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageContactEmailBuilder { - let builder = SSKProtoDataMessageContactEmailBuilder() - if let _value = value { - builder.setValue(_value) - } - if hasType { - builder.setType(type) - } - if let _value = label { - builder.setLabel(_value) - } - return builder - } - - @objc public class SSKProtoDataMessageContactEmailBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Contact.Email() - - @objc fileprivate override init() {} - - @objc public func setValue(_ valueParam: String) { - proto.value = valueParam - } - - @objc public func setType(_ valueParam: SSKProtoDataMessageContactEmailType) { - proto.type = SSKProtoDataMessageContactEmailTypeUnwrap(valueParam) - } - - @objc public func setLabel(_ valueParam: String) { - proto.label = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageContactEmail { - return try SSKProtoDataMessageContactEmail.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageContactEmail.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Contact.Email - - @objc public var value: String? { - guard proto.hasValue else { - return nil - } - return proto.value - } - @objc public var hasValue: Bool { - return proto.hasValue - } - - @objc public var type: SSKProtoDataMessageContactEmailType { - return SSKProtoDataMessageContactEmail.SSKProtoDataMessageContactEmailTypeWrap(proto.type) - } - @objc public var hasType: Bool { - return proto.hasType - } - - @objc public var label: String? { - guard proto.hasLabel else { - return nil - } - return proto.label - } - @objc public var hasLabel: Bool { - return proto.hasLabel - } - - private init(proto: SignalServiceProtos_DataMessage.Contact.Email) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageContactEmail { - let proto = try SignalServiceProtos_DataMessage.Contact.Email(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Contact.Email) throws -> SSKProtoDataMessageContactEmail { - // MARK: - Begin Validation Logic for SSKProtoDataMessageContactEmail - - - // MARK: - End Validation Logic for SSKProtoDataMessageContactEmail - - - let result = SSKProtoDataMessageContactEmail(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageContactEmail { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageContactEmail.SSKProtoDataMessageContactEmailBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageContactEmail? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageContactPostalAddress - -@objc public class SSKProtoDataMessageContactPostalAddress: NSObject { - - // MARK: - SSKProtoDataMessageContactPostalAddressType - - @objc public enum SSKProtoDataMessageContactPostalAddressType: Int32 { - case home = 1 - case work = 2 - case custom = 3 - } - - private class func SSKProtoDataMessageContactPostalAddressTypeWrap(_ value: SignalServiceProtos_DataMessage.Contact.PostalAddress.TypeEnum) -> SSKProtoDataMessageContactPostalAddressType { - switch value { - case .home: return .home - case .work: return .work - case .custom: return .custom - } - } - - private class func SSKProtoDataMessageContactPostalAddressTypeUnwrap(_ value: SSKProtoDataMessageContactPostalAddressType) -> SignalServiceProtos_DataMessage.Contact.PostalAddress.TypeEnum { - switch value { - case .home: return .home - case .work: return .work - case .custom: return .custom - } - } - - // MARK: - SSKProtoDataMessageContactPostalAddressBuilder - - @objc public class func builder() -> SSKProtoDataMessageContactPostalAddressBuilder { - return SSKProtoDataMessageContactPostalAddressBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageContactPostalAddressBuilder { - let builder = SSKProtoDataMessageContactPostalAddressBuilder() - if hasType { - builder.setType(type) - } - if let _value = label { - builder.setLabel(_value) - } - if let _value = street { - builder.setStreet(_value) - } - if let _value = pobox { - builder.setPobox(_value) - } - if let _value = neighborhood { - builder.setNeighborhood(_value) - } - if let _value = city { - builder.setCity(_value) - } - if let _value = region { - builder.setRegion(_value) - } - if let _value = postcode { - builder.setPostcode(_value) - } - if let _value = country { - builder.setCountry(_value) - } - return builder - } - - @objc public class SSKProtoDataMessageContactPostalAddressBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Contact.PostalAddress() - - @objc fileprivate override init() {} - - @objc public func setType(_ valueParam: SSKProtoDataMessageContactPostalAddressType) { - proto.type = SSKProtoDataMessageContactPostalAddressTypeUnwrap(valueParam) - } - - @objc public func setLabel(_ valueParam: String) { - proto.label = valueParam - } - - @objc public func setStreet(_ valueParam: String) { - proto.street = valueParam - } - - @objc public func setPobox(_ valueParam: String) { - proto.pobox = valueParam - } - - @objc public func setNeighborhood(_ valueParam: String) { - proto.neighborhood = valueParam - } - - @objc public func setCity(_ valueParam: String) { - proto.city = valueParam - } - - @objc public func setRegion(_ valueParam: String) { - proto.region = valueParam - } - - @objc public func setPostcode(_ valueParam: String) { - proto.postcode = valueParam - } - - @objc public func setCountry(_ valueParam: String) { - proto.country = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageContactPostalAddress { - return try SSKProtoDataMessageContactPostalAddress.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageContactPostalAddress.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Contact.PostalAddress - - @objc public var type: SSKProtoDataMessageContactPostalAddressType { - return SSKProtoDataMessageContactPostalAddress.SSKProtoDataMessageContactPostalAddressTypeWrap(proto.type) - } - @objc public var hasType: Bool { - return proto.hasType - } - - @objc public var label: String? { - guard proto.hasLabel else { - return nil - } - return proto.label - } - @objc public var hasLabel: Bool { - return proto.hasLabel - } - - @objc public var street: String? { - guard proto.hasStreet else { - return nil - } - return proto.street - } - @objc public var hasStreet: Bool { - return proto.hasStreet - } - - @objc public var pobox: String? { - guard proto.hasPobox else { - return nil - } - return proto.pobox - } - @objc public var hasPobox: Bool { - return proto.hasPobox - } - - @objc public var neighborhood: String? { - guard proto.hasNeighborhood else { - return nil - } - return proto.neighborhood - } - @objc public var hasNeighborhood: Bool { - return proto.hasNeighborhood - } - - @objc public var city: String? { - guard proto.hasCity else { - return nil - } - return proto.city - } - @objc public var hasCity: Bool { - return proto.hasCity - } - - @objc public var region: String? { - guard proto.hasRegion else { - return nil - } - return proto.region - } - @objc public var hasRegion: Bool { - return proto.hasRegion - } - - @objc public var postcode: String? { - guard proto.hasPostcode else { - return nil - } - return proto.postcode - } - @objc public var hasPostcode: Bool { - return proto.hasPostcode - } - - @objc public var country: String? { - guard proto.hasCountry else { - return nil - } - return proto.country - } - @objc public var hasCountry: Bool { - return proto.hasCountry - } - - private init(proto: SignalServiceProtos_DataMessage.Contact.PostalAddress) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageContactPostalAddress { - let proto = try SignalServiceProtos_DataMessage.Contact.PostalAddress(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Contact.PostalAddress) throws -> SSKProtoDataMessageContactPostalAddress { - // MARK: - Begin Validation Logic for SSKProtoDataMessageContactPostalAddress - - - // MARK: - End Validation Logic for SSKProtoDataMessageContactPostalAddress - - - let result = SSKProtoDataMessageContactPostalAddress(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageContactPostalAddress { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageContactPostalAddress.SSKProtoDataMessageContactPostalAddressBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageContactPostalAddress? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageContactAvatar - -@objc public class SSKProtoDataMessageContactAvatar: NSObject { - - // MARK: - SSKProtoDataMessageContactAvatarBuilder - - @objc public class func builder() -> SSKProtoDataMessageContactAvatarBuilder { - return SSKProtoDataMessageContactAvatarBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageContactAvatarBuilder { - let builder = SSKProtoDataMessageContactAvatarBuilder() - if let _value = avatar { - builder.setAvatar(_value) - } - if hasIsProfile { - builder.setIsProfile(isProfile) - } - return builder - } - - @objc public class SSKProtoDataMessageContactAvatarBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Contact.Avatar() - - @objc fileprivate override init() {} - - @objc public func setAvatar(_ valueParam: SSKProtoAttachmentPointer) { - proto.avatar = valueParam.proto - } - - @objc public func setIsProfile(_ valueParam: Bool) { - proto.isProfile = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageContactAvatar { - return try SSKProtoDataMessageContactAvatar.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageContactAvatar.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Contact.Avatar - - @objc public let avatar: SSKProtoAttachmentPointer? - - @objc public var isProfile: Bool { - return proto.isProfile - } - @objc public var hasIsProfile: Bool { - return proto.hasIsProfile - } - - private init(proto: SignalServiceProtos_DataMessage.Contact.Avatar, - avatar: SSKProtoAttachmentPointer?) { - self.proto = proto - self.avatar = avatar - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageContactAvatar { - let proto = try SignalServiceProtos_DataMessage.Contact.Avatar(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Contact.Avatar) throws -> SSKProtoDataMessageContactAvatar { - var avatar: SSKProtoAttachmentPointer? = nil - if proto.hasAvatar { - avatar = try SSKProtoAttachmentPointer.parseProto(proto.avatar) - } - - // MARK: - Begin Validation Logic for SSKProtoDataMessageContactAvatar - - - // MARK: - End Validation Logic for SSKProtoDataMessageContactAvatar - - - let result = SSKProtoDataMessageContactAvatar(proto: proto, - avatar: avatar) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageContactAvatar { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageContactAvatar.SSKProtoDataMessageContactAvatarBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageContactAvatar? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageContact - -@objc public class SSKProtoDataMessageContact: NSObject { - - // MARK: - SSKProtoDataMessageContactBuilder - - @objc public class func builder() -> SSKProtoDataMessageContactBuilder { - return SSKProtoDataMessageContactBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageContactBuilder { - let builder = SSKProtoDataMessageContactBuilder() - if let _value = name { - builder.setName(_value) - } - builder.setNumber(number) - builder.setEmail(email) - builder.setAddress(address) - if let _value = avatar { - builder.setAvatar(_value) - } - if let _value = organization { - builder.setOrganization(_value) - } - return builder - } - - @objc public class SSKProtoDataMessageContactBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Contact() - - @objc fileprivate override init() {} - - @objc public func setName(_ valueParam: SSKProtoDataMessageContactName) { - proto.name = valueParam.proto - } - - @objc public func addNumber(_ valueParam: SSKProtoDataMessageContactPhone) { - var items = proto.number - items.append(valueParam.proto) - proto.number = items - } - - @objc public func setNumber(_ wrappedItems: [SSKProtoDataMessageContactPhone]) { - proto.number = wrappedItems.map { $0.proto } - } - - @objc public func addEmail(_ valueParam: SSKProtoDataMessageContactEmail) { - var items = proto.email - items.append(valueParam.proto) - proto.email = items - } - - @objc public func setEmail(_ wrappedItems: [SSKProtoDataMessageContactEmail]) { - proto.email = wrappedItems.map { $0.proto } - } - - @objc public func addAddress(_ valueParam: SSKProtoDataMessageContactPostalAddress) { - var items = proto.address - items.append(valueParam.proto) - proto.address = items - } - - @objc public func setAddress(_ wrappedItems: [SSKProtoDataMessageContactPostalAddress]) { - proto.address = wrappedItems.map { $0.proto } - } - - @objc public func setAvatar(_ valueParam: SSKProtoDataMessageContactAvatar) { - proto.avatar = valueParam.proto - } - - @objc public func setOrganization(_ valueParam: String) { - proto.organization = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageContact { - return try SSKProtoDataMessageContact.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageContact.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Contact - - @objc public let name: SSKProtoDataMessageContactName? - - @objc public let number: [SSKProtoDataMessageContactPhone] - - @objc public let email: [SSKProtoDataMessageContactEmail] - - @objc public let address: [SSKProtoDataMessageContactPostalAddress] - - @objc public let avatar: SSKProtoDataMessageContactAvatar? - - @objc public var organization: String? { - guard proto.hasOrganization else { - return nil - } - return proto.organization - } - @objc public var hasOrganization: Bool { - return proto.hasOrganization - } - - private init(proto: SignalServiceProtos_DataMessage.Contact, - name: SSKProtoDataMessageContactName?, - number: [SSKProtoDataMessageContactPhone], - email: [SSKProtoDataMessageContactEmail], - address: [SSKProtoDataMessageContactPostalAddress], - avatar: SSKProtoDataMessageContactAvatar?) { - self.proto = proto - self.name = name - self.number = number - self.email = email - self.address = address - self.avatar = avatar - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageContact { - let proto = try SignalServiceProtos_DataMessage.Contact(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Contact) throws -> SSKProtoDataMessageContact { - var name: SSKProtoDataMessageContactName? = nil - if proto.hasName { - name = try SSKProtoDataMessageContactName.parseProto(proto.name) - } - - var number: [SSKProtoDataMessageContactPhone] = [] - number = try proto.number.map { try SSKProtoDataMessageContactPhone.parseProto($0) } - - var email: [SSKProtoDataMessageContactEmail] = [] - email = try proto.email.map { try SSKProtoDataMessageContactEmail.parseProto($0) } - - var address: [SSKProtoDataMessageContactPostalAddress] = [] - address = try proto.address.map { try SSKProtoDataMessageContactPostalAddress.parseProto($0) } - - var avatar: SSKProtoDataMessageContactAvatar? = nil - if proto.hasAvatar { - avatar = try SSKProtoDataMessageContactAvatar.parseProto(proto.avatar) - } - - // MARK: - Begin Validation Logic for SSKProtoDataMessageContact - - - // MARK: - End Validation Logic for SSKProtoDataMessageContact - - - let result = SSKProtoDataMessageContact(proto: proto, - name: name, - number: number, - email: email, - address: address, - avatar: avatar) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageContact { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageContact.SSKProtoDataMessageContactBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageContact? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessagePreview - -@objc public class SSKProtoDataMessagePreview: NSObject { - - // MARK: - SSKProtoDataMessagePreviewBuilder - - @objc public class func builder(url: String) -> SSKProtoDataMessagePreviewBuilder { - return SSKProtoDataMessagePreviewBuilder(url: url) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessagePreviewBuilder { - let builder = SSKProtoDataMessagePreviewBuilder(url: url) - if let _value = title { - builder.setTitle(_value) - } - if let _value = image { - builder.setImage(_value) - } - return builder - } - - @objc public class SSKProtoDataMessagePreviewBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.Preview() - - @objc fileprivate override init() {} - - @objc fileprivate init(url: String) { - super.init() - - setUrl(url) - } - - @objc public func setUrl(_ valueParam: String) { - proto.url = valueParam - } - - @objc public func setTitle(_ valueParam: String) { - proto.title = valueParam - } - - @objc public func setImage(_ valueParam: SSKProtoAttachmentPointer) { - proto.image = valueParam.proto - } - - @objc public func build() throws -> SSKProtoDataMessagePreview { - return try SSKProtoDataMessagePreview.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessagePreview.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.Preview - - @objc public let url: String - - @objc public let image: SSKProtoAttachmentPointer? - - @objc public var title: String? { - guard proto.hasTitle else { - return nil - } - return proto.title - } - @objc public var hasTitle: Bool { - return proto.hasTitle - } - - private init(proto: SignalServiceProtos_DataMessage.Preview, - url: String, - image: SSKProtoAttachmentPointer?) { - self.proto = proto - self.url = url - self.image = image - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessagePreview { - let proto = try SignalServiceProtos_DataMessage.Preview(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.Preview) throws -> SSKProtoDataMessagePreview { - guard proto.hasURL else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: url") - } - let url = proto.url - - var image: SSKProtoAttachmentPointer? = nil - if proto.hasImage { - image = try SSKProtoAttachmentPointer.parseProto(proto.image) - } - - // MARK: - Begin Validation Logic for SSKProtoDataMessagePreview - - - // MARK: - End Validation Logic for SSKProtoDataMessagePreview - - - let result = SSKProtoDataMessagePreview(proto: proto, - url: url, - image: image) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessagePreview { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessagePreview.SSKProtoDataMessagePreviewBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessagePreview? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageLokiProfile - -@objc public class SSKProtoDataMessageLokiProfile: NSObject { - - // MARK: - SSKProtoDataMessageLokiProfileBuilder - - @objc public class func builder() -> SSKProtoDataMessageLokiProfileBuilder { - return SSKProtoDataMessageLokiProfileBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageLokiProfileBuilder { - let builder = SSKProtoDataMessageLokiProfileBuilder() - if let _value = displayName { - builder.setDisplayName(_value) - } - if let _value = profilePicture { - builder.setProfilePicture(_value) - } - return builder - } - - @objc public class SSKProtoDataMessageLokiProfileBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.LokiProfile() - - @objc fileprivate override init() {} - - @objc public func setDisplayName(_ valueParam: String) { - proto.displayName = valueParam - } - - @objc public func setProfilePicture(_ valueParam: String) { - proto.profilePicture = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageLokiProfile { - return try SSKProtoDataMessageLokiProfile.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageLokiProfile.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.LokiProfile - - @objc public var displayName: String? { - guard proto.hasDisplayName else { - return nil - } - return proto.displayName - } - @objc public var hasDisplayName: Bool { - return proto.hasDisplayName - } - - @objc public var profilePicture: String? { - guard proto.hasProfilePicture else { - return nil - } - return proto.profilePicture - } - @objc public var hasProfilePicture: Bool { - return proto.hasProfilePicture - } - - private init(proto: SignalServiceProtos_DataMessage.LokiProfile) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageLokiProfile { - let proto = try SignalServiceProtos_DataMessage.LokiProfile(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.LokiProfile) throws -> SSKProtoDataMessageLokiProfile { - // MARK: - Begin Validation Logic for SSKProtoDataMessageLokiProfile - - - // MARK: - End Validation Logic for SSKProtoDataMessageLokiProfile - - - let result = SSKProtoDataMessageLokiProfile(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageLokiProfile { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageLokiProfile? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageClosedGroupUpdateSenderKey - -@objc public class SSKProtoDataMessageClosedGroupUpdateSenderKey: NSObject { - - // MARK: - SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder - - @objc public class func builder(chainKey: Data, keyIndex: UInt32, publicKey: Data) -> SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { - return SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder(chainKey: chainKey, keyIndex: keyIndex, publicKey: publicKey) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { - let builder = SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder(chainKey: chainKey, keyIndex: keyIndex, publicKey: publicKey) - return builder - } - - @objc public class SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey() - - @objc fileprivate override init() {} - - @objc fileprivate init(chainKey: Data, keyIndex: UInt32, publicKey: Data) { - super.init() - - setChainKey(chainKey) - setKeyIndex(keyIndex) - setPublicKey(publicKey) - } - - @objc public func setChainKey(_ valueParam: Data) { - proto.chainKey = valueParam - } - - @objc public func setKeyIndex(_ valueParam: UInt32) { - proto.keyIndex = valueParam - } - - @objc public func setPublicKey(_ valueParam: Data) { - proto.publicKey = valueParam - } - - @objc public func build() throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { - return try SSKProtoDataMessageClosedGroupUpdateSenderKey.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageClosedGroupUpdateSenderKey.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey - - @objc public let chainKey: Data - - @objc public let keyIndex: UInt32 - - @objc public let publicKey: Data - - private init(proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey, - chainKey: Data, - keyIndex: UInt32, - publicKey: Data) { - self.proto = proto - self.chainKey = chainKey - self.keyIndex = keyIndex - self.publicKey = publicKey - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { - let proto = try SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey) throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { - guard proto.hasChainKey else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: chainKey") - } - let chainKey = proto.chainKey - - guard proto.hasKeyIndex else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: keyIndex") - } - let keyIndex = proto.keyIndex - - guard proto.hasPublicKey else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: publicKey") - } - let publicKey = proto.publicKey - - // MARK: - Begin Validation Logic for SSKProtoDataMessageClosedGroupUpdateSenderKey - - - // MARK: - End Validation Logic for SSKProtoDataMessageClosedGroupUpdateSenderKey - - - let result = SSKProtoDataMessageClosedGroupUpdateSenderKey(proto: proto, - chainKey: chainKey, - keyIndex: keyIndex, - publicKey: publicKey) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageClosedGroupUpdateSenderKey { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageClosedGroupUpdateSenderKey.SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageClosedGroupUpdateSenderKey? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessageClosedGroupUpdate - -@objc public class SSKProtoDataMessageClosedGroupUpdate: NSObject { - - // MARK: - SSKProtoDataMessageClosedGroupUpdateType - - @objc public enum SSKProtoDataMessageClosedGroupUpdateType: Int32 { - case new = 0 - case info = 1 - case senderKeyRequest = 2 - case senderKey = 3 - } - - private class func SSKProtoDataMessageClosedGroupUpdateTypeWrap(_ value: SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum) -> SSKProtoDataMessageClosedGroupUpdateType { - switch value { - case .new: return .new - case .info: return .info - case .senderKeyRequest: return .senderKeyRequest - case .senderKey: return .senderKey - } - } - - private class func SSKProtoDataMessageClosedGroupUpdateTypeUnwrap(_ value: SSKProtoDataMessageClosedGroupUpdateType) -> SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum { - switch value { - case .new: return .new - case .info: return .info - case .senderKeyRequest: return .senderKeyRequest - case .senderKey: return .senderKey - } - } - - // MARK: - SSKProtoDataMessageClosedGroupUpdateBuilder - - @objc public class func builder(groupPublicKey: Data, type: SSKProtoDataMessageClosedGroupUpdateType) -> SSKProtoDataMessageClosedGroupUpdateBuilder { - return SSKProtoDataMessageClosedGroupUpdateBuilder(groupPublicKey: groupPublicKey, type: type) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageClosedGroupUpdateBuilder { - let builder = SSKProtoDataMessageClosedGroupUpdateBuilder(groupPublicKey: groupPublicKey, type: type) - if let _value = name { - builder.setName(_value) - } - if let _value = groupPrivateKey { - builder.setGroupPrivateKey(_value) - } - builder.setSenderKeys(senderKeys) - builder.setMembers(members) - builder.setAdmins(admins) - return builder - } - - @objc public class SSKProtoDataMessageClosedGroupUpdateBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage.ClosedGroupUpdate() - - @objc fileprivate override init() {} - - @objc fileprivate init(groupPublicKey: Data, type: SSKProtoDataMessageClosedGroupUpdateType) { - super.init() - - setGroupPublicKey(groupPublicKey) - setType(type) - } - - @objc public func setName(_ valueParam: String) { - proto.name = valueParam - } - - @objc public func setGroupPublicKey(_ valueParam: Data) { - proto.groupPublicKey = valueParam - } - - @objc public func setGroupPrivateKey(_ valueParam: Data) { - proto.groupPrivateKey = valueParam - } - - @objc public func addSenderKeys(_ valueParam: SSKProtoDataMessageClosedGroupUpdateSenderKey) { - var items = proto.senderKeys - items.append(valueParam.proto) - proto.senderKeys = items - } - - @objc public func setSenderKeys(_ wrappedItems: [SSKProtoDataMessageClosedGroupUpdateSenderKey]) { - proto.senderKeys = wrappedItems.map { $0.proto } - } - - @objc public func addMembers(_ valueParam: Data) { - var items = proto.members - items.append(valueParam) - proto.members = items - } - - @objc public func setMembers(_ wrappedItems: [Data]) { - proto.members = wrappedItems - } - - @objc public func addAdmins(_ valueParam: Data) { - var items = proto.admins - items.append(valueParam) - proto.admins = items - } - - @objc public func setAdmins(_ wrappedItems: [Data]) { - proto.admins = wrappedItems - } - - @objc public func setType(_ valueParam: SSKProtoDataMessageClosedGroupUpdateType) { - proto.type = SSKProtoDataMessageClosedGroupUpdateTypeUnwrap(valueParam) - } - - @objc public func build() throws -> SSKProtoDataMessageClosedGroupUpdate { - return try SSKProtoDataMessageClosedGroupUpdate.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessageClosedGroupUpdate.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate - - @objc public let groupPublicKey: Data - - @objc public let senderKeys: [SSKProtoDataMessageClosedGroupUpdateSenderKey] - - @objc public let type: SSKProtoDataMessageClosedGroupUpdateType - - @objc public var name: String? { - guard proto.hasName else { - return nil - } - return proto.name - } - @objc public var hasName: Bool { - return proto.hasName - } - - @objc public var groupPrivateKey: Data? { - guard proto.hasGroupPrivateKey else { - return nil - } - return proto.groupPrivateKey - } - @objc public var hasGroupPrivateKey: Bool { - return proto.hasGroupPrivateKey - } - - @objc public var members: [Data] { - return proto.members - } - - @objc public var admins: [Data] { - return proto.admins - } - - private init(proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate, - groupPublicKey: Data, - senderKeys: [SSKProtoDataMessageClosedGroupUpdateSenderKey], - type: SSKProtoDataMessageClosedGroupUpdateType) { - self.proto = proto - self.groupPublicKey = groupPublicKey - self.senderKeys = senderKeys - self.type = type - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageClosedGroupUpdate { - let proto = try SignalServiceProtos_DataMessage.ClosedGroupUpdate(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate) throws -> SSKProtoDataMessageClosedGroupUpdate { - guard proto.hasGroupPublicKey else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: groupPublicKey") - } - let groupPublicKey = proto.groupPublicKey - - var senderKeys: [SSKProtoDataMessageClosedGroupUpdateSenderKey] = [] - senderKeys = try proto.senderKeys.map { try SSKProtoDataMessageClosedGroupUpdateSenderKey.parseProto($0) } - - guard proto.hasType else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: type") - } - let type = SSKProtoDataMessageClosedGroupUpdateTypeWrap(proto.type) - - // MARK: - Begin Validation Logic for SSKProtoDataMessageClosedGroupUpdate - - - // MARK: - End Validation Logic for SSKProtoDataMessageClosedGroupUpdate - - - let result = SSKProtoDataMessageClosedGroupUpdate(proto: proto, - groupPublicKey: groupPublicKey, - senderKeys: senderKeys, - type: type) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessageClosedGroupUpdate { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessageClosedGroupUpdate.SSKProtoDataMessageClosedGroupUpdateBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessageClosedGroupUpdate? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoDataMessage - -@objc public class SSKProtoDataMessage: NSObject { - - // MARK: - SSKProtoDataMessageFlags - - @objc public enum SSKProtoDataMessageFlags: Int32 { - case endSession = 1 - case expirationTimerUpdate = 2 - case profileKeyUpdate = 4 - case unlinkDevice = 128 - } - - private class func SSKProtoDataMessageFlagsWrap(_ value: SignalServiceProtos_DataMessage.Flags) -> SSKProtoDataMessageFlags { - switch value { - case .endSession: return .endSession - case .expirationTimerUpdate: return .expirationTimerUpdate - case .profileKeyUpdate: return .profileKeyUpdate - case .unlinkDevice: return .unlinkDevice - } - } - - private class func SSKProtoDataMessageFlagsUnwrap(_ value: SSKProtoDataMessageFlags) -> SignalServiceProtos_DataMessage.Flags { - switch value { - case .endSession: return .endSession - case .expirationTimerUpdate: return .expirationTimerUpdate - case .profileKeyUpdate: return .profileKeyUpdate - case .unlinkDevice: return .unlinkDevice - } - } - - // MARK: - SSKProtoDataMessageBuilder - - @objc public class func builder() -> SSKProtoDataMessageBuilder { - return SSKProtoDataMessageBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoDataMessageBuilder { - let builder = SSKProtoDataMessageBuilder() - if let _value = body { - builder.setBody(_value) - } - builder.setAttachments(attachments) - if let _value = group { - builder.setGroup(_value) - } - if hasFlags { - builder.setFlags(flags) - } - if hasExpireTimer { - builder.setExpireTimer(expireTimer) - } - if let _value = profileKey { - builder.setProfileKey(_value) - } - if hasTimestamp { - builder.setTimestamp(timestamp) - } - if let _value = quote { - builder.setQuote(_value) - } - builder.setContact(contact) - builder.setPreview(preview) - if let _value = profile { - builder.setProfile(_value) - } - if let _value = closedGroupUpdate { - builder.setClosedGroupUpdate(_value) - } - if let _value = publicChatInfo { - builder.setPublicChatInfo(_value) - } - return builder - } - - @objc public class SSKProtoDataMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_DataMessage() - - @objc fileprivate override init() {} - - @objc public func setBody(_ valueParam: String) { - proto.body = valueParam - } - - @objc public func addAttachments(_ valueParam: SSKProtoAttachmentPointer) { - var items = proto.attachments - items.append(valueParam.proto) - proto.attachments = items - } - - @objc public func setAttachments(_ wrappedItems: [SSKProtoAttachmentPointer]) { - proto.attachments = wrappedItems.map { $0.proto } - } - - @objc public func setGroup(_ valueParam: SSKProtoGroupContext) { - proto.group = valueParam.proto - } - - @objc public func setFlags(_ valueParam: UInt32) { - proto.flags = valueParam - } - - @objc public func setExpireTimer(_ valueParam: UInt32) { - proto.expireTimer = valueParam - } - - @objc public func setProfileKey(_ valueParam: Data) { - proto.profileKey = valueParam - } - - @objc public func setTimestamp(_ valueParam: UInt64) { - proto.timestamp = valueParam - } - - @objc public func setQuote(_ valueParam: SSKProtoDataMessageQuote) { - proto.quote = valueParam.proto - } - - @objc public func addContact(_ valueParam: SSKProtoDataMessageContact) { - var items = proto.contact - items.append(valueParam.proto) - proto.contact = items - } - - @objc public func setContact(_ wrappedItems: [SSKProtoDataMessageContact]) { - proto.contact = wrappedItems.map { $0.proto } - } - - @objc public func addPreview(_ valueParam: SSKProtoDataMessagePreview) { - var items = proto.preview - items.append(valueParam.proto) - proto.preview = items - } - - @objc public func setPreview(_ wrappedItems: [SSKProtoDataMessagePreview]) { - proto.preview = wrappedItems.map { $0.proto } - } - - @objc public func setProfile(_ valueParam: SSKProtoDataMessageLokiProfile) { - proto.profile = valueParam.proto - } - - @objc public func setClosedGroupUpdate(_ valueParam: SSKProtoDataMessageClosedGroupUpdate) { - proto.closedGroupUpdate = valueParam.proto - } - - @objc public func setPublicChatInfo(_ valueParam: SSKProtoPublicChatInfo) { - proto.publicChatInfo = valueParam.proto - } - - @objc public func build() throws -> SSKProtoDataMessage { - return try SSKProtoDataMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoDataMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_DataMessage - - @objc public let attachments: [SSKProtoAttachmentPointer] - - @objc public let group: SSKProtoGroupContext? - - @objc public let quote: SSKProtoDataMessageQuote? - - @objc public let contact: [SSKProtoDataMessageContact] - - @objc public let preview: [SSKProtoDataMessagePreview] - - @objc public let profile: SSKProtoDataMessageLokiProfile? - - @objc public let closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate? - - @objc public let publicChatInfo: SSKProtoPublicChatInfo? - - @objc public var body: String? { - guard proto.hasBody else { - return nil - } - return proto.body - } - @objc public var hasBody: Bool { - return proto.hasBody - } - - @objc public var flags: UInt32 { - return proto.flags - } - @objc public var hasFlags: Bool { - return proto.hasFlags - } - - @objc public var expireTimer: UInt32 { - return proto.expireTimer - } - @objc public var hasExpireTimer: Bool { - return proto.hasExpireTimer - } - - @objc public var profileKey: Data? { - guard proto.hasProfileKey else { - return nil - } - return proto.profileKey - } - @objc public var hasProfileKey: Bool { - return proto.hasProfileKey - } - - @objc public var timestamp: UInt64 { - return proto.timestamp - } - @objc public var hasTimestamp: Bool { - return proto.hasTimestamp - } - - private init(proto: SignalServiceProtos_DataMessage, - attachments: [SSKProtoAttachmentPointer], - group: SSKProtoGroupContext?, - quote: SSKProtoDataMessageQuote?, - contact: [SSKProtoDataMessageContact], - preview: [SSKProtoDataMessagePreview], - profile: SSKProtoDataMessageLokiProfile?, - closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate?, - publicChatInfo: SSKProtoPublicChatInfo?) { - self.proto = proto - self.attachments = attachments - self.group = group - self.quote = quote - self.contact = contact - self.preview = preview - self.profile = profile - self.closedGroupUpdate = closedGroupUpdate - self.publicChatInfo = publicChatInfo - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessage { - let proto = try SignalServiceProtos_DataMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage) throws -> SSKProtoDataMessage { - var attachments: [SSKProtoAttachmentPointer] = [] - attachments = try proto.attachments.map { try SSKProtoAttachmentPointer.parseProto($0) } - - var group: SSKProtoGroupContext? = nil - if proto.hasGroup { - group = try SSKProtoGroupContext.parseProto(proto.group) - } - - var quote: SSKProtoDataMessageQuote? = nil - if proto.hasQuote { - quote = try SSKProtoDataMessageQuote.parseProto(proto.quote) - } - - var contact: [SSKProtoDataMessageContact] = [] - contact = try proto.contact.map { try SSKProtoDataMessageContact.parseProto($0) } - - var preview: [SSKProtoDataMessagePreview] = [] - preview = try proto.preview.map { try SSKProtoDataMessagePreview.parseProto($0) } - - var profile: SSKProtoDataMessageLokiProfile? = nil - if proto.hasProfile { - profile = try SSKProtoDataMessageLokiProfile.parseProto(proto.profile) - } - - var closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate? = nil - if proto.hasClosedGroupUpdate { - closedGroupUpdate = try SSKProtoDataMessageClosedGroupUpdate.parseProto(proto.closedGroupUpdate) - } - - var publicChatInfo: SSKProtoPublicChatInfo? = nil - if proto.hasPublicChatInfo { - publicChatInfo = try SSKProtoPublicChatInfo.parseProto(proto.publicChatInfo) - } - - // MARK: - Begin Validation Logic for SSKProtoDataMessage - - - // MARK: - End Validation Logic for SSKProtoDataMessage - - - let result = SSKProtoDataMessage(proto: proto, - attachments: attachments, - group: group, - quote: quote, - contact: contact, - preview: preview, - profile: profile, - closedGroupUpdate: closedGroupUpdate, - publicChatInfo: publicChatInfo) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoDataMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoDataMessage.SSKProtoDataMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoDataMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoNullMessage - -@objc public class SSKProtoNullMessage: NSObject { - - // MARK: - SSKProtoNullMessageBuilder - - @objc public class func builder() -> SSKProtoNullMessageBuilder { - return SSKProtoNullMessageBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoNullMessageBuilder { - let builder = SSKProtoNullMessageBuilder() - if let _value = padding { - builder.setPadding(_value) - } - return builder - } - - @objc public class SSKProtoNullMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_NullMessage() - - @objc fileprivate override init() {} - - @objc public func setPadding(_ valueParam: Data) { - proto.padding = valueParam - } - - @objc public func build() throws -> SSKProtoNullMessage { - return try SSKProtoNullMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoNullMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_NullMessage - - @objc public var padding: Data? { - guard proto.hasPadding else { - return nil - } - return proto.padding - } - @objc public var hasPadding: Bool { - return proto.hasPadding - } - - private init(proto: SignalServiceProtos_NullMessage) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoNullMessage { - let proto = try SignalServiceProtos_NullMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_NullMessage) throws -> SSKProtoNullMessage { - // MARK: - Begin Validation Logic for SSKProtoNullMessage - - - // MARK: - End Validation Logic for SSKProtoNullMessage - - - let result = SSKProtoNullMessage(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoNullMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoNullMessage.SSKProtoNullMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoNullMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoReceiptMessage - -@objc public class SSKProtoReceiptMessage: NSObject { - - // MARK: - SSKProtoReceiptMessageType - - @objc public enum SSKProtoReceiptMessageType: Int32 { - case delivery = 0 - case read = 1 - } - - private class func SSKProtoReceiptMessageTypeWrap(_ value: SignalServiceProtos_ReceiptMessage.TypeEnum) -> SSKProtoReceiptMessageType { - switch value { - case .delivery: return .delivery - case .read: return .read - } - } - - private class func SSKProtoReceiptMessageTypeUnwrap(_ value: SSKProtoReceiptMessageType) -> SignalServiceProtos_ReceiptMessage.TypeEnum { - switch value { - case .delivery: return .delivery - case .read: return .read - } - } - - // MARK: - SSKProtoReceiptMessageBuilder - - @objc public class func builder(type: SSKProtoReceiptMessageType) -> SSKProtoReceiptMessageBuilder { - return SSKProtoReceiptMessageBuilder(type: type) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoReceiptMessageBuilder { - let builder = SSKProtoReceiptMessageBuilder(type: type) - builder.setTimestamp(timestamp) - return builder - } - - @objc public class SSKProtoReceiptMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_ReceiptMessage() - - @objc fileprivate override init() {} - - @objc fileprivate init(type: SSKProtoReceiptMessageType) { - super.init() - - setType(type) - } - - @objc public func setType(_ valueParam: SSKProtoReceiptMessageType) { - proto.type = SSKProtoReceiptMessageTypeUnwrap(valueParam) - } - - @objc public func addTimestamp(_ valueParam: UInt64) { - var items = proto.timestamp - items.append(valueParam) - proto.timestamp = items - } - - @objc public func setTimestamp(_ wrappedItems: [UInt64]) { - proto.timestamp = wrappedItems - } - - @objc public func build() throws -> SSKProtoReceiptMessage { - return try SSKProtoReceiptMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoReceiptMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_ReceiptMessage - - @objc public let type: SSKProtoReceiptMessageType - - @objc public var timestamp: [UInt64] { - return proto.timestamp - } - - private init(proto: SignalServiceProtos_ReceiptMessage, - type: SSKProtoReceiptMessageType) { - self.proto = proto - self.type = type - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoReceiptMessage { - let proto = try SignalServiceProtos_ReceiptMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_ReceiptMessage) throws -> SSKProtoReceiptMessage { - guard proto.hasType else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: type") - } - let type = SSKProtoReceiptMessageTypeWrap(proto.type) - - // MARK: - Begin Validation Logic for SSKProtoReceiptMessage - - - // MARK: - End Validation Logic for SSKProtoReceiptMessage - - - let result = SSKProtoReceiptMessage(proto: proto, - type: type) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoReceiptMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoReceiptMessage.SSKProtoReceiptMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoReceiptMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoVerified - -@objc public class SSKProtoVerified: NSObject { - - // MARK: - SSKProtoVerifiedState - - @objc public enum SSKProtoVerifiedState: Int32 { - case `default` = 0 - case verified = 1 - case unverified = 2 - } - - private class func SSKProtoVerifiedStateWrap(_ value: SignalServiceProtos_Verified.State) -> SSKProtoVerifiedState { - switch value { - case .default: return .default - case .verified: return .verified - case .unverified: return .unverified - } - } - - private class func SSKProtoVerifiedStateUnwrap(_ value: SSKProtoVerifiedState) -> SignalServiceProtos_Verified.State { - switch value { - case .default: return .default - case .verified: return .verified - case .unverified: return .unverified - } - } - - // MARK: - SSKProtoVerifiedBuilder - - @objc public class func builder(destination: String) -> SSKProtoVerifiedBuilder { - return SSKProtoVerifiedBuilder(destination: destination) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoVerifiedBuilder { - let builder = SSKProtoVerifiedBuilder(destination: destination) - if let _value = identityKey { - builder.setIdentityKey(_value) - } - if hasState { - builder.setState(state) - } - if let _value = nullMessage { - builder.setNullMessage(_value) - } - return builder - } - - @objc public class SSKProtoVerifiedBuilder: NSObject { - - private var proto = SignalServiceProtos_Verified() - - @objc fileprivate override init() {} - - @objc fileprivate init(destination: String) { - super.init() - - setDestination(destination) - } - - @objc public func setDestination(_ valueParam: String) { - proto.destination = valueParam - } - - @objc public func setIdentityKey(_ valueParam: Data) { - proto.identityKey = valueParam - } - - @objc public func setState(_ valueParam: SSKProtoVerifiedState) { - proto.state = SSKProtoVerifiedStateUnwrap(valueParam) - } - - @objc public func setNullMessage(_ valueParam: Data) { - proto.nullMessage = valueParam - } - - @objc public func build() throws -> SSKProtoVerified { - return try SSKProtoVerified.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoVerified.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_Verified - - @objc public let destination: String - - @objc public var identityKey: Data? { - guard proto.hasIdentityKey else { - return nil - } - return proto.identityKey - } - @objc public var hasIdentityKey: Bool { - return proto.hasIdentityKey - } - - @objc public var state: SSKProtoVerifiedState { - return SSKProtoVerified.SSKProtoVerifiedStateWrap(proto.state) - } - @objc public var hasState: Bool { - return proto.hasState - } - - @objc public var nullMessage: Data? { - guard proto.hasNullMessage else { - return nil - } - return proto.nullMessage - } - @objc public var hasNullMessage: Bool { - return proto.hasNullMessage - } - - private init(proto: SignalServiceProtos_Verified, - destination: String) { - self.proto = proto - self.destination = destination - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoVerified { - let proto = try SignalServiceProtos_Verified(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_Verified) throws -> SSKProtoVerified { - guard proto.hasDestination else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: destination") - } - let destination = proto.destination - - // MARK: - Begin Validation Logic for SSKProtoVerified - - - // MARK: - End Validation Logic for SSKProtoVerified - - - let result = SSKProtoVerified(proto: proto, - destination: destination) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoVerified { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoVerified.SSKProtoVerifiedBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoVerified? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageSentUnidentifiedDeliveryStatus - -@objc public class SSKProtoSyncMessageSentUnidentifiedDeliveryStatus: NSObject { - - // MARK: - SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder - - @objc public class func builder() -> SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder { - return SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder { - let builder = SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder() - if let _value = destination { - builder.setDestination(_value) - } - if hasUnidentified { - builder.setUnidentified(unidentified) - } - return builder - } - - @objc public class SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus() - - @objc fileprivate override init() {} - - @objc public func setDestination(_ valueParam: String) { - proto.destination = valueParam - } - - @objc public func setUnidentified(_ valueParam: Bool) { - proto.unidentified = valueParam - } - - @objc public func build() throws -> SSKProtoSyncMessageSentUnidentifiedDeliveryStatus { - return try SSKProtoSyncMessageSentUnidentifiedDeliveryStatus.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageSentUnidentifiedDeliveryStatus.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus - - @objc public var destination: String? { - guard proto.hasDestination else { - return nil - } - return proto.destination - } - @objc public var hasDestination: Bool { - return proto.hasDestination - } - - @objc public var unidentified: Bool { - return proto.unidentified - } - @objc public var hasUnidentified: Bool { - return proto.hasUnidentified - } - - private init(proto: SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageSentUnidentifiedDeliveryStatus { - let proto = try SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus) throws -> SSKProtoSyncMessageSentUnidentifiedDeliveryStatus { - // MARK: - Begin Validation Logic for SSKProtoSyncMessageSentUnidentifiedDeliveryStatus - - - // MARK: - End Validation Logic for SSKProtoSyncMessageSentUnidentifiedDeliveryStatus - - - let result = SSKProtoSyncMessageSentUnidentifiedDeliveryStatus(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageSentUnidentifiedDeliveryStatus { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageSentUnidentifiedDeliveryStatus.SSKProtoSyncMessageSentUnidentifiedDeliveryStatusBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageSentUnidentifiedDeliveryStatus? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageSent - -@objc public class SSKProtoSyncMessageSent: NSObject { - - // MARK: - SSKProtoSyncMessageSentBuilder - - @objc public class func builder() -> SSKProtoSyncMessageSentBuilder { - return SSKProtoSyncMessageSentBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageSentBuilder { - let builder = SSKProtoSyncMessageSentBuilder() - if let _value = destination { - builder.setDestination(_value) - } - if hasTimestamp { - builder.setTimestamp(timestamp) - } - if let _value = message { - builder.setMessage(_value) - } - if hasExpirationStartTimestamp { - builder.setExpirationStartTimestamp(expirationStartTimestamp) - } - builder.setUnidentifiedStatus(unidentifiedStatus) - if hasIsRecipientUpdate { - builder.setIsRecipientUpdate(isRecipientUpdate) - } - return builder - } - - @objc public class SSKProtoSyncMessageSentBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Sent() - - @objc fileprivate override init() {} - - @objc public func setDestination(_ valueParam: String) { - proto.destination = valueParam - } - - @objc public func setTimestamp(_ valueParam: UInt64) { - proto.timestamp = valueParam - } - - @objc public func setMessage(_ valueParam: SSKProtoDataMessage) { - proto.message = valueParam.proto - } - - @objc public func setExpirationStartTimestamp(_ valueParam: UInt64) { - proto.expirationStartTimestamp = valueParam - } - - @objc public func addUnidentifiedStatus(_ valueParam: SSKProtoSyncMessageSentUnidentifiedDeliveryStatus) { - var items = proto.unidentifiedStatus - items.append(valueParam.proto) - proto.unidentifiedStatus = items - } - - @objc public func setUnidentifiedStatus(_ wrappedItems: [SSKProtoSyncMessageSentUnidentifiedDeliveryStatus]) { - proto.unidentifiedStatus = wrappedItems.map { $0.proto } - } - - @objc public func setIsRecipientUpdate(_ valueParam: Bool) { - proto.isRecipientUpdate = valueParam - } - - @objc public func build() throws -> SSKProtoSyncMessageSent { - return try SSKProtoSyncMessageSent.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageSent.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Sent - - @objc public let message: SSKProtoDataMessage? - - @objc public let unidentifiedStatus: [SSKProtoSyncMessageSentUnidentifiedDeliveryStatus] - - @objc public var destination: String? { - guard proto.hasDestination else { - return nil - } - return proto.destination - } - @objc public var hasDestination: Bool { - return proto.hasDestination - } - - @objc public var timestamp: UInt64 { - return proto.timestamp - } - @objc public var hasTimestamp: Bool { - return proto.hasTimestamp - } - - @objc public var expirationStartTimestamp: UInt64 { - return proto.expirationStartTimestamp - } - @objc public var hasExpirationStartTimestamp: Bool { - return proto.hasExpirationStartTimestamp - } - - @objc public var isRecipientUpdate: Bool { - return proto.isRecipientUpdate - } - @objc public var hasIsRecipientUpdate: Bool { - return proto.hasIsRecipientUpdate - } - - private init(proto: SignalServiceProtos_SyncMessage.Sent, - message: SSKProtoDataMessage?, - unidentifiedStatus: [SSKProtoSyncMessageSentUnidentifiedDeliveryStatus]) { - self.proto = proto - self.message = message - self.unidentifiedStatus = unidentifiedStatus - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageSent { - let proto = try SignalServiceProtos_SyncMessage.Sent(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Sent) throws -> SSKProtoSyncMessageSent { - var message: SSKProtoDataMessage? = nil - if proto.hasMessage { - message = try SSKProtoDataMessage.parseProto(proto.message) - } - - var unidentifiedStatus: [SSKProtoSyncMessageSentUnidentifiedDeliveryStatus] = [] - unidentifiedStatus = try proto.unidentifiedStatus.map { try SSKProtoSyncMessageSentUnidentifiedDeliveryStatus.parseProto($0) } - - // MARK: - Begin Validation Logic for SSKProtoSyncMessageSent - - - // MARK: - End Validation Logic for SSKProtoSyncMessageSent - - - let result = SSKProtoSyncMessageSent(proto: proto, - message: message, - unidentifiedStatus: unidentifiedStatus) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageSent { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageSent.SSKProtoSyncMessageSentBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageSent? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageContacts - -@objc public class SSKProtoSyncMessageContacts: NSObject { - - // MARK: - SSKProtoSyncMessageContactsBuilder - - @objc public class func builder() -> SSKProtoSyncMessageContactsBuilder { - return SSKProtoSyncMessageContactsBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageContactsBuilder { - let builder = SSKProtoSyncMessageContactsBuilder() - if let _value = blob { - builder.setBlob(_value) - } - if hasIsComplete { - builder.setIsComplete(isComplete) - } - if let _value = data { - builder.setData(_value) - } - return builder - } - - @objc public class SSKProtoSyncMessageContactsBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Contacts() - - @objc fileprivate override init() {} - - @objc public func setBlob(_ valueParam: SSKProtoAttachmentPointer) { - proto.blob = valueParam.proto - } - - @objc public func setIsComplete(_ valueParam: Bool) { - proto.isComplete = valueParam - } - - @objc public func setData(_ valueParam: Data) { - proto.data = valueParam - } - - @objc public func build() throws -> SSKProtoSyncMessageContacts { - return try SSKProtoSyncMessageContacts.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageContacts.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Contacts - - @objc public let blob: SSKProtoAttachmentPointer? - - @objc public var isComplete: Bool { - return proto.isComplete - } - @objc public var hasIsComplete: Bool { - return proto.hasIsComplete - } - - @objc public var data: Data? { - guard proto.hasData else { - return nil - } - return proto.data - } - @objc public var hasData: Bool { - return proto.hasData - } - - private init(proto: SignalServiceProtos_SyncMessage.Contacts, - blob: SSKProtoAttachmentPointer?) { - self.proto = proto - self.blob = blob - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageContacts { - let proto = try SignalServiceProtos_SyncMessage.Contacts(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Contacts) throws -> SSKProtoSyncMessageContacts { - var blob: SSKProtoAttachmentPointer? = nil - if proto.hasBlob { - blob = try SSKProtoAttachmentPointer.parseProto(proto.blob) - } - - // MARK: - Begin Validation Logic for SSKProtoSyncMessageContacts - - - // MARK: - End Validation Logic for SSKProtoSyncMessageContacts - - - let result = SSKProtoSyncMessageContacts(proto: proto, - blob: blob) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageContacts { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageContacts.SSKProtoSyncMessageContactsBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageContacts? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageGroups - -@objc public class SSKProtoSyncMessageGroups: NSObject { - - // MARK: - SSKProtoSyncMessageGroupsBuilder - - @objc public class func builder() -> SSKProtoSyncMessageGroupsBuilder { - return SSKProtoSyncMessageGroupsBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageGroupsBuilder { - let builder = SSKProtoSyncMessageGroupsBuilder() - if let _value = blob { - builder.setBlob(_value) - } - if let _value = data { - builder.setData(_value) - } - return builder - } - - @objc public class SSKProtoSyncMessageGroupsBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Groups() - - @objc fileprivate override init() {} - - @objc public func setBlob(_ valueParam: SSKProtoAttachmentPointer) { - proto.blob = valueParam.proto - } - - @objc public func setData(_ valueParam: Data) { - proto.data = valueParam - } - - @objc public func build() throws -> SSKProtoSyncMessageGroups { - return try SSKProtoSyncMessageGroups.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageGroups.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Groups - - @objc public let blob: SSKProtoAttachmentPointer? - - @objc public var data: Data? { - guard proto.hasData else { - return nil - } - return proto.data - } - @objc public var hasData: Bool { - return proto.hasData - } - - private init(proto: SignalServiceProtos_SyncMessage.Groups, - blob: SSKProtoAttachmentPointer?) { - self.proto = proto - self.blob = blob - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageGroups { - let proto = try SignalServiceProtos_SyncMessage.Groups(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Groups) throws -> SSKProtoSyncMessageGroups { - var blob: SSKProtoAttachmentPointer? = nil - if proto.hasBlob { - blob = try SSKProtoAttachmentPointer.parseProto(proto.blob) - } - - // MARK: - Begin Validation Logic for SSKProtoSyncMessageGroups - - - // MARK: - End Validation Logic for SSKProtoSyncMessageGroups - - - let result = SSKProtoSyncMessageGroups(proto: proto, - blob: blob) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageGroups { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageGroups.SSKProtoSyncMessageGroupsBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageGroups? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageOpenGroupDetails - -@objc public class SSKProtoSyncMessageOpenGroupDetails: NSObject { - - // MARK: - SSKProtoSyncMessageOpenGroupDetailsBuilder - - @objc public class func builder(url: String, channelID: UInt64) -> SSKProtoSyncMessageOpenGroupDetailsBuilder { - return SSKProtoSyncMessageOpenGroupDetailsBuilder(url: url, channelID: channelID) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageOpenGroupDetailsBuilder { - let builder = SSKProtoSyncMessageOpenGroupDetailsBuilder(url: url, channelID: channelID) - return builder - } - - @objc public class SSKProtoSyncMessageOpenGroupDetailsBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.OpenGroupDetails() - - @objc fileprivate override init() {} - - @objc fileprivate init(url: String, channelID: UInt64) { - super.init() - - setUrl(url) - setChannelID(channelID) - } - - @objc public func setUrl(_ valueParam: String) { - proto.url = valueParam - } - - @objc public func setChannelID(_ valueParam: UInt64) { - proto.channelID = valueParam - } - - @objc public func build() throws -> SSKProtoSyncMessageOpenGroupDetails { - return try SSKProtoSyncMessageOpenGroupDetails.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageOpenGroupDetails.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.OpenGroupDetails - - @objc public let url: String - - @objc public let channelID: UInt64 - - private init(proto: SignalServiceProtos_SyncMessage.OpenGroupDetails, - url: String, - channelID: UInt64) { - self.proto = proto - self.url = url - self.channelID = channelID - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageOpenGroupDetails { - let proto = try SignalServiceProtos_SyncMessage.OpenGroupDetails(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.OpenGroupDetails) throws -> SSKProtoSyncMessageOpenGroupDetails { - guard proto.hasURL else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: url") - } - let url = proto.url - - guard proto.hasChannelID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: channelID") - } - let channelID = proto.channelID - - // MARK: - Begin Validation Logic for SSKProtoSyncMessageOpenGroupDetails - - - // MARK: - End Validation Logic for SSKProtoSyncMessageOpenGroupDetails - - - let result = SSKProtoSyncMessageOpenGroupDetails(proto: proto, - url: url, - channelID: channelID) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageOpenGroupDetails { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageOpenGroupDetails.SSKProtoSyncMessageOpenGroupDetailsBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageOpenGroupDetails? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageBlocked - -@objc public class SSKProtoSyncMessageBlocked: NSObject { - - // MARK: - SSKProtoSyncMessageBlockedBuilder - - @objc public class func builder() -> SSKProtoSyncMessageBlockedBuilder { - return SSKProtoSyncMessageBlockedBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageBlockedBuilder { - let builder = SSKProtoSyncMessageBlockedBuilder() - builder.setNumbers(numbers) - builder.setGroupIds(groupIds) - return builder - } - - @objc public class SSKProtoSyncMessageBlockedBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Blocked() - - @objc fileprivate override init() {} - - @objc public func addNumbers(_ valueParam: String) { - var items = proto.numbers - items.append(valueParam) - proto.numbers = items - } - - @objc public func setNumbers(_ wrappedItems: [String]) { - proto.numbers = wrappedItems - } - - @objc public func addGroupIds(_ valueParam: Data) { - var items = proto.groupIds - items.append(valueParam) - proto.groupIds = items - } - - @objc public func setGroupIds(_ wrappedItems: [Data]) { - proto.groupIds = wrappedItems - } - - @objc public func build() throws -> SSKProtoSyncMessageBlocked { - return try SSKProtoSyncMessageBlocked.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageBlocked.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Blocked - - @objc public var numbers: [String] { - return proto.numbers - } - - @objc public var groupIds: [Data] { - return proto.groupIds - } - - private init(proto: SignalServiceProtos_SyncMessage.Blocked) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageBlocked { - let proto = try SignalServiceProtos_SyncMessage.Blocked(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Blocked) throws -> SSKProtoSyncMessageBlocked { - // MARK: - Begin Validation Logic for SSKProtoSyncMessageBlocked - - - // MARK: - End Validation Logic for SSKProtoSyncMessageBlocked - - - let result = SSKProtoSyncMessageBlocked(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageBlocked { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageBlocked.SSKProtoSyncMessageBlockedBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageBlocked? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageRequest - -@objc public class SSKProtoSyncMessageRequest: NSObject { - - // MARK: - SSKProtoSyncMessageRequestType - - @objc public enum SSKProtoSyncMessageRequestType: Int32 { - case unknown = 0 - case contacts = 1 - case groups = 2 - case blocked = 3 - case configuration = 4 - } - - private class func SSKProtoSyncMessageRequestTypeWrap(_ value: SignalServiceProtos_SyncMessage.Request.TypeEnum) -> SSKProtoSyncMessageRequestType { - switch value { - case .unknown: return .unknown - case .contacts: return .contacts - case .groups: return .groups - case .blocked: return .blocked - case .configuration: return .configuration - } - } - - private class func SSKProtoSyncMessageRequestTypeUnwrap(_ value: SSKProtoSyncMessageRequestType) -> SignalServiceProtos_SyncMessage.Request.TypeEnum { - switch value { - case .unknown: return .unknown - case .contacts: return .contacts - case .groups: return .groups - case .blocked: return .blocked - case .configuration: return .configuration - } - } - - // MARK: - SSKProtoSyncMessageRequestBuilder - - @objc public class func builder(type: SSKProtoSyncMessageRequestType) -> SSKProtoSyncMessageRequestBuilder { - return SSKProtoSyncMessageRequestBuilder(type: type) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageRequestBuilder { - let builder = SSKProtoSyncMessageRequestBuilder(type: type) - return builder - } - - @objc public class SSKProtoSyncMessageRequestBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Request() - - @objc fileprivate override init() {} - - @objc fileprivate init(type: SSKProtoSyncMessageRequestType) { - super.init() - - setType(type) - } - - @objc public func setType(_ valueParam: SSKProtoSyncMessageRequestType) { - proto.type = SSKProtoSyncMessageRequestTypeUnwrap(valueParam) - } - - @objc public func build() throws -> SSKProtoSyncMessageRequest { - return try SSKProtoSyncMessageRequest.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageRequest.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Request - - @objc public let type: SSKProtoSyncMessageRequestType - - private init(proto: SignalServiceProtos_SyncMessage.Request, - type: SSKProtoSyncMessageRequestType) { - self.proto = proto - self.type = type - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageRequest { - let proto = try SignalServiceProtos_SyncMessage.Request(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Request) throws -> SSKProtoSyncMessageRequest { - guard proto.hasType else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: type") - } - let type = SSKProtoSyncMessageRequestTypeWrap(proto.type) - - // MARK: - Begin Validation Logic for SSKProtoSyncMessageRequest - - - // MARK: - End Validation Logic for SSKProtoSyncMessageRequest - - - let result = SSKProtoSyncMessageRequest(proto: proto, - type: type) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageRequest { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageRequest.SSKProtoSyncMessageRequestBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageRequest? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageRead - -@objc public class SSKProtoSyncMessageRead: NSObject { - - // MARK: - SSKProtoSyncMessageReadBuilder - - @objc public class func builder(sender: String, timestamp: UInt64) -> SSKProtoSyncMessageReadBuilder { - return SSKProtoSyncMessageReadBuilder(sender: sender, timestamp: timestamp) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageReadBuilder { - let builder = SSKProtoSyncMessageReadBuilder(sender: sender, timestamp: timestamp) - return builder - } - - @objc public class SSKProtoSyncMessageReadBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Read() - - @objc fileprivate override init() {} - - @objc fileprivate init(sender: String, timestamp: UInt64) { - super.init() - - setSender(sender) - setTimestamp(timestamp) - } - - @objc public func setSender(_ valueParam: String) { - proto.sender = valueParam - } - - @objc public func setTimestamp(_ valueParam: UInt64) { - proto.timestamp = valueParam - } - - @objc public func build() throws -> SSKProtoSyncMessageRead { - return try SSKProtoSyncMessageRead.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageRead.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Read - - @objc public let sender: String - - @objc public let timestamp: UInt64 - - private init(proto: SignalServiceProtos_SyncMessage.Read, - sender: String, - timestamp: UInt64) { - self.proto = proto - self.sender = sender - self.timestamp = timestamp - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageRead { - let proto = try SignalServiceProtos_SyncMessage.Read(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Read) throws -> SSKProtoSyncMessageRead { - guard proto.hasSender else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: sender") - } - let sender = proto.sender - - guard proto.hasTimestamp else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: timestamp") - } - let timestamp = proto.timestamp - - // MARK: - Begin Validation Logic for SSKProtoSyncMessageRead - - - // MARK: - End Validation Logic for SSKProtoSyncMessageRead - - - let result = SSKProtoSyncMessageRead(proto: proto, - sender: sender, - timestamp: timestamp) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageRead { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageRead.SSKProtoSyncMessageReadBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageRead? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessageConfiguration - -@objc public class SSKProtoSyncMessageConfiguration: NSObject { - - // MARK: - SSKProtoSyncMessageConfigurationBuilder - - @objc public class func builder() -> SSKProtoSyncMessageConfigurationBuilder { - return SSKProtoSyncMessageConfigurationBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageConfigurationBuilder { - let builder = SSKProtoSyncMessageConfigurationBuilder() - if hasReadReceipts { - builder.setReadReceipts(readReceipts) - } - if hasUnidentifiedDeliveryIndicators { - builder.setUnidentifiedDeliveryIndicators(unidentifiedDeliveryIndicators) - } - if hasTypingIndicators { - builder.setTypingIndicators(typingIndicators) - } - if hasLinkPreviews { - builder.setLinkPreviews(linkPreviews) - } - return builder - } - - @objc public class SSKProtoSyncMessageConfigurationBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage.Configuration() - - @objc fileprivate override init() {} - - @objc public func setReadReceipts(_ valueParam: Bool) { - proto.readReceipts = valueParam - } - - @objc public func setUnidentifiedDeliveryIndicators(_ valueParam: Bool) { - proto.unidentifiedDeliveryIndicators = valueParam - } - - @objc public func setTypingIndicators(_ valueParam: Bool) { - proto.typingIndicators = valueParam - } - - @objc public func setLinkPreviews(_ valueParam: Bool) { - proto.linkPreviews = valueParam - } - - @objc public func build() throws -> SSKProtoSyncMessageConfiguration { - return try SSKProtoSyncMessageConfiguration.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessageConfiguration.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage.Configuration - - @objc public var readReceipts: Bool { - return proto.readReceipts - } - @objc public var hasReadReceipts: Bool { - return proto.hasReadReceipts - } - - @objc public var unidentifiedDeliveryIndicators: Bool { - return proto.unidentifiedDeliveryIndicators - } - @objc public var hasUnidentifiedDeliveryIndicators: Bool { - return proto.hasUnidentifiedDeliveryIndicators - } - - @objc public var typingIndicators: Bool { - return proto.typingIndicators - } - @objc public var hasTypingIndicators: Bool { - return proto.hasTypingIndicators - } - - @objc public var linkPreviews: Bool { - return proto.linkPreviews - } - @objc public var hasLinkPreviews: Bool { - return proto.hasLinkPreviews - } - - private init(proto: SignalServiceProtos_SyncMessage.Configuration) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessageConfiguration { - let proto = try SignalServiceProtos_SyncMessage.Configuration(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage.Configuration) throws -> SSKProtoSyncMessageConfiguration { - // MARK: - Begin Validation Logic for SSKProtoSyncMessageConfiguration - - - // MARK: - End Validation Logic for SSKProtoSyncMessageConfiguration - - - let result = SSKProtoSyncMessageConfiguration(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessageConfiguration { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessageConfiguration.SSKProtoSyncMessageConfigurationBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessageConfiguration? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoSyncMessage - -@objc public class SSKProtoSyncMessage: NSObject { - - // MARK: - SSKProtoSyncMessageBuilder - - @objc public class func builder() -> SSKProtoSyncMessageBuilder { - return SSKProtoSyncMessageBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoSyncMessageBuilder { - let builder = SSKProtoSyncMessageBuilder() - if let _value = sent { - builder.setSent(_value) - } - if let _value = contacts { - builder.setContacts(_value) - } - if let _value = groups { - builder.setGroups(_value) - } - if let _value = request { - builder.setRequest(_value) - } - builder.setRead(read) - if let _value = blocked { - builder.setBlocked(_value) - } - if let _value = verified { - builder.setVerified(_value) - } - if let _value = configuration { - builder.setConfiguration(_value) - } - if let _value = padding { - builder.setPadding(_value) - } - builder.setOpenGroups(openGroups) - return builder - } - - @objc public class SSKProtoSyncMessageBuilder: NSObject { - - private var proto = SignalServiceProtos_SyncMessage() - - @objc fileprivate override init() {} - - @objc public func setSent(_ valueParam: SSKProtoSyncMessageSent) { - proto.sent = valueParam.proto - } - - @objc public func setContacts(_ valueParam: SSKProtoSyncMessageContacts) { - proto.contacts = valueParam.proto - } - - @objc public func setGroups(_ valueParam: SSKProtoSyncMessageGroups) { - proto.groups = valueParam.proto - } - - @objc public func setRequest(_ valueParam: SSKProtoSyncMessageRequest) { - proto.request = valueParam.proto - } - - @objc public func addRead(_ valueParam: SSKProtoSyncMessageRead) { - var items = proto.read - items.append(valueParam.proto) - proto.read = items - } - - @objc public func setRead(_ wrappedItems: [SSKProtoSyncMessageRead]) { - proto.read = wrappedItems.map { $0.proto } - } - - @objc public func setBlocked(_ valueParam: SSKProtoSyncMessageBlocked) { - proto.blocked = valueParam.proto - } - - @objc public func setVerified(_ valueParam: SSKProtoVerified) { - proto.verified = valueParam.proto - } - - @objc public func setConfiguration(_ valueParam: SSKProtoSyncMessageConfiguration) { - proto.configuration = valueParam.proto - } - - @objc public func setPadding(_ valueParam: Data) { - proto.padding = valueParam - } - - @objc public func addOpenGroups(_ valueParam: SSKProtoSyncMessageOpenGroupDetails) { - var items = proto.openGroups - items.append(valueParam.proto) - proto.openGroups = items - } - - @objc public func setOpenGroups(_ wrappedItems: [SSKProtoSyncMessageOpenGroupDetails]) { - proto.openGroups = wrappedItems.map { $0.proto } - } - - @objc public func build() throws -> SSKProtoSyncMessage { - return try SSKProtoSyncMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoSyncMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_SyncMessage - - @objc public let sent: SSKProtoSyncMessageSent? - - @objc public let contacts: SSKProtoSyncMessageContacts? - - @objc public let groups: SSKProtoSyncMessageGroups? - - @objc public let request: SSKProtoSyncMessageRequest? - - @objc public let read: [SSKProtoSyncMessageRead] - - @objc public let blocked: SSKProtoSyncMessageBlocked? - - @objc public let verified: SSKProtoVerified? - - @objc public let configuration: SSKProtoSyncMessageConfiguration? - - @objc public let openGroups: [SSKProtoSyncMessageOpenGroupDetails] - - @objc public var padding: Data? { - guard proto.hasPadding else { - return nil - } - return proto.padding - } - @objc public var hasPadding: Bool { - return proto.hasPadding - } - - private init(proto: SignalServiceProtos_SyncMessage, - sent: SSKProtoSyncMessageSent?, - contacts: SSKProtoSyncMessageContacts?, - groups: SSKProtoSyncMessageGroups?, - request: SSKProtoSyncMessageRequest?, - read: [SSKProtoSyncMessageRead], - blocked: SSKProtoSyncMessageBlocked?, - verified: SSKProtoVerified?, - configuration: SSKProtoSyncMessageConfiguration?, - openGroups: [SSKProtoSyncMessageOpenGroupDetails]) { - self.proto = proto - self.sent = sent - self.contacts = contacts - self.groups = groups - self.request = request - self.read = read - self.blocked = blocked - self.verified = verified - self.configuration = configuration - self.openGroups = openGroups - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoSyncMessage { - let proto = try SignalServiceProtos_SyncMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_SyncMessage) throws -> SSKProtoSyncMessage { - var sent: SSKProtoSyncMessageSent? = nil - if proto.hasSent { - sent = try SSKProtoSyncMessageSent.parseProto(proto.sent) - } - - var contacts: SSKProtoSyncMessageContacts? = nil - if proto.hasContacts { - contacts = try SSKProtoSyncMessageContacts.parseProto(proto.contacts) - } - - var groups: SSKProtoSyncMessageGroups? = nil - if proto.hasGroups { - groups = try SSKProtoSyncMessageGroups.parseProto(proto.groups) - } - - var request: SSKProtoSyncMessageRequest? = nil - if proto.hasRequest { - request = try SSKProtoSyncMessageRequest.parseProto(proto.request) - } - - var read: [SSKProtoSyncMessageRead] = [] - read = try proto.read.map { try SSKProtoSyncMessageRead.parseProto($0) } - - var blocked: SSKProtoSyncMessageBlocked? = nil - if proto.hasBlocked { - blocked = try SSKProtoSyncMessageBlocked.parseProto(proto.blocked) - } - - var verified: SSKProtoVerified? = nil - if proto.hasVerified { - verified = try SSKProtoVerified.parseProto(proto.verified) - } - - var configuration: SSKProtoSyncMessageConfiguration? = nil - if proto.hasConfiguration { - configuration = try SSKProtoSyncMessageConfiguration.parseProto(proto.configuration) - } - - var openGroups: [SSKProtoSyncMessageOpenGroupDetails] = [] - openGroups = try proto.openGroups.map { try SSKProtoSyncMessageOpenGroupDetails.parseProto($0) } - - // MARK: - Begin Validation Logic for SSKProtoSyncMessage - - - // MARK: - End Validation Logic for SSKProtoSyncMessage - - - let result = SSKProtoSyncMessage(proto: proto, - sent: sent, - contacts: contacts, - groups: groups, - request: request, - read: read, - blocked: blocked, - verified: verified, - configuration: configuration, - openGroups: openGroups) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoSyncMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoSyncMessage.SSKProtoSyncMessageBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoSyncMessage? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoAttachmentPointer - -@objc public class SSKProtoAttachmentPointer: NSObject { - - // MARK: - SSKProtoAttachmentPointerFlags - - @objc public enum SSKProtoAttachmentPointerFlags: Int32 { - case voiceMessage = 1 - } - - private class func SSKProtoAttachmentPointerFlagsWrap(_ value: SignalServiceProtos_AttachmentPointer.Flags) -> SSKProtoAttachmentPointerFlags { - switch value { - case .voiceMessage: return .voiceMessage - } - } - - private class func SSKProtoAttachmentPointerFlagsUnwrap(_ value: SSKProtoAttachmentPointerFlags) -> SignalServiceProtos_AttachmentPointer.Flags { - switch value { - case .voiceMessage: return .voiceMessage - } - } - - // MARK: - SSKProtoAttachmentPointerBuilder - - @objc public class func builder(id: UInt64) -> SSKProtoAttachmentPointerBuilder { - return SSKProtoAttachmentPointerBuilder(id: id) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoAttachmentPointerBuilder { - let builder = SSKProtoAttachmentPointerBuilder(id: id) - if let _value = contentType { - builder.setContentType(_value) - } - if let _value = key { - builder.setKey(_value) - } - if hasSize { - builder.setSize(size) - } - if let _value = thumbnail { - builder.setThumbnail(_value) - } - if let _value = digest { - builder.setDigest(_value) - } - if let _value = fileName { - builder.setFileName(_value) - } - if hasFlags { - builder.setFlags(flags) - } - if hasWidth { - builder.setWidth(width) - } - if hasHeight { - builder.setHeight(height) - } - if let _value = caption { - builder.setCaption(_value) - } - if let _value = url { - builder.setUrl(_value) - } - return builder - } - - @objc public class SSKProtoAttachmentPointerBuilder: NSObject { - - private var proto = SignalServiceProtos_AttachmentPointer() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: UInt64) { - super.init() - - setId(id) - } - - @objc public func setId(_ valueParam: UInt64) { - proto.id = valueParam - } - - @objc public func setContentType(_ valueParam: String) { - proto.contentType = valueParam - } - - @objc public func setKey(_ valueParam: Data) { - proto.key = valueParam - } - - @objc public func setSize(_ valueParam: UInt32) { - proto.size = valueParam - } - - @objc public func setThumbnail(_ valueParam: Data) { - proto.thumbnail = valueParam - } - - @objc public func setDigest(_ valueParam: Data) { - proto.digest = valueParam - } - - @objc public func setFileName(_ valueParam: String) { - proto.fileName = valueParam - } - - @objc public func setFlags(_ valueParam: UInt32) { - proto.flags = valueParam - } - - @objc public func setWidth(_ valueParam: UInt32) { - proto.width = valueParam - } - - @objc public func setHeight(_ valueParam: UInt32) { - proto.height = valueParam - } - - @objc public func setCaption(_ valueParam: String) { - proto.caption = valueParam - } - - @objc public func setUrl(_ valueParam: String) { - proto.url = valueParam - } - - @objc public func build() throws -> SSKProtoAttachmentPointer { - return try SSKProtoAttachmentPointer.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoAttachmentPointer.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_AttachmentPointer - - @objc public let id: UInt64 - - @objc public var contentType: String? { - guard proto.hasContentType else { - return nil - } - return proto.contentType - } - @objc public var hasContentType: Bool { - return proto.hasContentType - } - - @objc public var key: Data? { - guard proto.hasKey else { - return nil - } - return proto.key - } - @objc public var hasKey: Bool { - return proto.hasKey - } - - @objc public var size: UInt32 { - return proto.size - } - @objc public var hasSize: Bool { - return proto.hasSize - } - - @objc public var thumbnail: Data? { - guard proto.hasThumbnail else { - return nil - } - return proto.thumbnail - } - @objc public var hasThumbnail: Bool { - return proto.hasThumbnail - } - - @objc public var digest: Data? { - guard proto.hasDigest else { - return nil - } - return proto.digest - } - @objc public var hasDigest: Bool { - return proto.hasDigest - } - - @objc public var fileName: String? { - guard proto.hasFileName else { - return nil - } - return proto.fileName - } - @objc public var hasFileName: Bool { - return proto.hasFileName - } - - @objc public var flags: UInt32 { - return proto.flags - } - @objc public var hasFlags: Bool { - return proto.hasFlags - } - - @objc public var width: UInt32 { - return proto.width - } - @objc public var hasWidth: Bool { - return proto.hasWidth - } - - @objc public var height: UInt32 { - return proto.height - } - @objc public var hasHeight: Bool { - return proto.hasHeight - } - - @objc public var caption: String? { - guard proto.hasCaption else { - return nil - } - return proto.caption - } - @objc public var hasCaption: Bool { - return proto.hasCaption - } - - @objc public var url: String? { - guard proto.hasURL else { - return nil - } - return proto.url - } - @objc public var hasURL: Bool { - return proto.hasURL - } - - private init(proto: SignalServiceProtos_AttachmentPointer, - id: UInt64) { - self.proto = proto - self.id = id - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoAttachmentPointer { - let proto = try SignalServiceProtos_AttachmentPointer(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_AttachmentPointer) throws -> SSKProtoAttachmentPointer { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - // MARK: - Begin Validation Logic for SSKProtoAttachmentPointer - - - // MARK: - End Validation Logic for SSKProtoAttachmentPointer - - - let result = SSKProtoAttachmentPointer(proto: proto, - id: id) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoAttachmentPointer { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoAttachmentPointer.SSKProtoAttachmentPointerBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoAttachmentPointer? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoGroupContext - -@objc public class SSKProtoGroupContext: NSObject { - - // MARK: - SSKProtoGroupContextType - - @objc public enum SSKProtoGroupContextType: Int32 { - case unknown = 0 - case update = 1 - case deliver = 2 - case quit = 3 - case requestInfo = 4 - } - - private class func SSKProtoGroupContextTypeWrap(_ value: SignalServiceProtos_GroupContext.TypeEnum) -> SSKProtoGroupContextType { - switch value { - case .unknown: return .unknown - case .update: return .update - case .deliver: return .deliver - case .quit: return .quit - case .requestInfo: return .requestInfo - } - } - - private class func SSKProtoGroupContextTypeUnwrap(_ value: SSKProtoGroupContextType) -> SignalServiceProtos_GroupContext.TypeEnum { - switch value { - case .unknown: return .unknown - case .update: return .update - case .deliver: return .deliver - case .quit: return .quit - case .requestInfo: return .requestInfo - } - } - - // MARK: - SSKProtoGroupContextBuilder - - @objc public class func builder(id: Data, type: SSKProtoGroupContextType) -> SSKProtoGroupContextBuilder { - return SSKProtoGroupContextBuilder(id: id, type: type) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoGroupContextBuilder { - let builder = SSKProtoGroupContextBuilder(id: id, type: type) - if let _value = name { - builder.setName(_value) - } - builder.setMembers(members) - if let _value = avatar { - builder.setAvatar(_value) - } - builder.setAdmins(admins) - return builder - } - - @objc public class SSKProtoGroupContextBuilder: NSObject { - - private var proto = SignalServiceProtos_GroupContext() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: Data, type: SSKProtoGroupContextType) { - super.init() - - setId(id) - setType(type) - } - - @objc public func setId(_ valueParam: Data) { - proto.id = valueParam - } - - @objc public func setType(_ valueParam: SSKProtoGroupContextType) { - proto.type = SSKProtoGroupContextTypeUnwrap(valueParam) - } - - @objc public func setName(_ valueParam: String) { - proto.name = valueParam - } - - @objc public func addMembers(_ valueParam: String) { - var items = proto.members - items.append(valueParam) - proto.members = items - } - - @objc public func setMembers(_ wrappedItems: [String]) { - proto.members = wrappedItems - } - - @objc public func setAvatar(_ valueParam: SSKProtoAttachmentPointer) { - proto.avatar = valueParam.proto - } - - @objc public func addAdmins(_ valueParam: String) { - var items = proto.admins - items.append(valueParam) - proto.admins = items - } - - @objc public func setAdmins(_ wrappedItems: [String]) { - proto.admins = wrappedItems - } - - @objc public func build() throws -> SSKProtoGroupContext { - return try SSKProtoGroupContext.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoGroupContext.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_GroupContext - - @objc public let id: Data - - @objc public let type: SSKProtoGroupContextType - - @objc public let avatar: SSKProtoAttachmentPointer? - - @objc public var name: String? { - guard proto.hasName else { - return nil - } - return proto.name - } - @objc public var hasName: Bool { - return proto.hasName - } - - @objc public var members: [String] { - return proto.members - } - - @objc public var admins: [String] { - return proto.admins - } - - private init(proto: SignalServiceProtos_GroupContext, - id: Data, - type: SSKProtoGroupContextType, - avatar: SSKProtoAttachmentPointer?) { - self.proto = proto - self.id = id - self.type = type - self.avatar = avatar - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoGroupContext { - let proto = try SignalServiceProtos_GroupContext(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_GroupContext) throws -> SSKProtoGroupContext { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - guard proto.hasType else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: type") - } - let type = SSKProtoGroupContextTypeWrap(proto.type) - - var avatar: SSKProtoAttachmentPointer? = nil - if proto.hasAvatar { - avatar = try SSKProtoAttachmentPointer.parseProto(proto.avatar) - } - - // MARK: - Begin Validation Logic for SSKProtoGroupContext - - - // MARK: - End Validation Logic for SSKProtoGroupContext - - - let result = SSKProtoGroupContext(proto: proto, - id: id, - type: type, - avatar: avatar) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoGroupContext { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoGroupContext.SSKProtoGroupContextBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoGroupContext? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoContactDetailsAvatar - -@objc public class SSKProtoContactDetailsAvatar: NSObject { - - // MARK: - SSKProtoContactDetailsAvatarBuilder - - @objc public class func builder() -> SSKProtoContactDetailsAvatarBuilder { - return SSKProtoContactDetailsAvatarBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoContactDetailsAvatarBuilder { - let builder = SSKProtoContactDetailsAvatarBuilder() - if let _value = contentType { - builder.setContentType(_value) - } - if hasLength { - builder.setLength(length) - } - return builder - } - - @objc public class SSKProtoContactDetailsAvatarBuilder: NSObject { - - private var proto = SignalServiceProtos_ContactDetails.Avatar() - - @objc fileprivate override init() {} - - @objc public func setContentType(_ valueParam: String) { - proto.contentType = valueParam - } - - @objc public func setLength(_ valueParam: UInt32) { - proto.length = valueParam - } - - @objc public func build() throws -> SSKProtoContactDetailsAvatar { - return try SSKProtoContactDetailsAvatar.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoContactDetailsAvatar.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_ContactDetails.Avatar - - @objc public var contentType: String? { - guard proto.hasContentType else { - return nil - } - return proto.contentType - } - @objc public var hasContentType: Bool { - return proto.hasContentType - } - - @objc public var length: UInt32 { - return proto.length - } - @objc public var hasLength: Bool { - return proto.hasLength - } - - private init(proto: SignalServiceProtos_ContactDetails.Avatar) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoContactDetailsAvatar { - let proto = try SignalServiceProtos_ContactDetails.Avatar(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_ContactDetails.Avatar) throws -> SSKProtoContactDetailsAvatar { - // MARK: - Begin Validation Logic for SSKProtoContactDetailsAvatar - - - // MARK: - End Validation Logic for SSKProtoContactDetailsAvatar - - - let result = SSKProtoContactDetailsAvatar(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoContactDetailsAvatar { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoContactDetailsAvatar.SSKProtoContactDetailsAvatarBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoContactDetailsAvatar? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoContactDetails - -@objc public class SSKProtoContactDetails: NSObject { - - // MARK: - SSKProtoContactDetailsBuilder - - @objc public class func builder(number: String) -> SSKProtoContactDetailsBuilder { - return SSKProtoContactDetailsBuilder(number: number) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoContactDetailsBuilder { - let builder = SSKProtoContactDetailsBuilder(number: number) - if let _value = name { - builder.setName(_value) - } - if let _value = avatar { - builder.setAvatar(_value) - } - if let _value = color { - builder.setColor(_value) - } - if let _value = verified { - builder.setVerified(_value) - } - if let _value = profileKey { - builder.setProfileKey(_value) - } - if hasBlocked { - builder.setBlocked(blocked) - } - if hasExpireTimer { - builder.setExpireTimer(expireTimer) - } - if let _value = nickname { - builder.setNickname(_value) - } - return builder - } - - @objc public class SSKProtoContactDetailsBuilder: NSObject { - - private var proto = SignalServiceProtos_ContactDetails() - - @objc fileprivate override init() {} - - @objc fileprivate init(number: String) { - super.init() - - setNumber(number) - } - - @objc public func setNumber(_ valueParam: String) { - proto.number = valueParam - } - - @objc public func setName(_ valueParam: String) { - proto.name = valueParam - } - - @objc public func setAvatar(_ valueParam: SSKProtoContactDetailsAvatar) { - proto.avatar = valueParam.proto - } - - @objc public func setColor(_ valueParam: String) { - proto.color = valueParam - } - - @objc public func setVerified(_ valueParam: SSKProtoVerified) { - proto.verified = valueParam.proto - } - - @objc public func setProfileKey(_ valueParam: Data) { - proto.profileKey = valueParam - } - - @objc public func setBlocked(_ valueParam: Bool) { - proto.blocked = valueParam - } - - @objc public func setExpireTimer(_ valueParam: UInt32) { - proto.expireTimer = valueParam - } - - @objc public func setNickname(_ valueParam: String) { - proto.nickname = valueParam - } - - @objc public func build() throws -> SSKProtoContactDetails { - return try SSKProtoContactDetails.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoContactDetails.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_ContactDetails - - @objc public let number: String - - @objc public let avatar: SSKProtoContactDetailsAvatar? - - @objc public let verified: SSKProtoVerified? - - @objc public var name: String? { - guard proto.hasName else { - return nil - } - return proto.name - } - @objc public var hasName: Bool { - return proto.hasName - } - - @objc public var color: String? { - guard proto.hasColor else { - return nil - } - return proto.color - } - @objc public var hasColor: Bool { - return proto.hasColor - } - - @objc public var profileKey: Data? { - guard proto.hasProfileKey else { - return nil - } - return proto.profileKey - } - @objc public var hasProfileKey: Bool { - return proto.hasProfileKey - } - - @objc public var blocked: Bool { - return proto.blocked - } - @objc public var hasBlocked: Bool { - return proto.hasBlocked - } - - @objc public var expireTimer: UInt32 { - return proto.expireTimer - } - @objc public var hasExpireTimer: Bool { - return proto.hasExpireTimer - } - - @objc public var nickname: String? { - guard proto.hasNickname else { - return nil - } - return proto.nickname - } - @objc public var hasNickname: Bool { - return proto.hasNickname - } - - private init(proto: SignalServiceProtos_ContactDetails, - number: String, - avatar: SSKProtoContactDetailsAvatar?, - verified: SSKProtoVerified?) { - self.proto = proto - self.number = number - self.avatar = avatar - self.verified = verified - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoContactDetails { - let proto = try SignalServiceProtos_ContactDetails(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_ContactDetails) throws -> SSKProtoContactDetails { - guard proto.hasNumber else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: number") - } - let number = proto.number - - var avatar: SSKProtoContactDetailsAvatar? = nil - if proto.hasAvatar { - avatar = try SSKProtoContactDetailsAvatar.parseProto(proto.avatar) - } - - var verified: SSKProtoVerified? = nil - if proto.hasVerified { - verified = try SSKProtoVerified.parseProto(proto.verified) - } - - // MARK: - Begin Validation Logic for SSKProtoContactDetails - - - // MARK: - End Validation Logic for SSKProtoContactDetails - - - let result = SSKProtoContactDetails(proto: proto, - number: number, - avatar: avatar, - verified: verified) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoContactDetails { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoContactDetails.SSKProtoContactDetailsBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoContactDetails? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoGroupDetailsAvatar - -@objc public class SSKProtoGroupDetailsAvatar: NSObject { - - // MARK: - SSKProtoGroupDetailsAvatarBuilder - - @objc public class func builder() -> SSKProtoGroupDetailsAvatarBuilder { - return SSKProtoGroupDetailsAvatarBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoGroupDetailsAvatarBuilder { - let builder = SSKProtoGroupDetailsAvatarBuilder() - if let _value = contentType { - builder.setContentType(_value) - } - if hasLength { - builder.setLength(length) - } - return builder - } - - @objc public class SSKProtoGroupDetailsAvatarBuilder: NSObject { - - private var proto = SignalServiceProtos_GroupDetails.Avatar() - - @objc fileprivate override init() {} - - @objc public func setContentType(_ valueParam: String) { - proto.contentType = valueParam - } - - @objc public func setLength(_ valueParam: UInt32) { - proto.length = valueParam - } - - @objc public func build() throws -> SSKProtoGroupDetailsAvatar { - return try SSKProtoGroupDetailsAvatar.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoGroupDetailsAvatar.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_GroupDetails.Avatar - - @objc public var contentType: String? { - guard proto.hasContentType else { - return nil - } - return proto.contentType - } - @objc public var hasContentType: Bool { - return proto.hasContentType - } - - @objc public var length: UInt32 { - return proto.length - } - @objc public var hasLength: Bool { - return proto.hasLength - } - - private init(proto: SignalServiceProtos_GroupDetails.Avatar) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoGroupDetailsAvatar { - let proto = try SignalServiceProtos_GroupDetails.Avatar(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_GroupDetails.Avatar) throws -> SSKProtoGroupDetailsAvatar { - // MARK: - Begin Validation Logic for SSKProtoGroupDetailsAvatar - - - // MARK: - End Validation Logic for SSKProtoGroupDetailsAvatar - - - let result = SSKProtoGroupDetailsAvatar(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoGroupDetailsAvatar { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoGroupDetailsAvatar.SSKProtoGroupDetailsAvatarBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoGroupDetailsAvatar? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoGroupDetails - -@objc public class SSKProtoGroupDetails: NSObject { - - // MARK: - SSKProtoGroupDetailsBuilder - - @objc public class func builder(id: Data) -> SSKProtoGroupDetailsBuilder { - return SSKProtoGroupDetailsBuilder(id: id) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoGroupDetailsBuilder { - let builder = SSKProtoGroupDetailsBuilder(id: id) - if let _value = name { - builder.setName(_value) - } - builder.setMembers(members) - if let _value = avatar { - builder.setAvatar(_value) - } - if hasActive { - builder.setActive(active) - } - if hasExpireTimer { - builder.setExpireTimer(expireTimer) - } - if let _value = color { - builder.setColor(_value) - } - if hasBlocked { - builder.setBlocked(blocked) - } - builder.setAdmins(admins) - return builder - } - - @objc public class SSKProtoGroupDetailsBuilder: NSObject { - - private var proto = SignalServiceProtos_GroupDetails() - - @objc fileprivate override init() {} - - @objc fileprivate init(id: Data) { - super.init() - - setId(id) - } - - @objc public func setId(_ valueParam: Data) { - proto.id = valueParam - } - - @objc public func setName(_ valueParam: String) { - proto.name = valueParam - } - - @objc public func addMembers(_ valueParam: String) { - var items = proto.members - items.append(valueParam) - proto.members = items - } - - @objc public func setMembers(_ wrappedItems: [String]) { - proto.members = wrappedItems - } - - @objc public func setAvatar(_ valueParam: SSKProtoGroupDetailsAvatar) { - proto.avatar = valueParam.proto - } - - @objc public func setActive(_ valueParam: Bool) { - proto.active = valueParam - } - - @objc public func setExpireTimer(_ valueParam: UInt32) { - proto.expireTimer = valueParam - } - - @objc public func setColor(_ valueParam: String) { - proto.color = valueParam - } - - @objc public func setBlocked(_ valueParam: Bool) { - proto.blocked = valueParam - } - - @objc public func addAdmins(_ valueParam: String) { - var items = proto.admins - items.append(valueParam) - proto.admins = items - } - - @objc public func setAdmins(_ wrappedItems: [String]) { - proto.admins = wrappedItems - } - - @objc public func build() throws -> SSKProtoGroupDetails { - return try SSKProtoGroupDetails.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoGroupDetails.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_GroupDetails - - @objc public let id: Data - - @objc public let avatar: SSKProtoGroupDetailsAvatar? - - @objc public var name: String? { - guard proto.hasName else { - return nil - } - return proto.name - } - @objc public var hasName: Bool { - return proto.hasName - } - - @objc public var members: [String] { - return proto.members - } - - @objc public var active: Bool { - return proto.active - } - @objc public var hasActive: Bool { - return proto.hasActive - } - - @objc public var expireTimer: UInt32 { - return proto.expireTimer - } - @objc public var hasExpireTimer: Bool { - return proto.hasExpireTimer - } - - @objc public var color: String? { - guard proto.hasColor else { - return nil - } - return proto.color - } - @objc public var hasColor: Bool { - return proto.hasColor - } - - @objc public var blocked: Bool { - return proto.blocked - } - @objc public var hasBlocked: Bool { - return proto.hasBlocked - } - - @objc public var admins: [String] { - return proto.admins - } - - private init(proto: SignalServiceProtos_GroupDetails, - id: Data, - avatar: SSKProtoGroupDetailsAvatar?) { - self.proto = proto - self.id = id - self.avatar = avatar - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoGroupDetails { - let proto = try SignalServiceProtos_GroupDetails(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_GroupDetails) throws -> SSKProtoGroupDetails { - guard proto.hasID else { - throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: id") - } - let id = proto.id - - var avatar: SSKProtoGroupDetailsAvatar? = nil - if proto.hasAvatar { - avatar = try SSKProtoGroupDetailsAvatar.parseProto(proto.avatar) - } - - // MARK: - Begin Validation Logic for SSKProtoGroupDetails - - - // MARK: - End Validation Logic for SSKProtoGroupDetails - - - let result = SSKProtoGroupDetails(proto: proto, - id: id, - avatar: avatar) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoGroupDetails { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoGroupDetails.SSKProtoGroupDetailsBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoGroupDetails? { - return try! self.build() - } -} - -#endif - -// MARK: - SSKProtoPublicChatInfo - -@objc public class SSKProtoPublicChatInfo: NSObject { - - // MARK: - SSKProtoPublicChatInfoBuilder - - @objc public class func builder() -> SSKProtoPublicChatInfoBuilder { - return SSKProtoPublicChatInfoBuilder() - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> SSKProtoPublicChatInfoBuilder { - let builder = SSKProtoPublicChatInfoBuilder() - if hasServerID { - builder.setServerID(serverID) - } - return builder - } - - @objc public class SSKProtoPublicChatInfoBuilder: NSObject { - - private var proto = SignalServiceProtos_PublicChatInfo() - - @objc fileprivate override init() {} - - @objc public func setServerID(_ valueParam: UInt64) { - proto.serverID = valueParam - } - - @objc public func build() throws -> SSKProtoPublicChatInfo { - return try SSKProtoPublicChatInfo.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try SSKProtoPublicChatInfo.parseProto(proto).serializedData() - } - } - - fileprivate let proto: SignalServiceProtos_PublicChatInfo - - @objc public var serverID: UInt64 { - return proto.serverID - } - @objc public var hasServerID: Bool { - return proto.hasServerID - } - - private init(proto: SignalServiceProtos_PublicChatInfo) { - self.proto = proto - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoPublicChatInfo { - let proto = try SignalServiceProtos_PublicChatInfo(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: SignalServiceProtos_PublicChatInfo) throws -> SSKProtoPublicChatInfo { - // MARK: - Begin Validation Logic for SSKProtoPublicChatInfo - - - // MARK: - End Validation Logic for SSKProtoPublicChatInfo - - - let result = SSKProtoPublicChatInfo(proto: proto) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension SSKProtoPublicChatInfo { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension SSKProtoPublicChatInfo.SSKProtoPublicChatInfoBuilder { - @objc public func buildIgnoringErrors() -> SSKProtoPublicChatInfo? { - return try! self.build() - } -} - -#endif diff --git a/SignalUtilitiesKit/SignalMessage.swift b/SignalUtilitiesKit/SignalMessage.swift index c4cb88249..96920b7b7 100644 --- a/SignalUtilitiesKit/SignalMessage.swift +++ b/SignalUtilitiesKit/SignalMessage.swift @@ -1,7 +1,7 @@ @objc(LKSignalMessage) public final class SignalMessage : NSObject { - @objc public let type: SSKProtoEnvelope.SSKProtoEnvelopeType + @objc public let type: SNProtoEnvelope.SNProtoEnvelopeType @objc public let timestamp: UInt64 @objc public let senderPublicKey: String @objc public let senderDeviceID: UInt32 @@ -13,7 +13,7 @@ public final class SignalMessage : NSObject { public var ttl: UInt64? { return objc_ttl != 0 ? objc_ttl : nil } - @objc public init(type: SSKProtoEnvelope.SSKProtoEnvelopeType, timestamp: UInt64, senderID: String, senderDeviceID: UInt32, + @objc public init(type: SNProtoEnvelope.SNProtoEnvelopeType, timestamp: UInt64, senderID: String, senderDeviceID: UInt32, content: String, recipientID: String, ttl: UInt64, isPing: Bool) { self.type = type self.timestamp = timestamp diff --git a/SignalUtilitiesKit/TSCall.h b/SignalUtilitiesKit/TSCall.h deleted file mode 100644 index f175aad3d..000000000 --- a/SignalUtilitiesKit/TSCall.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@class TSContactThread; - -typedef enum { - RPRecentCallTypeIncoming = 1, - RPRecentCallTypeOutgoing, - RPRecentCallTypeIncomingMissed, - // These call types are used until the call connects. - RPRecentCallTypeOutgoingIncomplete, - RPRecentCallTypeIncomingIncomplete, - RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity, - RPRecentCallTypeIncomingDeclined, - RPRecentCallTypeOutgoingMissed, -} RPRecentCallType; - -NSString *NSStringFromCallType(RPRecentCallType callType); - -@interface TSCall : TSInteraction - -@property (nonatomic, readonly) RPRecentCallType callType; - -- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; - -- (instancetype)initWithTimestamp:(uint64_t)timestamp - withCallNumber:(NSString *)contactNumber - callType:(RPRecentCallType)callType - inThread:(TSContactThread *)thread NS_DESIGNATED_INITIALIZER; - -- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -- (void)updateCallType:(RPRecentCallType)callType; -- (void)updateCallType:(RPRecentCallType)callType transaction:(YapDatabaseReadWriteTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/TSCall.m b/SignalUtilitiesKit/TSCall.m deleted file mode 100644 index c2ccf0590..000000000 --- a/SignalUtilitiesKit/TSCall.m +++ /dev/null @@ -1,178 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "TSCall.h" -#import "TSContactThread.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *NSStringFromCallType(RPRecentCallType callType) -{ - switch (callType) { - case RPRecentCallTypeIncoming: - return @"RPRecentCallTypeIncoming"; - case RPRecentCallTypeOutgoing: - return @"RPRecentCallTypeOutgoing"; - case RPRecentCallTypeIncomingMissed: - return @"RPRecentCallTypeIncomingMissed"; - case RPRecentCallTypeOutgoingIncomplete: - return @"RPRecentCallTypeOutgoingIncomplete"; - case RPRecentCallTypeIncomingIncomplete: - return @"RPRecentCallTypeIncomingIncomplete"; - case RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity: - return @"RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity"; - case RPRecentCallTypeIncomingDeclined: - return @"RPRecentCallTypeIncomingDeclined"; - case RPRecentCallTypeOutgoingMissed: - return @"RPRecentCallTypeOutgoingMissed"; - } -} - -NSUInteger TSCallCurrentSchemaVersion = 1; - -@interface TSCall () - -@property (nonatomic, getter=wasRead) BOOL read; - -@property (nonatomic, readonly) NSUInteger callSchemaVersion; - -@end - -#pragma mark - - -@implementation TSCall - -- (instancetype)initWithTimestamp:(uint64_t)timestamp - withCallNumber:(NSString *)contactNumber - callType:(RPRecentCallType)callType - inThread:(TSContactThread *)thread -{ - self = [super initInteractionWithTimestamp:timestamp inThread:thread]; - - if (!self) { - return self; - } - - _callSchemaVersion = TSCallCurrentSchemaVersion; - _callType = callType; - - // Ensure users are notified of missed calls. - BOOL isIncomingMissed = (_callType == RPRecentCallTypeIncomingMissed - || _callType == RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity); - if (isIncomingMissed) { - _read = NO; - } else { - _read = YES; - } - - return self; -} - -- (instancetype)initWithCoder:(NSCoder *)coder -{ - self = [super initWithCoder:coder]; - if (!self) { - return self; - } - - if (self.callSchemaVersion < 1) { - // Assume user has already seen any call that predate read-tracking - _read = YES; - } - - _callSchemaVersion = TSCallCurrentSchemaVersion; - - return self; -} - -- (OWSInteractionType)interactionType -{ - return OWSInteractionType_Call; -} - -- (NSString *)previewTextWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - // We don't actually use the `transaction` but other sibling classes do. - switch (_callType) { - case RPRecentCallTypeIncoming: - return NSLocalizedString(@"INCOMING_CALL", @"info message text in conversation view"); - case RPRecentCallTypeOutgoing: - return NSLocalizedString(@"OUTGOING_CALL", @"info message text in conversation view"); - case RPRecentCallTypeIncomingMissed: - return NSLocalizedString(@"MISSED_CALL", @"info message text in conversation view"); - case RPRecentCallTypeOutgoingIncomplete: - return NSLocalizedString(@"OUTGOING_INCOMPLETE_CALL", @"info message text in conversation view"); - case RPRecentCallTypeIncomingIncomplete: - return NSLocalizedString(@"INCOMING_INCOMPLETE_CALL", @"info message text in conversation view"); - case RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity: - return NSLocalizedString(@"INFO_MESSAGE_MISSED_CALL_DUE_TO_CHANGED_IDENITY", @"info message text shown in conversation view"); - case RPRecentCallTypeIncomingDeclined: - return NSLocalizedString(@"INCOMING_DECLINED_CALL", - @"info message recorded in conversation history when local user declined a call"); - case RPRecentCallTypeOutgoingMissed: - return NSLocalizedString(@"OUTGOING_MISSED_CALL", - @"info message recorded in conversation history when local user tries and fails to call another user."); - } -} - -#pragma mark - OWSReadTracking - -- (uint64_t)expireStartedAt -{ - return 0; -} - -- (BOOL)shouldAffectUnreadCounts -{ - return YES; -} - -- (void)markAsReadAtTimestamp:(uint64_t)readTimestamp - sendReadReceipt:(BOOL)sendReadReceipt - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - - OWSAssertDebug(transaction); - - if (_read) { - return; - } - - OWSLogDebug(@"marking as read uniqueId: %@ which has timestamp: %llu", self.uniqueId, self.timestamp); - _read = YES; - [self saveWithTransaction:transaction]; - - // Ignore sendReadReceipt - it doesn't apply to calls. -} - -#pragma mark - Methods - -- (void)updateCallType:(RPRecentCallType)callType -{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self updateCallType:callType transaction:transaction]; - }]; -} - -- (void)updateCallType:(RPRecentCallType)callType transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - OWSLogInfo(@"updating call type of call: %@ -> %@ with uniqueId: %@ which has timestamp: %llu", - NSStringFromCallType(_callType), - NSStringFromCallType(callType), - self.uniqueId, - self.timestamp); - - _callType = callType; - - [self saveWithTransaction:transaction]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/ThreadUtil.m b/SignalUtilitiesKit/ThreadUtil.m index b69fded03..f8b4c34b6 100644 --- a/SignalUtilitiesKit/ThreadUtil.m +++ b/SignalUtilitiesKit/ThreadUtil.m @@ -11,7 +11,6 @@ #import #import #import -#import #import #import #import diff --git a/SignalUtilitiesKit/Threads/TSContactThread.m b/SignalUtilitiesKit/Threads/TSContactThread.m index e7896f555..9db8c904f 100644 --- a/SignalUtilitiesKit/Threads/TSContactThread.m +++ b/SignalUtilitiesKit/Threads/TSContactThread.m @@ -79,6 +79,11 @@ NSString *const TSContactThreadPrefix = @"c"; return !![[OWSIdentityManager sharedManager] identityKeyForRecipientId:self.contactIdentifier]; } +- (NSString *)name +{ + return [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.contactIdentifier avoidingWriteTransaction:YES]; +} + + (NSString *)threadIdFromContactId:(NSString *)contactId { return [TSContactThreadPrefix stringByAppendingString:contactId]; } diff --git a/SignalUtilitiesKit/Threads/TSGroupThread.h b/SignalUtilitiesKit/Threads/TSGroupThread.h index 141247a2b..7abf873f3 100644 --- a/SignalUtilitiesKit/Threads/TSGroupThread.h +++ b/SignalUtilitiesKit/Threads/TSGroupThread.h @@ -36,7 +36,7 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId; + (NSString *)defaultGroupName; -- (BOOL)isCurrentUserInGroup; +- (BOOL)isCurrentUserMemberInGroup; - (BOOL)isUserMemberInGroup:(NSString *)publicKey; - (BOOL)isUserAdminInGroup:(NSString *)publicKey; diff --git a/SignalUtilitiesKit/Threads/TSGroupThread.m b/SignalUtilitiesKit/Threads/TSGroupThread.m index e100cb933..ba2d23403 100644 --- a/SignalUtilitiesKit/Threads/TSGroupThread.m +++ b/SignalUtilitiesKit/Threads/TSGroupThread.m @@ -246,16 +246,15 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (void)leaveGroupWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { -// NSMutableSet *newGroupMemberIDs = [NSMutableSet setWithArray:self.groupModel.groupMemberIds]; -// NSString *userPublicKey = TSAccountManager.localNumber; -// if (userPublicKey == nil) { return; } -// NSSet *userLinkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:userPublicKey in:transaction]; -// [newGroupMemberIDs minusSet:userLinkedDevices]; -// self.groupModel.groupMemberIds = newGroupMemberIDs.allObjects; -// [self saveWithTransaction:transaction]; -// [transaction addCompletionQueue:dispatch_get_main_queue() completionBlock:^{ -// [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.groupThreadUpdated object:self.uniqueId]; -// }]; + NSMutableSet *newGroupMemberIDs = [NSMutableSet setWithArray:self.groupModel.groupMemberIds]; + NSString *userPublicKey = TSAccountManager.localNumber; + if (userPublicKey == nil) { return; } + [newGroupMemberIDs removeObject:userPublicKey]; + self.groupModel.groupMemberIds = newGroupMemberIDs.allObjects; + [self saveWithTransaction:transaction]; + [transaction addCompletionQueue:dispatch_get_main_queue() completionBlock:^{ + [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.groupThreadUpdated object:self.uniqueId]; + }]; } - (void)softDeleteGroupThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction diff --git a/SignalUtilitiesKit/Threads/TSThread.m b/SignalUtilitiesKit/Threads/TSThread.m index 6bd591aa7..ea0577995 100644 --- a/SignalUtilitiesKit/Threads/TSThread.m +++ b/SignalUtilitiesKit/Threads/TSThread.m @@ -211,7 +211,7 @@ BOOL IsNoteToSelfEnabled(void) [self.dbReadWriteConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self enumerateInteractionsWithTransaction:transaction usingBlock:^( - TSInteraction *interaction, YapDatabaseReadTransaction *transaction) { + TSInteraction *interaction, YapDatabaseReadTransaction *t) { block(interaction); }]; diff --git a/SignalUtilitiesKit/ECKeyPair+Hexadecimal.swift b/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift similarity index 91% rename from SignalUtilitiesKit/ECKeyPair+Hexadecimal.swift rename to SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift index 894fd19ca..86a579f16 100644 --- a/SignalUtilitiesKit/ECKeyPair+Hexadecimal.swift +++ b/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift @@ -10,7 +10,7 @@ public extension ECKeyPair { return "05" + publicKey.map { String(format: "%02hhx", $0) }.joined() } - @objc public static func isValidHexEncodedPublicKey(candidate: String) -> Bool { + @objc static func isValidHexEncodedPublicKey(candidate: String) -> Bool { // Check that it's a valid hexadecimal encoding let allowedCharacters = CharacterSet(charactersIn: "0123456789ABCDEF") guard candidate.uppercased().unicodeScalars.allSatisfy({ allowedCharacters.contains($0) }) else { return false } diff --git a/SignalUtilitiesKit/GeneralUtilities.swift b/SignalUtilitiesKit/Utilities/GeneralUtilities.swift similarity index 100% rename from SignalUtilitiesKit/GeneralUtilities.swift rename to SignalUtilitiesKit/Utilities/GeneralUtilities.swift diff --git a/SignalUtilitiesKit/GroupUtilities.swift b/SignalUtilitiesKit/Utilities/GroupUtilities.swift similarity index 100% rename from SignalUtilitiesKit/GroupUtilities.swift rename to SignalUtilitiesKit/Utilities/GroupUtilities.swift diff --git a/SignalUtilitiesKit/LKGroupUtilities.h b/SignalUtilitiesKit/Utilities/LKGroupUtilities.h similarity index 100% rename from SignalUtilitiesKit/LKGroupUtilities.h rename to SignalUtilitiesKit/Utilities/LKGroupUtilities.h diff --git a/SignalUtilitiesKit/LKGroupUtilities.m b/SignalUtilitiesKit/Utilities/LKGroupUtilities.m similarity index 100% rename from SignalUtilitiesKit/LKGroupUtilities.m rename to SignalUtilitiesKit/Utilities/LKGroupUtilities.m diff --git a/SignalUtilitiesKit/LKUserDefaults.swift b/SignalUtilitiesKit/Utilities/LKUserDefaults.swift similarity index 100% rename from SignalUtilitiesKit/LKUserDefaults.swift rename to SignalUtilitiesKit/Utilities/LKUserDefaults.swift diff --git a/SignalUtilitiesKit/NSAttributedString+OWS.h b/SignalUtilitiesKit/Utilities/NSAttributedString+OWS.h similarity index 100% rename from SignalUtilitiesKit/NSAttributedString+OWS.h rename to SignalUtilitiesKit/Utilities/NSAttributedString+OWS.h diff --git a/SignalUtilitiesKit/Utilities/ProtoUtils.h b/SignalUtilitiesKit/Utilities/ProtoUtils.h index b8a466fc7..74c6ae3a5 100644 --- a/SignalUtilitiesKit/Utilities/ProtoUtils.h +++ b/SignalUtilitiesKit/Utilities/ProtoUtils.h @@ -6,8 +6,8 @@ NS_ASSUME_NONNULL_BEGIN -@class SSKProtoCallMessageBuilder; -@class SSKProtoDataMessageBuilder; +@class SNProtoCallMessageBuilder; +@class SNProtoDataMessageBuilder; @class TSThread; @interface ProtoUtils : NSObject @@ -16,13 +16,13 @@ NS_ASSUME_NONNULL_BEGIN + (void)addLocalProfileKeyIfNecessary:(TSThread *)thread recipientId:(NSString *_Nullable)recipientId - dataMessageBuilder:(SSKProtoDataMessageBuilder *)dataMessageBuilder; + dataMessageBuilder:(SNProtoDataMessageBuilder *)dataMessageBuilder; -+ (void)addLocalProfileKeyToDataMessageBuilder:(SSKProtoDataMessageBuilder *)dataMessageBuilder; ++ (void)addLocalProfileKeyToDataMessageBuilder:(SNProtoDataMessageBuilder *)dataMessageBuilder; + (void)addLocalProfileKeyIfNecessary:(TSThread *)thread recipientId:(NSString *)recipientId - callMessageBuilder:(SSKProtoCallMessageBuilder *)callMessageBuilder; + callMessageBuilder:(SNProtoCallMessageBuilder *)callMessageBuilder; @end diff --git a/SignalUtilitiesKit/Utilities/ProtoUtils.m b/SignalUtilitiesKit/Utilities/ProtoUtils.m index 9f330d66a..7e98369f7 100644 --- a/SignalUtilitiesKit/Utilities/ProtoUtils.m +++ b/SignalUtilitiesKit/Utilities/ProtoUtils.m @@ -34,7 +34,7 @@ NS_ASSUME_NONNULL_BEGIN + (void)addLocalProfileKeyIfNecessary:(TSThread *)thread recipientId:(NSString *_Nullable)recipientId - dataMessageBuilder:(SSKProtoDataMessageBuilder *)dataMessageBuilder + dataMessageBuilder:(SNProtoDataMessageBuilder *)dataMessageBuilder { OWSAssertDebug(thread); OWSAssertDebug(dataMessageBuilder); @@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN } } -+ (void)addLocalProfileKeyToDataMessageBuilder:(SSKProtoDataMessageBuilder *)dataMessageBuilder ++ (void)addLocalProfileKeyToDataMessageBuilder:(SNProtoDataMessageBuilder *)dataMessageBuilder { OWSAssertDebug(dataMessageBuilder); @@ -53,7 +53,7 @@ NS_ASSUME_NONNULL_BEGIN + (void)addLocalProfileKeyIfNecessary:(TSThread *)thread recipientId:(NSString *)recipientId - callMessageBuilder:(SSKProtoCallMessageBuilder *)callMessageBuilder + callMessageBuilder:(SNProtoCallMessageBuilder *)callMessageBuilder { OWSAssertDebug(thread); OWSAssertDebug(recipientId.length > 0); diff --git a/SignalUtilitiesKit/Utilities/String+SSK.swift b/SignalUtilitiesKit/Utilities/String+SSK.swift index cdfdaee57..e63f6e427 100644 --- a/SignalUtilitiesKit/Utilities/String+SSK.swift +++ b/SignalUtilitiesKit/Utilities/String+SSK.swift @@ -5,7 +5,7 @@ import Foundation public extension String { - public var digitsOnly: String { + var digitsOnly: String { return (self as NSString).digitsOnly() } @@ -13,11 +13,11 @@ public extension String { return (self as NSString).rtlSafeAppend(string) } - public func substring(from index: Int) -> String { + func substring(from index: Int) -> String { return String(self[self.index(self.startIndex, offsetBy: index)...]) } - public func substring(to index: Int) -> String { + func substring(to index: Int) -> String { return String(prefix(index)) } @@ -32,7 +32,7 @@ private let selectorOffset: UInt32 = 17 public extension String { - public func caesar(shift: UInt32) throws -> String { + func caesar(shift: UInt32) throws -> String { let shiftedScalars: [UnicodeScalar] = try unicodeScalars.map { c in guard let shiftedScalar = UnicodeScalar((c.value + shift) % 127) else { owsFailDebug("invalidCharacterShift") @@ -43,7 +43,7 @@ public extension String { return String(String.UnicodeScalarView(shiftedScalars)) } - public var encodedForSelector: String? { + var encodedForSelector: String? { guard let shifted = try? self.caesar(shift: selectorOffset) else { owsFailDebug("shifted was unexpectedly nil") return nil @@ -57,7 +57,7 @@ public extension String { return data.base64EncodedString() } - public var decodedForSelector: String? { + var decodedForSelector: String? { guard let data = Data(base64Encoded: self) else { owsFailDebug("data was unexpectedly nil") return nil @@ -75,12 +75,12 @@ public extension String { public extension NSString { @objc - public var encodedForSelector: String? { + var encodedForSelector: String? { return (self as String).encodedForSelector } @objc - public var decodedForSelector: String? { + var decodedForSelector: String? { return (self as String).decodedForSelector } } diff --git a/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift b/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift new file mode 100644 index 000000000..051e9831f --- /dev/null +++ b/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift @@ -0,0 +1,21 @@ + +public extension TSIncomingMessage { + + static func from(_ visibleMessage: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage { + let sender = visibleMessage.sender! + let thread = TSContactThread.getOrCreateThread(withContactId: sender, transaction: transaction) + return TSIncomingMessage( + timestamp: visibleMessage.receivedTimestamp!, + in: thread, + authorId: sender, + sourceDeviceId: 1, + messageBody: visibleMessage.text!, + attachmentIds: [], + expiresInSeconds: 0, + quotedMessage: nil, + linkPreview: nil, + serverTimestamp: nil, + wasReceivedByUD: true + ) + } +} diff --git a/SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift b/SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift index 26f1ba3a9..4ff5524a1 100644 --- a/SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift +++ b/SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift @@ -11,7 +11,7 @@ public extension UIDevice { } @objc - public var hasIPhoneXNotch: Bool { + var hasIPhoneXNotch: Bool { switch UIScreen.main.nativeBounds.height { case 960: // iPad in iPhone compatibility mode (using old iPhone 4 screen size) @@ -42,12 +42,12 @@ public extension UIDevice { } @objc - public var isShorterThanIPhone5: Bool { + var isShorterThanIPhone5: Bool { return UIScreen.main.bounds.height < 568 } @objc - public var isIPad: Bool { + var isIPad: Bool { let isNativeIPad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad let isCompatabilityModeIPad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.phone && self.model.hasPrefix("iPad") @@ -55,7 +55,7 @@ public extension UIDevice { } @objc - public func ows_setOrientation(_ orientation: UIInterfaceOrientation) { + func ows_setOrientation(_ orientation: UIInterfaceOrientation) { // XXX - This is not officially supported, but there's no other way to programmatically rotate // the interface. let orientationKey = "orientation" diff --git a/SignalUtilitiesKit/VersionMigrations.m b/SignalUtilitiesKit/VersionMigrations.m index ceeced936..18b71738b 100644 --- a/SignalUtilitiesKit/VersionMigrations.m +++ b/SignalUtilitiesKit/VersionMigrations.m @@ -5,14 +5,11 @@ #import "VersionMigrations.h" #import "OWSDatabaseMigrationRunner.h" #import "SignalKeyingStorage.h" - #import #import #import #import - #import - #import #import #import From 7e9eb2f138f037074f23a3f5679b6e8090121789 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 18 Nov 2020 14:27:30 +1100 Subject: [PATCH 005/177] Make typing indicators work & implement job resuming --- .../Storage+SessionMessagingKit.swift | 63 ++++++++++++++++--- .../ConversationView/ConversationViewItem.m | 3 +- .../Jobs/AttachmentDownloadJob.swift | 1 + .../Jobs/AttachmentUploadJob.swift | 1 + SessionMessagingKit/Jobs/Job.swift | 1 + SessionMessagingKit/Jobs/JobQueue.swift | 10 ++- .../Jobs/MessageReceiveJob.swift | 1 + SessionMessagingKit/Jobs/MessageSendJob.swift | 1 + .../Jobs/NotifyPNServerJob.swift | 1 + .../Sending & Receiving/MessageReceiver.swift | 36 +++++++++-- SessionMessagingKit/Storage.swift | 40 +++++++++++- SignalUtilitiesKit/Messages/TSInteraction.h | 4 +- SignalUtilitiesKit/Messages/TSMessage.h | 2 - 13 files changed, 141 insertions(+), 23 deletions(-) diff --git a/Session/Database/Storage+SessionMessagingKit.swift b/Session/Database/Storage+SessionMessagingKit.swift index 854cd09aa..ff824e14f 100644 --- a/Session/Database/Storage+SessionMessagingKit.swift +++ b/Session/Database/Storage+SessionMessagingKit.swift @@ -57,18 +57,27 @@ extension Storage : SessionMessagingKitStorageProtocol { // MARK: - Jobs - private static let jobCollection = "SNJobCollection" - public func persist(_ job: Job, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).setObject(job, forKey: job.id!, inCollection: Storage.jobCollection) + (transaction as! YapDatabaseReadWriteTransaction).setObject(job, forKey: job.id!, inCollection: type(of: job).collection) } public func markJobAsSucceeded(_ job: Job, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: Storage.jobCollection) + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: type(of: job).collection) } public func markJobAsFailed(_ job: Job, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: Storage.jobCollection) + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: type(of: job).collection) + } + + public func getAllPendingJobs(of type: Job.Type) -> [Job] { + var result: [Job] = [] + Storage.read { transaction in + transaction.enumerateRows(inCollection: type.collection) { _, object, _, _ in + guard let job = object as? Job else { return } + result.append(job) + } + } + return result } @@ -216,8 +225,48 @@ extension Storage : SessionMessagingKitStorageProtocol { return (thread.uniqueId!, message) } - public func cancelTypingIndicatorsIfNeeded(for threadID: String, senderPublicKey: String) { - guard let thread = TSThread.fetch(uniqueId: threadID) else { return } + public func showTypingIndicatorIfNeeded(for senderPublicKey: String) { + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet + func showTypingIndicatorsIfNeeded() { + SSKEnvironment.shared.typingIndicators.didReceiveTypingStartedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) + } + if Thread.current.isMainThread { + showTypingIndicatorsIfNeeded() + } else { + DispatchQueue.main.async { + showTypingIndicatorsIfNeeded() + } + } + } + + public func hideTypingIndicatorIfNeeded(for senderPublicKey: String) { + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet + func hideTypingIndicatorsIfNeeded() { + SSKEnvironment.shared.typingIndicators.didReceiveTypingStoppedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) + } + if Thread.current.isMainThread { + hideTypingIndicatorsIfNeeded() + } else { + DispatchQueue.main.async { + hideTypingIndicatorsIfNeeded() + } + } + } + + public func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) { + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet func cancelTypingIndicatorsIfNeeded() { SSKEnvironment.shared.typingIndicators.didReceiveIncomingMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) } diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index 529afe50f..7544414b2 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -1172,8 +1172,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) // Only allow deletion on incoming messages if the user has moderation permission return [SNOpenGroupAPI isUserModerator:self.userHexEncodedPublicKey forChannel:publicChat.channel onServer:publicChat.server]; } else { - // Only allow deletion on outgoing messages if the user was the sender (i.e. it was not sent from another linked device) - return [self.interaction.actualSenderHexEncodedPublicKey isEqual:self.userHexEncodedPublicKey]; + return YES; } } diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 27babc0f0..58fb1758e 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -8,6 +8,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject public var failureCount: UInt = 0 // MARK: Settings + public class var collection: String { return "AttachmentDownloadJobCollection" } public static let maxFailureCount: UInt = 20 // MARK: Coding diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 0ae9dc76d..2efedb6f4 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -8,6 +8,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N public var failureCount: UInt = 0 // MARK: Settings + public class var collection: String { return "AttachmentUploadJobCollection" } public static let maxFailureCount: UInt = 20 // MARK: Coding diff --git a/SessionMessagingKit/Jobs/Job.swift b/SessionMessagingKit/Jobs/Job.swift index 87f82e2f5..39ed91557 100644 --- a/SessionMessagingKit/Jobs/Job.swift +++ b/SessionMessagingKit/Jobs/Job.swift @@ -5,6 +5,7 @@ public protocol Job : class, NSCoding { var id: String? { get set } var failureCount: UInt { get set } + static var collection: String { get } static var maxFailureCount: UInt { get } func execute() diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index fbfac1f10..f5e24568d 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -6,12 +6,20 @@ public final class JobQueue : NSObject, JobDelegate { @objc public static let shared = JobQueue() @objc public func add(_ job: Job, using transaction: Any) { - job.id = UUID().uuidString + job.id = String(NSDate.millisecondTimestamp()) Configuration.shared.storage.persist(job, using: transaction) job.delegate = self job.execute() } + @objc public func resumePendingJobs() { + let allJobTypes: [Job.Type] = [ AttachmentDownloadJob.self, AttachmentUploadJob.self, MessageReceiveJob.self, MessageSendJob.self, NotifyPNServerJob.self ] + allJobTypes.forEach { type in + let allPendingJobs = Configuration.shared.storage.getAllPendingJobs(of: type) + allPendingJobs.sorted(by: { $0.id! < $1.id! }).forEach { $0.execute() } // Retry the oldest jobs first + } + } + public func handleJobSucceeded(_ job: Job) { Configuration.shared.storage.withAsync({ transaction in Configuration.shared.storage.markJobAsSucceeded(job, using: transaction) diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 40b115304..3e6e8662e 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -8,6 +8,7 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC public var failureCount: UInt = 0 // MARK: Settings + public class var collection: String { return "MessageReceiveJobCollection" } public static let maxFailureCount: UInt = 10 // MARK: Initialization diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index ab1a74038..7f6bb4282 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -9,6 +9,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi public var failureCount: UInt = 0 // MARK: Settings + public class var collection: String { return "MessageSendJobCollection" } public static let maxFailureCount: UInt = 20 // MARK: Initialization diff --git a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift index a21bb2271..8cc35c6e3 100644 --- a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift +++ b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift @@ -9,6 +9,7 @@ public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSC public var failureCount: UInt = 0 // MARK: Settings + public class var collection: String { return "NotifyPNServerJobCollection" } public static let maxFailureCount: UInt = 20 // MARK: Initialization diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index c663548a4..3b2252d85 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -76,16 +76,40 @@ internal enum MessageReceiver { internal static func handle(_ message: Message, messageServerID: UInt64?, using transaction: Any) { switch message { - case is ReadReceipt: break - case is SessionRequest: break - case is TypingIndicator: break - case is ClosedGroupUpdate: break - case is ExpirationTimerUpdate: break + case let message as ReadReceipt: handleReadReceipt(message, using: transaction) + case let message as SessionRequest: handleSessionRequest(message, using: transaction) + case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) + case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) + case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) case let message as VisibleMessage: handleVisibleMessage(message, using: transaction) default: fatalError() } } + private static func handleReadReceipt(_ message: ReadReceipt, using transaction: Any) { + + } + + private static func handleSessionRequest(_ message: SessionRequest, using transaction: Any) { + + } + + private static func handleTypingIndicator(_ message: TypingIndicator, using transaction: Any) { + let storage = Configuration.shared.storage + switch message.kind! { + case .started: storage.showTypingIndicatorIfNeeded(for: message.sender!) + case .stopped: storage.hideTypingIndicatorIfNeeded(for: message.sender!) + } + } + + private static func handleClosedGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { + + } + + private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) { + + } + private static func handleVisibleMessage(_ message: VisibleMessage, using transaction: Any) { let storage = Configuration.shared.storage // Update profile if needed @@ -96,7 +120,7 @@ internal enum MessageReceiver { let (threadID, tsIncomingMessage) = storage.persist(message, using: transaction) message.threadID = threadID // Cancel any typing indicators - storage.cancelTypingIndicatorsIfNeeded(for: message.threadID!, senderPublicKey: message.sender!) + storage.cancelTypingIndicatorsIfNeeded(for: message.sender!) // Notify the user if needed storage.notifyUserIfNeeded(for: tsIncomingMessage, threadID: threadID) } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index c66e3c3c6..f3029dd37 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -2,38 +2,72 @@ import SessionProtocolKit public protocol SessionMessagingKitStorageProtocol { + // MARK: - Shared + func with(_ work: @escaping (Any) -> Void) func withAsync(_ work: @escaping (Any) -> Void, completion: @escaping () -> Void) + // MARK: - General + func getUserPublicKey() -> String? func getUserKeyPair() -> ECKeyPair? func getUserDisplayName() -> String? + + // MARK: - Signal Protocol + func getOrGenerateRegistrationID(using transaction: Any) -> UInt32 - func isClosedGroup(_ publicKey: String) -> Bool + func getSenderCertificate(for publicKey: String) -> SMKSenderCertificate + + // MARK: - Shared Sender Keys + func getClosedGroupPrivateKey(for publicKey: String) -> String? + func isClosedGroup(_ publicKey: String) -> Bool + + // MARK: - Jobs + func persist(_ job: Job, using transaction: Any) func markJobAsSucceeded(_ job: Job, using transaction: Any) func markJobAsFailed(_ job: Job, using transaction: Any) - func getSenderCertificate(for publicKey: String) -> SMKSenderCertificate + func getAllPendingJobs(of type: Job.Type) -> [Job] + + // MARK: - Authorization + func getAuthToken(for server: String) -> String? func setAuthToken(for server: String, to newValue: String, using transaction: Any) func removeAuthToken(for server: String, using transaction: Any) + + // MARK: - Open Group Public Keys + func getOpenGroupPublicKey(for server: String) -> String? func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any) + + // MARK: - Last Message Server ID + func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64? func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) func removeLastMessageServerID(for group: UInt64, on server: String, using transaction: Any) + + // MARK: - Last Deletion Server ID + func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64? func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) func removeLastDeletionServerID(for group: UInt64, on server: String, using transaction: Any) + + // MARK: - Open Group Metadata + func setUserCount(to newValue: Int, forOpenGroupWithID openGroupID: String, using transaction: Any) func getIDForMessage(withServerID serverID: UInt64) -> UInt64? func setOpenGroupDisplayName(to displayName: String, for publicKey: String, on channel: UInt64, server: String, using transaction: Any) func setLastProfilePictureUploadDate(_ date: Date) // Stored in user defaults so no transaction is needed + + // MARK: - Message Handling + func isBlocked(_ publicKey: String) -> Bool func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. func persist(_ message: VisibleMessage, using transaction: Any) -> (String, Any) - func cancelTypingIndicatorsIfNeeded(for threadID: String, senderPublicKey: String) + func showTypingIndicatorIfNeeded(for senderPublicKey: String) + func hideTypingIndicatorIfNeeded(for senderPublicKey: String) + func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) func notifyUserIfNeeded(for message: Any, threadID: String) } diff --git a/SignalUtilitiesKit/Messages/TSInteraction.h b/SignalUtilitiesKit/Messages/TSInteraction.h index c030eca35..477a59a7f 100644 --- a/SignalUtilitiesKit/Messages/TSInteraction.h +++ b/SignalUtilitiesKit/Messages/TSInteraction.h @@ -40,8 +40,8 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value); @property (nonatomic, readonly) uint64_t sortId; @property (nonatomic, readonly) uint64_t receivedAtTimestamp; @property (nonatomic, readonly) BOOL shouldUseServerTime; -/// Used for public chats where a message sent from a slave device is interpreted as having been sent from the master device. -@property (nonatomic) NSString *actualSenderHexEncodedPublicKey; +// Push notifications +@property (nonatomic) BOOL hasUnfetchedAttachmentsFromPN; - (void)setServerTimestampToReceivedTimestamp:(uint64_t)receivedAtTimestamp; diff --git a/SignalUtilitiesKit/Messages/TSMessage.h b/SignalUtilitiesKit/Messages/TSMessage.h index d7abfd6e3..ecf440bb1 100644 --- a/SignalUtilitiesKit/Messages/TSMessage.h +++ b/SignalUtilitiesKit/Messages/TSMessage.h @@ -31,8 +31,6 @@ NS_ASSUME_NONNULL_BEGIN // Open groups @property (nonatomic) uint64_t openGroupServerMessageID; @property (nonatomic, readonly) BOOL isOpenGroupMessage; -// Push notifications -@property (nonatomic) BOOL hasUnfetchedAttachmentsFromPN; - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; From 97545de75e057fac484b35c834995565169d1afe Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 18 Nov 2020 15:36:51 +1100 Subject: [PATCH 006/177] Handle expiration timer updates --- .../Storage+SessionMessagingKit.swift | 60 +++++++++++++++---- SessionMessagingKit/Jobs/JobDelegate.swift | 1 + SessionMessagingKit/Jobs/JobQueue.swift | 14 +++++ .../Jobs/MessageReceiveJob.swift | 10 +++- .../Sending & Receiving/MessageReceiver.swift | 26 +++++++- SessionMessagingKit/Storage.swift | 3 + SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 1 + .../TSIncomingMessage+Conversion.swift | 3 +- 8 files changed, 101 insertions(+), 17 deletions(-) diff --git a/Session/Database/Storage+SessionMessagingKit.swift b/Session/Database/Storage+SessionMessagingKit.swift index ff824e14f..7911e3c12 100644 --- a/Session/Database/Storage+SessionMessagingKit.swift +++ b/Session/Database/Storage+SessionMessagingKit.swift @@ -206,21 +206,21 @@ extension Storage : SessionMessagingKitStorageProtocol { } public func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) { -// let transaction = transaction as! YapDatabaseReadWriteTransaction -// let profileManager = SSKEnvironment.shared.profileManager -// if let displayName = profile.displayName { -// profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) -// } -// if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { -// profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) -// } + let transaction = transaction as! YapDatabaseReadWriteTransaction + let profileManager = SSKEnvironment.shared.profileManager + if let displayName = profile.displayName { + profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) + } + if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { + profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) + } } /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. public func persist(_ message: VisibleMessage, using transaction: Any) -> (String, Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction let thread = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) - let message = TSIncomingMessage.from(message, using: transaction) + let message = TSIncomingMessage.from(message, associatedWith: thread, using: transaction) message.save(with: transaction) return (thread.uniqueId!, message) } @@ -230,7 +230,7 @@ extension Storage : SessionMessagingKitStorageProtocol { Storage.read { transaction in threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) } - guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet + guard let thread = threadOrNil else { return } func showTypingIndicatorsIfNeeded() { SSKEnvironment.shared.typingIndicators.didReceiveTypingStartedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) } @@ -248,7 +248,7 @@ extension Storage : SessionMessagingKitStorageProtocol { Storage.read { transaction in threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) } - guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet + guard let thread = threadOrNil else { return } func hideTypingIndicatorsIfNeeded() { SSKEnvironment.shared.typingIndicators.didReceiveTypingStoppedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) } @@ -266,7 +266,7 @@ extension Storage : SessionMessagingKitStorageProtocol { Storage.read { transaction in threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) } - guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet + guard let thread = threadOrNil else { return } func cancelTypingIndicatorsIfNeeded() { SSKEnvironment.shared.typingIndicators.didReceiveIncomingMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) } @@ -285,4 +285,40 @@ extension Storage : SessionMessagingKitStorageProtocol { SSKEnvironment.shared.notificationsManager!.notifyUser(for: (message as! TSIncomingMessage), in: thread, transaction: transaction) } } + + public func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) { + SSKEnvironment.shared.readReceiptManager.processReadReceipts(fromRecipientId: senderPublicKey, sentTimestamps: timestamps.map { NSNumber(value: $0) }, readTimestamp: timestamp) + } + + public func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } + let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: true, durationSeconds: duration) + configuration.save(with: transaction) + let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) + let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, + configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) + message.save(with: transaction) + SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() + } + + public func disableExpirationTimer(for senderPublicKey: String, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } + let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: false, durationSeconds: 24 * 60 * 60) + configuration.save(with: transaction) + let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) + let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, + configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) + message.save(with: transaction) + SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() + } } diff --git a/SessionMessagingKit/Jobs/JobDelegate.swift b/SessionMessagingKit/Jobs/JobDelegate.swift index 461433e85..b45a5bf28 100644 --- a/SessionMessagingKit/Jobs/JobDelegate.swift +++ b/SessionMessagingKit/Jobs/JobDelegate.swift @@ -4,4 +4,5 @@ public protocol JobDelegate { func handleJobSucceeded(_ job: Job) func handleJobFailed(_ job: Job, with error: Error) + func handleJobFailedPermanently(_ job: Job, with error: Error) } diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index f5e24568d..8b97a725a 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -47,6 +47,20 @@ public final class JobQueue : NSObject, JobDelegate { }) } + public func handleJobFailedPermanently(_ job: Job, with error: Error) { + job.failureCount += 1 + let storage = Configuration.shared.storage + storage.withAsync({ transaction in + storage.persist(job, using: transaction) + }, completion: { // Intentionally capture self + storage.withAsync({ transaction in + storage.markJobAsFailed(job, using: transaction) + }, completion: { + // Do nothing + }) + }) + } + private func getRetryInterval(for job: Job) -> TimeInterval { // Arbitrary backoff factor... // try 1 delay: 0.00s diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 3e6e8662e..bd3ed8ae9 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -44,7 +44,11 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC self.handleSuccess() } catch { SNLog("Couldn't parse message due to error: \(error).") - self.handleFailure(error: error) + if let error = error as? MessageReceiver.Error, !error.isRetryable { + self.handlePermanentFailure(error: error) + } else { + self.handleFailure(error: error) + } } } }, completion: { }) @@ -54,6 +58,10 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC delegate?.handleJobSucceeded(self) } + private func handlePermanentFailure(error: Error) { + delegate?.handleJobFailedPermanently(self, with: error) + } + private func handleFailure(error: Error) { delegate?.handleJobFailed(self, with: error) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 3b2252d85..9bb04e4ef 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -1,5 +1,9 @@ import SessionUtilitiesKit +// TODO: +// • Threads don't show up on the first message; only on the second. +// • Profile pictures aren't showing up. + internal enum MessageReceiver { internal enum Error : LocalizedError { @@ -15,6 +19,13 @@ internal enum MessageReceiver { case sharedSecretGenerationFailed case selfSend + internal var isRetryable: Bool { + switch self { + case .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false + default: return true + } + } + internal var errorDescription: String? { switch self { case .invalidMessage: return "Invalid message." @@ -57,6 +68,7 @@ internal enum MessageReceiver { let message: Message? = { if let readReceipt = ReadReceipt.fromProto(proto) { return readReceipt } if let sessionRequest = SessionRequest.fromProto(proto) { return sessionRequest } + if let nullMessage = NullMessage.fromProto(proto) { return nullMessage } if let typingIndicator = TypingIndicator.fromProto(proto) { return typingIndicator } if let closedGroupUpdate = ClosedGroupUpdate.fromProto(proto) { return closedGroupUpdate } if let expirationTimerUpdate = ExpirationTimerUpdate.fromProto(proto) { return expirationTimerUpdate } @@ -78,6 +90,7 @@ internal enum MessageReceiver { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) case let message as SessionRequest: handleSessionRequest(message, using: transaction) + case let message as NullMessage: handleNullMessage(message, using: transaction) case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) @@ -87,11 +100,15 @@ internal enum MessageReceiver { } private static func handleReadReceipt(_ message: ReadReceipt, using transaction: Any) { - + Configuration.shared.storage.markMessagesAsRead(message.timestamps!, from: message.sender!, at: message.receivedTimestamp!) } private static func handleSessionRequest(_ message: SessionRequest, using transaction: Any) { + // TODO: Implement + } + private static func handleNullMessage(_ message: NullMessage, using transaction: Any) { + // TODO: Implement } private static func handleTypingIndicator(_ message: TypingIndicator, using transaction: Any) { @@ -107,7 +124,12 @@ internal enum MessageReceiver { } private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) { - + let storage = Configuration.shared.storage + if message.duration! > 0 { + storage.setExpirationTimer(to: message.duration!, for: message.sender!, using: transaction) + } else { + storage.disableExpirationTimer(for: message.sender!, using: transaction) + } } private static func handleVisibleMessage(_ message: VisibleMessage, using transaction: Any) { diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index f3029dd37..12ac5fd3e 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -70,4 +70,7 @@ public protocol SessionMessagingKitStorageProtocol { func hideTypingIndicatorIfNeeded(for senderPublicKey: String) func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) func notifyUserIfNeeded(for message: Any, threadID: String) + func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) + func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, using transaction: Any) + func disableExpirationTimer(for senderPublicKey: String, using transaction: Any) } diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 710dd8d5e..efc3b9b8b 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -33,6 +33,7 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import +#import #import #import #import diff --git a/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift b/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift index 051e9831f..59ca58cc7 100644 --- a/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift +++ b/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift @@ -1,9 +1,8 @@ public extension TSIncomingMessage { - static func from(_ visibleMessage: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage { + static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage { let sender = visibleMessage.sender! - let thread = TSContactThread.getOrCreateThread(withContactId: sender, transaction: transaction) return TSIncomingMessage( timestamp: visibleMessage.receivedTimestamp!, in: thread, From 58802936c1e45fad49276613257eb31c80e620bb Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 18 Nov 2020 15:53:45 +1100 Subject: [PATCH 007/177] Finish message receiving pipeline --- Session/AppDelegate+OpenGroupAPI.swift | 2 +- Session/Configuration.swift | 1 + .../Storage+SessionMessagingKit.swift | 124 +------ Session/MessageHandler.swift | 315 ++++++++++++++++++ SessionMessagingKit/Configuration.swift | 3 + .../Jobs/MessageReceiveJob.swift | 4 +- .../Control Message/ClosedGroupUpdate.swift | 38 ++- SessionMessagingKit/Messages/Message.swift | 2 + .../Sending & Receiving/MessageHandler.swift | 17 + .../Sending & Receiving/MessageReceiver.swift | 56 ++-- SessionMessagingKit/Storage.swift | 11 +- Signal.xcodeproj/project.pbxproj | 8 + SignalUtilitiesKit/ClosedGroupsProtocol.swift | 4 +- .../LokiPushNotificationManager.swift | 2 +- .../Storage+ClosedGroups.swift | 8 +- .../TSIncomingMessage+Conversion.swift | 4 +- 16 files changed, 438 insertions(+), 161 deletions(-) create mode 100644 Session/MessageHandler.swift create mode 100644 SessionMessagingKit/Sending & Receiving/MessageHandler.swift diff --git a/Session/AppDelegate+OpenGroupAPI.swift b/Session/AppDelegate+OpenGroupAPI.swift index 669c5880e..3681ccba0 100644 --- a/Session/AppDelegate+OpenGroupAPI.swift +++ b/Session/AppDelegate+OpenGroupAPI.swift @@ -4,7 +4,7 @@ extension AppDelegate : OpenGroupAPIDelegate { public func updateProfileIfNeeded(for channel: UInt64, on server: String, from info: OpenGroupInfo) { let storage = OWSPrimaryStorage.shared() let publicChatID = "\(server).\(channel)" - Storage.writeSync { transaction in + Storage.write { transaction in // Update user count storage.setUserCount(info.memberCount, forPublicChatWithID: publicChatID, in: transaction) let groupThread = TSGroupThread.getOrCreateThread(withGroupId: publicChatID.data(using: .utf8)!, groupType: .openGroup, transaction: transaction) diff --git a/Session/Configuration.swift b/Session/Configuration.swift index 4982d88a1..743658c20 100644 --- a/Session/Configuration.swift +++ b/Session/Configuration.swift @@ -11,6 +11,7 @@ final class Configuration : NSObject { @objc static func performMainSetup() { SNMessagingKit.configure( storage: Storage.shared, + messageReceiverDelegate: MessageReceiverDelegate.shared, signalStorage: OWSPrimaryStorage.shared(), identityKeyStore: OWSIdentityManager.shared(), sessionRestorationImplementation: SessionRestorationImplementation(), diff --git a/Session/Database/Storage+SessionMessagingKit.swift b/Session/Database/Storage+SessionMessagingKit.swift index 7911e3c12..1e3cc5818 100644 --- a/Session/Database/Storage+SessionMessagingKit.swift +++ b/Session/Database/Storage+SessionMessagingKit.swift @@ -201,124 +201,20 @@ extension Storage : SessionMessagingKitStorageProtocol { // MARK: - Message Handling - public func isBlocked(_ publicKey: String) -> Bool { - return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey) - } - - public func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) { - let transaction = transaction as! YapDatabaseReadWriteTransaction - let profileManager = SSKEnvironment.shared.profileManager - if let displayName = profile.displayName { - profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) - } - if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { - profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) - } - } - /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. - public func persist(_ message: VisibleMessage, using transaction: Any) -> (String, Any) { + public func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, Any)? { let transaction = transaction as! YapDatabaseReadWriteTransaction - let thread = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) + var threadOrNil: TSThread? + if let groupPublicKey = groupPublicKey { + guard Storage.shared.isClosedGroup(groupPublicKey) else { return nil } + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) + } else { + threadOrNil = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) + } + guard let thread = threadOrNil else { return nil } let message = TSIncomingMessage.from(message, associatedWith: thread, using: transaction) message.save(with: transaction) return (thread.uniqueId!, message) } - - public func showTypingIndicatorIfNeeded(for senderPublicKey: String) { - var threadOrNil: TSContactThread? - Storage.read { transaction in - threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) - } - guard let thread = threadOrNil else { return } - func showTypingIndicatorsIfNeeded() { - SSKEnvironment.shared.typingIndicators.didReceiveTypingStartedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) - } - if Thread.current.isMainThread { - showTypingIndicatorsIfNeeded() - } else { - DispatchQueue.main.async { - showTypingIndicatorsIfNeeded() - } - } - } - - public func hideTypingIndicatorIfNeeded(for senderPublicKey: String) { - var threadOrNil: TSContactThread? - Storage.read { transaction in - threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) - } - guard let thread = threadOrNil else { return } - func hideTypingIndicatorsIfNeeded() { - SSKEnvironment.shared.typingIndicators.didReceiveTypingStoppedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) - } - if Thread.current.isMainThread { - hideTypingIndicatorsIfNeeded() - } else { - DispatchQueue.main.async { - hideTypingIndicatorsIfNeeded() - } - } - } - - public func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) { - var threadOrNil: TSContactThread? - Storage.read { transaction in - threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) - } - guard let thread = threadOrNil else { return } - func cancelTypingIndicatorsIfNeeded() { - SSKEnvironment.shared.typingIndicators.didReceiveIncomingMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) - } - if Thread.current.isMainThread { - cancelTypingIndicatorsIfNeeded() - } else { - DispatchQueue.main.async { - cancelTypingIndicatorsIfNeeded() - } - } - } - - public func notifyUserIfNeeded(for message: Any, threadID: String) { - guard let thread = TSThread.fetch(uniqueId: threadID) else { return } - Storage.read { transaction in - SSKEnvironment.shared.notificationsManager!.notifyUser(for: (message as! TSIncomingMessage), in: thread, transaction: transaction) - } - } - - public func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) { - SSKEnvironment.shared.readReceiptManager.processReadReceipts(fromRecipientId: senderPublicKey, sentTimestamps: timestamps.map { NSNumber(value: $0) }, readTimestamp: timestamp) - } - - public func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, using transaction: Any) { - let transaction = transaction as! YapDatabaseReadWriteTransaction - var threadOrNil: TSContactThread? - Storage.read { transaction in - threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) - } - guard let thread = threadOrNil else { return } - let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: true, durationSeconds: duration) - configuration.save(with: transaction) - let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) - let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, - configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) - message.save(with: transaction) - SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() - } - - public func disableExpirationTimer(for senderPublicKey: String, using transaction: Any) { - let transaction = transaction as! YapDatabaseReadWriteTransaction - var threadOrNil: TSContactThread? - Storage.read { transaction in - threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) - } - guard let thread = threadOrNil else { return } - let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: false, durationSeconds: 24 * 60 * 60) - configuration.save(with: transaction) - let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) - let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, - configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) - message.save(with: transaction) - SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() - } } diff --git a/Session/MessageHandler.swift b/Session/MessageHandler.swift new file mode 100644 index 000000000..9d4ed5f85 --- /dev/null +++ b/Session/MessageHandler.swift @@ -0,0 +1,315 @@ +import SessionMessagingKit + +final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegate { + + static let shared = MessageReceiverDelegate() + + + + // MARK: - Blocking + + public func isBlocked(_ publicKey: String) -> Bool { + return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey) + } + + + + // MARK: - Profiles + + public func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + let profileManager = SSKEnvironment.shared.profileManager + if let displayName = profile.displayName { + profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) + } + if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { + profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) + } + } + + + + // MARK: - Typing Indicators + + public func showTypingIndicatorIfNeeded(for senderPublicKey: String) { + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } + func showTypingIndicatorsIfNeeded() { + SSKEnvironment.shared.typingIndicators.didReceiveTypingStartedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) + } + if Thread.current.isMainThread { + showTypingIndicatorsIfNeeded() + } else { + DispatchQueue.main.async { + showTypingIndicatorsIfNeeded() + } + } + } + + public func hideTypingIndicatorIfNeeded(for senderPublicKey: String) { + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } + func hideTypingIndicatorsIfNeeded() { + SSKEnvironment.shared.typingIndicators.didReceiveTypingStoppedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) + } + if Thread.current.isMainThread { + hideTypingIndicatorsIfNeeded() + } else { + DispatchQueue.main.async { + hideTypingIndicatorsIfNeeded() + } + } + } + + public func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) { + var threadOrNil: TSContactThread? + Storage.read { transaction in + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + guard let thread = threadOrNil else { return } + func cancelTypingIndicatorsIfNeeded() { + SSKEnvironment.shared.typingIndicators.didReceiveIncomingMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1) + } + if Thread.current.isMainThread { + cancelTypingIndicatorsIfNeeded() + } else { + DispatchQueue.main.async { + cancelTypingIndicatorsIfNeeded() + } + } + } + + + + // MARK: - Notifications + + public func notifyUserIfNeeded(for message: Any, threadID: String) { + guard let thread = TSThread.fetch(uniqueId: threadID) else { return } + Storage.read { transaction in + SSKEnvironment.shared.notificationsManager!.notifyUser(for: (message as! TSIncomingMessage), in: thread, transaction: transaction) + } + } + + + + // MARK: - Read Receipts + + public func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) { + SSKEnvironment.shared.readReceiptManager.processReadReceipts(fromRecipientId: senderPublicKey, sentTimestamps: timestamps.map { NSNumber(value: $0) }, readTimestamp: timestamp) + } + + + + // MARK: - Expiration + + public func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + var threadOrNil: TSThread? + Storage.read { transaction in + if let groupPublicKey = groupPublicKey { + guard Storage.shared.isClosedGroup(groupPublicKey) else { return } + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) + } else { + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + } + guard let thread = threadOrNil else { return } + let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: true, durationSeconds: duration) + configuration.save(with: transaction) + let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) + let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, + configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) + message.save(with: transaction) + SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() + } + + public func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + var threadOrNil: TSThread? + Storage.read { transaction in + if let groupPublicKey = groupPublicKey { + guard Storage.shared.isClosedGroup(groupPublicKey) else { return } + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) + } else { + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) + } + } + guard let thread = threadOrNil else { return } + let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: false, durationSeconds: 24 * 60 * 60) + configuration.save(with: transaction) + let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) + let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, + configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) + message.save(with: transaction) + SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() + } + + + + // MARK: - Closed Groups + + func handleNewGroup(_ message: ClosedGroupUpdate, using transaction: Any) { + guard case let .new(groupPublicKeyAsData, name, groupPrivateKey, senderKeys, membersAsData, adminsAsData) = message.kind else { return } + let transaction = transaction as! YapDatabaseReadWriteTransaction + let groupPublicKey = groupPublicKeyAsData.toHexString() + let members = membersAsData.map { $0.toHexString() } + let admins = adminsAsData.map { $0.toHexString() } + // Persist the ratchets + senderKeys.forEach { senderKey in + guard members.contains(senderKey.publicKey.toHexString()) else { return } + let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) + Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) + } + // Sort out any discrepancies between the provided sender keys and what's required + let missingSenderKeys = Set(members).subtracting(senderKeys.map { $0.publicKey.toHexString() }) + let userPublicKey = getUserHexEncodedPublicKey() + if missingSenderKeys.contains(userPublicKey) { + let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) + members.forEach { member in + guard member != userPublicKey else { return } + let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } + } + missingSenderKeys.subtracting([ userPublicKey ]).forEach { publicKey in + (UIApplication.shared.delegate as! AppDelegate).requestSenderKey(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + } + // Create the group + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) + let thread: TSGroupThread + if let t = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) { + thread = t + thread.setGroupModel(group, with: transaction) + } else { + thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction) + thread.usesSharedSenderKeys = true + thread.save(with: transaction) + } + // Add the group to the user's set of public keys to poll for + Storage.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction) + // Notify the PN server + let _ = LokiPushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) + // Notify the user + let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) + infoMessage.save(with: transaction) + } + + func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { + guard case let .info(groupPublicKeyAsData, name, senderKeys, membersAsData, adminsAsData) = message.kind else { return } + let transaction = transaction as! YapDatabaseReadWriteTransaction + let groupPublicKey = groupPublicKeyAsData.toHexString() + let members = membersAsData.map { $0.toHexString() } + let admins = adminsAsData.map { $0.toHexString() } + // Get the group + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { + return print("[Loki] Ignoring closed group info message for nonexistent group.") + } + let group = thread.groupModel + // Check that the sender is a member of the group (before the update) + guard Set(group.groupMemberIds).contains(message.sender!) else { + return print("[Loki] Ignoring closed group info message from non-member.") + } + // Store the ratchets for any new members (it's important that this happens before the code below) + senderKeys.forEach { senderKey in + let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) + Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) + } + // Delete all ratchets and either: + // • Send out the user's new ratchet using established channels if other members of the group left or were removed + // • Remove the group from the user's set of public keys to poll for if the current user was among the members that were removed + let oldMembers = group.groupMemberIds + let userPublicKey = getUserHexEncodedPublicKey() + let wasUserRemoved = !members.contains(userPublicKey) + if Set(members).intersection(oldMembers) != Set(oldMembers) { + let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) + for (senderPublicKey, oldRatchet) in allOldRatchets { + let collection = ClosedGroupRatchetCollectionType.old + Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) + } + Storage.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) + if wasUserRemoved { + Storage.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) + // Notify the PN server + let _ = LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + } else { + let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) + members.forEach { member in + guard member != userPublicKey else { return } + let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } + } + } + // Update the group + let newGroupModel = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) + thread.setGroupModel(newGroupModel, with: transaction) + // Notify the user if needed + if Set(members) != Set(oldMembers) || Set(admins) != Set(group.groupAdminIds) || name != group.groupName { + let infoMessageType: TSInfoMessageType = wasUserRemoved ? .typeGroupQuit : .typeGroupUpdate + let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel) + let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: infoMessageType, customMessage: updateInfo) + infoMessage.save(with: transaction) + } + } + + func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) { + guard case let .senderKeyRequest(groupPublicKeyAsData) = message.kind else { return } + let transaction = transaction as! YapDatabaseReadWriteTransaction + let userPublicKey = getUserHexEncodedPublicKey() + let groupPublicKey = groupPublicKeyAsData.toHexString() + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + guard let groupThread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { + return print("[Loki] Ignoring closed group sender key request for nonexistent group.") + } + let group = groupThread.groupModel + // Check that the requesting user is a member of the group + let members = Set(group.groupMemberIds) + guard members.contains(message.sender!) else { + return print("[Loki] Ignoring closed group sender key request from non-member.") + } + // Respond to the request + print("[Loki] Responding to sender key request from: \(message.sender!).") + SessionManagementProtocol.sendSessionRequestIfNeeded(to: message.sender!, using: transaction) + let userRatchet = Storage.shared.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey) + ?? SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) + let thread = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } + + func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) { + guard case let .senderKey(groupPublicKeyAsData, senderKey) = message.kind else { return } + let groupPublicKey = groupPublicKeyAsData.toHexString() + guard senderKey.publicKey.toHexString() == message.sender! else { + return print("[Loki] Ignoring invalid closed group sender key.") + } + // Store the sender key + print("[Loki] Received a sender key from: \(message.sender!).") + let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) + Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: message.sender!, ratchet: ratchet, using: transaction) + } +} diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index 525b9f9bb..0994ad56c 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -2,6 +2,7 @@ import SessionProtocolKit public struct Configuration { public let storage: SessionMessagingKitStorageProtocol + public let messageReceiverDelegate: MessageReceiverDelegate public let signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore public let identityKeyStore: IdentityKeyStore public let sessionRestorationImplementation: SessionRestorationProtocol @@ -17,6 +18,7 @@ public enum SNMessagingKit { // Just to make the external API nice public static func configure( storage: SessionMessagingKitStorageProtocol, + messageReceiverDelegate: MessageReceiverDelegate, signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore, identityKeyStore: IdentityKeyStore, sessionRestorationImplementation: SessionRestorationProtocol, @@ -27,6 +29,7 @@ public enum SNMessagingKit { // Just to make the external API nice ) { Configuration.shared = Configuration( storage: storage, + messageReceiverDelegate: messageReceiverDelegate, signalStorage: signalStorage, identityKeyStore: identityKeyStore, sessionRestorationImplementation: sessionRestorationImplementation, diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index bd3ed8ae9..13d8ee713 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -39,8 +39,8 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self Threading.workQueue.async { do { - let message = try MessageReceiver.parse(self.data, using: transaction) - MessageReceiver.handle(message, messageServerID: self.messageServerID, using: transaction) + let message = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) + try MessageReceiver.handle(message, using: transaction) self.handleSuccess() } catch { SNLog("Couldn't parse message due to error: \(error).") diff --git a/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift index 1e012b060..b0d343520 100644 --- a/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift @@ -23,8 +23,17 @@ public final class ClosedGroupUpdate : ControlMessage { // MARK: Validation public override var isValid: Bool { - guard super.isValid else { return false } - return kind != nil + guard super.isValid, let kind = kind else { return false } + switch kind { + case .new(let groupPublicKey, let name, let groupPrivateKey, _, let members, let admins): + return !groupPublicKey.isEmpty && !name.isEmpty && !groupPrivateKey.isEmpty && !members.isEmpty && !admins.isEmpty // senderKeys may be empty + case .info(let groupPublicKey, let name, _, let members, let admins): + return !groupPublicKey.isEmpty && !name.isEmpty && !members.isEmpty && !admins.isEmpty // senderKeys may be empty + case .senderKeyRequest(let groupPublicKey): + return !groupPublicKey.isEmpty + case .senderKey(let groupPublicKey, _): + return !groupPublicKey.isEmpty + } } // MARK: Coding @@ -86,7 +95,26 @@ public final class ClosedGroupUpdate : ControlMessage { // MARK: Proto Conversion public override class func fromProto(_ proto: SNProtoContent) -> ClosedGroupUpdate? { - return nil + guard let closedGroupUpdateProto = proto.dataMessage?.closedGroupUpdate else { return nil } + let groupPublicKey = closedGroupUpdateProto.groupPublicKey + let kind: Kind + switch closedGroupUpdateProto.type { + case .new: + guard let name = closedGroupUpdateProto.name, let groupPrivateKey = closedGroupUpdateProto.groupPrivateKey else { return nil } + let senderKeys = closedGroupUpdateProto.senderKeys.map { ClosedGroupSenderKey.fromProto($0) } + kind = .new(groupPublicKey: groupPublicKey, name: name, groupPrivateKey: groupPrivateKey, + senderKeys: senderKeys, members: closedGroupUpdateProto.members, admins: closedGroupUpdateProto.admins) + case .info: + guard let name = closedGroupUpdateProto.name else { return nil } + let senderKeys = closedGroupUpdateProto.senderKeys.map { ClosedGroupSenderKey.fromProto($0) } + kind = .info(groupPublicKey: groupPublicKey, name: name, senderKeys: senderKeys, members: closedGroupUpdateProto.members, admins: closedGroupUpdateProto.admins) + case .senderKeyRequest: + kind = .senderKeyRequest(groupPublicKey: groupPublicKey) + case .senderKey: + guard let senderKeyProto = closedGroupUpdateProto.senderKeys.first else { return nil } + kind = .senderKey(groupPublicKey: groupPublicKey, senderKey: ClosedGroupSenderKey.fromProto(senderKeyProto)) + } + return ClosedGroupUpdate(kind: kind) } public override func toProto() -> SNProtoContent? { @@ -130,6 +158,10 @@ public final class ClosedGroupUpdate : ControlMessage { private extension ClosedGroupSenderKey { + static func fromProto(_ proto: SNProtoDataMessageClosedGroupUpdateSenderKey) -> ClosedGroupSenderKey { + return ClosedGroupSenderKey(chainKey: proto.chainKey, keyIndex: UInt(proto.keyIndex), publicKey: proto.publicKey) + } + func toProto() throws -> SNProtoDataMessageClosedGroupUpdateSenderKey { return try SNProtoDataMessageClosedGroupUpdateSenderKey.builder(chainKey: chainKey, keyIndex: UInt32(keyIndex), publicKey: publicKey).build() } diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index 496238a86..59a8acd17 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -8,6 +8,8 @@ public class Message : NSObject, NSCoding { // NSObject/NSCoding conformance is public var receivedTimestamp: UInt64? public var recipient: String? public var sender: String? + public var groupPublicKey: String? + public var openGroupServerMessageID: UInt64? public class var ttl: UInt64 { 2 * 24 * 60 * 60 * 1000 } diff --git a/SessionMessagingKit/Sending & Receiving/MessageHandler.swift b/SessionMessagingKit/Sending & Receiving/MessageHandler.swift new file mode 100644 index 000000000..cba87224d --- /dev/null +++ b/SessionMessagingKit/Sending & Receiving/MessageHandler.swift @@ -0,0 +1,17 @@ + +public protocol MessageReceiverDelegate { + + func isBlocked(_ publicKey: String) -> Bool + func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) + func showTypingIndicatorIfNeeded(for senderPublicKey: String) + func hideTypingIndicatorIfNeeded(for senderPublicKey: String) + func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) + func notifyUserIfNeeded(for message: Any, threadID: String) + func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) + func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) + func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) + func handleNewGroup(_ message: ClosedGroupUpdate, using transaction: Any) + func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) + func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) + func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) +} diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 9bb04e4ef..ec4b75ae5 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -3,6 +3,7 @@ import SessionUtilitiesKit // TODO: // • Threads don't show up on the first message; only on the second. // • Profile pictures aren't showing up. +// • Check that message expiration works. internal enum MessageReceiver { @@ -13,6 +14,7 @@ internal enum MessageReceiver { case noUserPublicKey case noData case senderBlocked + case noThread // Shared sender keys case invalidGroupPublicKey case noGroupPrivateKey @@ -34,6 +36,7 @@ internal enum MessageReceiver { case .noUserPublicKey: return "Couldn't find user key pair." case .noData: return "Received an empty envelope." case .senderBlocked: return "Received a message from a blocked user." + case .noThread: return "Couldn't find thread for message." // Shared sender keys case .invalidGroupPublicKey: return "Invalid group public key." case .noGroupPrivateKey: return "Missing group private key." @@ -43,19 +46,22 @@ internal enum MessageReceiver { } } - internal static func parse(_ data: Data, using transaction: Any) throws -> Message { + internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> Message { // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) // Decrypt the contents let plaintext: Data let sender: String + var groupPublicKey: String? = nil switch envelope.type { case .unidentifiedSender: (plaintext, sender) = try decryptWithSignalProtocol(envelope: envelope, using: transaction) - case .closedGroupCiphertext: (plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) + case .closedGroupCiphertext: + (plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) + groupPublicKey = envelope.source default: throw Error.unknownEnvelopeType } // Don't process the envelope any further if the sender is blocked - guard !Configuration.shared.storage.isBlocked(sender) else { throw Error.senderBlocked } + guard !Configuration.shared.messageReceiverDelegate.isBlocked(sender) else { throw Error.senderBlocked } // Parse the proto let proto: SNProtoContent do { @@ -79,6 +85,8 @@ internal enum MessageReceiver { message.sender = sender message.recipient = Configuration.shared.storage.getUserPublicKey() message.receivedTimestamp = NSDate.millisecondTimestamp() + message.groupPublicKey = groupPublicKey + message.openGroupServerMessageID = messageServerID guard message.isValid else { throw Error.invalidMessage } return message } else { @@ -86,7 +94,7 @@ internal enum MessageReceiver { } } - internal static func handle(_ message: Message, messageServerID: UInt64?, using transaction: Any) { + internal static func handle(_ message: Message, using transaction: Any) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) case let message as SessionRequest: handleSessionRequest(message, using: transaction) @@ -94,56 +102,62 @@ internal enum MessageReceiver { case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) - case let message as VisibleMessage: handleVisibleMessage(message, using: transaction) + case let message as VisibleMessage: try handleVisibleMessage(message, using: transaction) default: fatalError() } } private static func handleReadReceipt(_ message: ReadReceipt, using transaction: Any) { - Configuration.shared.storage.markMessagesAsRead(message.timestamps!, from: message.sender!, at: message.receivedTimestamp!) + Configuration.shared.messageReceiverDelegate.markMessagesAsRead(message.timestamps!, from: message.sender!, at: message.receivedTimestamp!) } private static func handleSessionRequest(_ message: SessionRequest, using transaction: Any) { - // TODO: Implement + // We might not need this anymore } private static func handleNullMessage(_ message: NullMessage, using transaction: Any) { - // TODO: Implement + // We might not need this anymore } private static func handleTypingIndicator(_ message: TypingIndicator, using transaction: Any) { - let storage = Configuration.shared.storage + let delegate = Configuration.shared.messageReceiverDelegate switch message.kind! { - case .started: storage.showTypingIndicatorIfNeeded(for: message.sender!) - case .stopped: storage.hideTypingIndicatorIfNeeded(for: message.sender!) + case .started: delegate.showTypingIndicatorIfNeeded(for: message.sender!) + case .stopped: delegate.hideTypingIndicatorIfNeeded(for: message.sender!) } } private static func handleClosedGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { - + let delegate = Configuration.shared.messageReceiverDelegate + switch message.kind! { + case .new: delegate.handleNewGroup(message, using: transaction) + case .info: delegate.handleGroupUpdate(message, using: transaction) + case .senderKeyRequest: delegate.handleSenderKeyRequest(message, using: transaction) + case .senderKey: delegate.handleSenderKey(message, using: transaction) + } } private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) { - let storage = Configuration.shared.storage + let delegate = Configuration.shared.messageReceiverDelegate if message.duration! > 0 { - storage.setExpirationTimer(to: message.duration!, for: message.sender!, using: transaction) + delegate.setExpirationTimer(to: message.duration!, for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) } else { - storage.disableExpirationTimer(for: message.sender!, using: transaction) + delegate.disableExpirationTimer(for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) } } - private static func handleVisibleMessage(_ message: VisibleMessage, using transaction: Any) { - let storage = Configuration.shared.storage + private static func handleVisibleMessage(_ message: VisibleMessage, using transaction: Any) throws { + let delegate = Configuration.shared.messageReceiverDelegate // Update profile if needed if let profile = message.profile { - storage.updateProfile(for: message.sender!, from: profile, using: transaction) + delegate.updateProfile(for: message.sender!, from: profile, using: transaction) } // Persist the message - let (threadID, tsIncomingMessage) = storage.persist(message, using: transaction) + guard let (threadID, tsIncomingMessage) = Configuration.shared.storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } message.threadID = threadID // Cancel any typing indicators - storage.cancelTypingIndicatorsIfNeeded(for: message.sender!) + delegate.cancelTypingIndicatorsIfNeeded(for: message.sender!) // Notify the user if needed - storage.notifyUserIfNeeded(for: tsIncomingMessage, threadID: threadID) + delegate.notifyUserIfNeeded(for: tsIncomingMessage, threadID: threadID) } } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 12ac5fd3e..42ce0351f 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -62,15 +62,6 @@ public protocol SessionMessagingKitStorageProtocol { // MARK: - Message Handling - func isBlocked(_ publicKey: String) -> Bool - func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. - func persist(_ message: VisibleMessage, using transaction: Any) -> (String, Any) - func showTypingIndicatorIfNeeded(for senderPublicKey: String) - func hideTypingIndicatorIfNeeded(for senderPublicKey: String) - func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) - func notifyUserIfNeeded(for message: Any, threadID: String) - func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) - func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, using transaction: Any) - func disableExpirationTimer(for senderPublicKey: String, using transaction: Any) + func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, Any)? } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index b0fec9ae5..f23f06892 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -922,6 +922,8 @@ C3CA3B1D255CF3C800F4C6D4 /* MessageSender+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */; }; C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; + C3D697382564DCE6004AF766 /* MessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697372564DCE6004AF766 /* MessageHandler.swift */; }; + C3D6974A2564DEDC004AF766 /* MessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697492564DEDC004AF766 /* MessageHandler.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; @@ -2042,6 +2044,8 @@ C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Utilities.swift"; sourceTree = ""; }; C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NullMessage.swift; sourceTree = ""; }; C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = ""; }; + C3D697372564DCE6004AF766 /* MessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageHandler.swift; sourceTree = ""; }; + C3D697492564DEDC004AF766 /* MessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageHandler.swift; sourceTree = ""; }; C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = ""; }; C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; @@ -2705,6 +2709,7 @@ C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */, C300A5FB2554B0A000555489 /* MessageReceiver.swift */, C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */, + C3D697372564DCE6004AF766 /* MessageHandler.swift */, ); path = "Sending & Receiving"; sourceTree = ""; @@ -3811,6 +3816,7 @@ C3550A02255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift */, C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */, C3F0A5EB255C970D007BE2A3 /* Configuration.swift */, + C3D697492564DEDC004AF766 /* MessageHandler.swift */, B8CCF63B239757C10091D419 /* Components */, C31F812425258F9C00DD9FD9 /* Database */, C32B405424A961E1001117B5 /* Dependencies */, @@ -5208,6 +5214,7 @@ C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */, C352A30925574D8500338F3E /* Message+Destination.swift in Sources */, C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */, + C3D697382564DCE6004AF766 /* MessageHandler.swift in Sources */, C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */, C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */, C3C2A74425539EB700C340D1 /* Message.swift in Sources */, @@ -5380,6 +5387,7 @@ 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */, 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */, 2400888E239F30A600305217 /* SessionRestorationView.swift in Sources */, + C3D6974A2564DEDC004AF766 /* MessageHandler.swift in Sources */, B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */, 34EA69402194933900702471 /* MediaDownloadView.swift in Sources */, B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */, diff --git a/SignalUtilitiesKit/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/ClosedGroupsProtocol.swift index 43d76609d..2bf1e0566 100644 --- a/SignalUtilitiesKit/ClosedGroupsProtocol.swift +++ b/SignalUtilitiesKit/ClosedGroupsProtocol.swift @@ -128,7 +128,7 @@ public final class ClosedGroupsProtocol : NSObject { Storage.writeSync { transaction in let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) for (senderPublicKey, oldRatchet) in allOldRatchets { - let collection = Storage.ClosedGroupRatchetCollectionType.old + let collection = ClosedGroupRatchetCollectionType.old Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) } // Delete all ratchets (it's important that this happens * after * sending out the update) @@ -362,7 +362,7 @@ public final class ClosedGroupsProtocol : NSObject { if Set(members).intersection(oldMembers) != Set(oldMembers) { let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) for (senderPublicKey, oldRatchet) in allOldRatchets { - let collection = Storage.ClosedGroupRatchetCollectionType.old + let collection = ClosedGroupRatchetCollectionType.old Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) } Storage.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) diff --git a/SignalUtilitiesKit/LokiPushNotificationManager.swift b/SignalUtilitiesKit/LokiPushNotificationManager.swift index 50b172d6f..bccf00b4c 100644 --- a/SignalUtilitiesKit/LokiPushNotificationManager.swift +++ b/SignalUtilitiesKit/LokiPushNotificationManager.swift @@ -102,7 +102,7 @@ public final class LokiPushNotificationManager : NSObject { } @discardableResult - static func performOperation(_ operation: ClosedGroupOperation, for closedGroupPublicKey: String, publicKey: String) -> Promise { + public static func performOperation(_ operation: ClosedGroupOperation, for closedGroupPublicKey: String, publicKey: String) -> Promise { let isUsingFullAPNs = UserDefaults.standard[.isUsingFullAPNs] guard isUsingFullAPNs else { return Promise { $0.fulfill(()) } } let parameters = [ "closedGroupPublicKey" : closedGroupPublicKey, "pubKey" : publicKey] diff --git a/SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift b/SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift index f4e031dd3..32095d6ca 100644 --- a/SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift +++ b/SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift @@ -1,10 +1,6 @@ public extension Storage { - internal enum ClosedGroupRatchetCollectionType { - case old, current - } - // MARK: Ratchets internal static func getClosedGroupRatchetCollection(_ collection: ClosedGroupRatchetCollectionType, for groupPublicKey: String) -> String { switch collection { @@ -27,7 +23,7 @@ public extension Storage { transaction.setObject(ratchet, forKey: senderPublicKey, inCollection: collection) } - internal static func getAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> [(senderPublicKey: String, ratchet: ClosedGroupRatchet)] { + public static func getAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> [(senderPublicKey: String, ratchet: ClosedGroupRatchet)] { let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) var result: [(senderPublicKey: String, ratchet: ClosedGroupRatchet)] = [] read { transaction in @@ -45,7 +41,7 @@ public extension Storage { }) } - internal static func removeAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current, using transaction: YapDatabaseReadWriteTransaction) { + public static func removeAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current, using transaction: YapDatabaseReadWriteTransaction) { let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) transaction.removeAllObjects(inCollection: collection) } diff --git a/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift b/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift index 59ca58cc7..bd21269d6 100644 --- a/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift +++ b/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift @@ -3,7 +3,7 @@ public extension TSIncomingMessage { static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage { let sender = visibleMessage.sender! - return TSIncomingMessage( + let result = TSIncomingMessage( timestamp: visibleMessage.receivedTimestamp!, in: thread, authorId: sender, @@ -16,5 +16,7 @@ public extension TSIncomingMessage { serverTimestamp: nil, wasReceivedByUD: true ) + result.openGroupServerMessageID = visibleMessage.openGroupServerMessageID ?? 0 + return result } } From 4f3448d75dad8291c03898a01d77339c036127a4 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Nov 2020 10:37:18 +1100 Subject: [PATCH 008/177] Remove more Signal code --- Session/Components/ConversationCell.swift | 2 +- .../MentionCandidateSelectionView.swift | 5 +- ...er.swift => MessageReceiverDelegate.swift} | 0 Session/Signal/AddToGroupViewController.h | 27 - Session/Signal/AddToGroupViewController.m | 138 - Session/Signal/AppEnvironment.swift | 3 - Session/Signal/AvatarViewHelper.m | 8 - Session/Signal/CallVideoHintView.swift | 83 - Session/Signal/CallViewController.swift | 1227 ---- .../Signal/CompareSafetyNumbersActivity.swift | 103 - .../TypingIndicatorInteraction.swift | 0 .../Signal/LegacyNotificationsAdaptee.swift | 30 - .../Signal/MessageDetailViewController.swift | 2 - .../Signal/MessageRecipientStatusUtils.swift | 3 - ...otificationSettingsOptionsViewController.m | 3 - .../OnboardingCaptchaViewController.swift | 201 - Session/Signal/PeerConnectionClient.swift | 1378 ----- .../PrivacySettingsTableViewController.m | 6 - Session/Signal/UserNotificationsAdaptee.swift | 18 - Signal.xcodeproj/project.pbxproj | 244 +- SignalUtilitiesKit/ContactsManagerProtocol.h | 37 - .../CreatePreKeysOperation.swift | 8 +- SignalUtilitiesKit/Data+Streaming.swift | 22 - .../{ => Database}/OWSStorage+Subclass.h | 0 .../{ => Database}/SSKPreferences.swift | 0 .../{ => Database}/SignalKeyingStorage.h | 0 .../{ => Database}/SignalKeyingStorage.m | 0 .../TSDatabaseSecondaryIndexes.h | 0 .../TSDatabaseSecondaryIndexes.m | 0 .../{ => Database}/TSDatabaseView.h | 0 .../{ => Database}/TSDatabaseView.m | 0 .../{ => Database}/TSStorageHeaders.h | 0 .../{ => Database}/TSStorageKeys.h | 0 .../{ => Database}/ThreadViewHelper.h | 0 .../{ => Database}/ThreadViewHelper.m | 0 SignalUtilitiesKit/FullTextSearcher.swift | 76 +- .../{ => Messaging}/Mention.swift | 0 .../{ => Messaging}/MentionsManager.swift | 0 .../{ => Messaging}/OWSBlockingManager.h | 0 .../{ => Messaging}/OWSBlockingManager.m | 0 ...sappearingConfigurationUpdateInfoMessage.h | 0 ...sappearingConfigurationUpdateInfoMessage.m | 0 .../OWSDisappearingMessagesConfiguration.h | 0 .../OWSDisappearingMessagesConfiguration.m | 0 .../OWSDisappearingMessagesFinder.h | 0 .../OWSDisappearingMessagesFinder.m | 0 .../OWSDisappearingMessagesJob.h | 0 .../OWSDisappearingMessagesJob.m | 1 - .../OWSIncomingMessageFinder.h | 0 .../OWSIncomingMessageFinder.m | 0 .../{ => Messaging}/OWSLinkPreview.swift | 0 .../{ => Messaging}/OWSMessageUtils.h | 0 .../{ => Messaging}/OWSMessageUtils.m | 0 .../OWSOutgoingReceiptManager.h | 0 .../OWSOutgoingReceiptManager.m | 0 .../{ => Messaging}/OWSQuotedReplyModel.h | 0 .../{ => Messaging}/OWSQuotedReplyModel.m | 0 .../{ => Messaging}/OWSReadReceiptManager.h | 0 .../{ => Messaging}/OWSReadReceiptManager.m | 0 .../{ => Messaging}/OWSReadTracking.h | 0 .../{Messages => Messaging}/TSErrorMessage.h | 0 .../{Messages => Messaging}/TSErrorMessage.m | 1 - .../TSErrorMessage_privateConstructor.h | 0 .../TSIncomingMessage.h | 0 .../TSIncomingMessage.m | 0 .../{Messages => Messaging}/TSInfoMessage.h | 0 .../{Messages => Messaging}/TSInfoMessage.m | 1 - .../{Messages => Messaging}/TSInteraction.h | 0 .../{Messages => Messaging}/TSInteraction.m | 0 .../TSInvalidIdentityKeyErrorMessage.h | 0 .../TSInvalidIdentityKeyErrorMessage.m | 0 ...SInvalidIdentityKeyReceivingErrorMessage.h | 0 ...SInvalidIdentityKeyReceivingErrorMessage.m | 0 .../TSInvalidIdentityKeySendingErrorMessage.h | 0 .../TSInvalidIdentityKeySendingErrorMessage.m | 0 .../{Messages => Messaging}/TSMessage.h | 1 - .../{Messages => Messaging}/TSMessage.m | 0 .../TSOutgoingMessage.h | 0 .../TSOutgoingMessage.m | 0 .../{Messages => Messaging}/TSQuotedMessage.h | 0 .../{Messages => Messaging}/TSQuotedMessage.m | 0 .../TSUnreadIndicatorInteraction.h | 0 .../TSUnreadIndicatorInteraction.m | 0 .../{ => Messaging}/TypingIndicators.swift | 0 .../ClosedGroupPoller.swift | 0 .../LKUserDefaults.swift | 0 .../LokiDatabaseUtilities.swift | 0 .../LokiPushNotificationManager.swift | 0 .../OWSPrimaryStorage+Loki.h | 0 .../OWSPrimaryStorage+Loki.m | 0 .../OWSPrimaryStorage+Loki.swift | 0 .../{ => Move to Session}/Poller.swift | 0 .../PublicChatManager.swift | 0 .../PublicChatPoller.swift | 0 .../Storage+ClosedGroups.swift | 0 .../Storage+Collections.swift | 0 .../Storage+OnionRequests.swift | 0 .../Storage+PublicChats.swift | 0 .../Storage+SessionManagement.swift | 0 .../Storage+SnodeAPI.swift | 0 .../Storage.swift | 0 SignalUtilitiesKit/OWSContactsOutputStream.m | 2 - SignalUtilitiesKit/OWSMessageServiceParams.h | 37 - SignalUtilitiesKit/OWSMessageServiceParams.m | 45 - SignalUtilitiesKit/OWSProvisioningCipher.h | 18 - SignalUtilitiesKit/OWSProvisioningCipher.m | 157 - .../PreKeyRefreshOperation.swift | 14 +- SignalUtilitiesKit/Provisioning.pb.swift | 254 - SignalUtilitiesKit/ProvisioningProto.swift | 310 - .../{ => Remove}/ClosedGroupsProtocol.swift | 0 .../ContactCellView.h | 0 .../ContactCellView.m | 0 .../ContactTableViewCell.h | 0 .../ContactTableViewCell.m | 0 .../DisplayNameUtilities.swift | 0 .../DisplayNameUtilities2.swift | 0 .../GroupUtilities.swift | 0 .../OWSProfileManager.h | 0 .../OWSProfileManager.m | 0 .../{Remove Later => Remove}/OWSUserProfile.h | 0 .../{Remove Later => Remove}/OWSUserProfile.m | 0 .../ProfileManagerProtocol.h | 0 .../SessionManagementProtocol.swift | 0 .../SessionMetaProtocol.swift | 0 .../RotateSignedKeyOperation.swift | 13 +- SignalUtilitiesKit/SignalMessage.swift | 28 - SignalUtilitiesKit/SignalService.pb.swift | 5199 ----------------- SignalUtilitiesKit/SignalServiceProfile.swift | 54 - SignalUtilitiesKit/Threads/TSContactThread.m | 1 - SignalUtilitiesKit/Threads/TSGroupModel.h | 1 - SignalUtilitiesKit/{ => Threads}/ThreadUtil.h | 0 SignalUtilitiesKit/{ => Threads}/ThreadUtil.m | 14 +- .../{ => Utilities}/FunctionalUtil.h | 0 .../{ => Utilities}/FunctionalUtil.m | 0 .../Utilities/LKGroupUtilities.m | 10 +- .../{ => Utilities}/Notification+Loki.swift | 0 .../{ => Utilities}/ParamParser.swift | 0 .../SSKIncrementingIdFinder.swift | 0 .../{ => Utilities}/SwiftSingletons.swift | 0 139 files changed, 132 insertions(+), 9653 deletions(-) rename Session/{MessageHandler.swift => MessageReceiverDelegate.swift} (100%) delete mode 100644 Session/Signal/AddToGroupViewController.h delete mode 100644 Session/Signal/AddToGroupViewController.m delete mode 100644 Session/Signal/CallVideoHintView.swift delete mode 100644 Session/Signal/CallViewController.swift delete mode 100644 Session/Signal/CompareSafetyNumbersActivity.swift rename Session/Signal/ConversationView/{ => Cells}/TypingIndicatorInteraction.swift (100%) delete mode 100644 Session/Signal/OnboardingCaptchaViewController.swift delete mode 100644 Session/Signal/PeerConnectionClient.swift delete mode 100644 SignalUtilitiesKit/ContactsManagerProtocol.h delete mode 100644 SignalUtilitiesKit/Data+Streaming.swift rename SignalUtilitiesKit/{ => Database}/OWSStorage+Subclass.h (100%) rename SignalUtilitiesKit/{ => Database}/SSKPreferences.swift (100%) rename SignalUtilitiesKit/{ => Database}/SignalKeyingStorage.h (100%) rename SignalUtilitiesKit/{ => Database}/SignalKeyingStorage.m (100%) rename SignalUtilitiesKit/{ => Database}/TSDatabaseSecondaryIndexes.h (100%) rename SignalUtilitiesKit/{ => Database}/TSDatabaseSecondaryIndexes.m (100%) rename SignalUtilitiesKit/{ => Database}/TSDatabaseView.h (100%) rename SignalUtilitiesKit/{ => Database}/TSDatabaseView.m (100%) rename SignalUtilitiesKit/{ => Database}/TSStorageHeaders.h (100%) rename SignalUtilitiesKit/{ => Database}/TSStorageKeys.h (100%) rename SignalUtilitiesKit/{ => Database}/ThreadViewHelper.h (100%) rename SignalUtilitiesKit/{ => Database}/ThreadViewHelper.m (100%) rename SignalUtilitiesKit/{ => Messaging}/Mention.swift (100%) rename SignalUtilitiesKit/{ => Messaging}/MentionsManager.swift (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSBlockingManager.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSBlockingManager.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/OWSDisappearingConfigurationUpdateInfoMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/OWSDisappearingConfigurationUpdateInfoMessage.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSDisappearingMessagesConfiguration.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSDisappearingMessagesConfiguration.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSDisappearingMessagesFinder.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSDisappearingMessagesFinder.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSDisappearingMessagesJob.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSDisappearingMessagesJob.m (99%) rename SignalUtilitiesKit/{ => Messaging}/OWSIncomingMessageFinder.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSIncomingMessageFinder.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSLinkPreview.swift (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSMessageUtils.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSMessageUtils.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSOutgoingReceiptManager.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSOutgoingReceiptManager.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSQuotedReplyModel.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSQuotedReplyModel.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSReadReceiptManager.h (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSReadReceiptManager.m (100%) rename SignalUtilitiesKit/{ => Messaging}/OWSReadTracking.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSErrorMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSErrorMessage.m (99%) rename SignalUtilitiesKit/{Messages => Messaging}/TSErrorMessage_privateConstructor.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSIncomingMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSIncomingMessage.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInfoMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInfoMessage.m (99%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInteraction.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInteraction.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInvalidIdentityKeyErrorMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInvalidIdentityKeyErrorMessage.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInvalidIdentityKeyReceivingErrorMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInvalidIdentityKeyReceivingErrorMessage.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInvalidIdentityKeySendingErrorMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSInvalidIdentityKeySendingErrorMessage.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSMessage.h (99%) rename SignalUtilitiesKit/{Messages => Messaging}/TSMessage.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSOutgoingMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSOutgoingMessage.m (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSQuotedMessage.h (100%) rename SignalUtilitiesKit/{Messages => Messaging}/TSQuotedMessage.m (100%) rename SignalUtilitiesKit/{ => Messaging}/TSUnreadIndicatorInteraction.h (100%) rename SignalUtilitiesKit/{ => Messaging}/TSUnreadIndicatorInteraction.m (100%) rename SignalUtilitiesKit/{ => Messaging}/TypingIndicators.swift (100%) rename SignalUtilitiesKit/{ => Move to Session}/ClosedGroupPoller.swift (100%) rename SignalUtilitiesKit/{Utilities => Move to Session}/LKUserDefaults.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/LokiDatabaseUtilities.swift (100%) rename SignalUtilitiesKit/{ => Move to Session}/LokiPushNotificationManager.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/OWSPrimaryStorage+Loki.h (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/OWSPrimaryStorage+Loki.m (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/OWSPrimaryStorage+Loki.swift (100%) rename SignalUtilitiesKit/{ => Move to Session}/Poller.swift (100%) rename SignalUtilitiesKit/{ => Move to Session}/PublicChatManager.swift (100%) rename SignalUtilitiesKit/{ => Move to Session}/PublicChatPoller.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/Storage+ClosedGroups.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/Storage+Collections.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/Storage+OnionRequests.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/Storage+PublicChats.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/Storage+SessionManagement.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/Storage+SnodeAPI.swift (100%) rename SignalUtilitiesKit/{Move to main app => Move to Session}/Storage.swift (100%) delete mode 100644 SignalUtilitiesKit/OWSMessageServiceParams.h delete mode 100644 SignalUtilitiesKit/OWSMessageServiceParams.m delete mode 100644 SignalUtilitiesKit/OWSProvisioningCipher.h delete mode 100644 SignalUtilitiesKit/OWSProvisioningCipher.m delete mode 100644 SignalUtilitiesKit/Provisioning.pb.swift delete mode 100644 SignalUtilitiesKit/ProvisioningProto.swift rename SignalUtilitiesKit/{ => Remove}/ClosedGroupsProtocol.swift (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/ContactCellView.h (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/ContactCellView.m (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/ContactTableViewCell.h (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/ContactTableViewCell.m (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/DisplayNameUtilities.swift (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/DisplayNameUtilities2.swift (100%) rename SignalUtilitiesKit/{Utilities => Remove}/GroupUtilities.swift (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/OWSProfileManager.h (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/OWSProfileManager.m (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/OWSUserProfile.h (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/OWSUserProfile.m (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/ProfileManagerProtocol.h (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/SessionManagementProtocol.swift (100%) rename SignalUtilitiesKit/{Remove Later => Remove}/SessionMetaProtocol.swift (100%) delete mode 100644 SignalUtilitiesKit/SignalMessage.swift delete mode 100644 SignalUtilitiesKit/SignalService.pb.swift delete mode 100644 SignalUtilitiesKit/SignalServiceProfile.swift rename SignalUtilitiesKit/{ => Threads}/ThreadUtil.h (100%) rename SignalUtilitiesKit/{ => Threads}/ThreadUtil.m (97%) rename SignalUtilitiesKit/{ => Utilities}/FunctionalUtil.h (100%) rename SignalUtilitiesKit/{ => Utilities}/FunctionalUtil.m (100%) rename SignalUtilitiesKit/{ => Utilities}/Notification+Loki.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/ParamParser.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/SSKIncrementingIdFinder.swift (100%) rename SignalUtilitiesKit/{ => Utilities}/SwiftSingletons.swift (100%) diff --git a/Session/Components/ConversationCell.swift b/Session/Components/ConversationCell.swift index c86a5d098..e4230a88d 100644 --- a/Session/Components/ConversationCell.swift +++ b/Session/Components/ConversationCell.swift @@ -166,7 +166,7 @@ final class ConversationCell : UITableViewCell { let image: UIImage let status = MessageRecipientStatusUtils.recipientStatus(outgoingMessage: lastMessage) switch status { - case .calculatingPoW, .uploading, .sending: image = #imageLiteral(resourceName: "CircleDotDotDot").asTintedImage(color: Colors.text)! + case .uploading, .sending: image = #imageLiteral(resourceName: "CircleDotDotDot").asTintedImage(color: Colors.text)! case .sent, .skipped, .delivered: image = #imageLiteral(resourceName: "CircleCheck").asTintedImage(color: Colors.text)! case .read: statusIndicatorView.backgroundColor = isLightMode ? .black : .white diff --git a/Session/Components/MentionCandidateSelectionView.swift b/Session/Components/MentionCandidateSelectionView.swift index a2eef63e9..f62d50d8b 100644 --- a/Session/Components/MentionCandidateSelectionView.swift +++ b/Session/Components/MentionCandidateSelectionView.swift @@ -1,6 +1,4 @@ -// MARK: - User Selection View - @objc(LKMentionCandidateSelectionView) final class MentionCandidateSelectionView : UIView, UITableViewDataSource, UITableViewDelegate { @objc var mentionCandidates: [Mention] = [] { didSet { tableView.reloadData() } } @@ -173,7 +171,8 @@ private extension MentionCandidateSelectionView { } } -// MARK: Delegate +// MARK: - Delegate + @objc(LKMentionCandidateSelectionViewDelegate) protocol MentionCandidateSelectionViewDelegate { diff --git a/Session/MessageHandler.swift b/Session/MessageReceiverDelegate.swift similarity index 100% rename from Session/MessageHandler.swift rename to Session/MessageReceiverDelegate.swift diff --git a/Session/Signal/AddToGroupViewController.h b/Session/Signal/AddToGroupViewController.h deleted file mode 100644 index dae373b41..000000000 --- a/Session/Signal/AddToGroupViewController.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SelectRecipientViewController.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol AddToGroupViewControllerDelegate - -- (void)recipientIdWasAdded:(NSString *)recipientId; - -- (BOOL)isRecipientGroupMember:(NSString *)recipientId; - -@end - -#pragma mark - - -@interface AddToGroupViewController : SelectRecipientViewController - -@property (nonatomic, weak) id addToGroupDelegate; - -@property (nonatomic) BOOL hideContacts; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/AddToGroupViewController.m b/Session/Signal/AddToGroupViewController.m deleted file mode 100644 index c021ce8c3..000000000 --- a/Session/Signal/AddToGroupViewController.m +++ /dev/null @@ -1,138 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "AddToGroupViewController.h" -#import "BlockListUIUtils.h" - -#import "Session-Swift.h" - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface AddToGroupViewController () - -@end - -#pragma mark - - -@implementation AddToGroupViewController - -- (void)loadView -{ - self.delegate = self; - - [super loadView]; - - self.title = NSLocalizedString(@"ADD_GROUP_MEMBER_VIEW_TITLE", @"Title for the 'add group member' view."); -} - -- (NSString *)phoneNumberSectionTitle -{ - return NSLocalizedString(@"ADD_GROUP_MEMBER_VIEW_PHONE_NUMBER_TITLE", - @"Title for the 'add by phone number' section of the 'add group member' view."); -} - -- (NSString *)phoneNumberButtonText -{ - return NSLocalizedString(@"ADD_GROUP_MEMBER_VIEW_BUTTON", - @"A label for the 'add by phone number' button in the 'add group member' view"); -} - -- (NSString *)contactsSectionTitle -{ - return NSLocalizedString( - @"ADD_GROUP_MEMBER_VIEW_CONTACT_TITLE", @"Title for the 'add contact' section of the 'add group member' view."); -} - -- (void)phoneNumberWasSelected:(NSString *)phoneNumber -{ - OWSAssertDebug(phoneNumber.length > 0); - - __weak AddToGroupViewController *weakSelf = self; - - if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:phoneNumber]) { - [BlockListUIUtils showUnblockPhoneNumberActionSheet:phoneNumber - fromViewController:self - blockingManager:SSKEnvironment.shared.blockingManager - completionBlock:^(BOOL isBlocked) { - if (!isBlocked) { - [weakSelf addToGroup:phoneNumber]; - } - }]; - return; - } - - [self addToGroup:phoneNumber]; -} - -- (BOOL)canSignalAccountBeSelected:(SignalAccount *)signalAccount -{ - OWSAssertDebug(signalAccount); - - return ![self.addToGroupDelegate isRecipientGroupMember:signalAccount.recipientId]; -} - -- (void)signalAccountWasSelected:(SignalAccount *)signalAccount -{ - OWSAssertDebug(signalAccount); - - __weak AddToGroupViewController *weakSelf = self; - if ([self.addToGroupDelegate isRecipientGroupMember:signalAccount.recipientId]) { - OWSFailDebug(@"Cannot add user to group member if already a member."); - return; - } - - if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]) { - [BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount - fromViewController:self - blockingManager:SSKEnvironment.shared.blockingManager - completionBlock:^(BOOL isBlocked) { - if (!isBlocked) { - [weakSelf addToGroup:signalAccount.recipientId]; - } - }]; - return; - } - - [self addToGroup:signalAccount.recipientId]; -} - -- (void)addToGroup:(NSString *)recipientId -{ - OWSAssertDebug(recipientId.length > 0); - - [self.addToGroupDelegate recipientIdWasAdded:recipientId]; - [self.navigationController popViewControllerAnimated:YES]; -} - -- (BOOL)shouldHideLocalNumber -{ - return YES; -} - -- (BOOL)shouldHideContacts -{ - return self.hideContacts; -} - -- (BOOL)shouldValidatePhoneNumbers -{ - return YES; -} - -- (nullable NSString *)accessoryMessageForSignalAccount:(SignalAccount *)signalAccount -{ - OWSAssertDebug(signalAccount); - - if ([self.addToGroupDelegate isRecipientGroupMember:signalAccount.recipientId]) { - return NSLocalizedString(@"NEW_GROUP_MEMBER_LABEL", @"An indicator that a user is a member of the new group."); - } - - return nil; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Signal/AppEnvironment.swift b/Session/Signal/AppEnvironment.swift index 2df0f0dc8..cfacd98f3 100644 --- a/Session/Signal/AppEnvironment.swift +++ b/Session/Signal/AppEnvironment.swift @@ -86,10 +86,7 @@ import SignalUtilitiesKit @objc public func setup() { -// callService.createCallUIAdapter() - // Hang certain singletons on SSKEnvironment too. SSKEnvironment.shared.notificationsManager = notificationPresenter -// SSKEnvironment.shared.callMessageHandler = callMessageHandler } } diff --git a/Session/Signal/AvatarViewHelper.m b/Session/Signal/AvatarViewHelper.m index b5d4b7972..bf4664007 100644 --- a/Session/Signal/AvatarViewHelper.m +++ b/Session/Signal/AvatarViewHelper.m @@ -36,14 +36,6 @@ NS_ASSUME_NONNULL_BEGIN preferredStyle:UIAlertControllerStyleActionSheet]; [actionSheet addAction:[OWSAlerts cancelAction]]; -// UIAlertAction *takePictureAction = [UIAlertAction -// actionWithTitle:NSLocalizedString(@"MEDIA_FROM_CAMERA_BUTTON", @"media picker option to take photo or video") -// style:UIAlertActionStyleDefault -// handler:^(UIAlertAction *_Nonnull action) { -// [self takePicture]; -// }]; -// [actionSheet addAction:takePictureAction]; - UIAlertAction *choosePictureAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"MEDIA_FROM_LIBRARY_BUTTON", @"media picker option to choose from library") style:UIAlertActionStyleDefault diff --git a/Session/Signal/CallVideoHintView.swift b/Session/Signal/CallVideoHintView.swift deleted file mode 100644 index ba49030d0..000000000 --- a/Session/Signal/CallVideoHintView.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation - -protocol CallVideoHintViewDelegate: AnyObject { - func didTapCallVideoHintView(_ videoHintView: CallVideoHintView) -} - -class CallVideoHintView: UIView { - let label = UILabel() - var tapGesture: UITapGestureRecognizer! - weak var delegate: CallVideoHintViewDelegate? - - let kTailHMargin: CGFloat = 12 - let kTailWidth: CGFloat = 16 - let kTailHeight: CGFloat = 8 - - init() { - super.init(frame: .zero) - - tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(tapGesture:))) - addGestureRecognizer(tapGesture) - - let layerView = OWSLayerView(frame: .zero) { _ in } - let shapeLayer = CAShapeLayer() - shapeLayer.fillColor = UIColor.ows_signalBlue.cgColor - layerView.layer.addSublayer(shapeLayer) - addSubview(layerView) - layerView.autoPinEdgesToSuperviewEdges() - - let container = UIView() - addSubview(container) - container.autoSetDimension(.width, toSize: ScaleFromIPhone5(250), relation: .lessThanOrEqual) - container.layoutMargins = UIEdgeInsets(top: 7, leading: 12, bottom: 7, trailing: 12) - container.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets(top: 0, leading: 0, bottom: kTailHeight, trailing: 0)) - - container.addSubview(label) - label.autoPinEdgesToSuperviewMargins() - label.setCompressionResistanceHigh() - label.setContentHuggingHigh() - label.font = UIFont.ows_dynamicTypeBody - label.textColor = .ows_white - label.numberOfLines = 0 - label.text = NSLocalizedString("CALL_VIEW_ENABLE_VIDEO_HINT", comment: "tooltip label when remote party has enabled their video") - - layerView.layoutCallback = { view in - let bezierPath = UIBezierPath() - - // Bubble - let bubbleBounds = container.bounds - bezierPath.append(UIBezierPath(roundedRect: bubbleBounds, cornerRadius: 8)) - - // Tail - var tailBottom = CGPoint(x: self.kTailHMargin + self.kTailWidth * 0.5, y: view.height()) - var tailLeft = CGPoint(x: self.kTailHMargin, y: view.height() - self.kTailHeight) - var tailRight = CGPoint(x: self.kTailHMargin + self.kTailWidth, y: view.height() - self.kTailHeight) - if (!CurrentAppContext().isRTL) { - tailBottom.x = view.width() - tailBottom.x - tailLeft.x = view.width() - tailLeft.x - tailRight.x = view.width() - tailRight.x - } - bezierPath.move(to: tailBottom) - bezierPath.addLine(to: tailLeft) - bezierPath.addLine(to: tailRight) - bezierPath.addLine(to: tailBottom) - shapeLayer.path = bezierPath.cgPath - shapeLayer.frame = view.bounds - } - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - - - @objc - func didTap(tapGesture: UITapGestureRecognizer) { - self.delegate?.didTapCallVideoHintView(self) - } -} diff --git a/Session/Signal/CallViewController.swift b/Session/Signal/CallViewController.swift deleted file mode 100644 index 02e27363d..000000000 --- a/Session/Signal/CallViewController.swift +++ /dev/null @@ -1,1227 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import WebRTC -//import PromiseKit -//import SignalUtilitiesKit -//import SignalUtilitiesKit -// -//// TODO: Add category so that button handlers can be defined where button is created. -//// TODO: Ensure buttons enabled & disabled as necessary. -//class CallViewController: OWSViewController, CallObserver, CallServiceObserver, CallAudioServiceDelegate { -// -// // Dependencies -// -// var callUIAdapter: CallUIAdapter { -// return AppEnvironment.shared.callService.callUIAdapter -// } -// -// var proximityMonitoringManager: OWSProximityMonitoringManager { -// return Environment.shared.proximityMonitoringManager -// } -// -// // Feature Flag -// @objc public static let kShowCallViewOnSeparateWindow = true -// -// let contactsManager: OWSContactsManager -// -// // MARK: - Properties -// -// let thread: TSContactThread -// let call: SignalCall -// var hasDismissed = false -// -// // MARK: - Views -// -// var hasConstraints = false -// var blurView: UIVisualEffectView! -// var dateFormatter: DateFormatter? -// -// // MARK: - Contact Views -// -// var contactNameLabel: MarqueeLabel! -// var contactAvatarView: AvatarImageView! -// var contactAvatarContainerView: UIView! -// var callStatusLabel: UILabel! -// var callDurationTimer: Timer? -// var leaveCallViewButton: UIButton! -// -// // MARK: - Ongoing Call Controls -// -// var ongoingCallControls: UIStackView! -// -// var ongoingAudioCallControls: UIStackView! -// var ongoingVideoCallControls: UIStackView! -// -// var hangUpButton: UIButton! -// var audioSourceButton: UIButton! -// var audioModeMuteButton: UIButton! -// var audioModeVideoButton: UIButton! -// var videoModeMuteButton: UIButton! -// var videoModeVideoButton: UIButton! -// var videoModeFlipCameraButton: UIButton! -// -// // MARK: - Incoming Call Controls -// -// var incomingCallControls: UIStackView! -// -// var acceptIncomingButton: UIButton! -// var declineIncomingButton: UIButton! -// -// // MARK: - Video Views -// -// var remoteVideoView: RemoteVideoView! -// var localVideoView: RTCCameraPreviewView! -// var hasShownLocalVideo = false -// weak var localCaptureSession: AVCaptureSession? -// weak var remoteVideoTrack: RTCVideoTrack? -// -// override public var canBecomeFirstResponder: Bool { -// return true -// } -// -// var shouldRemoteVideoControlsBeHidden = false { -// didSet { -// updateCallUI(callState: call.state) -// } -// } -// -// // MARK: - Settings Nag Views -// -// var isShowingSettingsNag = false { -// didSet { -// if oldValue != isShowingSettingsNag { -// updateCallUI(callState: call.state) -// } -// } -// } -// var settingsNagView: UIView! -// var settingsNagDescriptionLabel: UILabel! -// -// // MARK: - Audio Source -// -// var hasAlternateAudioSources: Bool { -// Logger.info("available audio sources: \(allAudioSources)") -// // internal mic and speakerphone will be the first two, any more than one indicates e.g. an attached bluetooth device. -// -// // TODO is this sufficient? Are their devices w/ bluetooth but no external speaker? e.g. ipod? -// return allAudioSources.count > 2 -// } -// -// var allAudioSources: Set = Set() -// -// var appropriateAudioSources: Set { -// if call.hasLocalVideo { -// let appropriateForVideo = allAudioSources.filter { audioSource in -// if audioSource.isBuiltInSpeaker { -// return true -// } else { -// guard let portDescription = audioSource.portDescription else { -// owsFailDebug("Only built in speaker should be lacking a port description.") -// return false -// } -// -// // Don't use receiver when video is enabled. Only bluetooth or speaker -// return portDescription.portType != AVAudioSession.Port.builtInMic -// } -// } -// return Set(appropriateForVideo) -// } else { -// return allAudioSources -// } -// } -// -// // MARK: - Initializers -// -// @available(*, unavailable, message: "use init(call:) constructor instead.") -// required init?(coder aDecoder: NSCoder) { -// notImplemented() -// } -// -// required init(call: SignalCall) { -// contactsManager = Environment.shared.contactsManager -// self.call = call -// self.thread = TSContactThread.getOrCreateThread(contactId: call.remotePhoneNumber) -// super.init(nibName: nil, bundle: nil) -// -// allAudioSources = Set(callUIAdapter.audioService.availableInputs) -// -// self.shouldUseTheme = false -// } -// -// deinit { -// Logger.info("") -// NotificationCenter.default.removeObserver(self) -// self.proximityMonitoringManager.remove(lifetime: self) -// } -// -// @objc func didBecomeActive() { -// if (self.isViewLoaded) { -// shouldRemoteVideoControlsBeHidden = false -// } -// } -// -// // MARK: - View Lifecycle -// -// override func viewDidDisappear(_ animated: Bool) { -// super.viewDidDisappear(animated) -// -// callDurationTimer?.invalidate() -// callDurationTimer = nil -// } -// -// override func viewWillAppear(_ animated: Bool) { -// super.viewWillAppear(animated) -// -// ensureProximityMonitoring() -// -// updateCallUI(callState: call.state) -// -// self.becomeFirstResponder() -// } -// -// override func viewDidAppear(_ animated: Bool) { -// super.viewDidAppear(animated) -// -// self.becomeFirstResponder() -// } -// -// override func loadView() { -// self.view = UIView() -// self.view.backgroundColor = UIColor.black -// self.view.layoutMargins = UIEdgeInsets(top: 16, left: 20, bottom: 16, right: 20) -// -// createViews() -// createViewConstraints() -// } -// -// override func viewDidLoad() { -// super.viewDidLoad() -// -// contactNameLabel.text = contactsManager.stringForConversationTitle(withPhoneIdentifier: thread.contactIdentifier()) -// updateAvatarImage() -// NotificationCenter.default.addObserver(forName: .OWSContactsManagerSignalAccountsDidChange, object: nil, queue: nil) { [weak self] _ in -// guard let strongSelf = self else { return } -// Logger.info("updating avatar image") -// strongSelf.updateAvatarImage() -// } -// -// // Subscribe for future call updates -// call.addObserverAndSyncState(observer: self) -// -// AppEnvironment.shared.callService.addObserverAndSyncState(observer: self) -// -// assert(callUIAdapter.audioService.delegate == nil) -// callUIAdapter.audioService.delegate = self -// -// NotificationCenter.default.addObserver(self, -// selector: #selector(didBecomeActive), -// name: NSNotification.Name.OWSApplicationDidBecomeActive, -// object: nil) -// } -// -// override var supportedInterfaceOrientations: UIInterfaceOrientationMask { -// return .portrait -// } -// -// override var preferredStatusBarStyle: UIStatusBarStyle { -// return .lightContent -// } -// -// // MARK: - Create Views -// -// func createViews() { -// self.view.isUserInteractionEnabled = true -// self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, -// action: #selector(didTouchRootView))) -// -// videoHintView.delegate = self -// -// // Dark blurred background. -// let blurEffect = UIBlurEffect(style: .dark) -// blurView = UIVisualEffectView(effect: blurEffect) -// blurView.isUserInteractionEnabled = false -// self.view.addSubview(blurView) -// -// // Create the video views first, as they are under the other views. -// createVideoViews() -// createContactViews() -// createOngoingCallControls() -// createIncomingCallControls() -// createSettingsNagViews() -// } -// -// @objc func didTouchRootView(sender: UIGestureRecognizer) { -// if !remoteVideoView.isHidden { -// shouldRemoteVideoControlsBeHidden = !shouldRemoteVideoControlsBeHidden -// } -// } -// -// func createVideoViews() { -// remoteVideoView = RemoteVideoView() -// remoteVideoView.isUserInteractionEnabled = false -// localVideoView = RTCCameraPreviewView() -// -// remoteVideoView.isHidden = true -// localVideoView.isHidden = true -// self.view.addSubview(remoteVideoView) -// self.view.addSubview(localVideoView) -// } -// -// func createContactViews() { -// -// leaveCallViewButton = UIButton() -// let backButtonImage = CurrentAppContext().isRTL ? #imageLiteral(resourceName: "NavBarBackRTL") : #imageLiteral(resourceName: "NavBarBack") -// leaveCallViewButton.setImage(backButtonImage, for: .normal) -// leaveCallViewButton.autoSetDimensions(to: CGSize(width: 40, height: 40)) -// leaveCallViewButton.addTarget(self, action: #selector(didTapLeaveCall(sender:)), for: .touchUpInside) -// self.view.addSubview(leaveCallViewButton) -// -// contactNameLabel = MarqueeLabel() -// -// // marquee config -// contactNameLabel.type = .continuous -// // This feels pretty slow when you're initially waiting for it, but when you're overlaying video calls, anything faster is distracting. -// contactNameLabel.speed = .duration(30.0) -// contactNameLabel.animationCurve = .linear -// contactNameLabel.fadeLength = 10.0 -// contactNameLabel.animationDelay = 5 -// // Add trailing space after the name scrolls before it wraps around and scrolls back in. -// contactNameLabel.trailingBuffer = ScaleFromIPhone5(80.0) -// -// // label config -// contactNameLabel.font = UIFont.ows_dynamicTypeTitle1 -// contactNameLabel.textAlignment = .center -// contactNameLabel.textColor = UIColor.white -// contactNameLabel.layer.shadowOffset = CGSize.zero -// contactNameLabel.layer.shadowOpacity = 0.35 -// contactNameLabel.layer.shadowRadius = 4 -// -// self.view.addSubview(contactNameLabel) -// -// callStatusLabel = UILabel() -// callStatusLabel.font = UIFont.ows_dynamicTypeBody -// callStatusLabel.textAlignment = .center -// callStatusLabel.textColor = UIColor.white -// callStatusLabel.layer.shadowOffset = CGSize.zero -// callStatusLabel.layer.shadowOpacity = 0.35 -// callStatusLabel.layer.shadowRadius = 4 -// -// self.view.addSubview(callStatusLabel) -// -// contactAvatarContainerView = UIView.container() -// self.view.addSubview(contactAvatarContainerView) -// contactAvatarView = AvatarImageView() -// contactAvatarContainerView.addSubview(contactAvatarView) -// } -// -// func createSettingsNagViews() { -// settingsNagView = UIView() -// settingsNagView.isHidden = true -// self.view.addSubview(settingsNagView) -// -// let viewStack = UIView() -// settingsNagView.addSubview(viewStack) -// viewStack.autoPinWidthToSuperview() -// viewStack.autoVCenterInSuperview() -// -// settingsNagDescriptionLabel = UILabel() -// settingsNagDescriptionLabel.text = NSLocalizedString("CALL_VIEW_SETTINGS_NAG_DESCRIPTION_ALL", -// comment: "Reminder to the user of the benefits of enabling CallKit and disabling CallKit privacy.") -// settingsNagDescriptionLabel.font = UIFont.ows_regularFont(withSize: ScaleFromIPhone5To7Plus(16, 18)) -// settingsNagDescriptionLabel.textColor = UIColor.white -// settingsNagDescriptionLabel.numberOfLines = 0 -// settingsNagDescriptionLabel.lineBreakMode = .byWordWrapping -// viewStack.addSubview(settingsNagDescriptionLabel) -// settingsNagDescriptionLabel.autoPinWidthToSuperview() -// settingsNagDescriptionLabel.autoPinEdge(toSuperviewEdge: .top) -// -// let buttonHeight = ScaleFromIPhone5To7Plus(35, 45) -// let descriptionVSpacingHeight = ScaleFromIPhone5To7Plus(30, 60) -// -// let callSettingsButton = OWSFlatButton.button(title: NSLocalizedString("CALL_VIEW_SETTINGS_NAG_SHOW_CALL_SETTINGS", -// comment: "Label for button that shows the privacy settings."), -// font: OWSFlatButton.fontForHeight(buttonHeight), -// titleColor: UIColor.white, -// backgroundColor: UIColor.ows_signalBrandBlue, -// target: self, -// selector: #selector(didPressShowCallSettings)) -// viewStack.addSubview(callSettingsButton) -// callSettingsButton.autoSetDimension(.height, toSize: buttonHeight) -// callSettingsButton.autoPinWidthToSuperview() -// callSettingsButton.autoPinEdge(.top, to: .bottom, of: settingsNagDescriptionLabel, withOffset: descriptionVSpacingHeight) -// -// let notNowButton = OWSFlatButton.button(title: NSLocalizedString("CALL_VIEW_SETTINGS_NAG_NOT_NOW_BUTTON", -// comment: "Label for button that dismiss the call view's settings nag."), -// font: OWSFlatButton.fontForHeight(buttonHeight), -// titleColor: UIColor.white, -// backgroundColor: UIColor.ows_signalBrandBlue, -// target: self, -// selector: #selector(didPressDismissNag)) -// viewStack.addSubview(notNowButton) -// notNowButton.autoSetDimension(.height, toSize: buttonHeight) -// notNowButton.autoPinWidthToSuperview() -// notNowButton.autoPinEdge(toSuperviewEdge: .bottom) -// notNowButton.autoPinEdge(.top, to: .bottom, of: callSettingsButton, withOffset: 12) -// } -// -// func buttonSize() -> CGFloat { -// return ScaleFromIPhone5To7Plus(84, 108) -// } -// -// func buttonInset() -> CGFloat { -// return ScaleFromIPhone5To7Plus(7, 9) -// } -// -// func createOngoingCallControls() { -// -// audioSourceButton = createButton(image: #imageLiteral(resourceName: "audio-call-speaker-inactive"), -// action: #selector(didPressAudioSource)) -// audioSourceButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_AUDIO_SOURCE_LABEL", -// comment: "Accessibility label for selection the audio source") -// -// hangUpButton = createButton(image: #imageLiteral(resourceName: "hangup-active-wide"), -// action: #selector(didPressHangup)) -// hangUpButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_HANGUP_LABEL", -// comment: "Accessibility label for hang up call") -// -// audioModeMuteButton = createButton(image: #imageLiteral(resourceName: "audio-call-mute-inactive"), -// action: #selector(didPressMute)) -// audioModeMuteButton.setImage(#imageLiteral(resourceName: "audio-call-mute-active"), for: .selected) -// -// audioModeMuteButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_MUTE_LABEL", -// comment: "Accessibility label for muting the microphone") -// -// audioModeVideoButton = createButton(image: #imageLiteral(resourceName: "audio-call-video-inactive"), -// action: #selector(didPressVideo)) -// audioModeVideoButton.setImage(#imageLiteral(resourceName: "audio-call-video-active"), for: .selected) -// audioModeVideoButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_SWITCH_TO_VIDEO_LABEL", comment: "Accessibility label to switch to video call") -// -// videoModeMuteButton = createButton(image: #imageLiteral(resourceName: "video-mute-unselected"), -// action: #selector(didPressMute)) -// videoModeMuteButton.setImage(#imageLiteral(resourceName: "video-mute-selected"), for: .selected) -// videoModeMuteButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_MUTE_LABEL", comment: "Accessibility label for muting the microphone") -// videoModeMuteButton.alpha = 0.9 -// -// videoModeFlipCameraButton = createButton(image: #imageLiteral(resourceName: "video-switch-camera-unselected"), -// action: #selector(didPressFlipCamera)) -// -// videoModeFlipCameraButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_SWITCH_CAMERA_DIRECTION", comment: "Accessibility label to toggle front- vs. rear-facing camera") -// videoModeFlipCameraButton.alpha = 0.9 -// -// videoModeVideoButton = createButton(image: #imageLiteral(resourceName: "video-video-unselected"), -// action: #selector(didPressVideo)) -// videoModeVideoButton.setImage(#imageLiteral(resourceName: "video-video-selected"), for: .selected) -// videoModeVideoButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_SWITCH_TO_AUDIO_LABEL", comment: "Accessibility label to switch to audio only") -// videoModeVideoButton.alpha = 0.9 -// -// ongoingCallControls = UIStackView(arrangedSubviews: [hangUpButton]) -// ongoingCallControls.axis = .vertical -// ongoingCallControls.alignment = .center -// view.addSubview(ongoingCallControls) -// -// ongoingAudioCallControls = UIStackView(arrangedSubviews: [audioModeMuteButton, audioSourceButton, audioModeVideoButton]) -// ongoingAudioCallControls.distribution = .equalSpacing -// ongoingAudioCallControls.axis = .horizontal -// -// ongoingVideoCallControls = UIStackView(arrangedSubviews: [videoModeMuteButton, videoModeFlipCameraButton, videoModeVideoButton]) -// ongoingAudioCallControls.distribution = .equalSpacing -// ongoingVideoCallControls.axis = .horizontal -// } -// -// func presentAudioSourcePicker() { -// AssertIsOnMainThread() -// -// let actionSheetController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) -// -// let dismissAction = UIAlertAction(title: CommonStrings.dismissButton, style: .cancel, handler: nil) -// actionSheetController.addAction(dismissAction) -// -// let currentAudioSource = callUIAdapter.audioService.currentAudioSource(call: self.call) -// for audioSource in self.appropriateAudioSources { -// let routeAudioAction = UIAlertAction(title: audioSource.localizedName, style: .default) { _ in -// self.callUIAdapter.setAudioSource(call: self.call, audioSource: audioSource) -// } -// -// // HACK: private API to create checkmark for active audio source. -// routeAudioAction.setValue(currentAudioSource == audioSource, forKey: "checked") -// -// // TODO: pick some icons. Leaving out for MVP -// // HACK: private API to add image to actionsheet -// // routeAudioAction.setValue(audioSource.image, forKey: "image") -// -// actionSheetController.addAction(routeAudioAction) -// } -// -// // Note: It's critical that we present from this view and -// // not the "frontmost view controller" since this view may -// // reside on a separate window. -// presentAlert(actionSheetController) -// } -// -// func updateAvatarImage() { -// contactAvatarView.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: 400) -// } -// -// func createIncomingCallControls() { -// -// acceptIncomingButton = createButton(image: #imageLiteral(resourceName: "call-active-wide"), -// action: #selector(didPressAnswerCall)) -// acceptIncomingButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_ACCEPT_INCOMING_CALL_LABEL", -// comment: "Accessibility label for accepting incoming calls") -// declineIncomingButton = createButton(image: #imageLiteral(resourceName: "hangup-active-wide"), -// action: #selector(didPressDeclineCall)) -// declineIncomingButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", -// comment: "Accessibility label for declining incoming calls") -// -// incomingCallControls = UIStackView(arrangedSubviews: [acceptIncomingButton, declineIncomingButton]) -// incomingCallControls.axis = .horizontal -// incomingCallControls.alignment = .center -// incomingCallControls.distribution = .equalSpacing -// -// view.addSubview(incomingCallControls) -// } -// -// func createButton(image: UIImage, action: Selector) -> UIButton { -// let button = UIButton() -// button.setImage(image, for: .normal) -// button.imageEdgeInsets = UIEdgeInsets(top: buttonInset(), -// left: buttonInset(), -// bottom: buttonInset(), -// right: buttonInset()) -// button.addTarget(self, action: action, for: .touchUpInside) -// button.autoSetDimension(.width, toSize: buttonSize()) -// button.autoSetDimension(.height, toSize: buttonSize()) -// return button -// } -// -// // MARK: - Layout -// -// var localVideoViewTopConstraintDefault: NSLayoutConstraint! -// var localVideoViewTopConstraintHidden: NSLayoutConstraint! -// -// func createViewConstraints() { -// -// let contactVSpacing = CGFloat(3) -// let settingsNagHMargin = CGFloat(30) -// let ongoingBottomMargin = ScaleFromIPhone5To7Plus(23, 41) -// let incomingHMargin = ScaleFromIPhone5To7Plus(30, 56) -// let incomingBottomMargin = CGFloat(41) -// let settingsNagBottomMargin = CGFloat(41) -// let avatarTopSpacing = ScaleFromIPhone5To7Plus(25, 50) -// // The buttons have built-in 10% margins, so to appear centered -// // the avatar's bottom spacing should be a bit less. -// let avatarBottomSpacing = ScaleFromIPhone5To7Plus(18, 41) -// // Layout of the local video view is a bit unusual because -// // although the view is square, it will be used -// let videoPreviewHMargin = CGFloat(0) -// -// // Dark blurred background. -// blurView.autoPinEdgesToSuperviewEdges() -// -// leaveCallViewButton.autoPinEdge(toSuperviewEdge: .leading) -// -// if #available(iOS 11, *) { -// leaveCallViewButton.autoPinEdge(toSuperviewMargin: .top) -// contactNameLabel.autoPinEdge(toSuperviewMargin: .top) -// } else { -// leaveCallViewButton.autoPinEdge(.top, to: .top, of: view) -// contactNameLabel.autoPinEdge(.top, to: .top, of: view) -// } -// -// contactNameLabel.autoPinEdge(.leading, to: .trailing, of: leaveCallViewButton, withOffset: 8, relation: .greaterThanOrEqual) -// contactNameLabel.autoHCenterInSuperview() -// contactNameLabel.setContentHuggingVerticalHigh() -// contactNameLabel.setCompressionResistanceHigh() -// -// callStatusLabel.autoPinEdge(.top, to: .bottom, of: contactNameLabel, withOffset: contactVSpacing) -// callStatusLabel.autoHCenterInSuperview() -// callStatusLabel.setContentHuggingVerticalHigh() -// callStatusLabel.setCompressionResistanceHigh() -// -// localVideoView.autoPinTrailingToSuperviewMargin(withInset: videoPreviewHMargin) -// -// self.localVideoViewTopConstraintDefault = localVideoView.autoPinEdge(.top, to: .bottom, of: callStatusLabel, withOffset: 4) -// self.localVideoViewTopConstraintHidden = localVideoView.autoPinEdge(toSuperviewMargin: .top) -// let localVideoSize = ScaleFromIPhone5To7Plus(80, 100) -// localVideoView.autoSetDimension(.width, toSize: localVideoSize) -// localVideoView.autoSetDimension(.height, toSize: localVideoSize) -// -// remoteVideoView.autoPinEdgesToSuperviewEdges() -// -// contactAvatarContainerView.autoPinEdge(.top, to: .bottom, of: callStatusLabel, withOffset: +avatarTopSpacing) -// contactAvatarContainerView.autoPinEdge(.bottom, to: .top, of: ongoingCallControls, withOffset: -avatarBottomSpacing) -// contactAvatarContainerView.autoPinWidthToSuperview(withMargin: avatarTopSpacing) -// -// contactAvatarView.autoCenterInSuperview() -// -// // Ensure ContacAvatarView gets as close as possible to it's superview edges while maintaining -// // aspect ratio. -// contactAvatarView.autoPinToSquareAspectRatio() -// contactAvatarView.autoPinEdge(toSuperviewEdge: .top, withInset: 0, relation: .greaterThanOrEqual) -// contactAvatarView.autoPinEdge(toSuperviewEdge: .right, withInset: 0, relation: .greaterThanOrEqual) -// contactAvatarView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0, relation: .greaterThanOrEqual) -// contactAvatarView.autoPinEdge(toSuperviewEdge: .left, withInset: 0, relation: .greaterThanOrEqual) -// NSLayoutConstraint.autoSetPriority(UILayoutPriority.defaultLow) { -// contactAvatarView.autoPinEdgesToSuperviewMargins() -// } -// -// // Ongoing call controls -// ongoingCallControls.autoPinEdge(toSuperviewEdge: .bottom, withInset: ongoingBottomMargin) -// ongoingCallControls.autoPinLeadingToSuperviewMargin() -// ongoingCallControls.autoPinTrailingToSuperviewMargin() -// ongoingCallControls.setContentHuggingVerticalHigh() -// -// // Incoming call controls -// incomingCallControls.autoPinEdge(toSuperviewEdge: .bottom, withInset: incomingBottomMargin) -// incomingCallControls.autoPinLeadingToSuperviewMargin(withInset: incomingHMargin) -// incomingCallControls.autoPinTrailingToSuperviewMargin(withInset: incomingHMargin) -// incomingCallControls.setContentHuggingVerticalHigh() -// -// // Settings nag views -// settingsNagView.autoPinEdge(toSuperviewEdge: .bottom, withInset: settingsNagBottomMargin) -// settingsNagView.autoPinWidthToSuperview(withMargin: settingsNagHMargin) -// settingsNagView.autoPinEdge(.top, to: .bottom, of: callStatusLabel) -// } -// -// override func updateViewConstraints() { -// updateRemoteVideoLayout() -// updateLocalVideoLayout() -// -// super.updateViewConstraints() -// } -// -// internal func updateRemoteVideoLayout() { -// remoteVideoView.isHidden = !self.hasRemoteVideoTrack -// updateCallUI(callState: call.state) -// } -// -// let videoHintView = CallVideoHintView() -// -// internal func updateLocalVideoLayout() { -// if !localVideoView.isHidden { -// localVideoView.superview?.bringSubviewToFront(localVideoView) -// } -// -// updateCallUI(callState: call.state) -// } -// -// // MARK: - Methods -// -// func showCallFailed(error: Error) { -// // TODO Show something in UI. -// Logger.error("call failed with error: \(error)") -// } -// -// // MARK: - View State -// -// func localizedTextForCallState(_ callState: CallState) -> String { -// assert(Thread.isMainThread) -// -// switch callState { -// case .idle, .remoteHangup, .localHangup: -// return NSLocalizedString("IN_CALL_TERMINATED", comment: "Call setup status label") -// case .dialing: -// return NSLocalizedString("IN_CALL_CONNECTING", comment: "Call setup status label") -// case .remoteRinging, .localRinging: -// return NSLocalizedString("IN_CALL_RINGING", comment: "Call setup status label") -// case .answering: -// return NSLocalizedString("IN_CALL_SECURING", comment: "Call setup status label") -// case .connected: -// let callDuration = call.connectionDuration() -// let callDurationDate = Date(timeIntervalSinceReferenceDate: callDuration) -// if dateFormatter == nil { -// dateFormatter = DateFormatter() -// dateFormatter!.dateFormat = "HH:mm:ss" -// dateFormatter!.timeZone = TimeZone(identifier: "UTC")! -// } -// var formattedDate = dateFormatter!.string(from: callDurationDate) -// if formattedDate.hasPrefix("00:") { -// // Don't show the "hours" portion of the date format unless the -// // call duration is at least 1 hour. -// formattedDate = String(formattedDate[formattedDate.index(formattedDate.startIndex, offsetBy: 3)...]) -// } else { -// // If showing the "hours" portion of the date format, strip any leading -// // zeroes. -// if formattedDate.hasPrefix("0") { -// formattedDate = String(formattedDate[formattedDate.index(formattedDate.startIndex, offsetBy: 1)...]) -// } -// } -// return formattedDate -// case .reconnecting: -// return NSLocalizedString("IN_CALL_RECONNECTING", comment: "Call setup status label") -// case .remoteBusy: -// return NSLocalizedString("END_CALL_RESPONDER_IS_BUSY", comment: "Call setup status label") -// case .localFailure: -// if let error = call.error { -// switch error { -// case .timeout(description: _): -// if self.call.direction == .outgoing { -// return NSLocalizedString("CALL_SCREEN_STATUS_NO_ANSWER", comment: "Call setup status label after outgoing call times out") -// } -// default: -// break -// } -// } -// -// return NSLocalizedString("END_CALL_UNCATEGORIZED_FAILURE", comment: "Call setup status label") -// } -// } -// -// var isBlinkingReconnectLabel = false -// func updateCallStatusLabel(callState: CallState) { -// assert(Thread.isMainThread) -// -// let text = String(format: CallStrings.callStatusFormat, -// localizedTextForCallState(callState)) -// self.callStatusLabel.text = text -// -// // Handle reconnecting blinking -// if case .reconnecting = callState { -// if !isBlinkingReconnectLabel { -// isBlinkingReconnectLabel = true -// UIView.animate(withDuration: 0.7, delay: 0, options: [.autoreverse, .repeat], -// animations: { -// self.callStatusLabel.alpha = 0.2 -// }, completion: nil) -// } else { -// // already blinking -// } -// } else { -// // We're no longer in a reconnecting state, either the call failed or we reconnected. -// // Stop the blinking animation -// if isBlinkingReconnectLabel { -// self.callStatusLabel.layer.removeAllAnimations() -// self.callStatusLabel.alpha = 1 -// isBlinkingReconnectLabel = false -// } -// } -// } -// -// func updateCallUI(callState: CallState) { -// assert(Thread.isMainThread) -// updateCallStatusLabel(callState: callState) -// if isShowingSettingsNag { -// settingsNagView.isHidden = false -// contactAvatarView.isHidden = true -// ongoingCallControls.isHidden = true -// return -// } -// -// // Marquee scrolling is distracting during a video call, disable it. -// contactNameLabel.labelize = call.hasLocalVideo -// -// audioModeMuteButton.isSelected = call.isMuted -// videoModeMuteButton.isSelected = call.isMuted -// audioModeVideoButton.isSelected = call.hasLocalVideo -// videoModeVideoButton.isSelected = call.hasLocalVideo -// -// // Show Incoming vs. Ongoing call controls -// let isRinging = callState == .localRinging -// incomingCallControls.isHidden = !isRinging -// incomingCallControls.isUserInteractionEnabled = isRinging -// ongoingCallControls.isHidden = isRinging -// ongoingCallControls.isUserInteractionEnabled = !isRinging -// -// // Rework control state if remote video is available. -// let hasRemoteVideo = !remoteVideoView.isHidden -// contactAvatarView.isHidden = hasRemoteVideo -// -// // Rework control state if local video is available. -// let hasLocalVideo = !localVideoView.isHidden -// -// if hasLocalVideo { -// ongoingAudioCallControls.removeFromSuperview() -// ongoingCallControls.insertArrangedSubview(ongoingVideoCallControls, at: 0) -// } else { -// ongoingVideoCallControls.removeFromSuperview() -// ongoingCallControls.insertArrangedSubview(ongoingAudioCallControls, at: 0) -// } -// // Layout immediately to avoid spurious animation. -// ongoingCallControls.layoutIfNeeded() -// -// // Also hide other controls if user has tapped to hide them. -// if shouldRemoteVideoControlsBeHidden && !remoteVideoView.isHidden { -// leaveCallViewButton.isHidden = true -// contactNameLabel.isHidden = true -// callStatusLabel.isHidden = true -// ongoingCallControls.isHidden = true -// videoHintView.isHidden = true -// } else { -// leaveCallViewButton.isHidden = false -// contactNameLabel.isHidden = false -// callStatusLabel.isHidden = false -// -// if hasRemoteVideo && !hasLocalVideo && !hasShownLocalVideo && !hasUserDismissedVideoHint { -// view.addSubview(videoHintView) -// videoHintView.isHidden = false -// videoHintView.autoPinEdge(.bottom, to: .top, of: audioModeVideoButton) -// videoHintView.autoPinEdge(.trailing, to: .leading, of: audioModeVideoButton, withOffset: buttonSize() / 2 + videoHintView.kTailHMargin + videoHintView.kTailWidth / 2) -// } else { -// videoHintView.removeFromSuperview() -// } -// } -// -// let doLocalVideoLayout = { -// self.localVideoViewTopConstraintDefault.isActive = !self.contactNameLabel.isHidden -// self.localVideoViewTopConstraintHidden.isActive = self.contactNameLabel.isHidden -// self.localVideoView.superview?.layoutIfNeeded() -// } -// if hasShownLocalVideo { -// // Animate. -// UIView.animate(withDuration: 0.25, animations: doLocalVideoLayout) -// } else { -// // Don't animate. -// doLocalVideoLayout() -// } -// -// // Audio Source Handling (bluetooth) -// if self.hasAlternateAudioSources { -// // With bluetooth, button does not stay selected. Pressing it pops an actionsheet -// // and the button should immediately "unselect". -// audioSourceButton.isSelected = false -// -// if hasLocalVideo { -// audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_video_mode"), for: .normal) -// audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_video_mode"), for: .selected) -// } else { -// audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_audio_mode"), for: .normal) -// audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_audio_mode"), for: .selected) -// } -// audioSourceButton.isHidden = false -// } else { -// // No bluetooth audio detected -// audioSourceButton.setImage(#imageLiteral(resourceName: "audio-call-speaker-inactive"), for: .normal) -// audioSourceButton.setImage(#imageLiteral(resourceName: "audio-call-speaker-active"), for: .selected) -// -// // If there's no bluetooth, we always use speakerphone, so no need for -// // a button, giving more screen back for the video. -// audioSourceButton.isHidden = hasLocalVideo -// } -// -// // Dismiss Handling -// switch callState { -// case .remoteHangup, .remoteBusy, .localFailure: -// Logger.debug("dismissing after delay because new state is \(callState)") -// dismissIfPossible(shouldDelay: true) -// case .localHangup: -// Logger.debug("dismissing immediately from local hangup") -// dismissIfPossible(shouldDelay: false) -// default: break -// } -// -// if callState == .connected { -// if callDurationTimer == nil { -// let kDurationUpdateFrequencySeconds = 1 / 20.0 -// callDurationTimer = WeakTimer.scheduledTimer(timeInterval: TimeInterval(kDurationUpdateFrequencySeconds), -// target: self, -// userInfo: nil, -// repeats: true) {[weak self] _ in -// self?.updateCallDuration() -// } -// } -// } else { -// callDurationTimer?.invalidate() -// callDurationTimer = nil -// } -// } -// -// func updateCallDuration() { -// updateCallStatusLabel(callState: call.state) -// } -// -// // We update the audioSourceButton outside of the main `updateCallUI` -// // because `updateCallUI` is intended to be idempotent, which isn't possible -// // with external speaker state because: -// // - the system API which enables the external speaker is a (somewhat slow) asyncronous -// // operation -// // - we want to give immediate UI feedback by marking the pressed button as selected -// // before the operation completes. -// func updateAudioSourceButtonIsSelected() { -// guard callUIAdapter.audioService.isSpeakerphoneEnabled else { -// self.audioSourceButton.isSelected = false -// return -// } -// -// // VideoChat mode enables the output speaker, but we don't -// // want to highlight the speaker button in that case. -// guard !call.hasLocalVideo else { -// self.audioSourceButton.isSelected = false -// return -// } -// -// self.audioSourceButton.isSelected = true -// } -// -// // MARK: - Actions -// -// /** -// * Ends a connected call. Do not confuse with `didPressDeclineCall`. -// */ -// @objc func didPressHangup(sender: UIButton) { -// Logger.info("") -// -// callUIAdapter.localHangupCall(call) -// -// dismissIfPossible(shouldDelay: false) -// } -// -// @objc func didPressMute(sender muteButton: UIButton) { -// Logger.info("") -// muteButton.isSelected = !muteButton.isSelected -// -// callUIAdapter.setIsMuted(call: call, isMuted: muteButton.isSelected) -// } -// -// @objc func didPressAudioSource(sender button: UIButton) { -// Logger.info("") -// -// if self.hasAlternateAudioSources { -// presentAudioSourcePicker() -// } else { -// didPressSpeakerphone(sender: button) -// } -// } -// -// func didPressSpeakerphone(sender button: UIButton) { -// Logger.info("") -// -// button.isSelected = !button.isSelected -// callUIAdapter.audioService.requestSpeakerphone(isEnabled: button.isSelected) -// } -// -// func didPressTextMessage(sender button: UIButton) { -// Logger.info("") -// -// dismissIfPossible(shouldDelay: false) -// } -// -// @objc func didPressAnswerCall(sender: UIButton) { -// Logger.info("") -// -// callUIAdapter.answerCall(call) -// } -// -// @objc func didPressVideo(sender: UIButton) { -// Logger.info("") -// let hasLocalVideo = !sender.isSelected -// -// callUIAdapter.setHasLocalVideo(call: call, hasLocalVideo: hasLocalVideo) -// } -// -// @objc func didPressFlipCamera(sender: UIButton) { -// sender.isSelected = !sender.isSelected -// -// let isUsingFrontCamera = !sender.isSelected -// Logger.info("with isUsingFrontCamera: \(isUsingFrontCamera)") -// -// callUIAdapter.setCameraSource(call: call, isUsingFrontCamera: isUsingFrontCamera) -// } -// -// /** -// * Denies an incoming not-yet-connected call, Do not confuse with `didPressHangup`. -// */ -// @objc func didPressDeclineCall(sender: UIButton) { -// Logger.info("") -// -// callUIAdapter.declineCall(call) -// -// dismissIfPossible(shouldDelay: false) -// } -// -// @objc func didPressShowCallSettings(sender: UIButton) { -// Logger.info("") -// -// markSettingsNagAsComplete() -// -// dismissIfPossible(shouldDelay: false, ignoreNag: true, completion: { -// // Find the frontmost presented UIViewController from which to present the -// // settings views. -// let fromViewController = UIApplication.shared.findFrontmostViewController(ignoringAlerts: true) -// assert(fromViewController != nil) -// -// // Construct the "settings" view & push the "privacy settings" view. -// let navigationController = AppSettingsViewController.inModalNavigationController() -// navigationController.pushViewController(PrivacySettingsTableViewController(), animated: false) -// -// fromViewController?.present(navigationController, animated: true, completion: nil) -// }) -// } -// -// @objc func didPressDismissNag(sender: UIButton) { -// Logger.info("") -// -// markSettingsNagAsComplete() -// -// dismissIfPossible(shouldDelay: false, ignoreNag: true) -// } -// -// // We only show the "blocking" settings nag until the user has chosen -// // to view the privacy settings _or_ dismissed the nag at least once. -// // -// // In either case, we set the "CallKit enabled" and "CallKit privacy enabled" -// // settings to their default values to indicate that the user has reviewed -// // them. -// private func markSettingsNagAsComplete() { -// Logger.info("") -// -// let preferences = Environment.shared.preferences! -// -// preferences.setIsCallKitEnabled(preferences.isCallKitEnabled()) -// preferences.setIsCallKitPrivacyEnabled(preferences.isCallKitPrivacyEnabled()) -// } -// -// @objc func didTapLeaveCall(sender: UIButton) { -// OWSWindowManager.shared().leaveCallView() -// } -// -// // MARK: - CallObserver -// -// internal func stateDidChange(call: SignalCall, state: CallState) { -// AssertIsOnMainThread() -// Logger.info("new call status: \(state)") -// -// self.updateCallUI(callState: state) -// } -// -// internal func hasLocalVideoDidChange(call: SignalCall, hasLocalVideo: Bool) { -// AssertIsOnMainThread() -// self.updateCallUI(callState: call.state) -// } -// -// internal func muteDidChange(call: SignalCall, isMuted: Bool) { -// AssertIsOnMainThread() -// self.updateCallUI(callState: call.state) -// } -// -// func holdDidChange(call: SignalCall, isOnHold: Bool) { -// AssertIsOnMainThread() -// self.updateCallUI(callState: call.state) -// } -// -// internal func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) { -// AssertIsOnMainThread() -// self.updateCallUI(callState: call.state) -// } -// -// // MARK: - CallAudioServiceDelegate -// -// func callAudioService(_ callAudioService: CallAudioService, didUpdateIsSpeakerphoneEnabled isSpeakerphoneEnabled: Bool) { -// AssertIsOnMainThread() -// -// updateAudioSourceButtonIsSelected() -// } -// -// func callAudioServiceDidChangeAudioSession(_ callAudioService: CallAudioService) { -// AssertIsOnMainThread() -// -// // Which sources are available depends on the state of your Session. -// // When the audio session is not yet in PlayAndRecord none are available -// // Then if we're in speakerphone, bluetooth isn't available. -// // So we accrue all possible audio sources in a set, and that list lives as longs as the CallViewController -// // The downside of this is that if you e.g. unpair your bluetooth mid call, it will still appear as an option -// // until your next call. -// // FIXME: There's got to be a better way, but this is where I landed after a bit of work, and seems to work -// // pretty well in practice. -// let availableInputs = callAudioService.availableInputs -// self.allAudioSources.formUnion(availableInputs) -// } -// -// // MARK: - Video -// -// internal func updateLocalVideo(captureSession: AVCaptureSession?) { -// -// AssertIsOnMainThread() -// -// guard localVideoView.captureSession != captureSession else { -// Logger.debug("ignoring redundant update") -// return -// } -// -// localVideoView.captureSession = captureSession -// let isHidden = captureSession == nil -// -// Logger.info("isHidden: \(isHidden)") -// localVideoView.isHidden = isHidden -// -// updateLocalVideoLayout() -// updateAudioSourceButtonIsSelected() -// -// // Don't animate layout of local video view until it has been presented. -// if !isHidden { -// hasShownLocalVideo = true -// } -// } -// -// var hasRemoteVideoTrack: Bool { -// return self.remoteVideoTrack != nil -// } -// -// var hasUserDismissedVideoHint: Bool = false -// -// internal func updateRemoteVideoTrack(remoteVideoTrack: RTCVideoTrack?) { -// AssertIsOnMainThread() -// -// guard self.remoteVideoTrack != remoteVideoTrack else { -// Logger.debug("ignoring redundant update") -// return -// } -// -// self.remoteVideoTrack?.remove(remoteVideoView) -// self.remoteVideoTrack = nil -// remoteVideoView.renderFrame(nil) -// self.remoteVideoTrack = remoteVideoTrack -// self.remoteVideoTrack?.add(remoteVideoView) -// -// shouldRemoteVideoControlsBeHidden = false -// -// if remoteVideoTrack != nil { -// playRemoteEnabledVideoHapticFeedback() -// } -// -// updateRemoteVideoLayout() -// } -// -// // MARK: Video Haptics -// -// let feedbackGenerator = NotificationHapticFeedback() -// var lastHapticTime: TimeInterval = CACurrentMediaTime() -// func playRemoteEnabledVideoHapticFeedback() { -// let currentTime = CACurrentMediaTime() -// guard currentTime - lastHapticTime > 5 else { -// Logger.debug("ignoring haptic feedback since it's too soon") -// return -// } -// feedbackGenerator.notificationOccurred(.success) -// lastHapticTime = currentTime -// } -// -// // MARK: - Dismiss -// -// internal func dismissIfPossible(shouldDelay: Bool, ignoreNag ignoreNagParam: Bool = false, completion: (() -> Void)? = nil) { -// callUIAdapter.audioService.delegate = nil -// -// let ignoreNag: Bool = { -// // Nothing to nag about on iOS11 -// if #available(iOS 11, *) { -// return true -// } else { -// // otherwise on iOS10, nag as specified -// return ignoreNagParam -// } -// }() -// -// if hasDismissed { -// // Don't dismiss twice. -// return -// } else if !ignoreNag && -// call.direction == .incoming && -// UIDevice.current.supportsCallKit && -// (!Environment.shared.preferences.isCallKitEnabled() || -// Environment.shared.preferences.isCallKitPrivacyEnabled()) { -// -// isShowingSettingsNag = true -// -// // Update the nag view's copy to reflect the settings state. -// if Environment.shared.preferences.isCallKitEnabled() { -// settingsNagDescriptionLabel.text = NSLocalizedString("CALL_VIEW_SETTINGS_NAG_DESCRIPTION_PRIVACY", -// comment: "Reminder to the user of the benefits of disabling CallKit privacy.") -// } else { -// settingsNagDescriptionLabel.text = NSLocalizedString("CALL_VIEW_SETTINGS_NAG_DESCRIPTION_ALL", -// comment: "Reminder to the user of the benefits of enabling CallKit and disabling CallKit privacy.") -// } -// settingsNagDescriptionLabel.superview?.setNeedsLayout() -// -// if Environment.shared.preferences.isCallKitEnabledSet() || -// Environment.shared.preferences.isCallKitPrivacySet() { -// // User has already touched these preferences, only show -// // the "fleeting" nag, not the "blocking" nag. -// -// // Show nag for N seconds. -// DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [weak self] in -// guard let strongSelf = self else { return } -// strongSelf.dismissIfPossible(shouldDelay: false, ignoreNag: true) -// } -// } -// } else if shouldDelay { -// hasDismissed = true -// DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in -// guard let strongSelf = self else { return } -// strongSelf.dismissImmediately(completion: completion) -// } -// } else { -// hasDismissed = true -// dismissImmediately(completion: completion) -// } -// } -// -// internal func dismissImmediately(completion: (() -> Void)?) { -// if CallViewController.kShowCallViewOnSeparateWindow { -// OWSWindowManager.shared().endCall(self) -// completion?() -// } else { -// self.dismiss(animated: true, completion: completion) -// } -// } -// -// // MARK: - CallServiceObserver -// -// internal func didUpdateCall(call: SignalCall?) { -// // Do nothing. -// } -// -// internal func didUpdateVideoTracks(call: SignalCall?, -// localCaptureSession: AVCaptureSession?, -// remoteVideoTrack: RTCVideoTrack?) { -// AssertIsOnMainThread() -// -// updateLocalVideo(captureSession: localCaptureSession) -// updateRemoteVideoTrack(remoteVideoTrack: remoteVideoTrack) -// } -// -// // MARK: - Proximity Monitoring -// -// func ensureProximityMonitoring() { -// if #available(iOS 11, *) { -// // BUG: Adding `self` as a Weak reference to the proximityMonitoringManager results in -// // the CallViewController never being deallocated, which, besides being a memory leak -// // can interfere with subsequent video capture - presumably because the old capture -// // session is still retained via the callViewController.localVideoView. -// // -// // A code audit has not revealed a retain cycle. -// // -// // Using the XCode memory debugger shows that a strong reference is held by -// // windowManager.callNavigationController->_childViewControllers. -// // Even though, when inspecting via the debugger, the CallViewController is not shown as -// // a childViewController. -// // -// // (lldb) po [[[OWSWindowManager sharedManager] callNavigationController] childViewControllers] -// // <__NSSingleObjectArrayI 0x1c0418bd0>( -// // -// // ) -// // -// // Weirder still, when presenting another CallViewController, the old one remains unallocated -// // and inspecting it in the memory debugger shows _no_ strong references to it (yet it -// // is not deallocated). Some weak references do remain - from the proximityMonitoringManager -// // and the callObserver, both of which use the Weak struct, which could be related. -// // -// // In any case, we can apparently avoid this behavior by not adding self as a Weak lifetime -// // and as of iOS11, the system automatically managages proximityMonitoring -// // via CallKit and AudioSessions. Proximity monitoring will be enabled whenever a call -// // is active, unless we switch to VideoChat audio mode (which is actually desirable -// // behavior), so the proximityMonitoringManager is redundant for calls on iOS11+. -// } else { -// // before iOS11, manually enable proximityMonitoring while we're on a call. -// self.proximityMonitoringManager.add(lifetime: self) -// } -// } -//} -// -//extension CallViewController: CallVideoHintViewDelegate { -// func didTapCallVideoHintView(_ videoHintView: CallVideoHintView) { -// self.hasUserDismissedVideoHint = true -// updateRemoteVideoLayout() -// } -//} diff --git a/Session/Signal/CompareSafetyNumbersActivity.swift b/Session/Signal/CompareSafetyNumbersActivity.swift deleted file mode 100644 index 0d7a22222..000000000 --- a/Session/Signal/CompareSafetyNumbersActivity.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit - -let CompareSafetyNumbersActivityType = "org.whispersystems.signal.activity.CompareSafetyNumbers" - -@objc(OWSCompareSafetyNumbersActivityDelegate) -protocol CompareSafetyNumbersActivityDelegate { - func compareSafetyNumbersActivitySucceeded(activity: CompareSafetyNumbersActivity) - func compareSafetyNumbersActivity(_ activity: CompareSafetyNumbersActivity, failedWithError error: Error) -} - -@objc (OWSCompareSafetyNumbersActivity) -class CompareSafetyNumbersActivity: UIActivity { - - var mySafetyNumbers: String? - let delegate: CompareSafetyNumbersActivityDelegate - - @objc - required init(delegate: CompareSafetyNumbersActivityDelegate) { - self.delegate = delegate - super.init() - } - - // MARK: UIActivity - - override class var activityCategory: UIActivity.Category { - get { return .action } - } - - override var activityType: UIActivity.ActivityType? { - get { return UIActivity.ActivityType(rawValue: CompareSafetyNumbersActivityType) } - } - - override var activityTitle: String? { - get { - return NSLocalizedString("COMPARE_SAFETY_NUMBER_ACTION", comment: "Activity Sheet label") - } - } - - override var activityImage: UIImage? { - get { - return #imageLiteral(resourceName: "ic_lock_outline") - } - } - - override func canPerform(withActivityItems activityItems: [Any]) -> Bool { - return stringsFrom(activityItems: activityItems).count > 0 - } - - override func prepare(withActivityItems activityItems: [Any]) { - let myFormattedSafetyNumbers = stringsFrom(activityItems: activityItems).first - mySafetyNumbers = numericOnly(string: myFormattedSafetyNumbers) - } - - override func perform() { - defer { activityDidFinish(true) } - - let pasteboardString = numericOnly(string: UIPasteboard.general.string) - guard (pasteboardString != nil && pasteboardString!.count == 60) else { - Logger.warn("no valid safety numbers found in pasteboard: \(String(describing: pasteboardString))") - let error = OWSErrorWithCodeDescription(OWSErrorCode.userError, - NSLocalizedString("PRIVACY_VERIFICATION_FAILED_NO_SAFETY_NUMBERS_IN_CLIPBOARD", comment: "Alert body for user error")) - - delegate.compareSafetyNumbersActivity(self, failedWithError: error) - return - } - - let pasteboardSafetyNumbers = pasteboardString! - - if pasteboardSafetyNumbers == mySafetyNumbers { - Logger.info("successfully matched safety numbers. local numbers: \(String(describing: mySafetyNumbers)) pasteboard:\(pasteboardSafetyNumbers)") - delegate.compareSafetyNumbersActivitySucceeded(activity: self) - } else { - Logger.warn("local numbers: \(String(describing: mySafetyNumbers)) didn't match pasteboard:\(pasteboardSafetyNumbers)") - let error = OWSErrorWithCodeDescription(OWSErrorCode.privacyVerificationFailure, - NSLocalizedString("PRIVACY_VERIFICATION_FAILED_MISMATCHED_SAFETY_NUMBERS_IN_CLIPBOARD", comment: "Alert body")) - delegate.compareSafetyNumbersActivity(self, failedWithError: error) - } - } - - // MARK: Helpers - - func numericOnly(string: String?) -> String? { - guard let string = string else { - return nil - } - - var numericOnly: String? - if let regex = try? NSRegularExpression(pattern: "\\D", options: .caseInsensitive) { - numericOnly = regex.stringByReplacingMatches(in: string, options: .withTransparentBounds, range: NSRange(location: 0, length: string.utf16.count), withTemplate: "") - } - - return numericOnly - } - - func stringsFrom(activityItems: [Any]) -> [String] { - return activityItems.map { $0 as? String }.filter { $0 != nil }.map { $0! } - } -} diff --git a/Session/Signal/ConversationView/TypingIndicatorInteraction.swift b/Session/Signal/ConversationView/Cells/TypingIndicatorInteraction.swift similarity index 100% rename from Session/Signal/ConversationView/TypingIndicatorInteraction.swift rename to Session/Signal/ConversationView/Cells/TypingIndicatorInteraction.swift diff --git a/Session/Signal/LegacyNotificationsAdaptee.swift b/Session/Signal/LegacyNotificationsAdaptee.swift index 6d92bd199..10cb0e538 100644 --- a/Session/Signal/LegacyNotificationsAdaptee.swift +++ b/Session/Signal/LegacyNotificationsAdaptee.swift @@ -18,30 +18,6 @@ struct LegacyNotificationConfig { static func notificationAction(_ action: AppNotificationAction) -> UIUserNotificationAction { switch action { -// case .answerCall: -// let mutableAction = UIMutableUserNotificationAction() -// mutableAction.identifier = action.identifier -// mutableAction.title = CallStrings.answerCallButtonTitle -// mutableAction.activationMode = .foreground -// mutableAction.isDestructive = false -// mutableAction.isAuthenticationRequired = false -// return mutableAction -// case .callBack: -// let mutableAction = UIMutableUserNotificationAction() -// mutableAction.identifier = action.identifier -// mutableAction.title = CallStrings.callBackButtonTitle -// mutableAction.activationMode = .foreground -// mutableAction.isDestructive = false -// mutableAction.isAuthenticationRequired = true -// return mutableAction -// case .declineCall: -// let mutableAction = UIMutableUserNotificationAction() -// mutableAction.identifier = action.identifier -// mutableAction.title = CallStrings.declineCallButtonTitle -// mutableAction.activationMode = .background -// mutableAction.isDestructive = false -// mutableAction.isAuthenticationRequired = false -// return mutableAction case .markAsRead: let mutableAction = UIMutableUserNotificationAction() mutableAction.identifier = action.identifier @@ -283,12 +259,6 @@ public class LegacyNotificationActionHandler: NSObject { } switch action { -// case .answerCall: -// return try actionHandler.answerCall(userInfo: userInfo) -// case .callBack: -// return try actionHandler.callBack(userInfo: userInfo) -// case .declineCall: -// return try actionHandler.declineCall(userInfo: userInfo) case .markAsRead: return try actionHandler.markAsRead(userInfo: userInfo) case .reply: diff --git a/Session/Signal/MessageDetailViewController.swift b/Session/Signal/MessageDetailViewController.swift index f752c5391..89d6cdcf2 100644 --- a/Session/Signal/MessageDetailViewController.swift +++ b/Session/Signal/MessageDetailViewController.swift @@ -546,8 +546,6 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele private func string(for messageReceiptStatus: MessageReceiptStatus) -> String { switch messageReceiptStatus { - case .calculatingPoW: - return NSLocalizedString("Calculating proof of work", comment: "") case .uploading: return NSLocalizedString("MESSAGE_METADATA_VIEW_MESSAGE_STATUS_UPLOADING", comment: "Status label for messages which are uploading.") diff --git a/Session/Signal/MessageRecipientStatusUtils.swift b/Session/Signal/MessageRecipientStatusUtils.swift index 5e7f8638e..52ac383ff 100644 --- a/Session/Signal/MessageRecipientStatusUtils.swift +++ b/Session/Signal/MessageRecipientStatusUtils.swift @@ -14,7 +14,6 @@ import SignalUtilitiesKit case read case failed case skipped - case calculatingPoW } @objc @@ -165,8 +164,6 @@ public class MessageRecipientStatusUtils: NSObject { return "failed" case .skipped: return "skipped" - case .calculatingPoW: - return "calculatingPoW" } } } diff --git a/Session/Signal/NotificationSettingsOptionsViewController.m b/Session/Signal/NotificationSettingsOptionsViewController.m index 2a15a33ba..8f675bd10 100644 --- a/Session/Signal/NotificationSettingsOptionsViewController.m +++ b/Session/Signal/NotificationSettingsOptionsViewController.m @@ -63,9 +63,6 @@ { [Environment.shared.preferences setNotificationPreviewType:notificationType]; - // rebuild callUIAdapter since notification configuration changed. -// [AppEnvironment.shared.callService createCallUIAdapter]; - [self.navigationController popViewControllerAnimated:YES]; } diff --git a/Session/Signal/OnboardingCaptchaViewController.swift b/Session/Signal/OnboardingCaptchaViewController.swift deleted file mode 100644 index a9f76abcc..000000000 --- a/Session/Signal/OnboardingCaptchaViewController.swift +++ /dev/null @@ -1,201 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -/* -import UIKit -import WebKit - -@objc -public class OnboardingCaptchaViewController: OnboardingBaseViewController { - - private var webView: WKWebView? - - override public func loadView() { - super.loadView() - - view.backgroundColor = Theme.backgroundColor - view.layoutMargins = .zero - - let titleLabel = self.createTitleLabel(text: NSLocalizedString("ONBOARDING_CAPTCHA_TITLE", comment: "Title of the 'onboarding Captcha' view.")) - titleLabel.accessibilityIdentifier = "onboarding.captcha." + "titleLabel" - - let titleRow = UIStackView(arrangedSubviews: [ - titleLabel - ]) - titleRow.axis = .vertical - titleRow.alignment = .fill - titleRow.layoutMargins = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0) - titleRow.isLayoutMarginsRelativeArrangement = true - - // We want the CAPTCHA web content to "fill the screen (honoring margins)". - // The way to do this with WKWebView is to inject a javascript snippet that - // manipulates the viewport. - let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);" - let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true) - let wkUController = WKUserContentController() - wkUController.addUserScript(userScript) - let wkWebConfig = WKWebViewConfiguration() - wkWebConfig.userContentController = wkUController - let webView = WKWebView(frame: self.view.bounds, configuration: wkWebConfig) - self.webView = webView - webView.navigationDelegate = self - webView.allowsBackForwardNavigationGestures = false - webView.customUserAgent = "Signal iOS (+https://signal.org/download)" - webView.allowsLinkPreview = false - webView.scrollView.contentInset = .zero - webView.layoutMargins = .zero - webView.accessibilityIdentifier = "onboarding.captcha." + "webView" - - let stackView = UIStackView(arrangedSubviews: [ - titleRow, - webView - ]) - stackView.axis = .vertical - stackView.alignment = .fill - stackView.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) - stackView.isLayoutMarginsRelativeArrangement = true - view.addSubview(stackView) - stackView.autoPinWidthToSuperviewMargins() - stackView.autoPinEdge(.top, to: .top, of: view) - autoPinView(toBottomOfViewControllerOrKeyboard: stackView, avoidNotch: true) - - NotificationCenter.default.addObserver(self, - selector: #selector(didBecomeActive), - name: NSNotification.Name.OWSApplicationDidBecomeActive, - object: nil) - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - loadContent() - - webView?.scrollView.contentOffset = .zero - } - - public override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - webView?.scrollView.contentOffset = .zero - } - - fileprivate let contentUrl = "https://signalcaptchas.org/registration/generate.html" - - private func loadContent() { - guard let webView = webView else { - owsFailDebug("Missing webView.") - return - } - guard let url = URL(string: contentUrl) else { - owsFailDebug("Invalid URL.") - return - } - webView.load(URLRequest(url: url)) - webView.scrollView.contentOffset = .zero - } - - // MARK: - Notifications - - @objc func didBecomeActive() { - AssertIsOnMainThread() - - loadContent() - } - - // MARK: - - - private func parseCaptchaAndTryToRegister(url: URL) { - Logger.info("") - - guard let captchaToken = parseCaptcha(url: url) else { - owsFailDebug("Could not parse captcha token: \(url)") - // TODO: Alert? - // - // Reload content so user can try again. - loadContent() - return - } - onboardingController.update(captchaToken: captchaToken) - - onboardingController.tryToRegister(fromViewController: self, smsVerification: true) - } - - private func parseCaptcha(url: URL) -> String? { - Logger.info("") - - // Example URL: - // signalcaptcha://03AF6jDqXgf1PocNNrWRJEENZ9l6RAMIsUoESi2dFKkxTgE2qjdZGVjEW6SZNFQqeRRTgGqOii6zHGG--uLyC1HnhSmRt8wHeKxHcg1hsK4ucTusANIeFXVB8wPPiV7U_0w2jUFVak5clMCvW9_JBfbfzj51_e9sou8DYfwc_R6THuTBTdpSV8Nh0yJalgget-nSukCxh6FPA6hRVbw7lP3r-me1QCykHOfh-V29UVaQ4Fs5upHvwB5rtiViqT_HN8WuGmdIdGcaWxaqy1lQTgFSs2Shdj593wZiXfhJnCWAw9rMn3jSgIZhkFxdXwKOmslQ2E_I8iWkm6 - guard let host = url.host, - host.count > 0 else { - owsFailDebug("Missing host.") - return nil - } - - return host - } -} - -// MARK: - - -extension OnboardingCaptchaViewController: WKNavigationDelegate { - public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { - Logger.verbose("navigationAction: \(String(describing: navigationAction.request.url))") - - guard let url: URL = navigationAction.request.url else { - owsFailDebug("Missing URL.") - decisionHandler(.cancel) - return - } - if url.scheme == "signalcaptcha" { - decisionHandler(.cancel) - DispatchQueue.main.async { - self.parseCaptchaAndTryToRegister(url: url) - } - return - } - - // Loading the Captcha content involves a series of actions. - decisionHandler(.allow) - } - - public func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { - Logger.verbose("navigationResponse: \(String(describing: navigationResponse))") - - decisionHandler(.allow) - } - - public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - Logger.verbose("navigation: \(String(describing: navigation))") - } - - public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - Logger.verbose("navigation: \(String(describing: navigation))") - } - - public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { - Logger.verbose("navigation: \(String(describing: navigation)), error: \(error)") - } - - public func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { - Logger.verbose("navigation: \(String(describing: navigation))") - } - - public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - Logger.verbose("navigation: \(String(describing: navigation))") - } - - public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { - Logger.verbose("navigation: \(String(describing: navigation)), error: \(error)") - } - - public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { - Logger.verbose("") - } -} - */ - diff --git a/Session/Signal/PeerConnectionClient.swift b/Session/Signal/PeerConnectionClient.swift deleted file mode 100644 index 1376ebd26..000000000 --- a/Session/Signal/PeerConnectionClient.swift +++ /dev/null @@ -1,1378 +0,0 @@ -//// -//// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -//// -// -//import Foundation -//import PromiseKit -//import WebRTC -//import SignalUtilitiesKit -//import SignalUtilitiesKit -// -//// HACK - Seeing crazy SEGFAULTs on iOS9 when accessing these objc externs. -//// iOS10 seems unaffected. Reproducible for ~1 in 3 calls. -//// Binding them to a file constant seems to work around the problem. -//let kAudioTrackType = kRTCMediaStreamTrackKindAudio -//let kVideoTrackType = kRTCMediaStreamTrackKindVideo -//let kMediaConstraintsMinWidth = kRTCMediaConstraintsMinWidth -//let kMediaConstraintsMaxWidth = kRTCMediaConstraintsMaxWidth -//let kMediaConstraintsMinHeight = kRTCMediaConstraintsMinHeight -//let kMediaConstraintsMaxHeight = kRTCMediaConstraintsMaxHeight -// -///** -// * The PeerConnectionClient notifies it's delegate (the CallService) of key events in the call signaling life cycle -// * -// * The delegate's methods will always be called on the main thread. -// */ -//protocol PeerConnectionClientDelegate: class { -// -// /** -// * The connection has been established. The clients can now communicate. -// * This can be called multiple times throughout the call in the event of temporary network disconnects. -// */ -// func peerConnectionClientIceConnected(_ peerconnectionClient: PeerConnectionClient) -// -// /** -// * The connection failed to establish. The clients will not be able to communicate. -// */ -// func peerConnectionClientIceFailed(_ peerconnectionClient: PeerConnectionClient) -// -// /** -// * After initially connecting, the connection disconnected. -// * It maybe be temporary, in which case `peerConnectionClientIceConnected` will be called again once we're reconnected. -// * Otherwise, `peerConnectionClientIceFailed` will eventually called. -// */ -// func peerConnectionClientIceDisconnected(_ peerconnectionClient: PeerConnectionClient) -// -// /** -// * During the Signaling process each client generates IceCandidates locally, which contain information about how to -// * reach the local client via the internet. The delegate must shuttle these IceCandates to the other (remote) client -// * out of band, as part of establishing a connection over WebRTC. -// */ -// func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, addedLocalIceCandidate iceCandidate: RTCIceCandidate) -// -// /** -// * Once the peerconnection is established, we can receive messages via the data channel, and notify the delegate. -// */ -// func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, received dataChannelMessage: WebRTCProtoData) -// -// /** -// * Fired whenever the local video track become active or inactive. -// */ -// func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, didUpdateLocalVideoCaptureSession captureSession: AVCaptureSession?) -// -// /** -// * Fired whenever the remote video track become active or inactive. -// */ -// func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, didUpdateRemoteVideoTrack videoTrack: RTCVideoTrack?) -//} -// -//// In Swift (at least in Swift v3.3), weak variables aren't thread safe. It -//// isn't safe to resolve/acquire/lock a weak reference into a strong reference -//// while the instance might be being deallocated on another thread. -//// -//// PeerConnectionProxy provides thread-safe access to a strong reference. -//// PeerConnectionClient has an PeerConnectionProxy to itself that its many async blocks -//// (which run on more than one thread) can use to safely try to acquire a strong -//// reference to the PeerConnectionClient. In ARC we'd normally, we'd avoid -//// having an instance retain a strong reference to itself to avoid retain -//// cycles, but it's safe in this case: PeerConnectionClient is owned (and only -//// used by) a single entity CallService and CallService always calls -//// [PeerConnectionClient terminate] when it is done with a PeerConnectionClient -//// instance, so terminate is a reliable place where we can break the retain cycle. -//// -//// Note that we use the proxy in two ways: -//// -//// * As a delegate for the peer connection and the data channel, -//// safely forwarding delegate method invocations to the PCC. -//// * To safely obtain references to the PCC within the PCC's -//// async blocks. -//// -//// This should be fixed in Swift 4, but it isn't. -//// -//// To test using the following scenarios: -//// -//// * Alice and Bob place simultaneous calls to each other. Both should get busy. -//// Repeat 10-20x. Then verify that they can connect a call by having just one -//// call the other. -//// * Alice or Bob (randomly alternating) calls the other. Recipient (randomly) -//// accepts call or hangs up. If accepted, Alice or Bob (randomly) hangs up. -//// Repeat immediately, as fast as you can, 10-20x. -//class PeerConnectionProxy: NSObject, RTCPeerConnectionDelegate, RTCDataChannelDelegate { -// -// private var value: PeerConnectionClient? -// -// deinit { -// Logger.info("[PeerConnectionProxy] deinit") -// } -// -// func set(value: PeerConnectionClient) { -// objc_sync_enter(self) -// self.value = value -// objc_sync_exit(self) -// } -// -// func get() -> PeerConnectionClient? { -// objc_sync_enter(self) -// let result = value -// objc_sync_exit(self) -// -// if result == nil { -// // Every time this method returns nil is a -// // possible crash avoided. -// Logger.verbose("cleared get.") -// } -// -// return result -// } -// -// func clear() { -// Logger.info("") -// -// objc_sync_enter(self) -// value = nil -// objc_sync_exit(self) -// } -// -// // MARK: - RTCPeerConnectionDelegate -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didChange stateChanged: RTCSignalingState) { -// self.get()?.peerConnection(peerConnection, didChange: stateChanged) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didAdd stream: RTCMediaStream) { -// self.get()?.peerConnection(peerConnection, didAdd: stream) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove stream: RTCMediaStream) { -// self.get()?.peerConnection(peerConnection, didRemove: stream) -// } -// -// public func peerConnectionShouldNegotiate(_ peerConnection: RTCPeerConnection) { -// self.get()?.peerConnectionShouldNegotiate(peerConnection) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didChange newState: RTCIceConnectionState) { -// self.get()?.peerConnection(peerConnection, didChange: newState) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didChange newState: RTCIceGatheringState) { -// self.get()?.peerConnection(peerConnection, didChange: newState) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didGenerate candidate: RTCIceCandidate) { -// self.get()?.peerConnection(peerConnection, didGenerate: candidate) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove candidates: [RTCIceCandidate]) { -// self.get()?.peerConnection(peerConnection, didRemove: candidates) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didOpen dataChannel: RTCDataChannel) { -// self.get()?.peerConnection(peerConnection, didOpen: dataChannel) -// } -// -// public func peerConnection(_ peerConnection: RTCPeerConnection, didChange connectionState: RTCPeerConnectionState) { -// self.get()?.peerConnection(peerConnection, didChange: connectionState) -// } -// -// // MARK: - RTCDataChannelDelegate -// -// public func dataChannelDidChangeState(_ dataChannel: RTCDataChannel) { -// self.get()?.dataChannelDidChangeState(dataChannel) -// } -// -// public func dataChannel(_ dataChannel: RTCDataChannel, didReceiveMessageWith buffer: RTCDataBuffer) { -// self.get()?.dataChannel(dataChannel, didReceiveMessageWith: buffer) -// } -// -// public func dataChannel(_ dataChannel: RTCDataChannel, didChangeBufferedAmount amount: UInt64) { -// self.get()?.dataChannel(dataChannel, didChangeBufferedAmount: amount) -// } -//} -// -///** -// * `PeerConnectionClient` is our interface to WebRTC. -// * -// * It is primarily a wrapper around `RTCPeerConnection`, which is responsible for sending and receiving our call data -// * including audio, video, and some post-connected signaling (hangup, add video) -// */ -//class PeerConnectionClient: NSObject, RTCPeerConnectionDelegate, RTCDataChannelDelegate, VideoCaptureSettingsDelegate { -// -// enum Identifiers: String { -// case mediaStream = "ARDAMS", -// videoTrack = "ARDAMSv0", -// audioTrack = "ARDAMSa0", -// dataChannelSignaling = "signaling" -// } -// -// // A state in this class should only be accessed on this queue in order to -// // serialize access. -// // -// // This queue is also used to perform expensive calls to the WebRTC API. -// private static let signalingQueue = DispatchQueue(label: "CallServiceSignalingQueue") -// -// // Delegate is notified of key events in the call lifecycle. -// // -// // This property should only be accessed on the main thread. -// private weak var delegate: PeerConnectionClientDelegate? -// -// // Connection -// -// private var peerConnection: RTCPeerConnection? -// private let iceServers: [RTCIceServer] -// private let connectionConstraints: RTCMediaConstraints -// private let configuration: RTCConfiguration -// private let factory: RTCPeerConnectionFactory -// -// // DataChannel -// -// private var dataChannel: RTCDataChannel? -// -// // Audio -// -// private var audioSender: RTCRtpSender? -// private var audioTrack: RTCAudioTrack? -// private var audioConstraints: RTCMediaConstraints -// -// // Video -// -// private var videoCaptureController: VideoCaptureController? -// private var videoSender: RTCRtpSender? -// -// // RTCVideoTrack is fragile and prone to throwing exceptions and/or -// // causing deadlock in its destructor. Therefore we take great care -// // with this property. -// private var localVideoTrack: RTCVideoTrack? -// private var remoteVideoTrack: RTCVideoTrack? -// private var cameraConstraints: RTCMediaConstraints -// -// private let proxy = PeerConnectionProxy() -// // Note that we're deliberately leaking proxy instances using this -// // collection to avoid EXC_BAD_ACCESS. Calls are rare and the proxy -// // is tiny (a single property), so it's better to leak and be safe. -// private static var expiredProxies = [PeerConnectionProxy]() -// -// init(iceServers: [RTCIceServer], delegate: PeerConnectionClientDelegate, callDirection: CallDirection, useTurnOnly: Bool) { -// AssertIsOnMainThread() -// -// self.iceServers = iceServers -// self.delegate = delegate -// -// // Ensure we enable SW decoders to enable VP8 support -// let decoderFactory = RTCDefaultVideoDecoderFactory() -// let encoderFactory = RTCDefaultVideoEncoderFactory() -// let factory = RTCPeerConnectionFactory(encoderFactory: encoderFactory, decoderFactory: decoderFactory) -// -// self.factory = factory -// configuration = RTCConfiguration() -// configuration.iceServers = iceServers -// configuration.bundlePolicy = .maxBundle -// configuration.rtcpMuxPolicy = .require -// if useTurnOnly { -// Logger.debug("using iceTransportPolicy: relay") -// configuration.iceTransportPolicy = .relay -// } else { -// Logger.debug("using iceTransportPolicy: default") -// } -// -// let connectionConstraintsDict = ["DtlsSrtpKeyAgreement": "true"] -// connectionConstraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: connectionConstraintsDict) -// -// audioConstraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil) -// cameraConstraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil) -// -// super.init() -// -// proxy.set(value: self) -// -// peerConnection = factory.peerConnection(with: configuration, -// constraints: connectionConstraints, -// delegate: proxy) -// createAudioSender() -// createVideoSender() -// -// if callDirection == .outgoing { -// // When placing an outgoing call, it's our responsibility to create the DataChannel. -// // Recipient will not have to do this explicitly. -// createSignalingDataChannel() -// } -// } -// -// deinit { -// // TODO: We can demote this log level to debug once we're confident that -// // this class is always deallocated. -// Logger.info("[PeerConnectionClient] deinit") -// } -// -// // MARK: - Media Streams -// -// private func createSignalingDataChannel() { -// AssertIsOnMainThread() -// guard let peerConnection = peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// -// let configuration = RTCDataChannelConfiguration() -// // Insist upon an "ordered" TCP data channel for delivery reliability. -// configuration.isOrdered = true -// -// guard let dataChannel = peerConnection.dataChannel(forLabel: Identifiers.dataChannelSignaling.rawValue, -// configuration: configuration) else { -// -// // TODO fail outgoing call? -// owsFailDebug("dataChannel was unexpectedly nil") -// return -// } -// dataChannel.delegate = proxy -// -// assert(self.dataChannel == nil) -// self.dataChannel = dataChannel -// } -// -// // MARK: - Video -// -// fileprivate func createVideoSender() { -// AssertIsOnMainThread() -// Logger.debug("") -// assert(self.videoSender == nil, "\(#function) should only be called once.") -// -// guard !Platform.isSimulator else { -// Logger.warn("Refusing to create local video track on simulator which has no capture device.") -// return -// } -// guard let peerConnection = peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// -// let videoSource = factory.videoSource() -// -// let localVideoTrack = factory.videoTrack(with: videoSource, trackId: Identifiers.videoTrack.rawValue) -// self.localVideoTrack = localVideoTrack -// // Disable by default until call is connected. -// // FIXME - do we require mic permissions at this point? -// // if so maybe it would be better to not even add the track until the call is connected -// // instead of creating it and disabling it. -// localVideoTrack.isEnabled = false -// -// let capturer = RTCCameraVideoCapturer(delegate: videoSource) -// self.videoCaptureController = VideoCaptureController(capturer: capturer, settingsDelegate: self) -// -// let videoSender = peerConnection.sender(withKind: kVideoTrackType, streamId: Identifiers.mediaStream.rawValue) -// videoSender.track = localVideoTrack -// self.videoSender = videoSender -// } -// -// public func setCameraSource(isUsingFrontCamera: Bool) { -// AssertIsOnMainThread() -// -// let proxyCopy = self.proxy -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// -// guard let captureController = strongSelf.videoCaptureController else { -// owsFailDebug("captureController was unexpectedly nil") -// return -// } -// -// captureController.switchCamera(isUsingFrontCamera: isUsingFrontCamera) -// } -// } -// -// public func setLocalVideoEnabled(enabled: Bool) { -// AssertIsOnMainThread() -// let proxyCopy = self.proxy -// let completion = { -// guard let strongSelf = proxyCopy.get() else { return } -// guard let strongDelegate = strongSelf.delegate else { return } -// -// let captureSession: AVCaptureSession? = { -// guard enabled else { -// return nil -// } -// -// guard let captureController = strongSelf.videoCaptureController else { -// owsFailDebug("videoCaptureController was unexpectedly nil") -// return nil -// } -// -// return captureController.captureSession -// }() -// -// strongDelegate.peerConnectionClient(strongSelf, didUpdateLocalVideoCaptureSession: captureSession) -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard strongSelf.peerConnection != nil else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// -// guard let videoCaptureController = strongSelf.videoCaptureController else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// -// guard let localVideoTrack = strongSelf.localVideoTrack else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// localVideoTrack.isEnabled = enabled -// -// if enabled { -// Logger.debug("starting video capture") -// videoCaptureController.startCapture() -// } else { -// Logger.debug("stopping video capture") -// videoCaptureController.stopCapture() -// } -// -// DispatchQueue.main.async(execute: completion) -// } -// } -// -// // MARK: VideoCaptureSettingsDelegate -// -// var videoWidth: Int32 { -// return 400 -// } -// -// var videoHeight: Int32 { -// return 400 -// } -// -// // MARK: - Audio -// -// fileprivate func createAudioSender() { -// AssertIsOnMainThread() -// Logger.debug("") -// assert(self.audioSender == nil, "\(#function) should only be called once.") -// -// guard let peerConnection = peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// -// let audioSource = factory.audioSource(with: self.audioConstraints) -// -// let audioTrack = factory.audioTrack(with: audioSource, trackId: Identifiers.audioTrack.rawValue) -// self.audioTrack = audioTrack -// -// // Disable by default until call is connected. -// // FIXME - do we require mic permissions at this point? -// // if so maybe it would be better to not even add the track until the call is connected -// // instead of creating it and disabling it. -// audioTrack.isEnabled = false -// -// let audioSender = peerConnection.sender(withKind: kAudioTrackType, streamId: Identifiers.mediaStream.rawValue) -// audioSender.track = audioTrack -// self.audioSender = audioSender -// } -// -// public func setAudioEnabled(enabled: Bool) { -// AssertIsOnMainThread() -// let proxyCopy = self.proxy -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard strongSelf.peerConnection != nil else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// guard let audioTrack = strongSelf.audioTrack else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// -// audioTrack.isEnabled = enabled -// } -// } -// -// // MARK: - Session negotiation -// -// private var defaultOfferConstraints: RTCMediaConstraints { -// let mandatoryConstraints = [ -// "OfferToReceiveAudio": "true", -// "OfferToReceiveVideo": "true" -// ] -// return RTCMediaConstraints(mandatoryConstraints: mandatoryConstraints, optionalConstraints: nil) -// } -// -// public func createOffer() -> Promise { -// AssertIsOnMainThread() -// let proxyCopy = self.proxy -// let (promise, resolver) = Promise.pending() -// let completion: ((RTCSessionDescription?, Error?) -> Void) = { (sdp, error) in -// guard let strongSelf = proxyCopy.get() else { -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// strongSelf.assertOnSignalingQueue() -// guard strongSelf.peerConnection != nil else { -// Logger.debug("Ignoring obsolete event in terminated client") -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// if let error = error { -// resolver.reject(error) -// return -// } -// -// guard let sessionDescription = sdp else { -// Logger.error("No session description was obtained, even though there was no error reported.") -// let error = OWSErrorMakeUnableToProcessServerResponseError() -// resolver.reject(error) -// return -// } -// -// resolver.fulfill(HardenedRTCSessionDescription(rtcSessionDescription: sessionDescription)) -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// strongSelf.assertOnSignalingQueue() -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// -// peerConnection.offer(for: strongSelf.defaultOfferConstraints, completionHandler: { (sdp: RTCSessionDescription?, error: Error?) in -// PeerConnectionClient.signalingQueue.async { -// completion(sdp, error) -// } -// }) -// } -// -// return promise -// } -// -// public func setLocalSessionDescriptionInternal(_ sessionDescription: HardenedRTCSessionDescription) -> Promise { -// let proxyCopy = self.proxy -// let (promise, resolver) = Promise.pending() -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// strongSelf.assertOnSignalingQueue() -// -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// -// Logger.verbose("setting local session description: \(sessionDescription)") -// peerConnection.setLocalDescription(sessionDescription.rtcSessionDescription, completionHandler: { (error) in -// if let error = error { -// resolver.reject(error) -// } else { -// resolver.fulfill(()) -// } -// }) -// } -// return promise -// } -// -// public func setLocalSessionDescription(_ sessionDescription: HardenedRTCSessionDescription) -> Promise { -// AssertIsOnMainThread() -// let proxyCopy = self.proxy -// let (promise, resolver) = Promise.pending() -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// strongSelf.assertOnSignalingQueue() -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// -// Logger.verbose("setting local session description: \(sessionDescription)") -// peerConnection.setLocalDescription(sessionDescription.rtcSessionDescription, -// completionHandler: { error in -// if let error = error { -// resolver.reject(error) -// return -// } -// resolver.fulfill(()) -// }) -// } -// -// return promise -// } -// -// public func negotiateSessionDescription(remoteDescription: RTCSessionDescription, constraints: RTCMediaConstraints) -> Promise { -// AssertIsOnMainThread() -// let proxyCopy = self.proxy -// return setRemoteSessionDescription(remoteDescription) -// .then(on: PeerConnectionClient.signalingQueue) { _ -> Promise in -// guard let strongSelf = proxyCopy.get() else { -// return Promise(error: NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// } -// return strongSelf.negotiateAnswerSessionDescription(constraints: constraints) -// } -// } -// -// public func setRemoteSessionDescription(_ sessionDescription: RTCSessionDescription) -> Promise { -// AssertIsOnMainThread() -// let proxyCopy = self.proxy -// let (promise, resolver) = Promise.pending() -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// strongSelf.assertOnSignalingQueue() -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// Logger.verbose("setting remote description: \(sessionDescription)") -// peerConnection.setRemoteDescription(sessionDescription, -// completionHandler: { error in -// if let error = error { -// resolver.reject(error) -// return -// } -// resolver.fulfill(()) -// }) -// } -// return promise -// } -// -// private func negotiateAnswerSessionDescription(constraints: RTCMediaConstraints) -> Promise { -// assertOnSignalingQueue() -// let proxyCopy = self.proxy -// let (promise, resolver) = Promise.pending() -// let completion: ((RTCSessionDescription?, Error?) -> Void) = { (sdp, error) in -// guard let strongSelf = proxyCopy.get() else { -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// strongSelf.assertOnSignalingQueue() -// guard strongSelf.peerConnection != nil else { -// Logger.debug("Ignoring obsolete event in terminated client") -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// if let error = error { -// resolver.reject(error) -// return -// } -// -// guard let sessionDescription = sdp else { -// Logger.error("unexpected empty session description, even though no error was reported.") -// let error = OWSErrorMakeUnableToProcessServerResponseError() -// resolver.reject(error) -// return -// } -// -// let hardenedSessionDescription = HardenedRTCSessionDescription(rtcSessionDescription: sessionDescription) -// -// firstly { -// strongSelf.setLocalSessionDescriptionInternal(hardenedSessionDescription) -// }.done(on: PeerConnectionClient.signalingQueue) { -// resolver.fulfill(hardenedSessionDescription) -// }.catch { error in -// resolver.reject(error) -// }.retainUntilComplete() -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// strongSelf.assertOnSignalingQueue() -// -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// resolver.reject(NSError(domain: "Obsolete client", code: 0, userInfo: nil)) -// return -// } -// -// Logger.debug("negotiating answer session.") -// -// peerConnection.answer(for: constraints, completionHandler: { (sdp: RTCSessionDescription?, error: Error?) in -// PeerConnectionClient.signalingQueue.async { -// completion(sdp, error) -// } -// }) -// } -// return promise -// } -// -// public func addRemoteIceCandidate(_ candidate: RTCIceCandidate) { -// let proxyCopy = self.proxy -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// Logger.info("adding remote ICE candidate: \(candidate.sdp)") -// peerConnection.add(candidate) -// } -// } -// -// public func terminate() { -// AssertIsOnMainThread() -// Logger.debug("") -// -// // Clear the delegate immediately so that we can guarantee that -// // no delegate methods are called after terminate() returns. -// delegate = nil -// -// // Clear the proxy immediately so that enqueued work is aborted -// // going forward. -// PeerConnectionClient.expiredProxies.append(proxy) -// proxy.clear() -// -// // Don't use [weak self]; we always want to perform terminateInternal(). -// PeerConnectionClient.signalingQueue.async { -// self.terminateInternal() -// } -// } -// -// private func terminateInternal() { -// assertOnSignalingQueue() -// Logger.debug("") -// -// // Some notes on preventing crashes while disposing of peerConnection for video calls -// // from: https://groups.google.com/forum/#!searchin/discuss-webrtc/objc$20crash$20dealloc%7Csort:relevance/discuss-webrtc/7D-vk5yLjn8/rBW2D6EW4GYJ -// // The sequence to make it work appears to be -// // -// // [capturer stop]; // I had to add this as a method to RTCVideoCapturer -// // [localRenderer stop]; -// // [remoteRenderer stop]; -// // [peerConnection close]; -// -// // audioTrack is a strong property because we need access to it to mute/unmute, but I was seeing it -// // become nil when it was only a weak property. So we retain it and manually nil the reference here, because -// // we are likely to crash if we retain any peer connection properties when the peerconnection is released -// -// localVideoTrack?.isEnabled = false -// remoteVideoTrack?.isEnabled = false -// -// if let dataChannel = self.dataChannel { -// dataChannel.delegate = nil -// } -// -// dataChannel = nil -// audioSender = nil -// audioTrack = nil -// videoSender = nil -// localVideoTrack = nil -// remoteVideoTrack = nil -// videoCaptureController = nil -// -// if let peerConnection = peerConnection { -// peerConnection.delegate = nil -// peerConnection.close() -// } -// peerConnection = nil -// } -// -// // MARK: - Data Channel -// -// // should only be accessed on PeerConnectionClient.signalingQueue -// var pendingDataChannelMessages: [PendingDataChannelMessage] = [] -// struct PendingDataChannelMessage { -// let data: Data -// let description: String -// let isCritical: Bool -// } -// -// public func sendDataChannelMessage(data: Data, description: String, isCritical: Bool) { -// AssertIsOnMainThread() -// let proxyCopy = self.proxy -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// -// guard strongSelf.peerConnection != nil else { -// Logger.debug("Ignoring obsolete event in terminated client: \(description)") -// return -// } -// -// guard let dataChannel = strongSelf.dataChannel else { -// if isCritical { -// Logger.info("enqueuing critical data channel message for after we have a dataChannel: \(description)") -// strongSelf.pendingDataChannelMessages.append(PendingDataChannelMessage(data: data, description: description, isCritical: isCritical)) -// } else { -// Logger.error("ignoring sending \(data) for nil dataChannel: \(description)") -// } -// return -// } -// -// Logger.debug("sendDataChannelMessage trying: \(description)") -// -// let buffer = RTCDataBuffer(data: data, isBinary: false) -// let result = dataChannel.sendData(buffer) -// -// if result { -// Logger.debug("sendDataChannelMessage succeeded: \(description)") -// } else { -// Logger.warn("sendDataChannelMessage failed: \(description)") -// if isCritical { -// OWSProdError(OWSAnalyticsEvents.peerConnectionClientErrorSendDataChannelMessageFailed(), file: #file, function: #function, line: #line) -// } -// } -// } -// } -// -// // MARK: RTCDataChannelDelegate -// -// /** The data channel state changed. */ -// internal func dataChannelDidChangeState(_ dataChannel: RTCDataChannel) { -// Logger.debug("dataChannelDidChangeState: \(dataChannel)") -// } -// -// /** The data channel successfully received a data buffer. */ -// internal func dataChannel(_ dataChannel: RTCDataChannel, didReceiveMessageWith buffer: RTCDataBuffer) { -// let proxyCopy = self.proxy -// let completion: (WebRTCProtoData) -> Void = { (dataChannelMessage) in -// AssertIsOnMainThread() -// guard let strongSelf = proxyCopy.get() else { return } -// guard let strongDelegate = strongSelf.delegate else { return } -// strongDelegate.peerConnectionClient(strongSelf, received: dataChannelMessage) -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard strongSelf.peerConnection != nil else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// Logger.debug("dataChannel didReceiveMessageWith buffer:\(buffer)") -// -// var dataChannelMessage: WebRTCProtoData -// do { -// dataChannelMessage = try WebRTCProtoData.parseData(buffer.data) -// } catch { -// Logger.error("failed to parse dataProto") -// return -// } -// -// DispatchQueue.main.async { -// completion(dataChannelMessage) -// } -// } -// } -// -// /** The data channel's |bufferedAmount| changed. */ -// internal func dataChannel(_ dataChannel: RTCDataChannel, didChangeBufferedAmount amount: UInt64) { -// Logger.debug("didChangeBufferedAmount: \(amount)") -// } -// -// // MARK: - RTCPeerConnectionDelegate -// -// /** Called when the SignalingState changed. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didChange stateChanged: RTCSignalingState) { -// Logger.debug("didChange signalingState:\(stateChanged.debugDescription)") -// } -// -// /** Called when media is received on a new stream from remote peer. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didAdd stream: RTCMediaStream) { -// let proxyCopy = self.proxy -// let completion: (RTCVideoTrack) -> Void = { (remoteVideoTrack) in -// AssertIsOnMainThread() -// guard let strongSelf = proxyCopy.get() else { return } -// guard let strongDelegate = strongSelf.delegate else { return } -// -// // TODO: Consider checking for termination here. -// -// strongDelegate.peerConnectionClient(strongSelf, didUpdateRemoteVideoTrack: remoteVideoTrack) -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// guard peerConnection == peerConnectionParam else { -// owsFailDebug("mismatched peerConnection callback.") -// return -// } -// guard stream.videoTracks.count > 0 else { -// owsFailDebug("didAdd stream missing stream.") -// return -// } -// let remoteVideoTrack = stream.videoTracks[0] -// Logger.debug("didAdd stream:\(stream) video tracks: \(stream.videoTracks.count) audio tracks: \(stream.audioTracks.count)") -// -// strongSelf.remoteVideoTrack = remoteVideoTrack -// -// DispatchQueue.main.async { -// completion(remoteVideoTrack) -// } -// } -// } -// -// /** Called when a remote peer closes a stream. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didRemove stream: RTCMediaStream) { -// Logger.debug("didRemove Stream:\(stream)") -// } -// -// /** Called when negotiation is needed, for example ICE has restarted. */ -// internal func peerConnectionShouldNegotiate(_ peerConnectionParam: RTCPeerConnection) { -// Logger.debug("shouldNegotiate") -// } -// -// /** Called any time the IceConnectionState changes. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didChange newState: RTCIceConnectionState) { -// let proxyCopy = self.proxy -// let connectedCompletion : () -> Void = { -// AssertIsOnMainThread() -// guard let strongSelf = proxyCopy.get() else { return } -// guard let strongDelegate = strongSelf.delegate else { return } -// strongDelegate.peerConnectionClientIceConnected(strongSelf) -// } -// let failedCompletion : () -> Void = { -// AssertIsOnMainThread() -// guard let strongSelf = proxyCopy.get() else { return } -// guard let strongDelegate = strongSelf.delegate else { return } -// strongDelegate.peerConnectionClientIceFailed(strongSelf) -// } -// let disconnectedCompletion : () -> Void = { -// AssertIsOnMainThread() -// guard let strongSelf = proxyCopy.get() else { return } -// guard let strongDelegate = strongSelf.delegate else { return } -// strongDelegate.peerConnectionClientIceDisconnected(strongSelf) -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// guard peerConnection == peerConnectionParam else { -// owsFailDebug("mismatched peerConnection callback.") -// return -// } -// -// Logger.info("didChange IceConnectionState:\(newState.debugDescription)") -// switch newState { -// case .connected, .completed: -// DispatchQueue.main.async(execute: connectedCompletion) -// case .failed: -// Logger.warn("RTCIceConnection failed.") -// DispatchQueue.main.async(execute: failedCompletion) -// case .disconnected: -// Logger.warn("RTCIceConnection disconnected.") -// DispatchQueue.main.async(execute: disconnectedCompletion) -// default: -// Logger.debug("ignoring change IceConnectionState:\(newState.debugDescription)") -// } -// } -// } -// -// /** Called any time the IceGatheringState changes. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didChange newState: RTCIceGatheringState) { -// Logger.info("didChange IceGatheringState:\(newState.debugDescription)") -// } -// -// /** New ice candidate has been found. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didGenerate candidate: RTCIceCandidate) { -// let proxyCopy = self.proxy -// let completion: (RTCIceCandidate) -> Void = { (candidate) in -// AssertIsOnMainThread() -// guard let strongSelf = proxyCopy.get() else { return } -// guard let strongDelegate = strongSelf.delegate else { return } -// strongDelegate.peerConnectionClient(strongSelf, addedLocalIceCandidate: candidate) -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// guard peerConnection == peerConnectionParam else { -// owsFailDebug("mismatched peerConnection callback.") -// return -// } -// Logger.info("adding local ICE candidate:\(candidate.sdp)") -// DispatchQueue.main.async { -// completion(candidate) -// } -// } -// } -// -// /** Called when a group of local Ice candidates have been removed. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didRemove candidates: [RTCIceCandidate]) { -// Logger.debug("didRemove IceCandidates:\(candidates)") -// } -// -// /** New data channel has been opened. */ -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didOpen dataChannel: RTCDataChannel) { -// let proxyCopy = self.proxy -// let completion: ([PendingDataChannelMessage]) -> Void = { (pendingMessages) in -// AssertIsOnMainThread() -// guard let strongSelf = proxyCopy.get() else { return } -// pendingMessages.forEach { message in -// strongSelf.sendDataChannelMessage(data: message.data, description: message.description, isCritical: message.isCritical) -// } -// } -// -// PeerConnectionClient.signalingQueue.async { -// guard let strongSelf = proxyCopy.get() else { return } -// guard let peerConnection = strongSelf.peerConnection else { -// Logger.debug("Ignoring obsolete event in terminated client") -// return -// } -// guard peerConnection == peerConnectionParam else { -// owsFailDebug("mismatched peerConnection callback.") -// return -// } -// Logger.info("didOpen dataChannel:\(dataChannel)") -// if strongSelf.dataChannel != nil { -// owsFailDebug("dataChannel unexpectedly set twice.") -// } -// strongSelf.dataChannel = dataChannel -// dataChannel.delegate = strongSelf.proxy -// -// let pendingMessages = strongSelf.pendingDataChannelMessages -// strongSelf.pendingDataChannelMessages = [] -// DispatchQueue.main.async { -// completion(pendingMessages) -// } -// } -// } -// -// internal func peerConnection(_ peerConnectionParam: RTCPeerConnection, didChange connectionState: RTCPeerConnectionState) { -// Logger.info("didChange PeerConnectionState:\(connectionState.debugDescription)") -// } -// -// // MARK: Helpers -// -// /** -// * We synchronize access to state in this class using this queue. -// */ -// private func assertOnSignalingQueue() { -// assertOnQueue(type(of: self).signalingQueue) -// } -// -// // MARK: Test-only accessors -// -// internal func peerConnectionForTests() -> RTCPeerConnection { -// AssertIsOnMainThread() -// -// var result: RTCPeerConnection? -// PeerConnectionClient.signalingQueue.sync { -// result = peerConnection -// Logger.info("") -// } -// return result! -// } -// -// internal func dataChannelForTests() -> RTCDataChannel { -// AssertIsOnMainThread() -// -// var result: RTCDataChannel? -// PeerConnectionClient.signalingQueue.sync { -// result = dataChannel -// Logger.info("") -// } -// return result! -// } -// -// internal func flushSignalingQueueForTests() { -// AssertIsOnMainThread() -// -// PeerConnectionClient.signalingQueue.sync { -// // Noop. -// } -// } -//} -// -///** -// * Restrict an RTCSessionDescription to more secure parameters -// */ -//class HardenedRTCSessionDescription { -// let rtcSessionDescription: RTCSessionDescription -// var sdp: String { return rtcSessionDescription.sdp } -// -// init(rtcSessionDescription: RTCSessionDescription) { -// self.rtcSessionDescription = HardenedRTCSessionDescription.harden(rtcSessionDescription: rtcSessionDescription) -// } -// -// /** -// * Set some more secure parameters for the session description -// */ -// class func harden(rtcSessionDescription: RTCSessionDescription) -> RTCSessionDescription { -// var description = rtcSessionDescription.sdp -// -// // Enforce Constant bit rate. -// let cbrRegex = try! NSRegularExpression(pattern: "(a=fmtp:111 ((?!cbr=).)*)\r?\n", options: .caseInsensitive) -// description = cbrRegex.stringByReplacingMatches(in: description, options: [], range: NSRange(location: 0, length: description.utf16.count), withTemplate: "$1;cbr=1\r\n") -// -// // Strip plaintext audio-level details -// // https://tools.ietf.org/html/rfc6464 -// let audioLevelRegex = try! NSRegularExpression(pattern: ".+urn:ietf:params:rtp-hdrext:ssrc-audio-level.*\r?\n", options: .caseInsensitive) -// description = audioLevelRegex.stringByReplacingMatches(in: description, options: [], range: NSRange(location: 0, length: description.utf16.count), withTemplate: "") -// -// return RTCSessionDescription.init(type: rtcSessionDescription.type, sdp: description) -// } -// -// var logSafeDescription: String { -// #if DEBUG -// return sdp -// #else -// return redactIPV6(sdp: redactIcePwd(sdp: sdp)) -// #endif -// } -// -// private func redactIcePwd(sdp: String) -> String { -// #if DEBUG -// return sdp -// #else -// var text = sdp -// text = text.replacingOccurrences(of: "\r", with: "\n") -// text = text.replacingOccurrences(of: "\n\n", with: "\n") -// let lines = text.components(separatedBy: "\n") -// let filteredLines: [String] = lines.map { line in -// guard !line.contains("ice-pwd") else { -// return "[ REDACTED ice-pwd ]" -// } -// return line -// } -// let filteredText = filteredLines.joined(separator: "\n") -// return filteredText -// #endif -// } -// -// private func redactIPV6(sdp: String) -> String { -// #if DEBUG -// return sdp -// #else -// -// // Example values to match: -// // -// // * 2001:0db8:85a3:0000:0000:8a2e:0370:7334 -// // * 2001:db8:85a3::8a2e:370:7334 -// // * ::1 -// // * :: -// // * ::ffff:192.0.2.128 -// // -// // See: https://en.wikipedia.org/wiki/IPv6_addresshttps://en.wikipedia.org/wiki/IPv6_address -// do { -// let regex = try NSRegularExpression(pattern: "[\\da-f]*:[\\da-f]*:[\\da-f:\\.]*", -// options: .caseInsensitive) -// return regex.stringByReplacingMatches(in: sdp, options: [], range: NSRange(location: 0, length: sdp.utf16.count), withTemplate: "[ REDACTED_IPV6_ADDRESS ]") -// } catch { -// owsFailDebug("Could not redact IPv6 addresses.") -// return "[Could not redact IPv6 addresses.]" -// } -// #endif -// } -//} -// -//protocol VideoCaptureSettingsDelegate: class { -// var videoWidth: Int32 { get } -// var videoHeight: Int32 { get } -//} -// -//class VideoCaptureController { -// -// private let capturer: RTCCameraVideoCapturer -// private weak var settingsDelegate: VideoCaptureSettingsDelegate? -// private let serialQueue = DispatchQueue(label: "org.signal.videoCaptureController") -// private var isUsingFrontCamera: Bool = true -// -// public var captureSession: AVCaptureSession { -// return capturer.captureSession -// } -// -// public init(capturer: RTCCameraVideoCapturer, settingsDelegate: VideoCaptureSettingsDelegate) { -// self.capturer = capturer -// self.settingsDelegate = settingsDelegate -// } -// -// public func startCapture() { -// serialQueue.sync { [weak self] in -// guard let strongSelf = self else { -// return -// } -// -// strongSelf.startCaptureSync() -// } -// } -// -// public func stopCapture() { -// serialQueue.sync { [weak self] in -// guard let strongSelf = self else { -// return -// } -// -// strongSelf.capturer.stopCapture() -// } -// } -// -// public func switchCamera(isUsingFrontCamera: Bool) { -// serialQueue.sync { [weak self] in -// guard let strongSelf = self else { -// return -// } -// -// strongSelf.isUsingFrontCamera = isUsingFrontCamera -// strongSelf.startCaptureSync() -// } -// } -// -// private func assertIsOnSerialQueue() { -// if _isDebugAssertConfiguration(), #available(iOS 10.0, *) { -// assertOnQueue(serialQueue) -// } -// } -// -// private func startCaptureSync() { -// assertIsOnSerialQueue() -// -// let position: AVCaptureDevice.Position = isUsingFrontCamera ? .front : .back -// guard let device: AVCaptureDevice = self.device(position: position) else { -// owsFailDebug("unable to find captureDevice") -// return -// } -// -// guard let format: AVCaptureDevice.Format = self.format(device: device) else { -// owsFailDebug("unable to find captureDevice") -// return -// } -// -// let fps = self.framesPerSecond(format: format) -// capturer.startCapture(with: device, format: format, fps: fps) -// } -// -// private func device(position: AVCaptureDevice.Position) -> AVCaptureDevice? { -// let captureDevices = RTCCameraVideoCapturer.captureDevices() -// guard let device = (captureDevices.first { $0.position == position }) else { -// Logger.debug("unable to find desired position: \(position)") -// return captureDevices.first -// } -// -// return device -// } -// -// private func format(device: AVCaptureDevice) -> AVCaptureDevice.Format? { -// let formats = RTCCameraVideoCapturer.supportedFormats(for: device) -// let targetWidth = settingsDelegate?.videoWidth ?? 0 -// let targetHeight = settingsDelegate?.videoHeight ?? 0 -// -// var selectedFormat: AVCaptureDevice.Format? -// var currentDiff: Int32 = Int32.max -// -// for format in formats { -// let dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription) -// let diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height) -// if diff < currentDiff { -// selectedFormat = format -// currentDiff = diff -// } -// } -// -// if _isDebugAssertConfiguration(), let selectedFormat = selectedFormat { -// let dimension = CMVideoFormatDescriptionGetDimensions(selectedFormat.formatDescription) -// Logger.debug("selected format width: \(dimension.width) height: \(dimension.height)") -// } -// -// assert(selectedFormat != nil) -// -// return selectedFormat -// } -// -// private func framesPerSecond(format: AVCaptureDevice.Format) -> Int { -// var maxFrameRate: Float64 = 0 -// for range in format.videoSupportedFrameRateRanges { -// maxFrameRate = max(maxFrameRate, range.maxFrameRate) -// } -// -// return Int(maxFrameRate) -// } -//} -// -//// MARK: Pretty Print Objc enums. -// -//fileprivate extension RTCSignalingState { -// var debugDescription: String { -// switch self { -// case .stable: -// return "stable" -// case .haveLocalOffer: -// return "haveLocalOffer" -// case .haveLocalPrAnswer: -// return "haveLocalPrAnswer" -// case .haveRemoteOffer: -// return "haveRemoteOffer" -// case .haveRemotePrAnswer: -// return "haveRemotePrAnswer" -// case .closed: -// return "closed" -// } -// } -//} -// -//fileprivate extension RTCIceGatheringState { -// var debugDescription: String { -// switch self { -// case .new: -// return "new" -// case .gathering: -// return "gathering" -// case .complete: -// return "complete" -// } -// } -//} -// -//fileprivate extension RTCIceConnectionState { -// var debugDescription: String { -// switch self { -// case .new: -// return "new" -// case .checking: -// return "checking" -// case .connected: -// return "connected" -// case .completed: -// return "completed" -// case .failed: -// return "failed" -// case .disconnected: -// return "disconnected" -// case .closed: -// return "closed" -// case .count: -// return "count" -// } -// } -//} -// -//fileprivate extension RTCPeerConnectionState { -// var debugDescription: String { -// switch self { -// case .new: -// return "new" -// case .connecting: -// return "connecting" -// case .connected: -// return "connected" -// case .disconnected: -// return "disconnected" -// case .failed: -// return "failed" -// case .closed: -// return "closed" -// } -// } -//} diff --git a/Session/Signal/PrivacySettingsTableViewController.m b/Session/Signal/PrivacySettingsTableViewController.m index 038ff6c60..f3ad86240 100644 --- a/Session/Signal/PrivacySettingsTableViewController.m +++ b/Session/Signal/PrivacySettingsTableViewController.m @@ -269,9 +269,6 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s { OWSLogInfo(@"user toggled call kit preference: %@", (sender.isOn ? @"ON" : @"OFF")); [self.preferences setIsSystemCallLogEnabled:sender.isOn]; - - // rebuild callUIAdapter since CallKit configuration changed. -// [AppEnvironment.shared.callService createCallUIAdapter]; } - (void)didToggleEnableCallKitSwitch:(UISwitch *)sender @@ -279,9 +276,6 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s OWSLogInfo(@"user toggled call kit preference: %@", (sender.isOn ? @"ON" : @"OFF")); [self.preferences setIsCallKitEnabled:sender.isOn]; - // rebuild callUIAdapter since CallKit vs not changed. -// [AppEnvironment.shared.callService createCallUIAdapter]; - // Show/Hide dependent switch: CallKit privacy [self updateTableContents]; } diff --git a/Session/Signal/UserNotificationsAdaptee.swift b/Session/Signal/UserNotificationsAdaptee.swift index e5b9b7409..df1d622a1 100644 --- a/Session/Signal/UserNotificationsAdaptee.swift +++ b/Session/Signal/UserNotificationsAdaptee.swift @@ -27,18 +27,6 @@ class UserNotificationConfig { class func notificationAction(_ action: AppNotificationAction) -> UNNotificationAction { switch action { -// case .answerCall: -// return UNNotificationAction(identifier: action.identifier, -// title: CallStrings.answerCallButtonTitle, -// options: [.foreground]) -// case .callBack: -// return UNNotificationAction(identifier: action.identifier, -// title: CallStrings.callBackButtonTitle, -// options: [.foreground]) -// case .declineCall: -// return UNNotificationAction(identifier: action.identifier, -// title: CallStrings.declineCallButtonTitle, -// options: []) case .markAsRead: return UNNotificationAction(identifier: action.identifier, title: MessageStrings.markAsReadNotificationAction, @@ -255,12 +243,6 @@ public class UserNotificationActionHandler: NSObject { } switch action { -// case .answerCall: -// return try actionHandler.answerCall(userInfo: userInfo) -// case .callBack: -// return try actionHandler.callBack(userInfo: userInfo) -// case .declineCall: -// return try actionHandler.declineCall(userInfo: userInfo) case .markAsRead: return try actionHandler.markAsRead(userInfo: userInfo) case .reply: diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index f23f06892..b52c4960e 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ 340FC8B5204DAC8D007AEB0F /* AboutTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC893204DAC8C007AEB0F /* AboutTableViewController.m */; }; 340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */; }; 340FC8B7204DAC8D007AEB0F /* OWSConversationSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */; }; - 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */; }; 34129B8621EF877A005457A8 /* LinkPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34129B8521EF8779005457A8 /* LinkPreviewView.swift */; }; 341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 341341EE2187467900192D59 /* ConversationViewModel.m */; }; 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */; }; @@ -33,7 +32,6 @@ 3441FD9F21A3604F00BB9542 /* BackupRestoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */; }; 34480B361FD0929200BC14EF /* ShareAppExtensionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 34480B351FD0929200BC14EF /* ShareAppExtensionContext.m */; }; 344825C6211390C800DB4BD8 /* OWSOrphanDataCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */; }; - 3448E1662215B313004B052E /* OnboardingCaptchaViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */; }; 3461284B1FD0B94000532771 /* SAELoadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3461284A1FD0B93F00532771 /* SAELoadViewController.swift */; }; 3461293E1FD1D72B00532771 /* ExperienceUpgradeFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */; }; 346129991FD1E4DA00532771 /* SignalApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129971FD1E4D900532771 /* SignalApp.m */; }; @@ -66,7 +64,6 @@ 34ABC0E421DD20C500ED9469 /* ConversationMessageMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34ABC0E321DD20C500ED9469 /* ConversationMessageMapping.swift */; }; 34AC0A23211C829F00997B47 /* OWSLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 34AC0A21211C829E00997B47 /* OWSLabel.m */; }; 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B0796B1FCF46B000E248C2 /* MainAppContext.m */; }; - 34B3F8751E8DF1700035BE1A /* CallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F83B1E8DF1700035BE1A /* CallViewController.swift */; }; 34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */; }; 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */; }; 34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */; }; @@ -128,7 +125,6 @@ 455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457F671A20746193000EABCD /* QuotedReplyPreview.swift */; }; 45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */; }; 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; 45A2F005204473A3002E978A /* NewMessage.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45A2F004204473A3002E978A /* NewMessage.aifc */; }; 45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */; }; @@ -165,7 +161,6 @@ 45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; }; 45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */; }; 45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */; }; - 45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */; }; 45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; }; 45F32C222057297A00A300D5 /* MediaDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 45B9EE9B200E91FB005D2F2D /* MediaDetailViewController.m */; }; 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */; }; @@ -191,7 +186,6 @@ 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; }; 4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC613352227A00400E21A3A /* ConversationSearch.swift */; }; 4CEB78C92178EBAB00F315D2 /* OWSSessionResetJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */; }; - 4CFD151D22415AA400F2450F /* CallVideoHintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFD151C22415AA400F2450F /* CallVideoHintView.swift */; }; 4CFE6B6C21F92BA700006701 /* LegacyNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */; }; 5DF9AB212C6DB1E8BE70EFF6 /* Pods_SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB523C549815DE935E98151E /* Pods_SessionMessagingKit.framework */; }; 70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; }; @@ -347,7 +341,6 @@ C33FDC46255A581F00E217F9 /* PublicChatPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */; }; C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; }; C33FDC4A255A582000E217F9 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; }; - C33FDC4E255A582000E217F9 /* Data+Streaming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */; }; C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA96255A57FE00E217F9 /* OWSDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */; }; @@ -361,7 +354,6 @@ C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; C33FDC69255A582000E217F9 /* String+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAF255A580000E217F9 /* String+Trimming.swift */; }; - C33FDC6A255A582000E217F9 /* ProvisioningProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB0255A580000E217F9 /* ProvisioningProto.swift */; }; C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; }; C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB3255A580000E217F9 /* TSContactThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */; }; @@ -427,12 +419,9 @@ C33FDCDC255A582000E217F9 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; }; C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE3255A582000E217F9 /* NSData+Image.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB29255A580A00E217F9 /* NSData+Image.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE5255A582000E217F9 /* OWSProvisioningCipher.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */; }; C33FDCE6255A582000E217F9 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE9255A582000E217F9 /* ContactsManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCEB255A582000E217F9 /* SSKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB31255A580A00E217F9 /* SSKEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */; }; - C33FDCED255A582000E217F9 /* Provisioning.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB33255A580B00E217F9 /* Provisioning.pb.swift */; }; C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */; }; C33FDCF0255A582000E217F9 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; }; C33FDCF1255A582000E217F9 /* Storage+SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */; }; @@ -467,17 +456,14 @@ C33FDD17255A582000E217F9 /* TSErrorMessage_privateConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD19255A582000E217F9 /* YapDatabaseConnection+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD1A255A582000E217F9 /* TSMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB60255A580E00E217F9 /* TSMessage.m */; }; - C33FDD1C255A582000E217F9 /* OWSProvisioningCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB62255A580E00E217F9 /* OWSProvisioningCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */; }; C33FDD21255A582000E217F9 /* OWSMediaGalleryFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD22255A582000E217F9 /* ContentProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB68255A580F00E217F9 /* ContentProxy.swift */; }; C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB69255A580F00E217F9 /* FeatureFlags.swift */; }; - C33FDD24255A582000E217F9 /* SignalMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6A255A580F00E217F9 /* SignalMessage.swift */; }; C33FDD25255A582000E217F9 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */; }; C33FDD27255A582000E217F9 /* TSPreKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */; }; - C33FDD2A255A582000E217F9 /* OWSMessageServiceParams.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB70255A580F00E217F9 /* OWSMessageServiceParams.m */; }; C33FDD2B255A582000E217F9 /* OWSMediaGalleryFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */; }; C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB73255A581000E217F9 /* TSGroupModel.m */; }; C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */; }; @@ -508,7 +494,6 @@ C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */; }; C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */; }; - C33FDD5F255A582000E217F9 /* SignalServiceProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA5255A581400E217F9 /* SignalServiceProfile.swift */; }; C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */; }; C33FDD63255A582000E217F9 /* OWSIdentityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */; }; @@ -530,7 +515,6 @@ C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */; }; C33FDD84255A582000E217F9 /* LKGroupUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */; }; - C33FDD88255A582000E217F9 /* OWSMessageServiceParams.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */; }; C33FDD90255A582000E217F9 /* OWSUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */; }; @@ -556,7 +540,6 @@ C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC06255A581D00E217F9 /* SignalAccount.m */; }; C33FDDC1255A582000E217F9 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */; }; - C33FDDC2255A582000E217F9 /* SignalService.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC08255A581D00E217F9 /* SignalService.pb.swift */; }; C33FDDC5255A582000E217F9 /* OWSError.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0B255A581D00E217F9 /* OWSError.m */; }; C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */; }; C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC12255A581E00E217F9 /* TSConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -923,7 +906,7 @@ C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; C3D697382564DCE6004AF766 /* MessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697372564DCE6004AF766 /* MessageHandler.swift */; }; - C3D6974A2564DEDC004AF766 /* MessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697492564DEDC004AF766 /* MessageHandler.swift */; }; + C3D6974A2564DEDC004AF766 /* MessageReceiverDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; @@ -1071,9 +1054,7 @@ 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQRCodeScanningViewController.m; sourceTree = ""; }; 340FC899204DAC8D007AEB0F /* OWSConversationSettingsViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsViewDelegate.h; sourceTree = ""; }; 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSConversationSettingsViewController.m; sourceTree = ""; }; - 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddToGroupViewController.m; sourceTree = ""; }; 340FC8A0204DAC8D007AEB0F /* OWSConversationSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsViewController.h; sourceTree = ""; }; - 340FC8A4204DAC8D007AEB0F /* AddToGroupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddToGroupViewController.h; sourceTree = ""; }; 34129B8521EF8779005457A8 /* LinkPreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkPreviewView.swift; sourceTree = ""; }; 341341ED2187467900192D59 /* ConversationViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversationViewModel.h; sourceTree = ""; }; 341341EE2187467900192D59 /* ConversationViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationViewModel.m; sourceTree = ""; }; @@ -1097,7 +1078,6 @@ 34480B381FD092E300BC14EF /* SignalShareExtension-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SignalShareExtension-Prefix.pch"; sourceTree = ""; }; 344825C4211390C700DB4BD8 /* OWSOrphanDataCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOrphanDataCleaner.h; sourceTree = ""; }; 344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOrphanDataCleaner.m; sourceTree = ""; }; - 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingCaptchaViewController.swift; sourceTree = ""; }; 3461284A1FD0B93F00532771 /* SAELoadViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAELoadViewController.swift; sourceTree = ""; }; 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExperienceUpgradeFinder.swift; sourceTree = ""; }; 346129971FD1E4D900532771 /* SignalApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalApp.m; sourceTree = ""; }; @@ -1137,7 +1117,6 @@ 34B0796B1FCF46B000E248C2 /* MainAppContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainAppContext.m; sourceTree = ""; }; 34B0796C1FCF46B000E248C2 /* MainAppContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainAppContext.h; sourceTree = ""; }; 34B0796E1FD07B1E00E248C2 /* SignalShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SignalShareExtension.entitlements; sourceTree = ""; }; - 34B3F83B1E8DF1700035BE1A /* CallViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallViewController.swift; sourceTree = ""; }; 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = ""; }; 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorInteraction.swift; sourceTree = ""; }; 34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorCell.swift; sourceTree = ""; }; @@ -1222,7 +1201,6 @@ 455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 457F671A20746193000EABCD /* QuotedReplyPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuotedReplyPreview.swift; sourceTree = ""; }; 45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; - 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerConnectionClient.swift; sourceTree = ""; }; 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioningURLParser.h; sourceTree = ""; }; 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioningURLParser.m; sourceTree = ""; }; 45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Session/Meta/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; }; @@ -1263,7 +1241,6 @@ 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Session/Signal/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; }; 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncPushTokensJob.swift; sourceTree = ""; }; 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionResetJob.swift; sourceTree = ""; }; - 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompareSafetyNumbersActivity.swift; sourceTree = ""; }; 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabel.swift; sourceTree = ""; }; 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaPageViewController.swift; path = Session/Signal/MediaPageViewController.swift; sourceTree = SOURCE_ROOT; }; 4C043929220A9EC800BAEA63 /* VoiceNoteLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceNoteLock.swift; sourceTree = ""; }; @@ -1289,7 +1266,6 @@ 4CC613352227A00400E21A3A /* ConversationSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearch.swift; sourceTree = ""; }; 4CEB78C72178EBAB00F315D2 /* OWSSessionResetJobRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OWSSessionResetJobRecord.h; sourceTree = ""; }; 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OWSSessionResetJobRecord.m; sourceTree = ""; }; - 4CFD151C22415AA400F2450F /* CallVideoHintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallVideoHintView.swift; sourceTree = ""; }; 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyNotificationsAdaptee.swift; sourceTree = ""; }; 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuActionsViewController.swift; sourceTree = ""; }; 53D547348A367C8A14D37FC0 /* Pods_SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1466,7 +1442,6 @@ C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicChatPoller.swift; sourceTree = ""; }; C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFileSystem.m; sourceTree = ""; }; C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSYapDatabaseObject.m; sourceTree = ""; }; - C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Streaming.swift"; sourceTree = ""; }; C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSChunkedOutputStream.h; sourceTree = ""; }; C33FDA96255A57FE00E217F9 /* OWSDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDispatch.h; sourceTree = ""; }; C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSIncomingMessage.m; sourceTree = ""; }; @@ -1480,7 +1455,6 @@ C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = ""; }; C33FDAAA255A580000E217F9 /* NSObject+Casting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Casting.m"; sourceTree = ""; }; C33FDAAF255A580000E217F9 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = ""; }; - C33FDAB0255A580000E217F9 /* ProvisioningProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProvisioningProto.swift; sourceTree = ""; }; C33FDAB1255A580000E217F9 /* OWSStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSStorage.m; sourceTree = ""; }; C33FDAB3255A580000E217F9 /* TSContactThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSContactThread.h; sourceTree = ""; }; C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFailedMessagesJob.m; sourceTree = ""; }; @@ -1546,12 +1520,9 @@ C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMediaUtils.swift; sourceTree = ""; }; C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseSecondaryIndexes.h; sourceTree = ""; }; C33FDB29255A580A00E217F9 /* NSData+Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Image.h"; sourceTree = ""; }; - C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProvisioningCipher.m; sourceTree = ""; }; C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseView.h; sourceTree = ""; }; - C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsManagerProtocol.h; sourceTree = ""; }; C33FDB31255A580A00E217F9 /* SSKEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKEnvironment.h; sourceTree = ""; }; C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKIncrementingIdFinder.swift; sourceTree = ""; }; - C33FDB33255A580B00E217F9 /* Provisioning.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Provisioning.pb.swift; sourceTree = ""; }; C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupPoller.swift; sourceTree = ""; }; C33FDB36255A580B00E217F9 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+SnodeAPI.swift"; sourceTree = ""; }; @@ -1586,17 +1557,14 @@ C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSErrorMessage_privateConstructor.h; sourceTree = ""; }; C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseConnection+OWS.h"; sourceTree = ""; }; C33FDB60255A580E00E217F9 /* TSMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessage.m; sourceTree = ""; }; - C33FDB62255A580E00E217F9 /* OWSProvisioningCipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProvisioningCipher.h; sourceTree = ""; }; C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreKeyRefreshOperation.swift; sourceTree = ""; }; C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMediaGalleryFinder.h; sourceTree = ""; }; C33FDB68255A580F00E217F9 /* ContentProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentProxy.swift; sourceTree = ""; }; C33FDB69255A580F00E217F9 /* FeatureFlags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = ""; }; - C33FDB6A255A580F00E217F9 /* SignalMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalMessage.swift; sourceTree = ""; }; C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LKUserDefaults.swift; sourceTree = ""; }; C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNotificationCenter+OWS.m"; sourceTree = ""; }; C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSPreKeyManager.h; sourceTree = ""; }; C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingReceiptManager.m; sourceTree = ""; }; - C33FDB70255A580F00E217F9 /* OWSMessageServiceParams.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageServiceParams.m; sourceTree = ""; }; C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMediaGalleryFinder.m; sourceTree = ""; }; C33FDB73255A581000E217F9 /* TSGroupModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSGroupModel.m; sourceTree = ""; }; C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyErrorMessage.m; sourceTree = ""; }; @@ -1627,7 +1595,6 @@ C33FDBA1255A581400E217F9 /* OWSOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOperation.h; sourceTree = ""; }; C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionManagementProtocol.swift; sourceTree = ""; }; C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesConfiguration.m; sourceTree = ""; }; - C33FDBA5255A581400E217F9 /* SignalServiceProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalServiceProfile.swift; sourceTree = ""; }; C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeySendingErrorMessage.h; sourceTree = ""; }; C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSLinkPreview.swift; sourceTree = ""; }; C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIdentityManager.m; sourceTree = ""; }; @@ -1649,7 +1616,6 @@ C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreatePreKeysOperation.swift; sourceTree = ""; }; C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKGroupUtilities.h; sourceTree = ""; }; C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyReceivingErrorMessage.m; sourceTree = ""; }; - C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageServiceParams.h; sourceTree = ""; }; C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSSignalAddress.swift; sourceTree = ""; }; C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSUploadOperation.h; sourceTree = ""; }; C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageUtils.m; sourceTree = ""; }; @@ -1675,7 +1641,6 @@ C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingMessagesFinder.h; sourceTree = ""; }; C33FDC06255A581D00E217F9 /* SignalAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalAccount.m; sourceTree = ""; }; C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = ""; }; - C33FDC08255A581D00E217F9 /* SignalService.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalService.pb.swift; sourceTree = ""; }; C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = ""; }; C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInfoMessage.m; sourceTree = ""; }; C33FDC12255A581E00E217F9 /* TSConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSConstants.h; sourceTree = ""; }; @@ -1747,10 +1712,10 @@ C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SignalUtilitiesKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; - C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; + C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/Database/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; C38EF283255B6D84007E1867 /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VersionMigrations.h; path = SignalUtilitiesKit/VersionMigrations.h; sourceTree = SOURCE_ROOT; }; C38EF284255B6D84007E1867 /* AppSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppSetup.h; path = SignalUtilitiesKit/AppSetup.h; sourceTree = SOURCE_ROOT; }; - C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalKeyingStorage.h; path = SignalUtilitiesKit/SignalKeyingStorage.h; sourceTree = SOURCE_ROOT; }; + C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalKeyingStorage.h; path = SignalUtilitiesKit/Database/SignalKeyingStorage.h; sourceTree = SOURCE_ROOT; }; C38EF286255B6D85007E1867 /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VersionMigrations.m; path = SignalUtilitiesKit/VersionMigrations.m; sourceTree = SOURCE_ROOT; }; C38EF287255B6D85007E1867 /* AppSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppSetup.m; path = SignalUtilitiesKit/AppSetup.m; sourceTree = SOURCE_ROOT; }; C38EF288255B6D85007E1867 /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSounds.h; path = SignalUtilitiesKit/OWSSounds.h; sourceTree = SOURCE_ROOT; }; @@ -1760,12 +1725,12 @@ C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SignalUtilitiesKit/UI/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; }; C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIView+Utilities.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = SignalUtilitiesKit/TSUnreadIndicatorInteraction.h; sourceTree = SOURCE_ROOT; }; - C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = SignalUtilitiesKit/TSUnreadIndicatorInteraction.m; sourceTree = SOURCE_ROOT; }; - C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = "SignalUtilitiesKit/Remove Later/OWSProfileManager.m"; sourceTree = SOURCE_ROOT; }; - C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SignalUtilitiesKit/Remove Later/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; - C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = "SignalUtilitiesKit/Remove Later/OWSProfileManager.h"; sourceTree = SOURCE_ROOT; }; - C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = "SignalUtilitiesKit/Remove Later/OWSUserProfile.h"; sourceTree = SOURCE_ROOT; }; + C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.h; sourceTree = SOURCE_ROOT; }; + C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.m; sourceTree = SOURCE_ROOT; }; + C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = SignalUtilitiesKit/Remove/OWSProfileManager.m; sourceTree = SOURCE_ROOT; }; + C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = SignalUtilitiesKit/Remove/OWSUserProfile.m; sourceTree = SOURCE_ROOT; }; + C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = SignalUtilitiesKit/Remove/OWSProfileManager.h; sourceTree = SOURCE_ROOT; }; + C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = SignalUtilitiesKit/Remove/OWSUserProfile.h; sourceTree = SOURCE_ROOT; }; C38EF2E2255B6DB9007E1867 /* OWSScreenLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSScreenLock.swift; path = SignalUtilitiesKit/OWSScreenLock.swift; sourceTree = SOURCE_ROOT; }; C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUnreadIndicator.m; path = SignalUtilitiesKit/OWSUnreadIndicator.m; sourceTree = SOURCE_ROOT; }; C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FullTextSearcher.swift; path = SignalUtilitiesKit/FullTextSearcher.swift; sourceTree = SOURCE_ROOT; }; @@ -1828,8 +1793,8 @@ C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ApprovalRailCellView.swift; path = SignalUtilitiesKit/UI/ApprovalRailCellView.swift; sourceTree = SOURCE_ROOT; }; C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift; sourceTree = SOURCE_ROOT; }; C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadViewModel.swift; path = SignalUtilitiesKit/ThreadViewModel.swift; sourceTree = SOURCE_ROOT; }; - C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = SignalUtilitiesKit/OWSQuotedReplyModel.h; sourceTree = SOURCE_ROOT; }; - C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = SignalUtilitiesKit/OWSQuotedReplyModel.m; sourceTree = SOURCE_ROOT; }; + C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.h; sourceTree = SOURCE_ROOT; }; + C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.m; sourceTree = SOURCE_ROOT; }; C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorTextViewController.swift; sourceTree = SOURCE_ROOT; }; C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = SignalUtilitiesKit/UI/ImageEditorItem.swift; sourceTree = SOURCE_ROOT; }; @@ -1846,11 +1811,11 @@ C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "OWSViewController+ImageEditor.swift"; path = "SignalUtilitiesKit/UI/OWSViewController+ImageEditor.swift"; sourceTree = SOURCE_ROOT; }; C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorModel.swift; path = SignalUtilitiesKit/UI/ImageEditorModel.swift; sourceTree = SOURCE_ROOT; }; C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCanvasView.swift; path = SignalUtilitiesKit/UI/ImageEditorCanvasView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadViewHelper.m; path = SignalUtilitiesKit/ThreadViewHelper.m; sourceTree = SOURCE_ROOT; }; - C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; + C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadViewHelper.m; path = SignalUtilitiesKit/Database/ThreadViewHelper.m; sourceTree = SOURCE_ROOT; }; + C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/Database/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSearchBar.h; path = SignalUtilitiesKit/UI/OWSSearchBar.h; sourceTree = SOURCE_ROOT; }; C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisappearingTimerConfigurationView.swift; path = SignalUtilitiesKit/UI/DisappearingTimerConfigurationView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = "SignalUtilitiesKit/Remove Later/ContactCellView.m"; sourceTree = SOURCE_ROOT; }; + C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = SignalUtilitiesKit/Remove/ContactCellView.m; sourceTree = SOURCE_ROOT; }; C38EF3D7255B6DF0007E1867 /* OWSTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextField.h; path = SignalUtilitiesKit/UI/OWSTextField.h; sourceTree = SOURCE_ROOT; }; C38EF3D8255B6DF0007E1867 /* OWSTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextView.h; path = SignalUtilitiesKit/UI/OWSTextView.h; sourceTree = SOURCE_ROOT; }; C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSNavigationBar.swift; path = SignalUtilitiesKit/UI/OWSNavigationBar.swift; sourceTree = SOURCE_ROOT; }; @@ -1863,13 +1828,13 @@ C38EF3E2255B6DF3007E1867 /* GalleryRailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GalleryRailView.swift; path = SignalUtilitiesKit/UI/GalleryRailView.swift; sourceTree = SOURCE_ROOT; }; C38EF3E3255B6DF4007E1867 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoPlayerView.swift; path = SignalUtilitiesKit/UI/VideoPlayerView.swift; sourceTree = SOURCE_ROOT; }; C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CommonStrings.swift; path = SignalUtilitiesKit/CommonStrings.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E5255B6DF4007E1867 /* ContactCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactCellView.h; path = "SignalUtilitiesKit/Remove Later/ContactCellView.h"; sourceTree = SOURCE_ROOT; }; - C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactTableViewCell.h; path = "SignalUtilitiesKit/Remove Later/ContactTableViewCell.h"; sourceTree = SOURCE_ROOT; }; + C38EF3E5255B6DF4007E1867 /* ContactCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactCellView.h; path = SignalUtilitiesKit/Remove/ContactCellView.h; sourceTree = SOURCE_ROOT; }; + C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactTableViewCell.h; path = SignalUtilitiesKit/Remove/ContactTableViewCell.h; sourceTree = SOURCE_ROOT; }; C38EF3E7255B6DF5007E1867 /* OWSButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSButton.swift; path = SignalUtilitiesKit/UI/OWSButton.swift; sourceTree = SOURCE_ROOT; }; C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAlerts.swift; path = SignalUtilitiesKit/UI/OWSAlerts.swift; sourceTree = SOURCE_ROOT; }; C38EF3E9255B6DF6007E1867 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = SignalUtilitiesKit/UI/Toast.swift; sourceTree = SOURCE_ROOT; }; C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSearchBar.m; path = SignalUtilitiesKit/UI/OWSSearchBar.m; sourceTree = SOURCE_ROOT; }; - C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactTableViewCell.m; path = "SignalUtilitiesKit/Remove Later/ContactTableViewCell.m"; sourceTree = SOURCE_ROOT; }; + C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactTableViewCell.m; path = SignalUtilitiesKit/Remove/ContactTableViewCell.m; sourceTree = SOURCE_ROOT; }; C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSFlatButton.swift; path = SignalUtilitiesKit/UI/OWSFlatButton.swift; sourceTree = SOURCE_ROOT; }; C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = SignalUtilitiesKit/UI/TappableStackView.swift; sourceTree = SOURCE_ROOT; }; C38EF3EE255B6DF6007E1867 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = SignalUtilitiesKit/UI/GradientView.swift; sourceTree = SOURCE_ROOT; }; @@ -2045,7 +2010,7 @@ C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NullMessage.swift; sourceTree = ""; }; C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = ""; }; C3D697372564DCE6004AF766 /* MessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageHandler.swift; sourceTree = ""; }; - C3D697492564DEDC004AF766 /* MessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageHandler.swift; sourceTree = ""; }; + C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverDelegate.swift; sourceTree = ""; }; C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = ""; }; C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; @@ -2297,7 +2262,6 @@ 34D1F0721F8678AA0066283D /* ConversationViewLayout.m */, 341341ED2187467900192D59 /* ConversationViewModel.h */, 341341EE2187467900192D59 /* ConversationViewModel.m */, - 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */, ); path = ConversationView; sourceTree = ""; @@ -2314,6 +2278,7 @@ 34D1F0951F867BFC0066283D /* Cells */ = { isa = PBXGroup; children = ( + 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */, 34D1F0BB1F8D108C0066283D /* AttachmentUploadView.h */, 34D1F0BC1F8D108C0066283D /* AttachmentUploadView.m */, 3488F9352191CC4000E524CC /* ConversationMediaView.swift */, @@ -2370,10 +2335,10 @@ 76EB03C118170B33006006FC /* Signal */ = { isa = PBXGroup; children = ( + 3448BFC01EDF0EA7005B2D69 /* ConversationView */, 76EB03C218170B33006006FC /* AppDelegate.h */, 76EB03C318170B33006006FC /* AppDelegate.m */, 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */, - 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */, 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */, 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */, 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */, @@ -2391,7 +2356,6 @@ 4CEB78C72178EBAB00F315D2 /* OWSSessionResetJobRecord.h */, 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */, 451166BF1FD86B98000739BA /* AccountManager.swift */, - 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */, 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */, 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */, 4CB5F26820F7D060004D1B42 /* MessageActions.swift */, @@ -2399,8 +2363,6 @@ 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */, 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */, 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */, - 34B3F83B1E8DF1700035BE1A /* CallViewController.swift */, - 4CFD151C22415AA400F2450F /* CallVideoHintView.swift */, 340FC884204DAC8C007AEB0F /* AboutTableViewController.h */, 340FC893204DAC8C007AEB0F /* AboutTableViewController.m */, 340FC892204DAC8C007AEB0F /* AddToBlockListViewController.h */, @@ -2439,10 +2401,8 @@ 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */, 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */, 3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */, - 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */, - 340FC8A4204DAC8D007AEB0F /* AddToGroupViewController.h */, - 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */, 340FC8A0204DAC8D007AEB0F /* OWSConversationSettingsViewController.h */, + 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */, 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */, 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */, 4CA46F4B219CCC630038ABDE /* CaptionView.swift */, @@ -2494,11 +2454,9 @@ 450DF2041E0D74AC003D14BE /* Platform.swift */, 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */, 4CC613352227A00400E21A3A /* ConversationSearch.swift */, - 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */, 340FC899204DAC8D007AEB0F /* OWSConversationSettingsViewDelegate.h */, - 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */, - 3448BFC01EDF0EA7005B2D69 /* ConversationView */, 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */, + 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */, ); path = Signal; sourceTree = ""; @@ -2817,13 +2775,13 @@ isa = PBXGroup; children = ( C33FD9B7255A54A300E217F9 /* Meta */, + C3851CE3256250FA0061EEB0 /* Remove */, + C38BBA17255E327A0041B9A3 /* Move to Session */, C3CA3B11255CF17200F4C6D4 /* Utilities */, C3851CD225624B060061EEB0 /* UI */, - C3851CE3256250FA0061EEB0 /* Remove Later */, - C38BBA17255E327A0041B9A3 /* Move to main app */, C38BBA0B255E31EC0041B9A3 /* Attachments */, C38BBA0C255E32020041B9A3 /* Threads */, - C38BBA0D255E321C0041B9A3 /* Messages */, + C38BBA0D255E321C0041B9A3 /* Messaging */, C38BBA0E255E32440041B9A3 /* Database */, C33FDB8A255A581200E217F9 /* AppContext.h */, C33FDB85255A581100E217F9 /* AppContext.m */, @@ -2831,10 +2789,6 @@ C33FDB75255A581000E217F9 /* AppReadiness.m */, C33FDB4C255A580D00E217F9 /* AppVersion.h */, C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */, - C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, - C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, - C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, - C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */, C38EF2E5255B6DB9007E1867 /* AppPreferences.swift */, C38EF30B255B6DBE007E1867 /* BlockListCache.swift */, @@ -2848,36 +2802,22 @@ C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */, C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */, - C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, - C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, C38EF284255B6D84007E1867 /* AppSetup.h */, C38EF287255B6D85007E1867 /* AppSetup.m */, C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */, C38EF288255B6D85007E1867 /* OWSSounds.h */, C38EF28B255B6D86007E1867 /* OWSSounds.m */, - C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, - C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, + C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */, C38EF283255B6D84007E1867 /* VersionMigrations.h */, C38EF286255B6D85007E1867 /* VersionMigrations.m */, C33FDA8B255A57FD00E217F9 /* AppVersion.m */, - C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, - C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */, - C33FDB2F255A580A00E217F9 /* ContactsManagerProtocol.h */, C33FDB68255A580F00E217F9 /* ContentProxy.swift */, C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */, - C33FDA94255A57FE00E217F9 /* Data+Streaming.swift */, C33FDB54255A580D00E217F9 /* DataSource.h */, C33FDBB6255A581600E217F9 /* DataSource.m */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, - C33FDC16255A581E00E217F9 /* FunctionalUtil.h */, - C33FDB17255A580800E217F9 /* FunctionalUtil.m */, C33FDB87255A581100E217F9 /* JobQueue.swift */, - C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */, - C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */, - C33FDA7E255A57FB00E217F9 /* Mention.swift */, - C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, - C33FDB80255A581100E217F9 /* Notification+Loki.swift */, C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */, C33FDB0E255A580800E217F9 /* NSError+MessageSending.h */, C33FDB09255A580700E217F9 /* NSError+MessageSending.m */, @@ -2890,18 +2830,10 @@ C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */, C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */, C33FDB07255A580700E217F9 /* OWSBackupFragment.m */, - C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, - C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */, C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */, C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */, C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */, - C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, - C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, - C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, - C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */, - C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */, - C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */, C33FDA96255A57FE00E217F9 /* OWSDispatch.h */, C33FDAC3255A580200E217F9 /* OWSDispatch.m */, C33FDBF9255A581C00E217F9 /* OWSError.h */, @@ -2918,83 +2850,47 @@ C33FDBBF255A581700E217F9 /* OWSHTTPSecurityPolicy.m */, C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */, C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */, - C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, - C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, - C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */, C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */, - C33FDBCE255A581800E217F9 /* OWSMessageServiceParams.h */, - C33FDB70255A580F00E217F9 /* OWSMessageServiceParams.m */, - C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, - C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */, C33FDBA1255A581400E217F9 /* OWSOperation.h */, C33FDB78255A581000E217F9 /* OWSOperation.m */, - C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */, - C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */, - C33FDB62255A580E00E217F9 /* OWSProvisioningCipher.h */, - C33FDB2B255A580A00E217F9 /* OWSProvisioningCipher.m */, C33FDC19255A581F00E217F9 /* OWSQueues.h */, - C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */, - C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */, - C33FDAE1255A580400E217F9 /* OWSReadTracking.h */, C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */, C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */, C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */, C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */, C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */, - C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */, C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */, C33FDB5A255A580E00E217F9 /* OWSUDManager.swift */, C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */, C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */, - C33FDB8F255A581200E217F9 /* ParamParser.swift */, - C33FDB3A255A580B00E217F9 /* Poller.swift */, C33FDB53255A580D00E217F9 /* PreKeyBundle+jsonDict.h */, C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */, C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */, - C33FDB33255A580B00E217F9 /* Provisioning.pb.swift */, - C33FDAB0255A580000E217F9 /* ProvisioningProto.swift */, C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */, - C33FDADF255A580400E217F9 /* PublicChatManager.swift */, - C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */, C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */, C33FDA98255A57FE00E217F9 /* RotateSignedKeyOperation.swift */, C33FDBAE255A581500E217F9 /* SignalAccount.h */, C33FDC06255A581D00E217F9 /* SignalAccount.m */, C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */, C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */, - C33FDB6A255A580F00E217F9 /* SignalMessage.swift */, C33FDAEC255A580500E217F9 /* SignalRecipient.h */, C33FDBB7255A581600E217F9 /* SignalRecipient.m */, - C33FDC08255A581D00E217F9 /* SignalService.pb.swift */, - C33FDBA5255A581400E217F9 /* SignalServiceProfile.swift */, C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, - C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */, C33FDACD255A580200E217F9 /* SSKJobRecord.m */, C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */, C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */, - C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, - C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, C33FDB94255A581300E217F9 /* TSAccountManager.h */, C33FDB88255A581200E217F9 /* TSAccountManager.m */, C33FDC12255A581E00E217F9 /* TSConstants.h */, C33FDABE255A580100E217F9 /* TSConstants.m */, - C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, - C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */, - C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */, - C33FDB46255A580C00E217F9 /* TSDatabaseView.m */, C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */, C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */, - C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, - C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, - C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */, C37F53E8255BA9BB002AEA92 /* Environment.h */, C37F5402255BA9ED002AEA92 /* Environment.m */, - B8C2B33B2563770800551B4D /* ThreadUtil.h */, - B8C2B331256376F000551B4D /* ThreadUtil.m */, ); path = SignalUtilitiesKit; sourceTree = ""; @@ -3130,9 +3026,11 @@ path = UI; sourceTree = ""; }; - C3851CE3256250FA0061EEB0 /* Remove Later */ = { + C3851CE3256250FA0061EEB0 /* Remove */ = { isa = PBXGroup; children = ( + C33FDB19255A580900E217F9 /* GroupUtilities.swift */, + C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */, C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, @@ -3147,7 +3045,7 @@ C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */, C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */, ); - path = "Remove Later"; + path = Remove; sourceTree = ""; }; C38BBA0B255E31EC0041B9A3 /* Attachments */ = { @@ -3167,6 +3065,8 @@ C38BBA0C255E32020041B9A3 /* Threads */ = { isa = PBXGroup; children = ( + B8C2B33B2563770800551B4D /* ThreadUtil.h */, + B8C2B331256376F000551B4D /* ThreadUtil.m */, C33FDAB3255A580000E217F9 /* TSContactThread.h */, C33FDAF9255A580600E217F9 /* TSContactThread.m */, C33FDB0A255A580700E217F9 /* TSGroupModel.h */, @@ -3179,9 +3079,34 @@ path = Threads; sourceTree = ""; }; - C38BBA0D255E321C0041B9A3 /* Messages */ = { + C38BBA0D255E321C0041B9A3 /* Messaging */ = { isa = PBXGroup; children = ( + C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, + C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, + C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, + C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, + C33FDA7E255A57FB00E217F9 /* Mention.swift */, + C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, + C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, + C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, + C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, + C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */, + C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */, + C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */, + C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, + C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, + C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, + C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, + C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, + C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, + C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */, + C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */, + C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */, + C33FDAE1255A580400E217F9 /* OWSReadTracking.h */, + C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */, + C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */, + C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */, C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, @@ -3206,12 +3131,24 @@ C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */, C33FDB83255A581100E217F9 /* TSQuotedMessage.m */, ); - path = Messages; + path = Messaging; sourceTree = ""; }; C38BBA0E255E32440041B9A3 /* Database */ = { isa = PBXGroup; children = ( + C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, + C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, + C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, + C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, + C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, + C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, + C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, + C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */, + C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */, + C33FDB46255A580C00E217F9 /* TSDatabaseView.m */, + C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, + C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, @@ -3242,9 +3179,15 @@ path = Database; sourceTree = ""; }; - C38BBA17255E327A0041B9A3 /* Move to main app */ = { + C38BBA17255E327A0041B9A3 /* Move to Session */ = { isa = PBXGroup; children = ( + C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, + C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, + C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */, + C33FDB3A255A580B00E217F9 /* Poller.swift */, + C33FDADF255A580400E217F9 /* PublicChatManager.swift */, + C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */, C3EEA016256487B300C338BC /* LokiDatabaseUtilities.swift */, C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */, C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */, @@ -3257,7 +3200,7 @@ C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */, ); - path = "Move to main app"; + path = "Move to Session"; sourceTree = ""; }; C396DAE72518407300FF6DC5 /* SwiftCSV */ = { @@ -3630,12 +3573,16 @@ C3CA3B11255CF17200F4C6D4 /* Utilities */ = { isa = PBXGroup; children = ( + C33FDC16255A581E00E217F9 /* FunctionalUtil.h */, + C33FDB17255A580800E217F9 /* FunctionalUtil.m */, + C33FDB80255A581100E217F9 /* Notification+Loki.swift */, + C33FDB8F255A581200E217F9 /* ParamParser.swift */, + C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, + C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, - C33FDB19255A580900E217F9 /* GroupUtilities.swift */, C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, - C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, C33FDB81255A581100E217F9 /* UIImage+OWS.m */, C33FDB49255A580C00E217F9 /* WeakTimer.swift */, @@ -3816,7 +3763,7 @@ C3550A02255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift */, C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */, C3F0A5EB255C970D007BE2A3 /* Configuration.swift */, - C3D697492564DEDC004AF766 /* MessageHandler.swift */, + C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */, B8CCF63B239757C10091D419 /* Components */, C31F812425258F9C00DD9FD9 /* Database */, C32B405424A961E1001117B5 /* Dependencies */, @@ -3895,7 +3842,6 @@ C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */, C33FDC5B255A582000E217F9 /* TSYapDatabaseObject.h in Headers */, C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */, - C33FDD88255A582000E217F9 /* OWSMessageServiceParams.h in Headers */, C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */, C33FDCC4255A582000E217F9 /* TSGroupModel.h in Headers */, C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */, @@ -3916,7 +3862,6 @@ C38EF3F1255B6DF7007E1867 /* OWSSearchBar.h in Headers */, C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */, C33FDC5A255A582000E217F9 /* OWSRecipientIdentity.h in Headers */, - C33FDD1C255A582000E217F9 /* OWSProvisioningCipher.h in Headers */, C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */, C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */, C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */, @@ -3931,7 +3876,6 @@ C38EF366255B6DCC007E1867 /* ScreenLockViewController.h in Headers */, C33FDD16255A582000E217F9 /* NSArray+Functional.h in Headers */, C38EF35B255B6DCC007E1867 /* SelectThreadViewController.h in Headers */, - C33FDCE9255A582000E217F9 /* ContactsManagerProtocol.h in Headers */, C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */, C33FDC96255A582000E217F9 /* NSObject+Casting.h in Headers */, C33FDC75255A582000E217F9 /* OWSGroupsOutputStream.h in Headers */, @@ -4898,8 +4842,6 @@ C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */, C33FDD0A255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.m in Sources */, - C33FDC4E255A582000E217F9 /* Data+Streaming.swift in Sources */, - C33FDCE5255A582000E217F9 /* OWSProvisioningCipher.m in Sources */, C33FDD1A255A582000E217F9 /* TSMessage.m in Sources */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, @@ -4915,7 +4857,6 @@ C33FDD00255A582000E217F9 /* TSDatabaseView.m in Sources */, C3EEA017256487B300C338BC /* LokiDatabaseUtilities.swift in Sources */, C33FDD3B255A582000E217F9 /* UIImage+OWS.m in Sources */, - C33FDD5F255A582000E217F9 /* SignalServiceProfile.swift in Sources */, C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */, C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */, C33FDC7E255A582000E217F9 /* TSAttachmentStream.m in Sources */, @@ -4964,7 +4905,6 @@ C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */, C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */, C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, - C33FDD2A255A582000E217F9 /* OWSMessageServiceParams.m in Sources */, C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */, C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */, C33FDC46255A581F00E217F9 /* PublicChatPoller.swift in Sources */, @@ -4990,17 +4930,14 @@ C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */, C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */, C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */, - C33FDCED255A582000E217F9 /* Provisioning.pb.swift in Sources */, C33FDCF0255A582000E217F9 /* Storage.swift in Sources */, C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */, C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */, C38EF229255B6D5D007E1867 /* SignalAttachment.swift in Sources */, - C33FDDC2255A582000E217F9 /* SignalService.pb.swift in Sources */, C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */, C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */, C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */, C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */, - C33FDC6A255A582000E217F9 /* ProvisioningProto.swift in Sources */, C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */, C38EF24B255B6D67007E1867 /* UIView+OWS.m in Sources */, C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */, @@ -5068,7 +5005,6 @@ C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */, C38EF3FE255B6DF7007E1867 /* OWSTextField.m in Sources */, C33FDC40255A581F00E217F9 /* OWSDisappearingMessagesFinder.m in Sources */, - C33FDD24255A582000E217F9 /* SignalMessage.swift in Sources */, C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */, @@ -5302,7 +5238,6 @@ C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */, B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */, C3550A03255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift in Sources */, - 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */, B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */, B879D449247E1BE300DB3608 /* PathVC.swift in Sources */, 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */, @@ -5314,7 +5249,6 @@ 348570A820F67575004FF32B /* OWSMessageHeaderView.m in Sources */, 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */, 34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */, - 4CFD151D22415AA400F2450F /* CallVideoHintView.swift in Sources */, C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */, B82B408A2399EC0600A248E7 /* FakeChatView.swift in Sources */, 343A65981FC4CFE7000477A1 /* ConversationScrollButton.m in Sources */, @@ -5328,7 +5262,6 @@ 450D19131F85236600970622 /* RemoteVideoView.m in Sources */, 34129B8621EF877A005457A8 /* LinkPreviewView.swift in Sources */, 34386A54207D271D009F5D9C /* NeverClearView.swift in Sources */, - 45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */, 451166C01FD86B98000739BA /* AccountManager.swift in Sources */, B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */, 3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */, @@ -5387,7 +5320,7 @@ 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */, 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */, 2400888E239F30A600305217 /* SessionRestorationView.swift in Sources */, - C3D6974A2564DEDC004AF766 /* MessageHandler.swift in Sources */, + C3D6974A2564DEDC004AF766 /* MessageReceiverDelegate.swift in Sources */, B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */, 34EA69402194933900702471 /* MediaDownloadView.swift in Sources */, B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */, @@ -5395,7 +5328,6 @@ 3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */, C3550A1D255DD73500194B6A /* Storage+SessionMessagingKit.swift in Sources */, C331FFF42558FF0300070591 /* PNOptionView.swift in Sources */, - 34B3F8751E8DF1700035BE1A /* CallViewController.swift in Sources */, 4C4AE6A1224AF35700D4AF6F /* SendMediaNavigationController.swift in Sources */, 45F32C222057297A00A300D5 /* MediaDetailViewController.m in Sources */, C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */, @@ -5424,7 +5356,6 @@ B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */, 34D1F0C01F8EC1760066283D /* MessageRecipientStatusUtils.swift in Sources */, 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */, - 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */, C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */, B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */, 3488F9362191CC4000E524CC /* ConversationMediaView.swift in Sources */, @@ -5452,7 +5383,6 @@ B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */, C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */, C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */, - 3448E1662215B313004B052E /* OnboardingCaptchaViewController.swift in Sources */, 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */, 340FC8AC204DAC8D007AEB0F /* PrivacySettingsTableViewController.m in Sources */, B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */, diff --git a/SignalUtilitiesKit/ContactsManagerProtocol.h b/SignalUtilitiesKit/ContactsManagerProtocol.h deleted file mode 100644 index 7dff8e6c7..000000000 --- a/SignalUtilitiesKit/ContactsManagerProtocol.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class CNContact; -@class Contact; -@class PhoneNumber; -@class SignalAccount; -@class UIImage; -@class YapDatabaseReadTransaction; - -@protocol ContactsManagerProtocol - -- (NSString *)displayNameForPhoneIdentifier:(nullable NSString *)recipientId; -- (NSString *)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId - transaction:(YapDatabaseReadTransaction *)transaction; -- (NSArray *)signalAccounts; - -- (BOOL)isSystemContact:(NSString *)recipientId; -- (BOOL)isSystemContactWithSignalAccount:(NSString *)recipientId; - -- (NSComparisonResult)compareSignalAccount:(SignalAccount *)left - withSignalAccount:(SignalAccount *)right NS_SWIFT_NAME(compare(signalAccount:with:)); - -#pragma mark - CNContacts - -- (nullable CNContact *)cnContactWithId:(nullable NSString *)contactId; -- (nullable NSData *)avatarDataForCNContactId:(nullable NSString *)contactId; -- (nullable UIImage *)avatarImageForCNContactId:(nullable NSString *)contactId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/CreatePreKeysOperation.swift b/SignalUtilitiesKit/CreatePreKeysOperation.swift index c74f96d13..cda43567c 100644 --- a/SignalUtilitiesKit/CreatePreKeysOperation.swift +++ b/SignalUtilitiesKit/CreatePreKeysOperation.swift @@ -8,7 +8,7 @@ import PromiseKit @objc(SSKCreatePreKeysOperation) public class CreatePreKeysOperation: OWSOperation { - private var primaryStorage: OWSPrimaryStorage { + private var storage: OWSPrimaryStorage { return OWSPrimaryStorage.shared() } @@ -23,7 +23,11 @@ public class CreatePreKeysOperation: OWSOperation { identityKeyManager.generateNewIdentityKeyPair() } - SessionManagementProtocol.createPreKeys() + let signedPreKeyRecord = storage.generateRandomSignedRecord() + signedPreKeyRecord.markAsAcceptedByService() + storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) + storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) + print("[Loki] Pre keys created successfully.") reportSuccess() } } diff --git a/SignalUtilitiesKit/Data+Streaming.swift b/SignalUtilitiesKit/Data+Streaming.swift deleted file mode 100644 index 745dc3792..000000000 --- a/SignalUtilitiesKit/Data+Streaming.swift +++ /dev/null @@ -1,22 +0,0 @@ - -extension Data { - - init(from inputStream: InputStream) throws { - self.init() - inputStream.open() - defer { inputStream.close() } - let bufferSize = 1024 - let buffer = UnsafeMutablePointer.allocate(capacity: bufferSize) - defer { buffer.deallocate() } - while inputStream.hasBytesAvailable { - let count = inputStream.read(buffer, maxLength: bufferSize) - if count < 0 { - throw inputStream.streamError! - } else if count == 0 { - break - } else { - append(buffer, count: count) - } - } - } -} diff --git a/SignalUtilitiesKit/OWSStorage+Subclass.h b/SignalUtilitiesKit/Database/OWSStorage+Subclass.h similarity index 100% rename from SignalUtilitiesKit/OWSStorage+Subclass.h rename to SignalUtilitiesKit/Database/OWSStorage+Subclass.h diff --git a/SignalUtilitiesKit/SSKPreferences.swift b/SignalUtilitiesKit/Database/SSKPreferences.swift similarity index 100% rename from SignalUtilitiesKit/SSKPreferences.swift rename to SignalUtilitiesKit/Database/SSKPreferences.swift diff --git a/SignalUtilitiesKit/SignalKeyingStorage.h b/SignalUtilitiesKit/Database/SignalKeyingStorage.h similarity index 100% rename from SignalUtilitiesKit/SignalKeyingStorage.h rename to SignalUtilitiesKit/Database/SignalKeyingStorage.h diff --git a/SignalUtilitiesKit/SignalKeyingStorage.m b/SignalUtilitiesKit/Database/SignalKeyingStorage.m similarity index 100% rename from SignalUtilitiesKit/SignalKeyingStorage.m rename to SignalUtilitiesKit/Database/SignalKeyingStorage.m diff --git a/SignalUtilitiesKit/TSDatabaseSecondaryIndexes.h b/SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.h similarity index 100% rename from SignalUtilitiesKit/TSDatabaseSecondaryIndexes.h rename to SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.h diff --git a/SignalUtilitiesKit/TSDatabaseSecondaryIndexes.m b/SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.m similarity index 100% rename from SignalUtilitiesKit/TSDatabaseSecondaryIndexes.m rename to SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.m diff --git a/SignalUtilitiesKit/TSDatabaseView.h b/SignalUtilitiesKit/Database/TSDatabaseView.h similarity index 100% rename from SignalUtilitiesKit/TSDatabaseView.h rename to SignalUtilitiesKit/Database/TSDatabaseView.h diff --git a/SignalUtilitiesKit/TSDatabaseView.m b/SignalUtilitiesKit/Database/TSDatabaseView.m similarity index 100% rename from SignalUtilitiesKit/TSDatabaseView.m rename to SignalUtilitiesKit/Database/TSDatabaseView.m diff --git a/SignalUtilitiesKit/TSStorageHeaders.h b/SignalUtilitiesKit/Database/TSStorageHeaders.h similarity index 100% rename from SignalUtilitiesKit/TSStorageHeaders.h rename to SignalUtilitiesKit/Database/TSStorageHeaders.h diff --git a/SignalUtilitiesKit/TSStorageKeys.h b/SignalUtilitiesKit/Database/TSStorageKeys.h similarity index 100% rename from SignalUtilitiesKit/TSStorageKeys.h rename to SignalUtilitiesKit/Database/TSStorageKeys.h diff --git a/SignalUtilitiesKit/ThreadViewHelper.h b/SignalUtilitiesKit/Database/ThreadViewHelper.h similarity index 100% rename from SignalUtilitiesKit/ThreadViewHelper.h rename to SignalUtilitiesKit/Database/ThreadViewHelper.h diff --git a/SignalUtilitiesKit/ThreadViewHelper.m b/SignalUtilitiesKit/Database/ThreadViewHelper.m similarity index 100% rename from SignalUtilitiesKit/ThreadViewHelper.m rename to SignalUtilitiesKit/Database/ThreadViewHelper.m diff --git a/SignalUtilitiesKit/FullTextSearcher.swift b/SignalUtilitiesKit/FullTextSearcher.swift index d711bd614..e0078fe3d 100644 --- a/SignalUtilitiesKit/FullTextSearcher.swift +++ b/SignalUtilitiesKit/FullTextSearcher.swift @@ -51,52 +51,23 @@ public class ConversationSearchResult: Comparable where SortKey: Compar } } -@objc -public class ContactSearchResult: NSObject, Comparable { - public let signalAccount: SignalAccount - public let contactsManager: ContactsManagerProtocol - - public var recipientId: String { - return signalAccount.recipientId - } - - init(signalAccount: SignalAccount, contactsManager: ContactsManagerProtocol) { - self.signalAccount = signalAccount - self.contactsManager = contactsManager - } - - // MARK: Comparable - - public static func < (lhs: ContactSearchResult, rhs: ContactSearchResult) -> Bool { - return lhs.contactsManager.compare(signalAccount: lhs.signalAccount, with: rhs.signalAccount) == .orderedAscending - } - - // MARK: Equatable - - public static func == (lhs: ContactSearchResult, rhs: ContactSearchResult) -> Bool { - return lhs.recipientId == rhs.recipientId - } -} - public class HomeScreenSearchResultSet: NSObject { public let searchText: String public let conversations: [ConversationSearchResult] - public let contacts: [ContactSearchResult] public let messages: [ConversationSearchResult] - public init(searchText: String, conversations: [ConversationSearchResult], contacts: [ContactSearchResult], messages: [ConversationSearchResult]) { + public init(searchText: String, conversations: [ConversationSearchResult], messages: [ConversationSearchResult]) { self.searchText = searchText self.conversations = conversations - self.contacts = contacts self.messages = messages } public class var empty: HomeScreenSearchResultSet { - return HomeScreenSearchResultSet(searchText: "", conversations: [], contacts: [], messages: []) + return HomeScreenSearchResultSet(searchText: "", conversations: [], messages: []) } public var isEmpty: Bool { - return conversations.isEmpty && contacts.isEmpty && messages.isEmpty + return conversations.isEmpty && messages.isEmpty } } @@ -138,26 +109,17 @@ public class ComposeScreenSearchResultSet: NSObject { return groups.compactMap { $0.thread.threadRecord as? TSGroupThread } } - @objc - public let signalContacts: [ContactSearchResult] - - @objc - public var signalAccounts: [SignalAccount] { - return signalContacts.map { $0.signalAccount } - } - - public init(searchText: String, groups: [GroupSearchResult], signalContacts: [ContactSearchResult]) { + public init(searchText: String, groups: [GroupSearchResult]) { self.searchText = searchText self.groups = groups - self.signalContacts = signalContacts } @objc - public static let empty = ComposeScreenSearchResultSet(searchText: "", groups: [], signalContacts: []) + public static let empty = ComposeScreenSearchResultSet(searchText: "", groups: []) @objc public var isEmpty: Bool { - return groups.isEmpty && signalContacts.isEmpty + return groups.isEmpty } } @@ -233,18 +195,13 @@ public class FullTextSearcher: NSObject { @objc public func searchForComposeScreen(searchText: String, - transaction: YapDatabaseReadTransaction, - contactsManager: ContactsManagerProtocol) -> ComposeScreenSearchResultSet { + transaction: YapDatabaseReadTransaction) -> ComposeScreenSearchResultSet { - var signalContacts: [ContactSearchResult] = [] var groups: [GroupSearchResult] = [] self.finder.enumerateObjects(searchText: searchText, transaction: transaction) { (match: Any, snippet: String?) in switch match { - case let signalAccount as SignalAccount: - let searchResult = ContactSearchResult(signalAccount: signalAccount, contactsManager: contactsManager) - signalContacts.append(searchResult) case let groupThread as TSGroupThread: let sortKey = ConversationSortKey(creationDate: groupThread.creationDate, lastMessageReceivedAtDate: groupThread.lastInteractionForInbox(transaction: transaction)?.receivedAtDate()) @@ -262,22 +219,17 @@ public class FullTextSearcher: NSObject { } } - // Order contact results by display name. - signalContacts.sort() - // Order the conversation and message results in reverse chronological order. // The contact results are pre-sorted by display name. groups.sort(by: >) - return ComposeScreenSearchResultSet(searchText: searchText, groups: groups, signalContacts: signalContacts) + return ComposeScreenSearchResultSet(searchText: searchText, groups: groups) } public func searchForHomeScreen(searchText: String, - transaction: YapDatabaseReadTransaction, - contactsManager: ContactsManagerProtocol) -> HomeScreenSearchResultSet { + transaction: YapDatabaseReadTransaction) -> HomeScreenSearchResultSet { var conversations: [ConversationSearchResult] = [] - var contacts: [ContactSearchResult] = [] var messages: [ConversationSearchResult] = [] var existingConversationRecipientIds: Set = Set() @@ -308,25 +260,17 @@ public class FullTextSearcher: NSObject { snippet: snippet) messages.append(searchResult) - } else if let signalAccount = match as? SignalAccount { - let searchResult = ContactSearchResult(signalAccount: signalAccount, contactsManager: contactsManager) - contacts.append(searchResult) } else { owsFailDebug("unhandled item: \(match)") } } - // Only show contacts which were not included in an existing 1:1 conversation. - var otherContacts: [ContactSearchResult] = contacts.filter { !existingConversationRecipientIds.contains($0.recipientId) } - // Order the conversation and message results in reverse chronological order. // The contact results are pre-sorted by display name. conversations.sort(by: >) messages.sort(by: >) - // Order "other" contact results by display name. - otherContacts.sort() - return HomeScreenSearchResultSet(searchText: searchText, conversations: conversations, contacts: otherContacts, messages: messages) + return HomeScreenSearchResultSet(searchText: searchText, conversations: conversations, messages: messages) } public func searchWithinConversation(thread: TSThread, diff --git a/SignalUtilitiesKit/Mention.swift b/SignalUtilitiesKit/Messaging/Mention.swift similarity index 100% rename from SignalUtilitiesKit/Mention.swift rename to SignalUtilitiesKit/Messaging/Mention.swift diff --git a/SignalUtilitiesKit/MentionsManager.swift b/SignalUtilitiesKit/Messaging/MentionsManager.swift similarity index 100% rename from SignalUtilitiesKit/MentionsManager.swift rename to SignalUtilitiesKit/Messaging/MentionsManager.swift diff --git a/SignalUtilitiesKit/OWSBlockingManager.h b/SignalUtilitiesKit/Messaging/OWSBlockingManager.h similarity index 100% rename from SignalUtilitiesKit/OWSBlockingManager.h rename to SignalUtilitiesKit/Messaging/OWSBlockingManager.h diff --git a/SignalUtilitiesKit/OWSBlockingManager.m b/SignalUtilitiesKit/Messaging/OWSBlockingManager.m similarity index 100% rename from SignalUtilitiesKit/OWSBlockingManager.m rename to SignalUtilitiesKit/Messaging/OWSBlockingManager.m diff --git a/SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.h b/SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.h rename to SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.h diff --git a/SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.m b/SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/OWSDisappearingConfigurationUpdateInfoMessage.m rename to SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.m diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.h b/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.h similarity index 100% rename from SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.h rename to SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.h diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.m b/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.m similarity index 100% rename from SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.m rename to SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.m diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesFinder.h b/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.h similarity index 100% rename from SignalUtilitiesKit/OWSDisappearingMessagesFinder.h rename to SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.h diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesFinder.m b/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.m similarity index 100% rename from SignalUtilitiesKit/OWSDisappearingMessagesFinder.m rename to SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.m diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesJob.h b/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.h similarity index 100% rename from SignalUtilitiesKit/OWSDisappearingMessagesJob.h rename to SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.h diff --git a/SignalUtilitiesKit/OWSDisappearingMessagesJob.m b/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.m similarity index 99% rename from SignalUtilitiesKit/OWSDisappearingMessagesJob.m rename to SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.m index 7f987a1fc..ee95b421c 100644 --- a/SignalUtilitiesKit/OWSDisappearingMessagesJob.m +++ b/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.m @@ -5,7 +5,6 @@ #import "OWSDisappearingMessagesJob.h" #import "AppContext.h" #import "AppReadiness.h" -#import "ContactsManagerProtocol.h" #import "OWSBackgroundTask.h" #import "OWSDisappearingConfigurationUpdateInfoMessage.h" #import "OWSDisappearingMessagesConfiguration.h" diff --git a/SignalUtilitiesKit/OWSIncomingMessageFinder.h b/SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.h similarity index 100% rename from SignalUtilitiesKit/OWSIncomingMessageFinder.h rename to SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.h diff --git a/SignalUtilitiesKit/OWSIncomingMessageFinder.m b/SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.m similarity index 100% rename from SignalUtilitiesKit/OWSIncomingMessageFinder.m rename to SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.m diff --git a/SignalUtilitiesKit/OWSLinkPreview.swift b/SignalUtilitiesKit/Messaging/OWSLinkPreview.swift similarity index 100% rename from SignalUtilitiesKit/OWSLinkPreview.swift rename to SignalUtilitiesKit/Messaging/OWSLinkPreview.swift diff --git a/SignalUtilitiesKit/OWSMessageUtils.h b/SignalUtilitiesKit/Messaging/OWSMessageUtils.h similarity index 100% rename from SignalUtilitiesKit/OWSMessageUtils.h rename to SignalUtilitiesKit/Messaging/OWSMessageUtils.h diff --git a/SignalUtilitiesKit/OWSMessageUtils.m b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m similarity index 100% rename from SignalUtilitiesKit/OWSMessageUtils.m rename to SignalUtilitiesKit/Messaging/OWSMessageUtils.m diff --git a/SignalUtilitiesKit/OWSOutgoingReceiptManager.h b/SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.h similarity index 100% rename from SignalUtilitiesKit/OWSOutgoingReceiptManager.h rename to SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.h diff --git a/SignalUtilitiesKit/OWSOutgoingReceiptManager.m b/SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.m similarity index 100% rename from SignalUtilitiesKit/OWSOutgoingReceiptManager.m rename to SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.m diff --git a/SignalUtilitiesKit/OWSQuotedReplyModel.h b/SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.h similarity index 100% rename from SignalUtilitiesKit/OWSQuotedReplyModel.h rename to SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.h diff --git a/SignalUtilitiesKit/OWSQuotedReplyModel.m b/SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.m similarity index 100% rename from SignalUtilitiesKit/OWSQuotedReplyModel.m rename to SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.m diff --git a/SignalUtilitiesKit/OWSReadReceiptManager.h b/SignalUtilitiesKit/Messaging/OWSReadReceiptManager.h similarity index 100% rename from SignalUtilitiesKit/OWSReadReceiptManager.h rename to SignalUtilitiesKit/Messaging/OWSReadReceiptManager.h diff --git a/SignalUtilitiesKit/OWSReadReceiptManager.m b/SignalUtilitiesKit/Messaging/OWSReadReceiptManager.m similarity index 100% rename from SignalUtilitiesKit/OWSReadReceiptManager.m rename to SignalUtilitiesKit/Messaging/OWSReadReceiptManager.m diff --git a/SignalUtilitiesKit/OWSReadTracking.h b/SignalUtilitiesKit/Messaging/OWSReadTracking.h similarity index 100% rename from SignalUtilitiesKit/OWSReadTracking.h rename to SignalUtilitiesKit/Messaging/OWSReadTracking.h diff --git a/SignalUtilitiesKit/Messages/TSErrorMessage.h b/SignalUtilitiesKit/Messaging/TSErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSErrorMessage.h rename to SignalUtilitiesKit/Messaging/TSErrorMessage.h diff --git a/SignalUtilitiesKit/Messages/TSErrorMessage.m b/SignalUtilitiesKit/Messaging/TSErrorMessage.m similarity index 99% rename from SignalUtilitiesKit/Messages/TSErrorMessage.m rename to SignalUtilitiesKit/Messaging/TSErrorMessage.m index 62464701d..09944f332 100644 --- a/SignalUtilitiesKit/Messages/TSErrorMessage.m +++ b/SignalUtilitiesKit/Messaging/TSErrorMessage.m @@ -3,7 +3,6 @@ // #import "TSErrorMessage.h" -#import "ContactsManagerProtocol.h" #import "SSKEnvironment.h" #import "TSContactThread.h" #import "TSErrorMessage_privateConstructor.h" diff --git a/SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h b/SignalUtilitiesKit/Messaging/TSErrorMessage_privateConstructor.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSErrorMessage_privateConstructor.h rename to SignalUtilitiesKit/Messaging/TSErrorMessage_privateConstructor.h diff --git a/SignalUtilitiesKit/Messages/TSIncomingMessage.h b/SignalUtilitiesKit/Messaging/TSIncomingMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSIncomingMessage.h rename to SignalUtilitiesKit/Messaging/TSIncomingMessage.h diff --git a/SignalUtilitiesKit/Messages/TSIncomingMessage.m b/SignalUtilitiesKit/Messaging/TSIncomingMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSIncomingMessage.m rename to SignalUtilitiesKit/Messaging/TSIncomingMessage.m diff --git a/SignalUtilitiesKit/Messages/TSInfoMessage.h b/SignalUtilitiesKit/Messaging/TSInfoMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSInfoMessage.h rename to SignalUtilitiesKit/Messaging/TSInfoMessage.h diff --git a/SignalUtilitiesKit/Messages/TSInfoMessage.m b/SignalUtilitiesKit/Messaging/TSInfoMessage.m similarity index 99% rename from SignalUtilitiesKit/Messages/TSInfoMessage.m rename to SignalUtilitiesKit/Messaging/TSInfoMessage.m index d47a01044..1db237167 100644 --- a/SignalUtilitiesKit/Messages/TSInfoMessage.m +++ b/SignalUtilitiesKit/Messaging/TSInfoMessage.m @@ -3,7 +3,6 @@ // #import "TSInfoMessage.h" -#import "ContactsManagerProtocol.h" #import "SSKEnvironment.h" #import #import diff --git a/SignalUtilitiesKit/Messages/TSInteraction.h b/SignalUtilitiesKit/Messaging/TSInteraction.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSInteraction.h rename to SignalUtilitiesKit/Messaging/TSInteraction.h diff --git a/SignalUtilitiesKit/Messages/TSInteraction.m b/SignalUtilitiesKit/Messaging/TSInteraction.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSInteraction.m rename to SignalUtilitiesKit/Messaging/TSInteraction.m diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.h b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.h rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.h diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.m b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSInvalidIdentityKeyErrorMessage.m rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.m diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.h rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.h diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSInvalidIdentityKeyReceivingErrorMessage.m rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.m diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.h b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.h rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.h diff --git a/SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.m b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSInvalidIdentityKeySendingErrorMessage.m rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.m diff --git a/SignalUtilitiesKit/Messages/TSMessage.h b/SignalUtilitiesKit/Messaging/TSMessage.h similarity index 99% rename from SignalUtilitiesKit/Messages/TSMessage.h rename to SignalUtilitiesKit/Messaging/TSMessage.h index ecf440bb1..6b5a1d660 100644 --- a/SignalUtilitiesKit/Messages/TSMessage.h +++ b/SignalUtilitiesKit/Messaging/TSMessage.h @@ -27,7 +27,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) BOOL isExpiringMessage; @property (nonatomic, readonly, nullable) TSQuotedMessage *quotedMessage; @property (nonatomic, nullable) OWSLinkPreview *linkPreview; -@property BOOL skipSave; // Open groups @property (nonatomic) uint64_t openGroupServerMessageID; @property (nonatomic, readonly) BOOL isOpenGroupMessage; diff --git a/SignalUtilitiesKit/Messages/TSMessage.m b/SignalUtilitiesKit/Messaging/TSMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSMessage.m rename to SignalUtilitiesKit/Messaging/TSMessage.m diff --git a/SignalUtilitiesKit/Messages/TSOutgoingMessage.h b/SignalUtilitiesKit/Messaging/TSOutgoingMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSOutgoingMessage.h rename to SignalUtilitiesKit/Messaging/TSOutgoingMessage.h diff --git a/SignalUtilitiesKit/Messages/TSOutgoingMessage.m b/SignalUtilitiesKit/Messaging/TSOutgoingMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSOutgoingMessage.m rename to SignalUtilitiesKit/Messaging/TSOutgoingMessage.m diff --git a/SignalUtilitiesKit/Messages/TSQuotedMessage.h b/SignalUtilitiesKit/Messaging/TSQuotedMessage.h similarity index 100% rename from SignalUtilitiesKit/Messages/TSQuotedMessage.h rename to SignalUtilitiesKit/Messaging/TSQuotedMessage.h diff --git a/SignalUtilitiesKit/Messages/TSQuotedMessage.m b/SignalUtilitiesKit/Messaging/TSQuotedMessage.m similarity index 100% rename from SignalUtilitiesKit/Messages/TSQuotedMessage.m rename to SignalUtilitiesKit/Messaging/TSQuotedMessage.m diff --git a/SignalUtilitiesKit/TSUnreadIndicatorInteraction.h b/SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.h similarity index 100% rename from SignalUtilitiesKit/TSUnreadIndicatorInteraction.h rename to SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.h diff --git a/SignalUtilitiesKit/TSUnreadIndicatorInteraction.m b/SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.m similarity index 100% rename from SignalUtilitiesKit/TSUnreadIndicatorInteraction.m rename to SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.m diff --git a/SignalUtilitiesKit/TypingIndicators.swift b/SignalUtilitiesKit/Messaging/TypingIndicators.swift similarity index 100% rename from SignalUtilitiesKit/TypingIndicators.swift rename to SignalUtilitiesKit/Messaging/TypingIndicators.swift diff --git a/SignalUtilitiesKit/ClosedGroupPoller.swift b/SignalUtilitiesKit/Move to Session/ClosedGroupPoller.swift similarity index 100% rename from SignalUtilitiesKit/ClosedGroupPoller.swift rename to SignalUtilitiesKit/Move to Session/ClosedGroupPoller.swift diff --git a/SignalUtilitiesKit/Utilities/LKUserDefaults.swift b/SignalUtilitiesKit/Move to Session/LKUserDefaults.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/LKUserDefaults.swift rename to SignalUtilitiesKit/Move to Session/LKUserDefaults.swift diff --git a/SignalUtilitiesKit/Move to main app/LokiDatabaseUtilities.swift b/SignalUtilitiesKit/Move to Session/LokiDatabaseUtilities.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/LokiDatabaseUtilities.swift rename to SignalUtilitiesKit/Move to Session/LokiDatabaseUtilities.swift diff --git a/SignalUtilitiesKit/LokiPushNotificationManager.swift b/SignalUtilitiesKit/Move to Session/LokiPushNotificationManager.swift similarity index 100% rename from SignalUtilitiesKit/LokiPushNotificationManager.swift rename to SignalUtilitiesKit/Move to Session/LokiPushNotificationManager.swift diff --git a/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.h b/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.h similarity index 100% rename from SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.h rename to SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.h diff --git a/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.m b/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.m similarity index 100% rename from SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.m rename to SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.m diff --git a/SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.swift b/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/OWSPrimaryStorage+Loki.swift rename to SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.swift diff --git a/SignalUtilitiesKit/Poller.swift b/SignalUtilitiesKit/Move to Session/Poller.swift similarity index 100% rename from SignalUtilitiesKit/Poller.swift rename to SignalUtilitiesKit/Move to Session/Poller.swift diff --git a/SignalUtilitiesKit/PublicChatManager.swift b/SignalUtilitiesKit/Move to Session/PublicChatManager.swift similarity index 100% rename from SignalUtilitiesKit/PublicChatManager.swift rename to SignalUtilitiesKit/Move to Session/PublicChatManager.swift diff --git a/SignalUtilitiesKit/PublicChatPoller.swift b/SignalUtilitiesKit/Move to Session/PublicChatPoller.swift similarity index 100% rename from SignalUtilitiesKit/PublicChatPoller.swift rename to SignalUtilitiesKit/Move to Session/PublicChatPoller.swift diff --git a/SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift b/SignalUtilitiesKit/Move to Session/Storage+ClosedGroups.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/Storage+ClosedGroups.swift rename to SignalUtilitiesKit/Move to Session/Storage+ClosedGroups.swift diff --git a/SignalUtilitiesKit/Move to main app/Storage+Collections.swift b/SignalUtilitiesKit/Move to Session/Storage+Collections.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/Storage+Collections.swift rename to SignalUtilitiesKit/Move to Session/Storage+Collections.swift diff --git a/SignalUtilitiesKit/Move to main app/Storage+OnionRequests.swift b/SignalUtilitiesKit/Move to Session/Storage+OnionRequests.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/Storage+OnionRequests.swift rename to SignalUtilitiesKit/Move to Session/Storage+OnionRequests.swift diff --git a/SignalUtilitiesKit/Move to main app/Storage+PublicChats.swift b/SignalUtilitiesKit/Move to Session/Storage+PublicChats.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/Storage+PublicChats.swift rename to SignalUtilitiesKit/Move to Session/Storage+PublicChats.swift diff --git a/SignalUtilitiesKit/Move to main app/Storage+SessionManagement.swift b/SignalUtilitiesKit/Move to Session/Storage+SessionManagement.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/Storage+SessionManagement.swift rename to SignalUtilitiesKit/Move to Session/Storage+SessionManagement.swift diff --git a/SignalUtilitiesKit/Move to main app/Storage+SnodeAPI.swift b/SignalUtilitiesKit/Move to Session/Storage+SnodeAPI.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/Storage+SnodeAPI.swift rename to SignalUtilitiesKit/Move to Session/Storage+SnodeAPI.swift diff --git a/SignalUtilitiesKit/Move to main app/Storage.swift b/SignalUtilitiesKit/Move to Session/Storage.swift similarity index 100% rename from SignalUtilitiesKit/Move to main app/Storage.swift rename to SignalUtilitiesKit/Move to Session/Storage.swift diff --git a/SignalUtilitiesKit/OWSContactsOutputStream.m b/SignalUtilitiesKit/OWSContactsOutputStream.m index cd0a85223..30eea5a3b 100644 --- a/SignalUtilitiesKit/OWSContactsOutputStream.m +++ b/SignalUtilitiesKit/OWSContactsOutputStream.m @@ -3,8 +3,6 @@ // #import "OWSContactsOutputStream.h" - -#import "ContactsManagerProtocol.h" #import "MIMETypeUtil.h" #import "NSData+keyVersionByte.h" #import "OWSBlockingManager.h" diff --git a/SignalUtilitiesKit/OWSMessageServiceParams.h b/SignalUtilitiesKit/OWSMessageServiceParams.h deleted file mode 100644 index 42872d680..000000000 --- a/SignalUtilitiesKit/OWSMessageServiceParams.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * Contstructs the per-device-message parameters used when submitting a message to - * the Signal Web Service. - * - * See: - * https://github.com/signalapp/libsignal-service-java/blob/master/java/src/main/java/org/whispersystems/signalservice/internal/push/OutgoingPushMessage.java - */ -@interface OWSMessageServiceParams : MTLModel - -@property (nonatomic, readonly) int type; -@property (nonatomic, readonly) NSString *destination; -@property (nonatomic, readonly) int destinationDeviceId; -@property (nonatomic, readonly) int destinationRegistrationId; -@property (nonatomic, readonly) NSString *content; -@property (nonatomic, readonly) BOOL silent; -@property (nonatomic, readonly) BOOL online; - -- (instancetype)initWithType:(TSWhisperMessageType)type - recipientId:(NSString *)destination - device:(int)deviceId - content:(NSData *)content - isSilent:(BOOL)isSilent - isOnline:(BOOL)isOnline - registrationId:(int)registrationId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSMessageServiceParams.m b/SignalUtilitiesKit/OWSMessageServiceParams.m deleted file mode 100644 index a2a66121c..000000000 --- a/SignalUtilitiesKit/OWSMessageServiceParams.m +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSMessageServiceParams.h" -#import "TSConstants.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSMessageServiceParams - -+ (NSDictionary *)JSONKeyPathsByPropertyKey -{ - return [NSDictionary mtl_identityPropertyMapWithModel:[self class]]; -} - -- (instancetype)initWithType:(TSWhisperMessageType)type - recipientId:(NSString *)destination - device:(int)deviceId - content:(NSData *)content - isSilent:(BOOL)isSilent - isOnline:(BOOL)isOnline - registrationId:(int)registrationId -{ - self = [super init]; - - if (!self) { - return self; - } - - _type = type; - _destination = destination; - _destinationDeviceId = deviceId; - _destinationRegistrationId = registrationId; - _content = [content base64EncodedString]; - _silent = isSilent; - _online = isOnline; - - return self; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSProvisioningCipher.h b/SignalUtilitiesKit/OWSProvisioningCipher.h deleted file mode 100644 index ede2142af..000000000 --- a/SignalUtilitiesKit/OWSProvisioningCipher.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSProvisioningCipher : NSObject - -@property (nonatomic, readonly) NSData *ourPublicKey; - -- (instancetype)initWithTheirPublicKey:(NSData *)theirPublicKey; -- (nullable NSData *)encrypt:(NSData *)plainText; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSProvisioningCipher.m b/SignalUtilitiesKit/OWSProvisioningCipher.m deleted file mode 100644 index e5d85bfcb..000000000 --- a/SignalUtilitiesKit/OWSProvisioningCipher.m +++ /dev/null @@ -1,157 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSProvisioningCipher.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSProvisioningCipher () - -@property (nonatomic, readonly) NSData *theirPublicKey; -@property (nonatomic, readonly) ECKeyPair *ourKeyPair; -@property (nonatomic, readonly) NSData *initializationVector; - -@end - -#pragma mark - - -@implementation OWSProvisioningCipher - -- (instancetype)initWithTheirPublicKey:(NSData *)theirPublicKey -{ - return [self initWithTheirPublicKey:theirPublicKey - ourKeyPair:[Curve25519 generateKeyPair] - initializationVector:[Cryptography generateRandomBytes:kCCBlockSizeAES128]]; -} - -// Private method which exposes dependencies for testing -- (instancetype)initWithTheirPublicKey:(NSData *)theirPublicKey - ourKeyPair:(ECKeyPair *)ourKeyPair - initializationVector:(NSData *)initializationVector -{ - self = [super init]; - if (!self) { - return self; - } - - _theirPublicKey = theirPublicKey; - _ourKeyPair = ourKeyPair; - _initializationVector = initializationVector; - - return self; -} - -- (NSData *)ourPublicKey -{ - return self.ourKeyPair.publicKey; -} - -- (nullable NSData *)encrypt:(NSData *)dataToEncrypt -{ - @try { - return [self throws_encryptWithData:dataToEncrypt]; - } @catch (NSException *exception) { - OWSFailDebug(@"exception: %@ of type: %@ with reason: %@, user info: %@.", - exception.description, - exception.name, - exception.reason, - exception.userInfo); - return nil; - } -} - -- (nullable NSData *)throws_encryptWithData:(NSData *)dataToEncrypt -{ - NSData *sharedSecret = - [Curve25519 throws_generateSharedSecretFromPublicKey:self.theirPublicKey privateKey:self.ourKeyPair.privateKey]; - - NSData *infoData = [@"TextSecure Provisioning Message" dataUsingEncoding:NSASCIIStringEncoding]; - NSData *nullSalt = [[NSMutableData dataWithLength:32] copy]; - NSData *derivedSecret = [HKDFKit deriveKey:sharedSecret info:infoData salt:nullSalt outputSize:64]; - NSData *cipherKey = [derivedSecret subdataWithRange:NSMakeRange(0, 32)]; - NSData *macKey = [derivedSecret subdataWithRange:NSMakeRange(32, 32)]; - if (cipherKey.length != 32) { - OWSFailDebug(@"Cipher Key must be 32 bytes"); - return nil; - } - if (macKey.length != 32) { - OWSFailDebug(@"Mac Key must be 32 bytes"); - return nil; - } - - u_int8_t versionByte[] = { 0x01 }; - NSMutableData *message = [NSMutableData dataWithBytes:&versionByte length:1]; - - NSData *_Nullable cipherText = [self encrypt:dataToEncrypt withKey:cipherKey]; - if (cipherText == nil) { - OWSFailDebug(@"Provisioning cipher failed."); - return nil; - } - - [message appendData:cipherText]; - - NSData *_Nullable mac = [self macForMessage:message withKey:macKey]; - if (mac == nil) { - OWSFailDebug(@"mac failed."); - return nil; - } - [message appendData:mac]; - - return [message copy]; -} - -- (nullable NSData *)encrypt:(NSData *)dataToEncrypt withKey:(NSData *)cipherKey -{ - NSData *iv = self.initializationVector; - if (iv.length != kCCBlockSizeAES128) { - OWSFailDebug(@"Unexpected length for iv"); - return nil; - } - if (dataToEncrypt.length >= SIZE_MAX - (kCCBlockSizeAES128 + iv.length)) { - OWSFailDebug(@"data is too long to encrypt."); - return nil; - } - - // allow space for message + padding any incomplete block. PKCS7 padding will always add at least one byte. - size_t ciphertextBufferSize = dataToEncrypt.length + kCCBlockSizeAES128; - - NSMutableData *ciphertextData = [[NSMutableData alloc] initWithLength:ciphertextBufferSize]; - - size_t bytesEncrypted = 0; - CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, - kCCAlgorithmAES, - kCCOptionPKCS7Padding, - cipherKey.bytes, - cipherKey.length, - iv.bytes, - dataToEncrypt.bytes, - dataToEncrypt.length, - ciphertextData.mutableBytes, - ciphertextBufferSize, - &bytesEncrypted); - - if (cryptStatus != kCCSuccess) { - OWSFailDebug(@"Encryption failed with status: %d", cryptStatus); - return nil; - } - - // message format is (iv || ciphertext) - NSMutableData *encryptedMessage = [NSMutableData new]; - [encryptedMessage appendData:iv]; - [encryptedMessage appendData:[ciphertextData subdataWithRange:NSMakeRange(0, bytesEncrypted)]]; - return [encryptedMessage copy]; -} - -- (nullable NSData *)macForMessage:(NSData *)message withKey:(NSData *)macKey -{ - return [Cryptography computeSHA256HMAC:message withHMACKey:macKey]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/PreKeyRefreshOperation.swift b/SignalUtilitiesKit/PreKeyRefreshOperation.swift index ed440fabe..077dd841b 100644 --- a/SignalUtilitiesKit/PreKeyRefreshOperation.swift +++ b/SignalUtilitiesKit/PreKeyRefreshOperation.swift @@ -16,10 +16,6 @@ public class RefreshPreKeysOperation: OWSOperation { return TSAccountManager.sharedInstance() } - private var primaryStorage: OWSPrimaryStorage { - return OWSPrimaryStorage.shared() - } - private var identityKeyManager: OWSIdentityManager { return OWSIdentityManager.shared() } @@ -33,7 +29,15 @@ public class RefreshPreKeysOperation: OWSOperation { } DispatchQueue.global().async { - SessionManagementProtocol.refreshSignedPreKey() + let storage = OWSPrimaryStorage.shared() + guard storage.currentSignedPrekeyId() == nil else { return } + let signedPreKeyRecord = storage.generateRandomSignedRecord() + signedPreKeyRecord.markAsAcceptedByService() + storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) + storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) + TSPreKeyManager.clearPreKeyUpdateFailureCount() + TSPreKeyManager.clearSignedPreKeyRecords() + print("[Loki] Signed pre key refreshed successfully.") self.reportSuccess() } } diff --git a/SignalUtilitiesKit/Provisioning.pb.swift b/SignalUtilitiesKit/Provisioning.pb.swift deleted file mode 100644 index 713fb00c9..000000000 --- a/SignalUtilitiesKit/Provisioning.pb.swift +++ /dev/null @@ -1,254 +0,0 @@ -// DO NOT EDIT. -// swift-format-ignore-file -// -// Generated by the Swift generator plugin for the protocol buffer compiler. -// Source: Provisioning.proto -// -// For information on using the generated types, please see the documentation: -// https://github.com/apple/swift-protobuf/ - -//* -// Copyright (C) 2014-2016 Open Whisper Systems -// -// Licensed according to the LICENSE file in this repository. - -/// iOS - since we use a modern proto-compiler, we must specify -/// the legacy proto format. - -import Foundation -import SwiftProtobuf - -// If the compiler emits an error on this type, it is because this file -// was generated by a version of the `protoc` Swift plug-in that is -// incompatible with the version of SwiftProtobuf to which you are linking. -// Please ensure that you are building against the same version of the API -// that was used to generate this file. -fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { - struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} - typealias Version = _2 -} - -struct ProvisioningProtos_ProvisionEnvelope { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var publicKey: Data { - get {return _publicKey ?? SwiftProtobuf.Internal.emptyData} - set {_publicKey = newValue} - } - /// Returns true if `publicKey` has been explicitly set. - var hasPublicKey: Bool {return self._publicKey != nil} - /// Clears the value of `publicKey`. Subsequent reads from it will return its default value. - mutating func clearPublicKey() {self._publicKey = nil} - - /// @required - var body: Data { - get {return _body ?? SwiftProtobuf.Internal.emptyData} - set {_body = newValue} - } - /// Returns true if `body` has been explicitly set. - var hasBody: Bool {return self._body != nil} - /// Clears the value of `body`. Subsequent reads from it will return its default value. - mutating func clearBody() {self._body = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _publicKey: Data? = nil - fileprivate var _body: Data? = nil -} - -struct ProvisioningProtos_ProvisionMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var identityKeyPublic: Data { - get {return _identityKeyPublic ?? SwiftProtobuf.Internal.emptyData} - set {_identityKeyPublic = newValue} - } - /// Returns true if `identityKeyPublic` has been explicitly set. - var hasIdentityKeyPublic: Bool {return self._identityKeyPublic != nil} - /// Clears the value of `identityKeyPublic`. Subsequent reads from it will return its default value. - mutating func clearIdentityKeyPublic() {self._identityKeyPublic = nil} - - /// @required - var identityKeyPrivate: Data { - get {return _identityKeyPrivate ?? SwiftProtobuf.Internal.emptyData} - set {_identityKeyPrivate = newValue} - } - /// Returns true if `identityKeyPrivate` has been explicitly set. - var hasIdentityKeyPrivate: Bool {return self._identityKeyPrivate != nil} - /// Clears the value of `identityKeyPrivate`. Subsequent reads from it will return its default value. - mutating func clearIdentityKeyPrivate() {self._identityKeyPrivate = nil} - - /// @required - var number: String { - get {return _number ?? String()} - set {_number = newValue} - } - /// Returns true if `number` has been explicitly set. - var hasNumber: Bool {return self._number != nil} - /// Clears the value of `number`. Subsequent reads from it will return its default value. - mutating func clearNumber() {self._number = nil} - - /// @required - var provisioningCode: String { - get {return _provisioningCode ?? String()} - set {_provisioningCode = newValue} - } - /// Returns true if `provisioningCode` has been explicitly set. - var hasProvisioningCode: Bool {return self._provisioningCode != nil} - /// Clears the value of `provisioningCode`. Subsequent reads from it will return its default value. - mutating func clearProvisioningCode() {self._provisioningCode = nil} - - /// @required - var userAgent: String { - get {return _userAgent ?? String()} - set {_userAgent = newValue} - } - /// Returns true if `userAgent` has been explicitly set. - var hasUserAgent: Bool {return self._userAgent != nil} - /// Clears the value of `userAgent`. Subsequent reads from it will return its default value. - mutating func clearUserAgent() {self._userAgent = nil} - - /// @required - var profileKey: Data { - get {return _profileKey ?? SwiftProtobuf.Internal.emptyData} - set {_profileKey = newValue} - } - /// Returns true if `profileKey` has been explicitly set. - var hasProfileKey: Bool {return self._profileKey != nil} - /// Clears the value of `profileKey`. Subsequent reads from it will return its default value. - mutating func clearProfileKey() {self._profileKey = nil} - - /// @required - var readReceipts: Bool { - get {return _readReceipts ?? false} - set {_readReceipts = newValue} - } - /// Returns true if `readReceipts` has been explicitly set. - var hasReadReceipts: Bool {return self._readReceipts != nil} - /// Clears the value of `readReceipts`. Subsequent reads from it will return its default value. - mutating func clearReadReceipts() {self._readReceipts = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _identityKeyPublic: Data? = nil - fileprivate var _identityKeyPrivate: Data? = nil - fileprivate var _number: String? = nil - fileprivate var _provisioningCode: String? = nil - fileprivate var _userAgent: String? = nil - fileprivate var _profileKey: Data? = nil - fileprivate var _readReceipts: Bool? = nil -} - -// MARK: - Code below here is support for the SwiftProtobuf runtime. - -fileprivate let _protobuf_package = "ProvisioningProtos" - -extension ProvisioningProtos_ProvisionEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".ProvisionEnvelope" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "publicKey"), - 2: .same(proto: "body"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._publicKey) - case 2: try decoder.decodeSingularBytesField(value: &self._body) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._publicKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - if let v = self._body { - try visitor.visitSingularBytesField(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: ProvisioningProtos_ProvisionEnvelope, rhs: ProvisioningProtos_ProvisionEnvelope) -> Bool { - if lhs._publicKey != rhs._publicKey {return false} - if lhs._body != rhs._body {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension ProvisioningProtos_ProvisionMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".ProvisionMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "identityKeyPublic"), - 2: .same(proto: "identityKeyPrivate"), - 3: .same(proto: "number"), - 4: .same(proto: "provisioningCode"), - 5: .same(proto: "userAgent"), - 6: .same(proto: "profileKey"), - 7: .same(proto: "readReceipts"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._identityKeyPublic) - case 2: try decoder.decodeSingularBytesField(value: &self._identityKeyPrivate) - case 3: try decoder.decodeSingularStringField(value: &self._number) - case 4: try decoder.decodeSingularStringField(value: &self._provisioningCode) - case 5: try decoder.decodeSingularStringField(value: &self._userAgent) - case 6: try decoder.decodeSingularBytesField(value: &self._profileKey) - case 7: try decoder.decodeSingularBoolField(value: &self._readReceipts) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._identityKeyPublic { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - if let v = self._identityKeyPrivate { - try visitor.visitSingularBytesField(value: v, fieldNumber: 2) - } - if let v = self._number { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - if let v = self._provisioningCode { - try visitor.visitSingularStringField(value: v, fieldNumber: 4) - } - if let v = self._userAgent { - try visitor.visitSingularStringField(value: v, fieldNumber: 5) - } - if let v = self._profileKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 6) - } - if let v = self._readReceipts { - try visitor.visitSingularBoolField(value: v, fieldNumber: 7) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: ProvisioningProtos_ProvisionMessage, rhs: ProvisioningProtos_ProvisionMessage) -> Bool { - if lhs._identityKeyPublic != rhs._identityKeyPublic {return false} - if lhs._identityKeyPrivate != rhs._identityKeyPrivate {return false} - if lhs._number != rhs._number {return false} - if lhs._provisioningCode != rhs._provisioningCode {return false} - if lhs._userAgent != rhs._userAgent {return false} - if lhs._profileKey != rhs._profileKey {return false} - if lhs._readReceipts != rhs._readReceipts {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} diff --git a/SignalUtilitiesKit/ProvisioningProto.swift b/SignalUtilitiesKit/ProvisioningProto.swift deleted file mode 100644 index 4b1f7c948..000000000 --- a/SignalUtilitiesKit/ProvisioningProto.swift +++ /dev/null @@ -1,310 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -// WARNING: This code is generated. Only edit within the markers. - -public enum ProvisioningProtoError: Error { - case invalidProtobuf(description: String) -} - -// MARK: - ProvisioningProtoProvisionEnvelope - -@objc public class ProvisioningProtoProvisionEnvelope: NSObject { - - // MARK: - ProvisioningProtoProvisionEnvelopeBuilder - - @objc public class func builder(publicKey: Data, body: Data) -> ProvisioningProtoProvisionEnvelopeBuilder { - return ProvisioningProtoProvisionEnvelopeBuilder(publicKey: publicKey, body: body) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> ProvisioningProtoProvisionEnvelopeBuilder { - let builder = ProvisioningProtoProvisionEnvelopeBuilder(publicKey: publicKey, body: body) - return builder - } - - @objc public class ProvisioningProtoProvisionEnvelopeBuilder: NSObject { - - private var proto = ProvisioningProtos_ProvisionEnvelope() - - @objc fileprivate override init() {} - - @objc fileprivate init(publicKey: Data, body: Data) { - super.init() - - setPublicKey(publicKey) - setBody(body) - } - - @objc public func setPublicKey(_ valueParam: Data) { - proto.publicKey = valueParam - } - - @objc public func setBody(_ valueParam: Data) { - proto.body = valueParam - } - - @objc public func build() throws -> ProvisioningProtoProvisionEnvelope { - return try ProvisioningProtoProvisionEnvelope.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try ProvisioningProtoProvisionEnvelope.parseProto(proto).serializedData() - } - } - - fileprivate let proto: ProvisioningProtos_ProvisionEnvelope - - @objc public let publicKey: Data - - @objc public let body: Data - - private init(proto: ProvisioningProtos_ProvisionEnvelope, - publicKey: Data, - body: Data) { - self.proto = proto - self.publicKey = publicKey - self.body = body - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> ProvisioningProtoProvisionEnvelope { - let proto = try ProvisioningProtos_ProvisionEnvelope(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: ProvisioningProtos_ProvisionEnvelope) throws -> ProvisioningProtoProvisionEnvelope { - guard proto.hasPublicKey else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: publicKey") - } - let publicKey = proto.publicKey - - guard proto.hasBody else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: body") - } - let body = proto.body - - // MARK: - Begin Validation Logic for ProvisioningProtoProvisionEnvelope - - - // MARK: - End Validation Logic for ProvisioningProtoProvisionEnvelope - - - let result = ProvisioningProtoProvisionEnvelope(proto: proto, - publicKey: publicKey, - body: body) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension ProvisioningProtoProvisionEnvelope { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension ProvisioningProtoProvisionEnvelope.ProvisioningProtoProvisionEnvelopeBuilder { - @objc public func buildIgnoringErrors() -> ProvisioningProtoProvisionEnvelope? { - return try! self.build() - } -} - -#endif - -// MARK: - ProvisioningProtoProvisionMessage - -@objc public class ProvisioningProtoProvisionMessage: NSObject { - - // MARK: - ProvisioningProtoProvisionMessageBuilder - - @objc public class func builder(identityKeyPublic: Data, identityKeyPrivate: Data, number: String, provisioningCode: String, userAgent: String, profileKey: Data, readReceipts: Bool) -> ProvisioningProtoProvisionMessageBuilder { - return ProvisioningProtoProvisionMessageBuilder(identityKeyPublic: identityKeyPublic, identityKeyPrivate: identityKeyPrivate, number: number, provisioningCode: provisioningCode, userAgent: userAgent, profileKey: profileKey, readReceipts: readReceipts) - } - - // asBuilder() constructs a builder that reflects the proto's contents. - @objc public func asBuilder() -> ProvisioningProtoProvisionMessageBuilder { - let builder = ProvisioningProtoProvisionMessageBuilder(identityKeyPublic: identityKeyPublic, identityKeyPrivate: identityKeyPrivate, number: number, provisioningCode: provisioningCode, userAgent: userAgent, profileKey: profileKey, readReceipts: readReceipts) - return builder - } - - @objc public class ProvisioningProtoProvisionMessageBuilder: NSObject { - - private var proto = ProvisioningProtos_ProvisionMessage() - - @objc fileprivate override init() {} - - @objc fileprivate init(identityKeyPublic: Data, identityKeyPrivate: Data, number: String, provisioningCode: String, userAgent: String, profileKey: Data, readReceipts: Bool) { - super.init() - - setIdentityKeyPublic(identityKeyPublic) - setIdentityKeyPrivate(identityKeyPrivate) - setNumber(number) - setProvisioningCode(provisioningCode) - setUserAgent(userAgent) - setProfileKey(profileKey) - setReadReceipts(readReceipts) - } - - @objc public func setIdentityKeyPublic(_ valueParam: Data) { - proto.identityKeyPublic = valueParam - } - - @objc public func setIdentityKeyPrivate(_ valueParam: Data) { - proto.identityKeyPrivate = valueParam - } - - @objc public func setNumber(_ valueParam: String) { - proto.number = valueParam - } - - @objc public func setProvisioningCode(_ valueParam: String) { - proto.provisioningCode = valueParam - } - - @objc public func setUserAgent(_ valueParam: String) { - proto.userAgent = valueParam - } - - @objc public func setProfileKey(_ valueParam: Data) { - proto.profileKey = valueParam - } - - @objc public func setReadReceipts(_ valueParam: Bool) { - proto.readReceipts = valueParam - } - - @objc public func build() throws -> ProvisioningProtoProvisionMessage { - return try ProvisioningProtoProvisionMessage.parseProto(proto) - } - - @objc public func buildSerializedData() throws -> Data { - return try ProvisioningProtoProvisionMessage.parseProto(proto).serializedData() - } - } - - fileprivate let proto: ProvisioningProtos_ProvisionMessage - - @objc public let identityKeyPublic: Data - - @objc public let identityKeyPrivate: Data - - @objc public let number: String - - @objc public let provisioningCode: String - - @objc public let userAgent: String - - @objc public let profileKey: Data - - @objc public let readReceipts: Bool - - private init(proto: ProvisioningProtos_ProvisionMessage, - identityKeyPublic: Data, - identityKeyPrivate: Data, - number: String, - provisioningCode: String, - userAgent: String, - profileKey: Data, - readReceipts: Bool) { - self.proto = proto - self.identityKeyPublic = identityKeyPublic - self.identityKeyPrivate = identityKeyPrivate - self.number = number - self.provisioningCode = provisioningCode - self.userAgent = userAgent - self.profileKey = profileKey - self.readReceipts = readReceipts - } - - @objc - public func serializedData() throws -> Data { - return try self.proto.serializedData() - } - - @objc public class func parseData(_ serializedData: Data) throws -> ProvisioningProtoProvisionMessage { - let proto = try ProvisioningProtos_ProvisionMessage(serializedData: serializedData) - return try parseProto(proto) - } - - fileprivate class func parseProto(_ proto: ProvisioningProtos_ProvisionMessage) throws -> ProvisioningProtoProvisionMessage { - guard proto.hasIdentityKeyPublic else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: identityKeyPublic") - } - let identityKeyPublic = proto.identityKeyPublic - - guard proto.hasIdentityKeyPrivate else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: identityKeyPrivate") - } - let identityKeyPrivate = proto.identityKeyPrivate - - guard proto.hasNumber else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: number") - } - let number = proto.number - - guard proto.hasProvisioningCode else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: provisioningCode") - } - let provisioningCode = proto.provisioningCode - - guard proto.hasUserAgent else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: userAgent") - } - let userAgent = proto.userAgent - - guard proto.hasProfileKey else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: profileKey") - } - let profileKey = proto.profileKey - - guard proto.hasReadReceipts else { - throw ProvisioningProtoError.invalidProtobuf(description: "\(logTag) missing required field: readReceipts") - } - let readReceipts = proto.readReceipts - - // MARK: - Begin Validation Logic for ProvisioningProtoProvisionMessage - - - // MARK: - End Validation Logic for ProvisioningProtoProvisionMessage - - - let result = ProvisioningProtoProvisionMessage(proto: proto, - identityKeyPublic: identityKeyPublic, - identityKeyPrivate: identityKeyPrivate, - number: number, - provisioningCode: provisioningCode, - userAgent: userAgent, - profileKey: profileKey, - readReceipts: readReceipts) - return result - } - - @objc public override var debugDescription: String { - return "\(proto)" - } -} - -#if DEBUG - -extension ProvisioningProtoProvisionMessage { - @objc public func serializedDataIgnoringErrors() -> Data? { - return try! self.serializedData() - } -} - -extension ProvisioningProtoProvisionMessage.ProvisioningProtoProvisionMessageBuilder { - @objc public func buildIgnoringErrors() -> ProvisioningProtoProvisionMessage? { - return try! self.build() - } -} - -#endif diff --git a/SignalUtilitiesKit/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/Remove/ClosedGroupsProtocol.swift similarity index 100% rename from SignalUtilitiesKit/ClosedGroupsProtocol.swift rename to SignalUtilitiesKit/Remove/ClosedGroupsProtocol.swift diff --git a/SignalUtilitiesKit/Remove Later/ContactCellView.h b/SignalUtilitiesKit/Remove/ContactCellView.h similarity index 100% rename from SignalUtilitiesKit/Remove Later/ContactCellView.h rename to SignalUtilitiesKit/Remove/ContactCellView.h diff --git a/SignalUtilitiesKit/Remove Later/ContactCellView.m b/SignalUtilitiesKit/Remove/ContactCellView.m similarity index 100% rename from SignalUtilitiesKit/Remove Later/ContactCellView.m rename to SignalUtilitiesKit/Remove/ContactCellView.m diff --git a/SignalUtilitiesKit/Remove Later/ContactTableViewCell.h b/SignalUtilitiesKit/Remove/ContactTableViewCell.h similarity index 100% rename from SignalUtilitiesKit/Remove Later/ContactTableViewCell.h rename to SignalUtilitiesKit/Remove/ContactTableViewCell.h diff --git a/SignalUtilitiesKit/Remove Later/ContactTableViewCell.m b/SignalUtilitiesKit/Remove/ContactTableViewCell.m similarity index 100% rename from SignalUtilitiesKit/Remove Later/ContactTableViewCell.m rename to SignalUtilitiesKit/Remove/ContactTableViewCell.m diff --git a/SignalUtilitiesKit/Remove Later/DisplayNameUtilities.swift b/SignalUtilitiesKit/Remove/DisplayNameUtilities.swift similarity index 100% rename from SignalUtilitiesKit/Remove Later/DisplayNameUtilities.swift rename to SignalUtilitiesKit/Remove/DisplayNameUtilities.swift diff --git a/SignalUtilitiesKit/Remove Later/DisplayNameUtilities2.swift b/SignalUtilitiesKit/Remove/DisplayNameUtilities2.swift similarity index 100% rename from SignalUtilitiesKit/Remove Later/DisplayNameUtilities2.swift rename to SignalUtilitiesKit/Remove/DisplayNameUtilities2.swift diff --git a/SignalUtilitiesKit/Utilities/GroupUtilities.swift b/SignalUtilitiesKit/Remove/GroupUtilities.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/GroupUtilities.swift rename to SignalUtilitiesKit/Remove/GroupUtilities.swift diff --git a/SignalUtilitiesKit/Remove Later/OWSProfileManager.h b/SignalUtilitiesKit/Remove/OWSProfileManager.h similarity index 100% rename from SignalUtilitiesKit/Remove Later/OWSProfileManager.h rename to SignalUtilitiesKit/Remove/OWSProfileManager.h diff --git a/SignalUtilitiesKit/Remove Later/OWSProfileManager.m b/SignalUtilitiesKit/Remove/OWSProfileManager.m similarity index 100% rename from SignalUtilitiesKit/Remove Later/OWSProfileManager.m rename to SignalUtilitiesKit/Remove/OWSProfileManager.m diff --git a/SignalUtilitiesKit/Remove Later/OWSUserProfile.h b/SignalUtilitiesKit/Remove/OWSUserProfile.h similarity index 100% rename from SignalUtilitiesKit/Remove Later/OWSUserProfile.h rename to SignalUtilitiesKit/Remove/OWSUserProfile.h diff --git a/SignalUtilitiesKit/Remove Later/OWSUserProfile.m b/SignalUtilitiesKit/Remove/OWSUserProfile.m similarity index 100% rename from SignalUtilitiesKit/Remove Later/OWSUserProfile.m rename to SignalUtilitiesKit/Remove/OWSUserProfile.m diff --git a/SignalUtilitiesKit/Remove Later/ProfileManagerProtocol.h b/SignalUtilitiesKit/Remove/ProfileManagerProtocol.h similarity index 100% rename from SignalUtilitiesKit/Remove Later/ProfileManagerProtocol.h rename to SignalUtilitiesKit/Remove/ProfileManagerProtocol.h diff --git a/SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift b/SignalUtilitiesKit/Remove/SessionManagementProtocol.swift similarity index 100% rename from SignalUtilitiesKit/Remove Later/SessionManagementProtocol.swift rename to SignalUtilitiesKit/Remove/SessionManagementProtocol.swift diff --git a/SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift b/SignalUtilitiesKit/Remove/SessionMetaProtocol.swift similarity index 100% rename from SignalUtilitiesKit/Remove Later/SessionMetaProtocol.swift rename to SignalUtilitiesKit/Remove/SessionMetaProtocol.swift diff --git a/SignalUtilitiesKit/RotateSignedKeyOperation.swift b/SignalUtilitiesKit/RotateSignedKeyOperation.swift index 578cb77f7..0142e69d7 100644 --- a/SignalUtilitiesKit/RotateSignedKeyOperation.swift +++ b/SignalUtilitiesKit/RotateSignedKeyOperation.swift @@ -11,10 +11,6 @@ public class RotateSignedPreKeyOperation: OWSOperation { return TSAccountManager.sharedInstance() } - private var primaryStorage: OWSPrimaryStorage { - return OWSPrimaryStorage.shared() - } - public override func run() { Logger.debug("") @@ -24,7 +20,14 @@ public class RotateSignedPreKeyOperation: OWSOperation { } DispatchQueue.global().async { - SessionManagementProtocol.rotateSignedPreKey() + let storage = OWSPrimaryStorage.shared() + let signedPreKeyRecord = storage.generateRandomSignedRecord() + signedPreKeyRecord.markAsAcceptedByService() + storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) + storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) + TSPreKeyManager.clearPreKeyUpdateFailureCount() + TSPreKeyManager.clearSignedPreKeyRecords() + print("[Loki] Signed pre key rotated successfully.") self.reportSuccess() } } diff --git a/SignalUtilitiesKit/SignalMessage.swift b/SignalUtilitiesKit/SignalMessage.swift deleted file mode 100644 index 96920b7b7..000000000 --- a/SignalUtilitiesKit/SignalMessage.swift +++ /dev/null @@ -1,28 +0,0 @@ - -@objc(LKSignalMessage) -public final class SignalMessage : NSObject { - @objc public let type: SNProtoEnvelope.SNProtoEnvelopeType - @objc public let timestamp: UInt64 - @objc public let senderPublicKey: String - @objc public let senderDeviceID: UInt32 - @objc public let content: String - @objc public let recipientPublicKey: String - @objc(ttl) - public let objc_ttl: UInt64 - @objc public let isPing: Bool - - public var ttl: UInt64? { return objc_ttl != 0 ? objc_ttl : nil } - - @objc public init(type: SNProtoEnvelope.SNProtoEnvelopeType, timestamp: UInt64, senderID: String, senderDeviceID: UInt32, - content: String, recipientID: String, ttl: UInt64, isPing: Bool) { - self.type = type - self.timestamp = timestamp - self.senderPublicKey = senderID - self.senderDeviceID = senderDeviceID - self.content = content - self.recipientPublicKey = recipientID - self.objc_ttl = ttl - self.isPing = isPing - super.init() - } -} diff --git a/SignalUtilitiesKit/SignalService.pb.swift b/SignalUtilitiesKit/SignalService.pb.swift deleted file mode 100644 index ac386523f..000000000 --- a/SignalUtilitiesKit/SignalService.pb.swift +++ /dev/null @@ -1,5199 +0,0 @@ -// DO NOT EDIT. -// swift-format-ignore-file -// -// Generated by the Swift generator plugin for the protocol buffer compiler. -// Source: SignalService.proto -// -// For information on using the generated types, please see the documentation: -// https://github.com/apple/swift-protobuf/ - -//* -// Copyright (C) 2014-2016 Open Whisper Systems -// -// Licensed according to the LICENSE file in this repository. - -/// iOS - since we use a modern proto-compiler, we must specify -/// the legacy proto format. - -import Foundation -import SwiftProtobuf - -// If the compiler emits an error on this type, it is because this file -// was generated by a version of the `protoc` Swift plug-in that is -// incompatible with the version of SwiftProtobuf to which you are linking. -// Please ensure that you are building against the same version of the API -// that was used to generate this file. -fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { - struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} - typealias Version = _2 -} - -struct SignalServiceProtos_Envelope { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var type: SignalServiceProtos_Envelope.TypeEnum { - get {return _type ?? .unknown} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var source: String { - get {return _source ?? String()} - set {_source = newValue} - } - /// Returns true if `source` has been explicitly set. - var hasSource: Bool {return self._source != nil} - /// Clears the value of `source`. Subsequent reads from it will return its default value. - mutating func clearSource() {self._source = nil} - - var sourceDevice: UInt32 { - get {return _sourceDevice ?? 0} - set {_sourceDevice = newValue} - } - /// Returns true if `sourceDevice` has been explicitly set. - var hasSourceDevice: Bool {return self._sourceDevice != nil} - /// Clears the value of `sourceDevice`. Subsequent reads from it will return its default value. - mutating func clearSourceDevice() {self._sourceDevice = nil} - - var relay: String { - get {return _relay ?? String()} - set {_relay = newValue} - } - /// Returns true if `relay` has been explicitly set. - var hasRelay: Bool {return self._relay != nil} - /// Clears the value of `relay`. Subsequent reads from it will return its default value. - mutating func clearRelay() {self._relay = nil} - - /// @required - var timestamp: UInt64 { - get {return _timestamp ?? 0} - set {_timestamp = newValue} - } - /// Returns true if `timestamp` has been explicitly set. - var hasTimestamp: Bool {return self._timestamp != nil} - /// Clears the value of `timestamp`. Subsequent reads from it will return its default value. - mutating func clearTimestamp() {self._timestamp = nil} - - /// Contains an encrypted DataMessage - var legacyMessage: Data { - get {return _legacyMessage ?? SwiftProtobuf.Internal.emptyData} - set {_legacyMessage = newValue} - } - /// Returns true if `legacyMessage` has been explicitly set. - var hasLegacyMessage: Bool {return self._legacyMessage != nil} - /// Clears the value of `legacyMessage`. Subsequent reads from it will return its default value. - mutating func clearLegacyMessage() {self._legacyMessage = nil} - - /// Contains an encrypted Content - var content: Data { - get {return _content ?? SwiftProtobuf.Internal.emptyData} - set {_content = newValue} - } - /// Returns true if `content` has been explicitly set. - var hasContent: Bool {return self._content != nil} - /// Clears the value of `content`. Subsequent reads from it will return its default value. - mutating func clearContent() {self._content = nil} - - /// We may eventually want to make this required. - var serverGuid: String { - get {return _serverGuid ?? String()} - set {_serverGuid = newValue} - } - /// Returns true if `serverGuid` has been explicitly set. - var hasServerGuid: Bool {return self._serverGuid != nil} - /// Clears the value of `serverGuid`. Subsequent reads from it will return its default value. - mutating func clearServerGuid() {self._serverGuid = nil} - - /// We may eventually want to make this required. - var serverTimestamp: UInt64 { - get {return _serverTimestamp ?? 0} - set {_serverTimestamp = newValue} - } - /// Returns true if `serverTimestamp` has been explicitly set. - var hasServerTimestamp: Bool {return self._serverTimestamp != nil} - /// Clears the value of `serverTimestamp`. Subsequent reads from it will return its default value. - mutating func clearServerTimestamp() {self._serverTimestamp = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - case unknown // = 0 - case ciphertext // = 1 - case keyExchange // = 2 - case prekeyBundle // = 3 - case receipt // = 5 - case unidentifiedSender // = 6 - - /// Loki - case closedGroupCiphertext // = 7 - - /// Loki: Encrypted using the fallback session cipher. Contains a pre key bundle if it's a session request. - case fallbackMessage // = 101 - - init() { - self = .unknown - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .unknown - case 1: self = .ciphertext - case 2: self = .keyExchange - case 3: self = .prekeyBundle - case 5: self = .receipt - case 6: self = .unidentifiedSender - case 7: self = .closedGroupCiphertext - case 101: self = .fallbackMessage - default: return nil - } - } - - var rawValue: Int { - switch self { - case .unknown: return 0 - case .ciphertext: return 1 - case .keyExchange: return 2 - case .prekeyBundle: return 3 - case .receipt: return 5 - case .unidentifiedSender: return 6 - case .closedGroupCiphertext: return 7 - case .fallbackMessage: return 101 - } - } - - } - - init() {} - - fileprivate var _type: SignalServiceProtos_Envelope.TypeEnum? = nil - fileprivate var _source: String? = nil - fileprivate var _sourceDevice: UInt32? = nil - fileprivate var _relay: String? = nil - fileprivate var _timestamp: UInt64? = nil - fileprivate var _legacyMessage: Data? = nil - fileprivate var _content: Data? = nil - fileprivate var _serverGuid: String? = nil - fileprivate var _serverTimestamp: UInt64? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_Envelope.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_TypingMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var timestamp: UInt64 { - get {return _timestamp ?? 0} - set {_timestamp = newValue} - } - /// Returns true if `timestamp` has been explicitly set. - var hasTimestamp: Bool {return self._timestamp != nil} - /// Clears the value of `timestamp`. Subsequent reads from it will return its default value. - mutating func clearTimestamp() {self._timestamp = nil} - - /// @required - var action: SignalServiceProtos_TypingMessage.Action { - get {return _action ?? .started} - set {_action = newValue} - } - /// Returns true if `action` has been explicitly set. - var hasAction: Bool {return self._action != nil} - /// Clears the value of `action`. Subsequent reads from it will return its default value. - mutating func clearAction() {self._action = nil} - - var groupID: Data { - get {return _groupID ?? SwiftProtobuf.Internal.emptyData} - set {_groupID = newValue} - } - /// Returns true if `groupID` has been explicitly set. - var hasGroupID: Bool {return self._groupID != nil} - /// Clears the value of `groupID`. Subsequent reads from it will return its default value. - mutating func clearGroupID() {self._groupID = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum Action: SwiftProtobuf.Enum { - typealias RawValue = Int - case started // = 0 - case stopped // = 1 - - init() { - self = .started - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .started - case 1: self = .stopped - default: return nil - } - } - - var rawValue: Int { - switch self { - case .started: return 0 - case .stopped: return 1 - } - } - - } - - init() {} - - fileprivate var _timestamp: UInt64? = nil - fileprivate var _action: SignalServiceProtos_TypingMessage.Action? = nil - fileprivate var _groupID: Data? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_TypingMessage.Action: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_Content { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var dataMessage: SignalServiceProtos_DataMessage { - get {return _dataMessage ?? SignalServiceProtos_DataMessage()} - set {_dataMessage = newValue} - } - /// Returns true if `dataMessage` has been explicitly set. - var hasDataMessage: Bool {return self._dataMessage != nil} - /// Clears the value of `dataMessage`. Subsequent reads from it will return its default value. - mutating func clearDataMessage() {self._dataMessage = nil} - - var syncMessage: SignalServiceProtos_SyncMessage { - get {return _syncMessage ?? SignalServiceProtos_SyncMessage()} - set {_syncMessage = newValue} - } - /// Returns true if `syncMessage` has been explicitly set. - var hasSyncMessage: Bool {return self._syncMessage != nil} - /// Clears the value of `syncMessage`. Subsequent reads from it will return its default value. - mutating func clearSyncMessage() {self._syncMessage = nil} - - var callMessage: SignalServiceProtos_CallMessage { - get {return _callMessage ?? SignalServiceProtos_CallMessage()} - set {_callMessage = newValue} - } - /// Returns true if `callMessage` has been explicitly set. - var hasCallMessage: Bool {return self._callMessage != nil} - /// Clears the value of `callMessage`. Subsequent reads from it will return its default value. - mutating func clearCallMessage() {self._callMessage = nil} - - var nullMessage: SignalServiceProtos_NullMessage { - get {return _nullMessage ?? SignalServiceProtos_NullMessage()} - set {_nullMessage = newValue} - } - /// Returns true if `nullMessage` has been explicitly set. - var hasNullMessage: Bool {return self._nullMessage != nil} - /// Clears the value of `nullMessage`. Subsequent reads from it will return its default value. - mutating func clearNullMessage() {self._nullMessage = nil} - - var receiptMessage: SignalServiceProtos_ReceiptMessage { - get {return _receiptMessage ?? SignalServiceProtos_ReceiptMessage()} - set {_receiptMessage = newValue} - } - /// Returns true if `receiptMessage` has been explicitly set. - var hasReceiptMessage: Bool {return self._receiptMessage != nil} - /// Clears the value of `receiptMessage`. Subsequent reads from it will return its default value. - mutating func clearReceiptMessage() {self._receiptMessage = nil} - - var typingMessage: SignalServiceProtos_TypingMessage { - get {return _typingMessage ?? SignalServiceProtos_TypingMessage()} - set {_typingMessage = newValue} - } - /// Returns true if `typingMessage` has been explicitly set. - var hasTypingMessage: Bool {return self._typingMessage != nil} - /// Clears the value of `typingMessage`. Subsequent reads from it will return its default value. - mutating func clearTypingMessage() {self._typingMessage = nil} - - /// Loki - var prekeyBundleMessage: SignalServiceProtos_PrekeyBundleMessage { - get {return _prekeyBundleMessage ?? SignalServiceProtos_PrekeyBundleMessage()} - set {_prekeyBundleMessage = newValue} - } - /// Returns true if `prekeyBundleMessage` has been explicitly set. - var hasPrekeyBundleMessage: Bool {return self._prekeyBundleMessage != nil} - /// Clears the value of `prekeyBundleMessage`. Subsequent reads from it will return its default value. - mutating func clearPrekeyBundleMessage() {self._prekeyBundleMessage = nil} - - /// Loki - var lokiDeviceLinkMessage: SignalServiceProtos_LokiDeviceLinkMessage { - get {return _lokiDeviceLinkMessage ?? SignalServiceProtos_LokiDeviceLinkMessage()} - set {_lokiDeviceLinkMessage = newValue} - } - /// Returns true if `lokiDeviceLinkMessage` has been explicitly set. - var hasLokiDeviceLinkMessage: Bool {return self._lokiDeviceLinkMessage != nil} - /// Clears the value of `lokiDeviceLinkMessage`. Subsequent reads from it will return its default value. - mutating func clearLokiDeviceLinkMessage() {self._lokiDeviceLinkMessage = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _dataMessage: SignalServiceProtos_DataMessage? = nil - fileprivate var _syncMessage: SignalServiceProtos_SyncMessage? = nil - fileprivate var _callMessage: SignalServiceProtos_CallMessage? = nil - fileprivate var _nullMessage: SignalServiceProtos_NullMessage? = nil - fileprivate var _receiptMessage: SignalServiceProtos_ReceiptMessage? = nil - fileprivate var _typingMessage: SignalServiceProtos_TypingMessage? = nil - fileprivate var _prekeyBundleMessage: SignalServiceProtos_PrekeyBundleMessage? = nil - fileprivate var _lokiDeviceLinkMessage: SignalServiceProtos_LokiDeviceLinkMessage? = nil -} - -/// Loki -struct SignalServiceProtos_PrekeyBundleMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var identityKey: Data { - get {return _identityKey ?? SwiftProtobuf.Internal.emptyData} - set {_identityKey = newValue} - } - /// Returns true if `identityKey` has been explicitly set. - var hasIdentityKey: Bool {return self._identityKey != nil} - /// Clears the value of `identityKey`. Subsequent reads from it will return its default value. - mutating func clearIdentityKey() {self._identityKey = nil} - - var deviceID: UInt32 { - get {return _deviceID ?? 0} - set {_deviceID = newValue} - } - /// Returns true if `deviceID` has been explicitly set. - var hasDeviceID: Bool {return self._deviceID != nil} - /// Clears the value of `deviceID`. Subsequent reads from it will return its default value. - mutating func clearDeviceID() {self._deviceID = nil} - - var prekeyID: UInt32 { - get {return _prekeyID ?? 0} - set {_prekeyID = newValue} - } - /// Returns true if `prekeyID` has been explicitly set. - var hasPrekeyID: Bool {return self._prekeyID != nil} - /// Clears the value of `prekeyID`. Subsequent reads from it will return its default value. - mutating func clearPrekeyID() {self._prekeyID = nil} - - var signedKeyID: UInt32 { - get {return _signedKeyID ?? 0} - set {_signedKeyID = newValue} - } - /// Returns true if `signedKeyID` has been explicitly set. - var hasSignedKeyID: Bool {return self._signedKeyID != nil} - /// Clears the value of `signedKeyID`. Subsequent reads from it will return its default value. - mutating func clearSignedKeyID() {self._signedKeyID = nil} - - var prekey: Data { - get {return _prekey ?? SwiftProtobuf.Internal.emptyData} - set {_prekey = newValue} - } - /// Returns true if `prekey` has been explicitly set. - var hasPrekey: Bool {return self._prekey != nil} - /// Clears the value of `prekey`. Subsequent reads from it will return its default value. - mutating func clearPrekey() {self._prekey = nil} - - var signedKey: Data { - get {return _signedKey ?? SwiftProtobuf.Internal.emptyData} - set {_signedKey = newValue} - } - /// Returns true if `signedKey` has been explicitly set. - var hasSignedKey: Bool {return self._signedKey != nil} - /// Clears the value of `signedKey`. Subsequent reads from it will return its default value. - mutating func clearSignedKey() {self._signedKey = nil} - - var signature: Data { - get {return _signature ?? SwiftProtobuf.Internal.emptyData} - set {_signature = newValue} - } - /// Returns true if `signature` has been explicitly set. - var hasSignature: Bool {return self._signature != nil} - /// Clears the value of `signature`. Subsequent reads from it will return its default value. - mutating func clearSignature() {self._signature = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _identityKey: Data? = nil - fileprivate var _deviceID: UInt32? = nil - fileprivate var _prekeyID: UInt32? = nil - fileprivate var _signedKeyID: UInt32? = nil - fileprivate var _prekey: Data? = nil - fileprivate var _signedKey: Data? = nil - fileprivate var _signature: Data? = nil -} - -/// Loki -struct SignalServiceProtos_LokiDeviceLinkMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var masterPublicKey: String { - get {return _masterPublicKey ?? String()} - set {_masterPublicKey = newValue} - } - /// Returns true if `masterPublicKey` has been explicitly set. - var hasMasterPublicKey: Bool {return self._masterPublicKey != nil} - /// Clears the value of `masterPublicKey`. Subsequent reads from it will return its default value. - mutating func clearMasterPublicKey() {self._masterPublicKey = nil} - - var slavePublicKey: String { - get {return _slavePublicKey ?? String()} - set {_slavePublicKey = newValue} - } - /// Returns true if `slavePublicKey` has been explicitly set. - var hasSlavePublicKey: Bool {return self._slavePublicKey != nil} - /// Clears the value of `slavePublicKey`. Subsequent reads from it will return its default value. - mutating func clearSlavePublicKey() {self._slavePublicKey = nil} - - var slaveSignature: Data { - get {return _slaveSignature ?? SwiftProtobuf.Internal.emptyData} - set {_slaveSignature = newValue} - } - /// Returns true if `slaveSignature` has been explicitly set. - var hasSlaveSignature: Bool {return self._slaveSignature != nil} - /// Clears the value of `slaveSignature`. Subsequent reads from it will return its default value. - mutating func clearSlaveSignature() {self._slaveSignature = nil} - - var masterSignature: Data { - get {return _masterSignature ?? SwiftProtobuf.Internal.emptyData} - set {_masterSignature = newValue} - } - /// Returns true if `masterSignature` has been explicitly set. - var hasMasterSignature: Bool {return self._masterSignature != nil} - /// Clears the value of `masterSignature`. Subsequent reads from it will return its default value. - mutating func clearMasterSignature() {self._masterSignature = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _masterPublicKey: String? = nil - fileprivate var _slavePublicKey: String? = nil - fileprivate var _slaveSignature: Data? = nil - fileprivate var _masterSignature: Data? = nil -} - -struct SignalServiceProtos_CallMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var offer: SignalServiceProtos_CallMessage.Offer { - get {return _offer ?? SignalServiceProtos_CallMessage.Offer()} - set {_offer = newValue} - } - /// Returns true if `offer` has been explicitly set. - var hasOffer: Bool {return self._offer != nil} - /// Clears the value of `offer`. Subsequent reads from it will return its default value. - mutating func clearOffer() {self._offer = nil} - - var answer: SignalServiceProtos_CallMessage.Answer { - get {return _answer ?? SignalServiceProtos_CallMessage.Answer()} - set {_answer = newValue} - } - /// Returns true if `answer` has been explicitly set. - var hasAnswer: Bool {return self._answer != nil} - /// Clears the value of `answer`. Subsequent reads from it will return its default value. - mutating func clearAnswer() {self._answer = nil} - - var iceUpdate: [SignalServiceProtos_CallMessage.IceUpdate] = [] - - var hangup: SignalServiceProtos_CallMessage.Hangup { - get {return _hangup ?? SignalServiceProtos_CallMessage.Hangup()} - set {_hangup = newValue} - } - /// Returns true if `hangup` has been explicitly set. - var hasHangup: Bool {return self._hangup != nil} - /// Clears the value of `hangup`. Subsequent reads from it will return its default value. - mutating func clearHangup() {self._hangup = nil} - - var busy: SignalServiceProtos_CallMessage.Busy { - get {return _busy ?? SignalServiceProtos_CallMessage.Busy()} - set {_busy = newValue} - } - /// Returns true if `busy` has been explicitly set. - var hasBusy: Bool {return self._busy != nil} - /// Clears the value of `busy`. Subsequent reads from it will return its default value. - mutating func clearBusy() {self._busy = nil} - - /// Signal-iOS sends profile key with call messages - /// for earlier discovery - var profileKey: Data { - get {return _profileKey ?? SwiftProtobuf.Internal.emptyData} - set {_profileKey = newValue} - } - /// Returns true if `profileKey` has been explicitly set. - var hasProfileKey: Bool {return self._profileKey != nil} - /// Clears the value of `profileKey`. Subsequent reads from it will return its default value. - mutating func clearProfileKey() {self._profileKey = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - struct Offer { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: UInt64 { - get {return _id ?? 0} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - /// Signal-iOS renamed the description field to avoid - /// conflicts with [NSObject description]. - /// @required - var sessionDescription: String { - get {return _sessionDescription ?? String()} - set {_sessionDescription = newValue} - } - /// Returns true if `sessionDescription` has been explicitly set. - var hasSessionDescription: Bool {return self._sessionDescription != nil} - /// Clears the value of `sessionDescription`. Subsequent reads from it will return its default value. - mutating func clearSessionDescription() {self._sessionDescription = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _id: UInt64? = nil - fileprivate var _sessionDescription: String? = nil - } - - struct Answer { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: UInt64 { - get {return _id ?? 0} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - /// Signal-iOS renamed the description field to avoid - /// conflicts with [NSObject description]. - /// @required - var sessionDescription: String { - get {return _sessionDescription ?? String()} - set {_sessionDescription = newValue} - } - /// Returns true if `sessionDescription` has been explicitly set. - var hasSessionDescription: Bool {return self._sessionDescription != nil} - /// Clears the value of `sessionDescription`. Subsequent reads from it will return its default value. - mutating func clearSessionDescription() {self._sessionDescription = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _id: UInt64? = nil - fileprivate var _sessionDescription: String? = nil - } - - struct IceUpdate { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: UInt64 { - get {return _id ?? 0} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - /// @required - var sdpMid: String { - get {return _sdpMid ?? String()} - set {_sdpMid = newValue} - } - /// Returns true if `sdpMid` has been explicitly set. - var hasSdpMid: Bool {return self._sdpMid != nil} - /// Clears the value of `sdpMid`. Subsequent reads from it will return its default value. - mutating func clearSdpMid() {self._sdpMid = nil} - - /// @required - var sdpMlineIndex: UInt32 { - get {return _sdpMlineIndex ?? 0} - set {_sdpMlineIndex = newValue} - } - /// Returns true if `sdpMlineIndex` has been explicitly set. - var hasSdpMlineIndex: Bool {return self._sdpMlineIndex != nil} - /// Clears the value of `sdpMlineIndex`. Subsequent reads from it will return its default value. - mutating func clearSdpMlineIndex() {self._sdpMlineIndex = nil} - - /// @required - var sdp: String { - get {return _sdp ?? String()} - set {_sdp = newValue} - } - /// Returns true if `sdp` has been explicitly set. - var hasSdp: Bool {return self._sdp != nil} - /// Clears the value of `sdp`. Subsequent reads from it will return its default value. - mutating func clearSdp() {self._sdp = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _id: UInt64? = nil - fileprivate var _sdpMid: String? = nil - fileprivate var _sdpMlineIndex: UInt32? = nil - fileprivate var _sdp: String? = nil - } - - struct Busy { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: UInt64 { - get {return _id ?? 0} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _id: UInt64? = nil - } - - struct Hangup { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: UInt64 { - get {return _id ?? 0} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _id: UInt64? = nil - } - - init() {} - - fileprivate var _offer: SignalServiceProtos_CallMessage.Offer? = nil - fileprivate var _answer: SignalServiceProtos_CallMessage.Answer? = nil - fileprivate var _hangup: SignalServiceProtos_CallMessage.Hangup? = nil - fileprivate var _busy: SignalServiceProtos_CallMessage.Busy? = nil - fileprivate var _profileKey: Data? = nil -} - -struct SignalServiceProtos_ClosedGroupCiphertextMessageWrapper { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var ciphertext: Data { - get {return _ciphertext ?? SwiftProtobuf.Internal.emptyData} - set {_ciphertext = newValue} - } - /// Returns true if `ciphertext` has been explicitly set. - var hasCiphertext: Bool {return self._ciphertext != nil} - /// Clears the value of `ciphertext`. Subsequent reads from it will return its default value. - mutating func clearCiphertext() {self._ciphertext = nil} - - /// @required - var ephemeralPublicKey: Data { - get {return _ephemeralPublicKey ?? SwiftProtobuf.Internal.emptyData} - set {_ephemeralPublicKey = newValue} - } - /// Returns true if `ephemeralPublicKey` has been explicitly set. - var hasEphemeralPublicKey: Bool {return self._ephemeralPublicKey != nil} - /// Clears the value of `ephemeralPublicKey`. Subsequent reads from it will return its default value. - mutating func clearEphemeralPublicKey() {self._ephemeralPublicKey = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _ciphertext: Data? = nil - fileprivate var _ephemeralPublicKey: Data? = nil -} - -struct SignalServiceProtos_DataMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var body: String { - get {return _body ?? String()} - set {_body = newValue} - } - /// Returns true if `body` has been explicitly set. - var hasBody: Bool {return self._body != nil} - /// Clears the value of `body`. Subsequent reads from it will return its default value. - mutating func clearBody() {self._body = nil} - - var attachments: [SignalServiceProtos_AttachmentPointer] = [] - - var group: SignalServiceProtos_GroupContext { - get {return _group ?? SignalServiceProtos_GroupContext()} - set {_group = newValue} - } - /// Returns true if `group` has been explicitly set. - var hasGroup: Bool {return self._group != nil} - /// Clears the value of `group`. Subsequent reads from it will return its default value. - mutating func clearGroup() {self._group = nil} - - var flags: UInt32 { - get {return _flags ?? 0} - set {_flags = newValue} - } - /// Returns true if `flags` has been explicitly set. - var hasFlags: Bool {return self._flags != nil} - /// Clears the value of `flags`. Subsequent reads from it will return its default value. - mutating func clearFlags() {self._flags = nil} - - var expireTimer: UInt32 { - get {return _expireTimer ?? 0} - set {_expireTimer = newValue} - } - /// Returns true if `expireTimer` has been explicitly set. - var hasExpireTimer: Bool {return self._expireTimer != nil} - /// Clears the value of `expireTimer`. Subsequent reads from it will return its default value. - mutating func clearExpireTimer() {self._expireTimer = nil} - - var profileKey: Data { - get {return _profileKey ?? SwiftProtobuf.Internal.emptyData} - set {_profileKey = newValue} - } - /// Returns true if `profileKey` has been explicitly set. - var hasProfileKey: Bool {return self._profileKey != nil} - /// Clears the value of `profileKey`. Subsequent reads from it will return its default value. - mutating func clearProfileKey() {self._profileKey = nil} - - var timestamp: UInt64 { - get {return _timestamp ?? 0} - set {_timestamp = newValue} - } - /// Returns true if `timestamp` has been explicitly set. - var hasTimestamp: Bool {return self._timestamp != nil} - /// Clears the value of `timestamp`. Subsequent reads from it will return its default value. - mutating func clearTimestamp() {self._timestamp = nil} - - var quote: SignalServiceProtos_DataMessage.Quote { - get {return _quote ?? SignalServiceProtos_DataMessage.Quote()} - set {_quote = newValue} - } - /// Returns true if `quote` has been explicitly set. - var hasQuote: Bool {return self._quote != nil} - /// Clears the value of `quote`. Subsequent reads from it will return its default value. - mutating func clearQuote() {self._quote = nil} - - var contact: [SignalServiceProtos_DataMessage.Contact] = [] - - var preview: [SignalServiceProtos_DataMessage.Preview] = [] - - /// Loki: The current user's profile - var profile: SignalServiceProtos_DataMessage.LokiProfile { - get {return _profile ?? SignalServiceProtos_DataMessage.LokiProfile()} - set {_profile = newValue} - } - /// Returns true if `profile` has been explicitly set. - var hasProfile: Bool {return self._profile != nil} - /// Clears the value of `profile`. Subsequent reads from it will return its default value. - mutating func clearProfile() {self._profile = nil} - - /// Loki - var closedGroupUpdate: SignalServiceProtos_DataMessage.ClosedGroupUpdate { - get {return _closedGroupUpdate ?? SignalServiceProtos_DataMessage.ClosedGroupUpdate()} - set {_closedGroupUpdate = newValue} - } - /// Returns true if `closedGroupUpdate` has been explicitly set. - var hasClosedGroupUpdate: Bool {return self._closedGroupUpdate != nil} - /// Clears the value of `closedGroupUpdate`. Subsequent reads from it will return its default value. - mutating func clearClosedGroupUpdate() {self._closedGroupUpdate = nil} - - /// Loki: Internal public chat info - var publicChatInfo: SignalServiceProtos_PublicChatInfo { - get {return _publicChatInfo ?? SignalServiceProtos_PublicChatInfo()} - set {_publicChatInfo = newValue} - } - /// Returns true if `publicChatInfo` has been explicitly set. - var hasPublicChatInfo: Bool {return self._publicChatInfo != nil} - /// Clears the value of `publicChatInfo`. Subsequent reads from it will return its default value. - mutating func clearPublicChatInfo() {self._publicChatInfo = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum Flags: SwiftProtobuf.Enum { - typealias RawValue = Int - case endSession // = 1 - case expirationTimerUpdate // = 2 - case profileKeyUpdate // = 4 - case unlinkDevice // = 128 - - init() { - self = .endSession - } - - init?(rawValue: Int) { - switch rawValue { - case 1: self = .endSession - case 2: self = .expirationTimerUpdate - case 4: self = .profileKeyUpdate - case 128: self = .unlinkDevice - default: return nil - } - } - - var rawValue: Int { - switch self { - case .endSession: return 1 - case .expirationTimerUpdate: return 2 - case .profileKeyUpdate: return 4 - case .unlinkDevice: return 128 - } - } - - } - - struct Quote { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: UInt64 { - get {return _id ?? 0} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - /// @required - var author: String { - get {return _author ?? String()} - set {_author = newValue} - } - /// Returns true if `author` has been explicitly set. - var hasAuthor: Bool {return self._author != nil} - /// Clears the value of `author`. Subsequent reads from it will return its default value. - mutating func clearAuthor() {self._author = nil} - - var text: String { - get {return _text ?? String()} - set {_text = newValue} - } - /// Returns true if `text` has been explicitly set. - var hasText: Bool {return self._text != nil} - /// Clears the value of `text`. Subsequent reads from it will return its default value. - mutating func clearText() {self._text = nil} - - var attachments: [SignalServiceProtos_DataMessage.Quote.QuotedAttachment] = [] - - var unknownFields = SwiftProtobuf.UnknownStorage() - - struct QuotedAttachment { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var contentType: String { - get {return _contentType ?? String()} - set {_contentType = newValue} - } - /// Returns true if `contentType` has been explicitly set. - var hasContentType: Bool {return self._contentType != nil} - /// Clears the value of `contentType`. Subsequent reads from it will return its default value. - mutating func clearContentType() {self._contentType = nil} - - var fileName: String { - get {return _fileName ?? String()} - set {_fileName = newValue} - } - /// Returns true if `fileName` has been explicitly set. - var hasFileName: Bool {return self._fileName != nil} - /// Clears the value of `fileName`. Subsequent reads from it will return its default value. - mutating func clearFileName() {self._fileName = nil} - - var thumbnail: SignalServiceProtos_AttachmentPointer { - get {return _thumbnail ?? SignalServiceProtos_AttachmentPointer()} - set {_thumbnail = newValue} - } - /// Returns true if `thumbnail` has been explicitly set. - var hasThumbnail: Bool {return self._thumbnail != nil} - /// Clears the value of `thumbnail`. Subsequent reads from it will return its default value. - mutating func clearThumbnail() {self._thumbnail = nil} - - var flags: UInt32 { - get {return _flags ?? 0} - set {_flags = newValue} - } - /// Returns true if `flags` has been explicitly set. - var hasFlags: Bool {return self._flags != nil} - /// Clears the value of `flags`. Subsequent reads from it will return its default value. - mutating func clearFlags() {self._flags = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum Flags: SwiftProtobuf.Enum { - typealias RawValue = Int - case voiceMessage // = 1 - - init() { - self = .voiceMessage - } - - init?(rawValue: Int) { - switch rawValue { - case 1: self = .voiceMessage - default: return nil - } - } - - var rawValue: Int { - switch self { - case .voiceMessage: return 1 - } - } - - } - - init() {} - - fileprivate var _contentType: String? = nil - fileprivate var _fileName: String? = nil - fileprivate var _thumbnail: SignalServiceProtos_AttachmentPointer? = nil - fileprivate var _flags: UInt32? = nil - } - - init() {} - - fileprivate var _id: UInt64? = nil - fileprivate var _author: String? = nil - fileprivate var _text: String? = nil - } - - struct Contact { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var name: SignalServiceProtos_DataMessage.Contact.Name { - get {return _name ?? SignalServiceProtos_DataMessage.Contact.Name()} - set {_name = newValue} - } - /// Returns true if `name` has been explicitly set. - var hasName: Bool {return self._name != nil} - /// Clears the value of `name`. Subsequent reads from it will return its default value. - mutating func clearName() {self._name = nil} - - var number: [SignalServiceProtos_DataMessage.Contact.Phone] = [] - - var email: [SignalServiceProtos_DataMessage.Contact.Email] = [] - - var address: [SignalServiceProtos_DataMessage.Contact.PostalAddress] = [] - - var avatar: SignalServiceProtos_DataMessage.Contact.Avatar { - get {return _avatar ?? SignalServiceProtos_DataMessage.Contact.Avatar()} - set {_avatar = newValue} - } - /// Returns true if `avatar` has been explicitly set. - var hasAvatar: Bool {return self._avatar != nil} - /// Clears the value of `avatar`. Subsequent reads from it will return its default value. - mutating func clearAvatar() {self._avatar = nil} - - var organization: String { - get {return _organization ?? String()} - set {_organization = newValue} - } - /// Returns true if `organization` has been explicitly set. - var hasOrganization: Bool {return self._organization != nil} - /// Clears the value of `organization`. Subsequent reads from it will return its default value. - mutating func clearOrganization() {self._organization = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - struct Name { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var givenName: String { - get {return _givenName ?? String()} - set {_givenName = newValue} - } - /// Returns true if `givenName` has been explicitly set. - var hasGivenName: Bool {return self._givenName != nil} - /// Clears the value of `givenName`. Subsequent reads from it will return its default value. - mutating func clearGivenName() {self._givenName = nil} - - var familyName: String { - get {return _familyName ?? String()} - set {_familyName = newValue} - } - /// Returns true if `familyName` has been explicitly set. - var hasFamilyName: Bool {return self._familyName != nil} - /// Clears the value of `familyName`. Subsequent reads from it will return its default value. - mutating func clearFamilyName() {self._familyName = nil} - - var prefix: String { - get {return _prefix ?? String()} - set {_prefix = newValue} - } - /// Returns true if `prefix` has been explicitly set. - var hasPrefix: Bool {return self._prefix != nil} - /// Clears the value of `prefix`. Subsequent reads from it will return its default value. - mutating func clearPrefix() {self._prefix = nil} - - var suffix: String { - get {return _suffix ?? String()} - set {_suffix = newValue} - } - /// Returns true if `suffix` has been explicitly set. - var hasSuffix: Bool {return self._suffix != nil} - /// Clears the value of `suffix`. Subsequent reads from it will return its default value. - mutating func clearSuffix() {self._suffix = nil} - - var middleName: String { - get {return _middleName ?? String()} - set {_middleName = newValue} - } - /// Returns true if `middleName` has been explicitly set. - var hasMiddleName: Bool {return self._middleName != nil} - /// Clears the value of `middleName`. Subsequent reads from it will return its default value. - mutating func clearMiddleName() {self._middleName = nil} - - var displayName: String { - get {return _displayName ?? String()} - set {_displayName = newValue} - } - /// Returns true if `displayName` has been explicitly set. - var hasDisplayName: Bool {return self._displayName != nil} - /// Clears the value of `displayName`. Subsequent reads from it will return its default value. - mutating func clearDisplayName() {self._displayName = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _givenName: String? = nil - fileprivate var _familyName: String? = nil - fileprivate var _prefix: String? = nil - fileprivate var _suffix: String? = nil - fileprivate var _middleName: String? = nil - fileprivate var _displayName: String? = nil - } - - struct Phone { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var value: String { - get {return _value ?? String()} - set {_value = newValue} - } - /// Returns true if `value` has been explicitly set. - var hasValue: Bool {return self._value != nil} - /// Clears the value of `value`. Subsequent reads from it will return its default value. - mutating func clearValue() {self._value = nil} - - var type: SignalServiceProtos_DataMessage.Contact.Phone.TypeEnum { - get {return _type ?? .home} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var label: String { - get {return _label ?? String()} - set {_label = newValue} - } - /// Returns true if `label` has been explicitly set. - var hasLabel: Bool {return self._label != nil} - /// Clears the value of `label`. Subsequent reads from it will return its default value. - mutating func clearLabel() {self._label = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - case home // = 1 - case mobile // = 2 - case work // = 3 - case custom // = 4 - - init() { - self = .home - } - - init?(rawValue: Int) { - switch rawValue { - case 1: self = .home - case 2: self = .mobile - case 3: self = .work - case 4: self = .custom - default: return nil - } - } - - var rawValue: Int { - switch self { - case .home: return 1 - case .mobile: return 2 - case .work: return 3 - case .custom: return 4 - } - } - - } - - init() {} - - fileprivate var _value: String? = nil - fileprivate var _type: SignalServiceProtos_DataMessage.Contact.Phone.TypeEnum? = nil - fileprivate var _label: String? = nil - } - - struct Email { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var value: String { - get {return _value ?? String()} - set {_value = newValue} - } - /// Returns true if `value` has been explicitly set. - var hasValue: Bool {return self._value != nil} - /// Clears the value of `value`. Subsequent reads from it will return its default value. - mutating func clearValue() {self._value = nil} - - var type: SignalServiceProtos_DataMessage.Contact.Email.TypeEnum { - get {return _type ?? .home} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var label: String { - get {return _label ?? String()} - set {_label = newValue} - } - /// Returns true if `label` has been explicitly set. - var hasLabel: Bool {return self._label != nil} - /// Clears the value of `label`. Subsequent reads from it will return its default value. - mutating func clearLabel() {self._label = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - case home // = 1 - case mobile // = 2 - case work // = 3 - case custom // = 4 - - init() { - self = .home - } - - init?(rawValue: Int) { - switch rawValue { - case 1: self = .home - case 2: self = .mobile - case 3: self = .work - case 4: self = .custom - default: return nil - } - } - - var rawValue: Int { - switch self { - case .home: return 1 - case .mobile: return 2 - case .work: return 3 - case .custom: return 4 - } - } - - } - - init() {} - - fileprivate var _value: String? = nil - fileprivate var _type: SignalServiceProtos_DataMessage.Contact.Email.TypeEnum? = nil - fileprivate var _label: String? = nil - } - - struct PostalAddress { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var type: SignalServiceProtos_DataMessage.Contact.PostalAddress.TypeEnum { - get {return _type ?? .home} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var label: String { - get {return _label ?? String()} - set {_label = newValue} - } - /// Returns true if `label` has been explicitly set. - var hasLabel: Bool {return self._label != nil} - /// Clears the value of `label`. Subsequent reads from it will return its default value. - mutating func clearLabel() {self._label = nil} - - var street: String { - get {return _street ?? String()} - set {_street = newValue} - } - /// Returns true if `street` has been explicitly set. - var hasStreet: Bool {return self._street != nil} - /// Clears the value of `street`. Subsequent reads from it will return its default value. - mutating func clearStreet() {self._street = nil} - - var pobox: String { - get {return _pobox ?? String()} - set {_pobox = newValue} - } - /// Returns true if `pobox` has been explicitly set. - var hasPobox: Bool {return self._pobox != nil} - /// Clears the value of `pobox`. Subsequent reads from it will return its default value. - mutating func clearPobox() {self._pobox = nil} - - var neighborhood: String { - get {return _neighborhood ?? String()} - set {_neighborhood = newValue} - } - /// Returns true if `neighborhood` has been explicitly set. - var hasNeighborhood: Bool {return self._neighborhood != nil} - /// Clears the value of `neighborhood`. Subsequent reads from it will return its default value. - mutating func clearNeighborhood() {self._neighborhood = nil} - - var city: String { - get {return _city ?? String()} - set {_city = newValue} - } - /// Returns true if `city` has been explicitly set. - var hasCity: Bool {return self._city != nil} - /// Clears the value of `city`. Subsequent reads from it will return its default value. - mutating func clearCity() {self._city = nil} - - var region: String { - get {return _region ?? String()} - set {_region = newValue} - } - /// Returns true if `region` has been explicitly set. - var hasRegion: Bool {return self._region != nil} - /// Clears the value of `region`. Subsequent reads from it will return its default value. - mutating func clearRegion() {self._region = nil} - - var postcode: String { - get {return _postcode ?? String()} - set {_postcode = newValue} - } - /// Returns true if `postcode` has been explicitly set. - var hasPostcode: Bool {return self._postcode != nil} - /// Clears the value of `postcode`. Subsequent reads from it will return its default value. - mutating func clearPostcode() {self._postcode = nil} - - var country: String { - get {return _country ?? String()} - set {_country = newValue} - } - /// Returns true if `country` has been explicitly set. - var hasCountry: Bool {return self._country != nil} - /// Clears the value of `country`. Subsequent reads from it will return its default value. - mutating func clearCountry() {self._country = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - case home // = 1 - case work // = 2 - case custom // = 3 - - init() { - self = .home - } - - init?(rawValue: Int) { - switch rawValue { - case 1: self = .home - case 2: self = .work - case 3: self = .custom - default: return nil - } - } - - var rawValue: Int { - switch self { - case .home: return 1 - case .work: return 2 - case .custom: return 3 - } - } - - } - - init() {} - - fileprivate var _type: SignalServiceProtos_DataMessage.Contact.PostalAddress.TypeEnum? = nil - fileprivate var _label: String? = nil - fileprivate var _street: String? = nil - fileprivate var _pobox: String? = nil - fileprivate var _neighborhood: String? = nil - fileprivate var _city: String? = nil - fileprivate var _region: String? = nil - fileprivate var _postcode: String? = nil - fileprivate var _country: String? = nil - } - - struct Avatar { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var avatar: SignalServiceProtos_AttachmentPointer { - get {return _avatar ?? SignalServiceProtos_AttachmentPointer()} - set {_avatar = newValue} - } - /// Returns true if `avatar` has been explicitly set. - var hasAvatar: Bool {return self._avatar != nil} - /// Clears the value of `avatar`. Subsequent reads from it will return its default value. - mutating func clearAvatar() {self._avatar = nil} - - var isProfile: Bool { - get {return _isProfile ?? false} - set {_isProfile = newValue} - } - /// Returns true if `isProfile` has been explicitly set. - var hasIsProfile: Bool {return self._isProfile != nil} - /// Clears the value of `isProfile`. Subsequent reads from it will return its default value. - mutating func clearIsProfile() {self._isProfile = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _avatar: SignalServiceProtos_AttachmentPointer? = nil - fileprivate var _isProfile: Bool? = nil - } - - init() {} - - fileprivate var _name: SignalServiceProtos_DataMessage.Contact.Name? = nil - fileprivate var _avatar: SignalServiceProtos_DataMessage.Contact.Avatar? = nil - fileprivate var _organization: String? = nil - } - - struct Preview { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var url: String { - get {return _url ?? String()} - set {_url = newValue} - } - /// Returns true if `url` has been explicitly set. - var hasURL: Bool {return self._url != nil} - /// Clears the value of `url`. Subsequent reads from it will return its default value. - mutating func clearURL() {self._url = nil} - - var title: String { - get {return _title ?? String()} - set {_title = newValue} - } - /// Returns true if `title` has been explicitly set. - var hasTitle: Bool {return self._title != nil} - /// Clears the value of `title`. Subsequent reads from it will return its default value. - mutating func clearTitle() {self._title = nil} - - var image: SignalServiceProtos_AttachmentPointer { - get {return _image ?? SignalServiceProtos_AttachmentPointer()} - set {_image = newValue} - } - /// Returns true if `image` has been explicitly set. - var hasImage: Bool {return self._image != nil} - /// Clears the value of `image`. Subsequent reads from it will return its default value. - mutating func clearImage() {self._image = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _url: String? = nil - fileprivate var _title: String? = nil - fileprivate var _image: SignalServiceProtos_AttachmentPointer? = nil - } - - /// Loki - struct LokiProfile { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var displayName: String { - get {return _displayName ?? String()} - set {_displayName = newValue} - } - /// Returns true if `displayName` has been explicitly set. - var hasDisplayName: Bool {return self._displayName != nil} - /// Clears the value of `displayName`. Subsequent reads from it will return its default value. - mutating func clearDisplayName() {self._displayName = nil} - - var profilePicture: String { - get {return _profilePicture ?? String()} - set {_profilePicture = newValue} - } - /// Returns true if `profilePicture` has been explicitly set. - var hasProfilePicture: Bool {return self._profilePicture != nil} - /// Clears the value of `profilePicture`. Subsequent reads from it will return its default value. - mutating func clearProfilePicture() {self._profilePicture = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _displayName: String? = nil - fileprivate var _profilePicture: String? = nil - } - - /// Loki - struct ClosedGroupUpdate { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var name: String { - get {return _name ?? String()} - set {_name = newValue} - } - /// Returns true if `name` has been explicitly set. - var hasName: Bool {return self._name != nil} - /// Clears the value of `name`. Subsequent reads from it will return its default value. - mutating func clearName() {self._name = nil} - - /// @required - var groupPublicKey: Data { - get {return _groupPublicKey ?? SwiftProtobuf.Internal.emptyData} - set {_groupPublicKey = newValue} - } - /// Returns true if `groupPublicKey` has been explicitly set. - var hasGroupPublicKey: Bool {return self._groupPublicKey != nil} - /// Clears the value of `groupPublicKey`. Subsequent reads from it will return its default value. - mutating func clearGroupPublicKey() {self._groupPublicKey = nil} - - var groupPrivateKey: Data { - get {return _groupPrivateKey ?? SwiftProtobuf.Internal.emptyData} - set {_groupPrivateKey = newValue} - } - /// Returns true if `groupPrivateKey` has been explicitly set. - var hasGroupPrivateKey: Bool {return self._groupPrivateKey != nil} - /// Clears the value of `groupPrivateKey`. Subsequent reads from it will return its default value. - mutating func clearGroupPrivateKey() {self._groupPrivateKey = nil} - - var senderKeys: [SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey] = [] - - var members: [Data] = [] - - var admins: [Data] = [] - - /// @required - var type: SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum { - get {return _type ?? .new} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - - /// groupPublicKey, name, groupPrivateKey, senderKeys, members, admins - case new // = 0 - - /// groupPublicKey, name, senderKeys, members, admins - case info // = 1 - - /// groupPublicKey - case senderKeyRequest // = 2 - - /// groupPublicKey, senderKeys - case senderKey // = 3 - - init() { - self = .new - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .new - case 1: self = .info - case 2: self = .senderKeyRequest - case 3: self = .senderKey - default: return nil - } - } - - var rawValue: Int { - switch self { - case .new: return 0 - case .info: return 1 - case .senderKeyRequest: return 2 - case .senderKey: return 3 - } - } - - } - - struct SenderKey { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var chainKey: Data { - get {return _chainKey ?? SwiftProtobuf.Internal.emptyData} - set {_chainKey = newValue} - } - /// Returns true if `chainKey` has been explicitly set. - var hasChainKey: Bool {return self._chainKey != nil} - /// Clears the value of `chainKey`. Subsequent reads from it will return its default value. - mutating func clearChainKey() {self._chainKey = nil} - - /// @required - var keyIndex: UInt32 { - get {return _keyIndex ?? 0} - set {_keyIndex = newValue} - } - /// Returns true if `keyIndex` has been explicitly set. - var hasKeyIndex: Bool {return self._keyIndex != nil} - /// Clears the value of `keyIndex`. Subsequent reads from it will return its default value. - mutating func clearKeyIndex() {self._keyIndex = nil} - - /// @required - var publicKey: Data { - get {return _publicKey ?? SwiftProtobuf.Internal.emptyData} - set {_publicKey = newValue} - } - /// Returns true if `publicKey` has been explicitly set. - var hasPublicKey: Bool {return self._publicKey != nil} - /// Clears the value of `publicKey`. Subsequent reads from it will return its default value. - mutating func clearPublicKey() {self._publicKey = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _chainKey: Data? = nil - fileprivate var _keyIndex: UInt32? = nil - fileprivate var _publicKey: Data? = nil - } - - init() {} - - fileprivate var _name: String? = nil - fileprivate var _groupPublicKey: Data? = nil - fileprivate var _groupPrivateKey: Data? = nil - fileprivate var _type: SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum? = nil - } - - init() {} - - fileprivate var _body: String? = nil - fileprivate var _group: SignalServiceProtos_GroupContext? = nil - fileprivate var _flags: UInt32? = nil - fileprivate var _expireTimer: UInt32? = nil - fileprivate var _profileKey: Data? = nil - fileprivate var _timestamp: UInt64? = nil - fileprivate var _quote: SignalServiceProtos_DataMessage.Quote? = nil - fileprivate var _profile: SignalServiceProtos_DataMessage.LokiProfile? = nil - fileprivate var _closedGroupUpdate: SignalServiceProtos_DataMessage.ClosedGroupUpdate? = nil - fileprivate var _publicChatInfo: SignalServiceProtos_PublicChatInfo? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_DataMessage.Flags: CaseIterable { - // Support synthesized by the compiler. -} - -extension SignalServiceProtos_DataMessage.Quote.QuotedAttachment.Flags: CaseIterable { - // Support synthesized by the compiler. -} - -extension SignalServiceProtos_DataMessage.Contact.Phone.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -extension SignalServiceProtos_DataMessage.Contact.Email.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -extension SignalServiceProtos_DataMessage.Contact.PostalAddress.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_NullMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var padding: Data { - get {return _padding ?? SwiftProtobuf.Internal.emptyData} - set {_padding = newValue} - } - /// Returns true if `padding` has been explicitly set. - var hasPadding: Bool {return self._padding != nil} - /// Clears the value of `padding`. Subsequent reads from it will return its default value. - mutating func clearPadding() {self._padding = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _padding: Data? = nil -} - -struct SignalServiceProtos_ReceiptMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var type: SignalServiceProtos_ReceiptMessage.TypeEnum { - get {return _type ?? .delivery} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var timestamp: [UInt64] = [] - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - case delivery // = 0 - case read // = 1 - - init() { - self = .delivery - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .delivery - case 1: self = .read - default: return nil - } - } - - var rawValue: Int { - switch self { - case .delivery: return 0 - case .read: return 1 - } - } - - } - - init() {} - - fileprivate var _type: SignalServiceProtos_ReceiptMessage.TypeEnum? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_ReceiptMessage.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_Verified { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var destination: String { - get {return _destination ?? String()} - set {_destination = newValue} - } - /// Returns true if `destination` has been explicitly set. - var hasDestination: Bool {return self._destination != nil} - /// Clears the value of `destination`. Subsequent reads from it will return its default value. - mutating func clearDestination() {self._destination = nil} - - var identityKey: Data { - get {return _identityKey ?? SwiftProtobuf.Internal.emptyData} - set {_identityKey = newValue} - } - /// Returns true if `identityKey` has been explicitly set. - var hasIdentityKey: Bool {return self._identityKey != nil} - /// Clears the value of `identityKey`. Subsequent reads from it will return its default value. - mutating func clearIdentityKey() {self._identityKey = nil} - - var state: SignalServiceProtos_Verified.State { - get {return _state ?? .default} - set {_state = newValue} - } - /// Returns true if `state` has been explicitly set. - var hasState: Bool {return self._state != nil} - /// Clears the value of `state`. Subsequent reads from it will return its default value. - mutating func clearState() {self._state = nil} - - var nullMessage: Data { - get {return _nullMessage ?? SwiftProtobuf.Internal.emptyData} - set {_nullMessage = newValue} - } - /// Returns true if `nullMessage` has been explicitly set. - var hasNullMessage: Bool {return self._nullMessage != nil} - /// Clears the value of `nullMessage`. Subsequent reads from it will return its default value. - mutating func clearNullMessage() {self._nullMessage = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum State: SwiftProtobuf.Enum { - typealias RawValue = Int - case `default` // = 0 - case verified // = 1 - case unverified // = 2 - - init() { - self = .default - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .default - case 1: self = .verified - case 2: self = .unverified - default: return nil - } - } - - var rawValue: Int { - switch self { - case .default: return 0 - case .verified: return 1 - case .unverified: return 2 - } - } - - } - - init() {} - - fileprivate var _destination: String? = nil - fileprivate var _identityKey: Data? = nil - fileprivate var _state: SignalServiceProtos_Verified.State? = nil - fileprivate var _nullMessage: Data? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_Verified.State: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_SyncMessage { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var sent: SignalServiceProtos_SyncMessage.Sent { - get {return _sent ?? SignalServiceProtos_SyncMessage.Sent()} - set {_sent = newValue} - } - /// Returns true if `sent` has been explicitly set. - var hasSent: Bool {return self._sent != nil} - /// Clears the value of `sent`. Subsequent reads from it will return its default value. - mutating func clearSent() {self._sent = nil} - - var contacts: SignalServiceProtos_SyncMessage.Contacts { - get {return _contacts ?? SignalServiceProtos_SyncMessage.Contacts()} - set {_contacts = newValue} - } - /// Returns true if `contacts` has been explicitly set. - var hasContacts: Bool {return self._contacts != nil} - /// Clears the value of `contacts`. Subsequent reads from it will return its default value. - mutating func clearContacts() {self._contacts = nil} - - var groups: SignalServiceProtos_SyncMessage.Groups { - get {return _groups ?? SignalServiceProtos_SyncMessage.Groups()} - set {_groups = newValue} - } - /// Returns true if `groups` has been explicitly set. - var hasGroups: Bool {return self._groups != nil} - /// Clears the value of `groups`. Subsequent reads from it will return its default value. - mutating func clearGroups() {self._groups = nil} - - var request: SignalServiceProtos_SyncMessage.Request { - get {return _request ?? SignalServiceProtos_SyncMessage.Request()} - set {_request = newValue} - } - /// Returns true if `request` has been explicitly set. - var hasRequest: Bool {return self._request != nil} - /// Clears the value of `request`. Subsequent reads from it will return its default value. - mutating func clearRequest() {self._request = nil} - - var read: [SignalServiceProtos_SyncMessage.Read] = [] - - var blocked: SignalServiceProtos_SyncMessage.Blocked { - get {return _blocked ?? SignalServiceProtos_SyncMessage.Blocked()} - set {_blocked = newValue} - } - /// Returns true if `blocked` has been explicitly set. - var hasBlocked: Bool {return self._blocked != nil} - /// Clears the value of `blocked`. Subsequent reads from it will return its default value. - mutating func clearBlocked() {self._blocked = nil} - - var verified: SignalServiceProtos_Verified { - get {return _verified ?? SignalServiceProtos_Verified()} - set {_verified = newValue} - } - /// Returns true if `verified` has been explicitly set. - var hasVerified: Bool {return self._verified != nil} - /// Clears the value of `verified`. Subsequent reads from it will return its default value. - mutating func clearVerified() {self._verified = nil} - - var configuration: SignalServiceProtos_SyncMessage.Configuration { - get {return _configuration ?? SignalServiceProtos_SyncMessage.Configuration()} - set {_configuration = newValue} - } - /// Returns true if `configuration` has been explicitly set. - var hasConfiguration: Bool {return self._configuration != nil} - /// Clears the value of `configuration`. Subsequent reads from it will return its default value. - mutating func clearConfiguration() {self._configuration = nil} - - var padding: Data { - get {return _padding ?? SwiftProtobuf.Internal.emptyData} - set {_padding = newValue} - } - /// Returns true if `padding` has been explicitly set. - var hasPadding: Bool {return self._padding != nil} - /// Clears the value of `padding`. Subsequent reads from it will return its default value. - mutating func clearPadding() {self._padding = nil} - - var openGroups: [SignalServiceProtos_SyncMessage.OpenGroupDetails] = [] - - var unknownFields = SwiftProtobuf.UnknownStorage() - - struct Sent { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var destination: String { - get {return _destination ?? String()} - set {_destination = newValue} - } - /// Returns true if `destination` has been explicitly set. - var hasDestination: Bool {return self._destination != nil} - /// Clears the value of `destination`. Subsequent reads from it will return its default value. - mutating func clearDestination() {self._destination = nil} - - var timestamp: UInt64 { - get {return _timestamp ?? 0} - set {_timestamp = newValue} - } - /// Returns true if `timestamp` has been explicitly set. - var hasTimestamp: Bool {return self._timestamp != nil} - /// Clears the value of `timestamp`. Subsequent reads from it will return its default value. - mutating func clearTimestamp() {self._timestamp = nil} - - var message: SignalServiceProtos_DataMessage { - get {return _message ?? SignalServiceProtos_DataMessage()} - set {_message = newValue} - } - /// Returns true if `message` has been explicitly set. - var hasMessage: Bool {return self._message != nil} - /// Clears the value of `message`. Subsequent reads from it will return its default value. - mutating func clearMessage() {self._message = nil} - - var expirationStartTimestamp: UInt64 { - get {return _expirationStartTimestamp ?? 0} - set {_expirationStartTimestamp = newValue} - } - /// Returns true if `expirationStartTimestamp` has been explicitly set. - var hasExpirationStartTimestamp: Bool {return self._expirationStartTimestamp != nil} - /// Clears the value of `expirationStartTimestamp`. Subsequent reads from it will return its default value. - mutating func clearExpirationStartTimestamp() {self._expirationStartTimestamp = nil} - - var unidentifiedStatus: [SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus] = [] - - var isRecipientUpdate: Bool { - get {return _isRecipientUpdate ?? false} - set {_isRecipientUpdate = newValue} - } - /// Returns true if `isRecipientUpdate` has been explicitly set. - var hasIsRecipientUpdate: Bool {return self._isRecipientUpdate != nil} - /// Clears the value of `isRecipientUpdate`. Subsequent reads from it will return its default value. - mutating func clearIsRecipientUpdate() {self._isRecipientUpdate = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - struct UnidentifiedDeliveryStatus { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var destination: String { - get {return _destination ?? String()} - set {_destination = newValue} - } - /// Returns true if `destination` has been explicitly set. - var hasDestination: Bool {return self._destination != nil} - /// Clears the value of `destination`. Subsequent reads from it will return its default value. - mutating func clearDestination() {self._destination = nil} - - var unidentified: Bool { - get {return _unidentified ?? false} - set {_unidentified = newValue} - } - /// Returns true if `unidentified` has been explicitly set. - var hasUnidentified: Bool {return self._unidentified != nil} - /// Clears the value of `unidentified`. Subsequent reads from it will return its default value. - mutating func clearUnidentified() {self._unidentified = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _destination: String? = nil - fileprivate var _unidentified: Bool? = nil - } - - init() {} - - fileprivate var _destination: String? = nil - fileprivate var _timestamp: UInt64? = nil - fileprivate var _message: SignalServiceProtos_DataMessage? = nil - fileprivate var _expirationStartTimestamp: UInt64? = nil - fileprivate var _isRecipientUpdate: Bool? = nil - } - - struct Contacts { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var blob: SignalServiceProtos_AttachmentPointer { - get {return _blob ?? SignalServiceProtos_AttachmentPointer()} - set {_blob = newValue} - } - /// Returns true if `blob` has been explicitly set. - var hasBlob: Bool {return self._blob != nil} - /// Clears the value of `blob`. Subsequent reads from it will return its default value. - mutating func clearBlob() {self._blob = nil} - - /// Signal-iOS renamed this property. - var isComplete: Bool { - get {return _isComplete ?? false} - set {_isComplete = newValue} - } - /// Returns true if `isComplete` has been explicitly set. - var hasIsComplete: Bool {return self._isComplete != nil} - /// Clears the value of `isComplete`. Subsequent reads from it will return its default value. - mutating func clearIsComplete() {self._isComplete = nil} - - /// Loki - var data: Data { - get {return _data ?? SwiftProtobuf.Internal.emptyData} - set {_data = newValue} - } - /// Returns true if `data` has been explicitly set. - var hasData: Bool {return self._data != nil} - /// Clears the value of `data`. Subsequent reads from it will return its default value. - mutating func clearData() {self._data = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _blob: SignalServiceProtos_AttachmentPointer? = nil - fileprivate var _isComplete: Bool? = nil - fileprivate var _data: Data? = nil - } - - struct Groups { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var blob: SignalServiceProtos_AttachmentPointer { - get {return _blob ?? SignalServiceProtos_AttachmentPointer()} - set {_blob = newValue} - } - /// Returns true if `blob` has been explicitly set. - var hasBlob: Bool {return self._blob != nil} - /// Clears the value of `blob`. Subsequent reads from it will return its default value. - mutating func clearBlob() {self._blob = nil} - - /// Loki - var data: Data { - get {return _data ?? SwiftProtobuf.Internal.emptyData} - set {_data = newValue} - } - /// Returns true if `data` has been explicitly set. - var hasData: Bool {return self._data != nil} - /// Clears the value of `data`. Subsequent reads from it will return its default value. - mutating func clearData() {self._data = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _blob: SignalServiceProtos_AttachmentPointer? = nil - fileprivate var _data: Data? = nil - } - - /// Loki - struct OpenGroupDetails { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var url: String { - get {return _url ?? String()} - set {_url = newValue} - } - /// Returns true if `url` has been explicitly set. - var hasURL: Bool {return self._url != nil} - /// Clears the value of `url`. Subsequent reads from it will return its default value. - mutating func clearURL() {self._url = nil} - - /// @required - var channelID: UInt64 { - get {return _channelID ?? 0} - set {_channelID = newValue} - } - /// Returns true if `channelID` has been explicitly set. - var hasChannelID: Bool {return self._channelID != nil} - /// Clears the value of `channelID`. Subsequent reads from it will return its default value. - mutating func clearChannelID() {self._channelID = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _url: String? = nil - fileprivate var _channelID: UInt64? = nil - } - - struct Blocked { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var numbers: [String] = [] - - var groupIds: [Data] = [] - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - } - - struct Request { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var type: SignalServiceProtos_SyncMessage.Request.TypeEnum { - get {return _type ?? .unknown} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - case unknown // = 0 - case contacts // = 1 - case groups // = 2 - case blocked // = 3 - case configuration // = 4 - - init() { - self = .unknown - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .unknown - case 1: self = .contacts - case 2: self = .groups - case 3: self = .blocked - case 4: self = .configuration - default: return nil - } - } - - var rawValue: Int { - switch self { - case .unknown: return 0 - case .contacts: return 1 - case .groups: return 2 - case .blocked: return 3 - case .configuration: return 4 - } - } - - } - - init() {} - - fileprivate var _type: SignalServiceProtos_SyncMessage.Request.TypeEnum? = nil - } - - struct Read { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var sender: String { - get {return _sender ?? String()} - set {_sender = newValue} - } - /// Returns true if `sender` has been explicitly set. - var hasSender: Bool {return self._sender != nil} - /// Clears the value of `sender`. Subsequent reads from it will return its default value. - mutating func clearSender() {self._sender = nil} - - /// @required - var timestamp: UInt64 { - get {return _timestamp ?? 0} - set {_timestamp = newValue} - } - /// Returns true if `timestamp` has been explicitly set. - var hasTimestamp: Bool {return self._timestamp != nil} - /// Clears the value of `timestamp`. Subsequent reads from it will return its default value. - mutating func clearTimestamp() {self._timestamp = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _sender: String? = nil - fileprivate var _timestamp: UInt64? = nil - } - - struct Configuration { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var readReceipts: Bool { - get {return _readReceipts ?? false} - set {_readReceipts = newValue} - } - /// Returns true if `readReceipts` has been explicitly set. - var hasReadReceipts: Bool {return self._readReceipts != nil} - /// Clears the value of `readReceipts`. Subsequent reads from it will return its default value. - mutating func clearReadReceipts() {self._readReceipts = nil} - - var unidentifiedDeliveryIndicators: Bool { - get {return _unidentifiedDeliveryIndicators ?? false} - set {_unidentifiedDeliveryIndicators = newValue} - } - /// Returns true if `unidentifiedDeliveryIndicators` has been explicitly set. - var hasUnidentifiedDeliveryIndicators: Bool {return self._unidentifiedDeliveryIndicators != nil} - /// Clears the value of `unidentifiedDeliveryIndicators`. Subsequent reads from it will return its default value. - mutating func clearUnidentifiedDeliveryIndicators() {self._unidentifiedDeliveryIndicators = nil} - - var typingIndicators: Bool { - get {return _typingIndicators ?? false} - set {_typingIndicators = newValue} - } - /// Returns true if `typingIndicators` has been explicitly set. - var hasTypingIndicators: Bool {return self._typingIndicators != nil} - /// Clears the value of `typingIndicators`. Subsequent reads from it will return its default value. - mutating func clearTypingIndicators() {self._typingIndicators = nil} - - var linkPreviews: Bool { - get {return _linkPreviews ?? false} - set {_linkPreviews = newValue} - } - /// Returns true if `linkPreviews` has been explicitly set. - var hasLinkPreviews: Bool {return self._linkPreviews != nil} - /// Clears the value of `linkPreviews`. Subsequent reads from it will return its default value. - mutating func clearLinkPreviews() {self._linkPreviews = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _readReceipts: Bool? = nil - fileprivate var _unidentifiedDeliveryIndicators: Bool? = nil - fileprivate var _typingIndicators: Bool? = nil - fileprivate var _linkPreviews: Bool? = nil - } - - init() {} - - fileprivate var _sent: SignalServiceProtos_SyncMessage.Sent? = nil - fileprivate var _contacts: SignalServiceProtos_SyncMessage.Contacts? = nil - fileprivate var _groups: SignalServiceProtos_SyncMessage.Groups? = nil - fileprivate var _request: SignalServiceProtos_SyncMessage.Request? = nil - fileprivate var _blocked: SignalServiceProtos_SyncMessage.Blocked? = nil - fileprivate var _verified: SignalServiceProtos_Verified? = nil - fileprivate var _configuration: SignalServiceProtos_SyncMessage.Configuration? = nil - fileprivate var _padding: Data? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_SyncMessage.Request.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_AttachmentPointer { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: UInt64 { - get {return _id ?? 0} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - var contentType: String { - get {return _contentType ?? String()} - set {_contentType = newValue} - } - /// Returns true if `contentType` has been explicitly set. - var hasContentType: Bool {return self._contentType != nil} - /// Clears the value of `contentType`. Subsequent reads from it will return its default value. - mutating func clearContentType() {self._contentType = nil} - - var key: Data { - get {return _key ?? SwiftProtobuf.Internal.emptyData} - set {_key = newValue} - } - /// Returns true if `key` has been explicitly set. - var hasKey: Bool {return self._key != nil} - /// Clears the value of `key`. Subsequent reads from it will return its default value. - mutating func clearKey() {self._key = nil} - - var size: UInt32 { - get {return _size ?? 0} - set {_size = newValue} - } - /// Returns true if `size` has been explicitly set. - var hasSize: Bool {return self._size != nil} - /// Clears the value of `size`. Subsequent reads from it will return its default value. - mutating func clearSize() {self._size = nil} - - var thumbnail: Data { - get {return _thumbnail ?? SwiftProtobuf.Internal.emptyData} - set {_thumbnail = newValue} - } - /// Returns true if `thumbnail` has been explicitly set. - var hasThumbnail: Bool {return self._thumbnail != nil} - /// Clears the value of `thumbnail`. Subsequent reads from it will return its default value. - mutating func clearThumbnail() {self._thumbnail = nil} - - var digest: Data { - get {return _digest ?? SwiftProtobuf.Internal.emptyData} - set {_digest = newValue} - } - /// Returns true if `digest` has been explicitly set. - var hasDigest: Bool {return self._digest != nil} - /// Clears the value of `digest`. Subsequent reads from it will return its default value. - mutating func clearDigest() {self._digest = nil} - - var fileName: String { - get {return _fileName ?? String()} - set {_fileName = newValue} - } - /// Returns true if `fileName` has been explicitly set. - var hasFileName: Bool {return self._fileName != nil} - /// Clears the value of `fileName`. Subsequent reads from it will return its default value. - mutating func clearFileName() {self._fileName = nil} - - var flags: UInt32 { - get {return _flags ?? 0} - set {_flags = newValue} - } - /// Returns true if `flags` has been explicitly set. - var hasFlags: Bool {return self._flags != nil} - /// Clears the value of `flags`. Subsequent reads from it will return its default value. - mutating func clearFlags() {self._flags = nil} - - var width: UInt32 { - get {return _width ?? 0} - set {_width = newValue} - } - /// Returns true if `width` has been explicitly set. - var hasWidth: Bool {return self._width != nil} - /// Clears the value of `width`. Subsequent reads from it will return its default value. - mutating func clearWidth() {self._width = nil} - - var height: UInt32 { - get {return _height ?? 0} - set {_height = newValue} - } - /// Returns true if `height` has been explicitly set. - var hasHeight: Bool {return self._height != nil} - /// Clears the value of `height`. Subsequent reads from it will return its default value. - mutating func clearHeight() {self._height = nil} - - var caption: String { - get {return _caption ?? String()} - set {_caption = newValue} - } - /// Returns true if `caption` has been explicitly set. - var hasCaption: Bool {return self._caption != nil} - /// Clears the value of `caption`. Subsequent reads from it will return its default value. - mutating func clearCaption() {self._caption = nil} - - /// Loki - var url: String { - get {return _url ?? String()} - set {_url = newValue} - } - /// Returns true if `url` has been explicitly set. - var hasURL: Bool {return self._url != nil} - /// Clears the value of `url`. Subsequent reads from it will return its default value. - mutating func clearURL() {self._url = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum Flags: SwiftProtobuf.Enum { - typealias RawValue = Int - case voiceMessage // = 1 - - init() { - self = .voiceMessage - } - - init?(rawValue: Int) { - switch rawValue { - case 1: self = .voiceMessage - default: return nil - } - } - - var rawValue: Int { - switch self { - case .voiceMessage: return 1 - } - } - - } - - init() {} - - fileprivate var _id: UInt64? = nil - fileprivate var _contentType: String? = nil - fileprivate var _key: Data? = nil - fileprivate var _size: UInt32? = nil - fileprivate var _thumbnail: Data? = nil - fileprivate var _digest: Data? = nil - fileprivate var _fileName: String? = nil - fileprivate var _flags: UInt32? = nil - fileprivate var _width: UInt32? = nil - fileprivate var _height: UInt32? = nil - fileprivate var _caption: String? = nil - fileprivate var _url: String? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_AttachmentPointer.Flags: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_GroupContext { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: Data { - get {return _id ?? SwiftProtobuf.Internal.emptyData} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - /// @required - var type: SignalServiceProtos_GroupContext.TypeEnum { - get {return _type ?? .unknown} - set {_type = newValue} - } - /// Returns true if `type` has been explicitly set. - var hasType: Bool {return self._type != nil} - /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {self._type = nil} - - var name: String { - get {return _name ?? String()} - set {_name = newValue} - } - /// Returns true if `name` has been explicitly set. - var hasName: Bool {return self._name != nil} - /// Clears the value of `name`. Subsequent reads from it will return its default value. - mutating func clearName() {self._name = nil} - - var members: [String] = [] - - var avatar: SignalServiceProtos_AttachmentPointer { - get {return _avatar ?? SignalServiceProtos_AttachmentPointer()} - set {_avatar = newValue} - } - /// Returns true if `avatar` has been explicitly set. - var hasAvatar: Bool {return self._avatar != nil} - /// Clears the value of `avatar`. Subsequent reads from it will return its default value. - mutating func clearAvatar() {self._avatar = nil} - - /// Loki - var admins: [String] = [] - - var unknownFields = SwiftProtobuf.UnknownStorage() - - enum TypeEnum: SwiftProtobuf.Enum { - typealias RawValue = Int - case unknown // = 0 - case update // = 1 - case deliver // = 2 - case quit // = 3 - case requestInfo // = 4 - - init() { - self = .unknown - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .unknown - case 1: self = .update - case 2: self = .deliver - case 3: self = .quit - case 4: self = .requestInfo - default: return nil - } - } - - var rawValue: Int { - switch self { - case .unknown: return 0 - case .update: return 1 - case .deliver: return 2 - case .quit: return 3 - case .requestInfo: return 4 - } - } - - } - - init() {} - - fileprivate var _id: Data? = nil - fileprivate var _type: SignalServiceProtos_GroupContext.TypeEnum? = nil - fileprivate var _name: String? = nil - fileprivate var _avatar: SignalServiceProtos_AttachmentPointer? = nil -} - -#if swift(>=4.2) - -extension SignalServiceProtos_GroupContext.TypeEnum: CaseIterable { - // Support synthesized by the compiler. -} - -#endif // swift(>=4.2) - -struct SignalServiceProtos_ContactDetails { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var number: String { - get {return _number ?? String()} - set {_number = newValue} - } - /// Returns true if `number` has been explicitly set. - var hasNumber: Bool {return self._number != nil} - /// Clears the value of `number`. Subsequent reads from it will return its default value. - mutating func clearNumber() {self._number = nil} - - var name: String { - get {return _name ?? String()} - set {_name = newValue} - } - /// Returns true if `name` has been explicitly set. - var hasName: Bool {return self._name != nil} - /// Clears the value of `name`. Subsequent reads from it will return its default value. - mutating func clearName() {self._name = nil} - - var avatar: SignalServiceProtos_ContactDetails.Avatar { - get {return _avatar ?? SignalServiceProtos_ContactDetails.Avatar()} - set {_avatar = newValue} - } - /// Returns true if `avatar` has been explicitly set. - var hasAvatar: Bool {return self._avatar != nil} - /// Clears the value of `avatar`. Subsequent reads from it will return its default value. - mutating func clearAvatar() {self._avatar = nil} - - var color: String { - get {return _color ?? String()} - set {_color = newValue} - } - /// Returns true if `color` has been explicitly set. - var hasColor: Bool {return self._color != nil} - /// Clears the value of `color`. Subsequent reads from it will return its default value. - mutating func clearColor() {self._color = nil} - - var verified: SignalServiceProtos_Verified { - get {return _verified ?? SignalServiceProtos_Verified()} - set {_verified = newValue} - } - /// Returns true if `verified` has been explicitly set. - var hasVerified: Bool {return self._verified != nil} - /// Clears the value of `verified`. Subsequent reads from it will return its default value. - mutating func clearVerified() {self._verified = nil} - - var profileKey: Data { - get {return _profileKey ?? SwiftProtobuf.Internal.emptyData} - set {_profileKey = newValue} - } - /// Returns true if `profileKey` has been explicitly set. - var hasProfileKey: Bool {return self._profileKey != nil} - /// Clears the value of `profileKey`. Subsequent reads from it will return its default value. - mutating func clearProfileKey() {self._profileKey = nil} - - var blocked: Bool { - get {return _blocked ?? false} - set {_blocked = newValue} - } - /// Returns true if `blocked` has been explicitly set. - var hasBlocked: Bool {return self._blocked != nil} - /// Clears the value of `blocked`. Subsequent reads from it will return its default value. - mutating func clearBlocked() {self._blocked = nil} - - var expireTimer: UInt32 { - get {return _expireTimer ?? 0} - set {_expireTimer = newValue} - } - /// Returns true if `expireTimer` has been explicitly set. - var hasExpireTimer: Bool {return self._expireTimer != nil} - /// Clears the value of `expireTimer`. Subsequent reads from it will return its default value. - mutating func clearExpireTimer() {self._expireTimer = nil} - - /// Loki - var nickname: String { - get {return _nickname ?? String()} - set {_nickname = newValue} - } - /// Returns true if `nickname` has been explicitly set. - var hasNickname: Bool {return self._nickname != nil} - /// Clears the value of `nickname`. Subsequent reads from it will return its default value. - mutating func clearNickname() {self._nickname = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - struct Avatar { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var contentType: String { - get {return _contentType ?? String()} - set {_contentType = newValue} - } - /// Returns true if `contentType` has been explicitly set. - var hasContentType: Bool {return self._contentType != nil} - /// Clears the value of `contentType`. Subsequent reads from it will return its default value. - mutating func clearContentType() {self._contentType = nil} - - var length: UInt32 { - get {return _length ?? 0} - set {_length = newValue} - } - /// Returns true if `length` has been explicitly set. - var hasLength: Bool {return self._length != nil} - /// Clears the value of `length`. Subsequent reads from it will return its default value. - mutating func clearLength() {self._length = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _contentType: String? = nil - fileprivate var _length: UInt32? = nil - } - - init() {} - - fileprivate var _number: String? = nil - fileprivate var _name: String? = nil - fileprivate var _avatar: SignalServiceProtos_ContactDetails.Avatar? = nil - fileprivate var _color: String? = nil - fileprivate var _verified: SignalServiceProtos_Verified? = nil - fileprivate var _profileKey: Data? = nil - fileprivate var _blocked: Bool? = nil - fileprivate var _expireTimer: UInt32? = nil - fileprivate var _nickname: String? = nil -} - -struct SignalServiceProtos_GroupDetails { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// @required - var id: Data { - get {return _id ?? SwiftProtobuf.Internal.emptyData} - set {_id = newValue} - } - /// Returns true if `id` has been explicitly set. - var hasID: Bool {return self._id != nil} - /// Clears the value of `id`. Subsequent reads from it will return its default value. - mutating func clearID() {self._id = nil} - - var name: String { - get {return _name ?? String()} - set {_name = newValue} - } - /// Returns true if `name` has been explicitly set. - var hasName: Bool {return self._name != nil} - /// Clears the value of `name`. Subsequent reads from it will return its default value. - mutating func clearName() {self._name = nil} - - var members: [String] = [] - - var avatar: SignalServiceProtos_GroupDetails.Avatar { - get {return _avatar ?? SignalServiceProtos_GroupDetails.Avatar()} - set {_avatar = newValue} - } - /// Returns true if `avatar` has been explicitly set. - var hasAvatar: Bool {return self._avatar != nil} - /// Clears the value of `avatar`. Subsequent reads from it will return its default value. - mutating func clearAvatar() {self._avatar = nil} - - var active: Bool { - get {return _active ?? true} - set {_active = newValue} - } - /// Returns true if `active` has been explicitly set. - var hasActive: Bool {return self._active != nil} - /// Clears the value of `active`. Subsequent reads from it will return its default value. - mutating func clearActive() {self._active = nil} - - var expireTimer: UInt32 { - get {return _expireTimer ?? 0} - set {_expireTimer = newValue} - } - /// Returns true if `expireTimer` has been explicitly set. - var hasExpireTimer: Bool {return self._expireTimer != nil} - /// Clears the value of `expireTimer`. Subsequent reads from it will return its default value. - mutating func clearExpireTimer() {self._expireTimer = nil} - - var color: String { - get {return _color ?? String()} - set {_color = newValue} - } - /// Returns true if `color` has been explicitly set. - var hasColor: Bool {return self._color != nil} - /// Clears the value of `color`. Subsequent reads from it will return its default value. - mutating func clearColor() {self._color = nil} - - var blocked: Bool { - get {return _blocked ?? false} - set {_blocked = newValue} - } - /// Returns true if `blocked` has been explicitly set. - var hasBlocked: Bool {return self._blocked != nil} - /// Clears the value of `blocked`. Subsequent reads from it will return its default value. - mutating func clearBlocked() {self._blocked = nil} - - /// Loki - var admins: [String] = [] - - var unknownFields = SwiftProtobuf.UnknownStorage() - - struct Avatar { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var contentType: String { - get {return _contentType ?? String()} - set {_contentType = newValue} - } - /// Returns true if `contentType` has been explicitly set. - var hasContentType: Bool {return self._contentType != nil} - /// Clears the value of `contentType`. Subsequent reads from it will return its default value. - mutating func clearContentType() {self._contentType = nil} - - var length: UInt32 { - get {return _length ?? 0} - set {_length = newValue} - } - /// Returns true if `length` has been explicitly set. - var hasLength: Bool {return self._length != nil} - /// Clears the value of `length`. Subsequent reads from it will return its default value. - mutating func clearLength() {self._length = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _contentType: String? = nil - fileprivate var _length: UInt32? = nil - } - - init() {} - - fileprivate var _id: Data? = nil - fileprivate var _name: String? = nil - fileprivate var _avatar: SignalServiceProtos_GroupDetails.Avatar? = nil - fileprivate var _active: Bool? = nil - fileprivate var _expireTimer: UInt32? = nil - fileprivate var _color: String? = nil - fileprivate var _blocked: Bool? = nil -} - -/// Internal - DO NOT SEND -struct SignalServiceProtos_PublicChatInfo { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - var serverID: UInt64 { - get {return _serverID ?? 0} - set {_serverID = newValue} - } - /// Returns true if `serverID` has been explicitly set. - var hasServerID: Bool {return self._serverID != nil} - /// Clears the value of `serverID`. Subsequent reads from it will return its default value. - mutating func clearServerID() {self._serverID = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - init() {} - - fileprivate var _serverID: UInt64? = nil -} - -// MARK: - Code below here is support for the SwiftProtobuf runtime. - -fileprivate let _protobuf_package = "SignalServiceProtos" - -extension SignalServiceProtos_Envelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".Envelope" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "type"), - 2: .same(proto: "source"), - 7: .same(proto: "sourceDevice"), - 3: .same(proto: "relay"), - 5: .same(proto: "timestamp"), - 6: .same(proto: "legacyMessage"), - 8: .same(proto: "content"), - 9: .same(proto: "serverGuid"), - 10: .same(proto: "serverTimestamp"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularEnumField(value: &self._type) - case 2: try decoder.decodeSingularStringField(value: &self._source) - case 3: try decoder.decodeSingularStringField(value: &self._relay) - case 5: try decoder.decodeSingularUInt64Field(value: &self._timestamp) - case 6: try decoder.decodeSingularBytesField(value: &self._legacyMessage) - case 7: try decoder.decodeSingularUInt32Field(value: &self._sourceDevice) - case 8: try decoder.decodeSingularBytesField(value: &self._content) - case 9: try decoder.decodeSingularStringField(value: &self._serverGuid) - case 10: try decoder.decodeSingularUInt64Field(value: &self._serverTimestamp) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 1) - } - if let v = self._source { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._relay { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - if let v = self._timestamp { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 5) - } - if let v = self._legacyMessage { - try visitor.visitSingularBytesField(value: v, fieldNumber: 6) - } - if let v = self._sourceDevice { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 7) - } - if let v = self._content { - try visitor.visitSingularBytesField(value: v, fieldNumber: 8) - } - if let v = self._serverGuid { - try visitor.visitSingularStringField(value: v, fieldNumber: 9) - } - if let v = self._serverTimestamp { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 10) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_Envelope, rhs: SignalServiceProtos_Envelope) -> Bool { - if lhs._type != rhs._type {return false} - if lhs._source != rhs._source {return false} - if lhs._sourceDevice != rhs._sourceDevice {return false} - if lhs._relay != rhs._relay {return false} - if lhs._timestamp != rhs._timestamp {return false} - if lhs._legacyMessage != rhs._legacyMessage {return false} - if lhs._content != rhs._content {return false} - if lhs._serverGuid != rhs._serverGuid {return false} - if lhs._serverTimestamp != rhs._serverTimestamp {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_Envelope.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "UNKNOWN"), - 1: .same(proto: "CIPHERTEXT"), - 2: .same(proto: "KEY_EXCHANGE"), - 3: .same(proto: "PREKEY_BUNDLE"), - 5: .same(proto: "RECEIPT"), - 6: .same(proto: "UNIDENTIFIED_SENDER"), - 7: .same(proto: "CLOSED_GROUP_CIPHERTEXT"), - 101: .same(proto: "FALLBACK_MESSAGE"), - ] -} - -extension SignalServiceProtos_TypingMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".TypingMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "timestamp"), - 2: .same(proto: "action"), - 3: .same(proto: "groupId"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._timestamp) - case 2: try decoder.decodeSingularEnumField(value: &self._action) - case 3: try decoder.decodeSingularBytesField(value: &self._groupID) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._timestamp { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - if let v = self._action { - try visitor.visitSingularEnumField(value: v, fieldNumber: 2) - } - if let v = self._groupID { - try visitor.visitSingularBytesField(value: v, fieldNumber: 3) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_TypingMessage, rhs: SignalServiceProtos_TypingMessage) -> Bool { - if lhs._timestamp != rhs._timestamp {return false} - if lhs._action != rhs._action {return false} - if lhs._groupID != rhs._groupID {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_TypingMessage.Action: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "STARTED"), - 1: .same(proto: "STOPPED"), - ] -} - -extension SignalServiceProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".Content" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "dataMessage"), - 2: .same(proto: "syncMessage"), - 3: .same(proto: "callMessage"), - 4: .same(proto: "nullMessage"), - 5: .same(proto: "receiptMessage"), - 6: .same(proto: "typingMessage"), - 101: .same(proto: "prekeyBundleMessage"), - 103: .same(proto: "lokiDeviceLinkMessage"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularMessageField(value: &self._dataMessage) - case 2: try decoder.decodeSingularMessageField(value: &self._syncMessage) - case 3: try decoder.decodeSingularMessageField(value: &self._callMessage) - case 4: try decoder.decodeSingularMessageField(value: &self._nullMessage) - case 5: try decoder.decodeSingularMessageField(value: &self._receiptMessage) - case 6: try decoder.decodeSingularMessageField(value: &self._typingMessage) - case 101: try decoder.decodeSingularMessageField(value: &self._prekeyBundleMessage) - case 103: try decoder.decodeSingularMessageField(value: &self._lokiDeviceLinkMessage) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._dataMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } - if let v = self._syncMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } - if let v = self._callMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - if let v = self._nullMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) - } - if let v = self._receiptMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 5) - } - if let v = self._typingMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 6) - } - if let v = self._prekeyBundleMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 101) - } - if let v = self._lokiDeviceLinkMessage { - try visitor.visitSingularMessageField(value: v, fieldNumber: 103) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_Content, rhs: SignalServiceProtos_Content) -> Bool { - if lhs._dataMessage != rhs._dataMessage {return false} - if lhs._syncMessage != rhs._syncMessage {return false} - if lhs._callMessage != rhs._callMessage {return false} - if lhs._nullMessage != rhs._nullMessage {return false} - if lhs._receiptMessage != rhs._receiptMessage {return false} - if lhs._typingMessage != rhs._typingMessage {return false} - if lhs._prekeyBundleMessage != rhs._prekeyBundleMessage {return false} - if lhs._lokiDeviceLinkMessage != rhs._lokiDeviceLinkMessage {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_PrekeyBundleMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".PrekeyBundleMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "identityKey"), - 2: .same(proto: "deviceID"), - 3: .same(proto: "prekeyID"), - 4: .same(proto: "signedKeyID"), - 5: .same(proto: "prekey"), - 6: .same(proto: "signedKey"), - 7: .same(proto: "signature"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._identityKey) - case 2: try decoder.decodeSingularUInt32Field(value: &self._deviceID) - case 3: try decoder.decodeSingularUInt32Field(value: &self._prekeyID) - case 4: try decoder.decodeSingularUInt32Field(value: &self._signedKeyID) - case 5: try decoder.decodeSingularBytesField(value: &self._prekey) - case 6: try decoder.decodeSingularBytesField(value: &self._signedKey) - case 7: try decoder.decodeSingularBytesField(value: &self._signature) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._identityKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - if let v = self._deviceID { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) - } - if let v = self._prekeyID { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 3) - } - if let v = self._signedKeyID { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 4) - } - if let v = self._prekey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 5) - } - if let v = self._signedKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 6) - } - if let v = self._signature { - try visitor.visitSingularBytesField(value: v, fieldNumber: 7) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_PrekeyBundleMessage, rhs: SignalServiceProtos_PrekeyBundleMessage) -> Bool { - if lhs._identityKey != rhs._identityKey {return false} - if lhs._deviceID != rhs._deviceID {return false} - if lhs._prekeyID != rhs._prekeyID {return false} - if lhs._signedKeyID != rhs._signedKeyID {return false} - if lhs._prekey != rhs._prekey {return false} - if lhs._signedKey != rhs._signedKey {return false} - if lhs._signature != rhs._signature {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_LokiDeviceLinkMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".LokiDeviceLinkMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "masterPublicKey"), - 2: .same(proto: "slavePublicKey"), - 3: .same(proto: "slaveSignature"), - 4: .same(proto: "masterSignature"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._masterPublicKey) - case 2: try decoder.decodeSingularStringField(value: &self._slavePublicKey) - case 3: try decoder.decodeSingularBytesField(value: &self._slaveSignature) - case 4: try decoder.decodeSingularBytesField(value: &self._masterSignature) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._masterPublicKey { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._slavePublicKey { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._slaveSignature { - try visitor.visitSingularBytesField(value: v, fieldNumber: 3) - } - if let v = self._masterSignature { - try visitor.visitSingularBytesField(value: v, fieldNumber: 4) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_LokiDeviceLinkMessage, rhs: SignalServiceProtos_LokiDeviceLinkMessage) -> Bool { - if lhs._masterPublicKey != rhs._masterPublicKey {return false} - if lhs._slavePublicKey != rhs._slavePublicKey {return false} - if lhs._slaveSignature != rhs._slaveSignature {return false} - if lhs._masterSignature != rhs._masterSignature {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".CallMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "offer"), - 2: .same(proto: "answer"), - 3: .same(proto: "iceUpdate"), - 4: .same(proto: "hangup"), - 5: .same(proto: "busy"), - 6: .same(proto: "profileKey"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularMessageField(value: &self._offer) - case 2: try decoder.decodeSingularMessageField(value: &self._answer) - case 3: try decoder.decodeRepeatedMessageField(value: &self.iceUpdate) - case 4: try decoder.decodeSingularMessageField(value: &self._hangup) - case 5: try decoder.decodeSingularMessageField(value: &self._busy) - case 6: try decoder.decodeSingularBytesField(value: &self._profileKey) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._offer { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } - if let v = self._answer { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } - if !self.iceUpdate.isEmpty { - try visitor.visitRepeatedMessageField(value: self.iceUpdate, fieldNumber: 3) - } - if let v = self._hangup { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) - } - if let v = self._busy { - try visitor.visitSingularMessageField(value: v, fieldNumber: 5) - } - if let v = self._profileKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 6) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_CallMessage, rhs: SignalServiceProtos_CallMessage) -> Bool { - if lhs._offer != rhs._offer {return false} - if lhs._answer != rhs._answer {return false} - if lhs.iceUpdate != rhs.iceUpdate {return false} - if lhs._hangup != rhs._hangup {return false} - if lhs._busy != rhs._busy {return false} - if lhs._profileKey != rhs._profileKey {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_CallMessage.Offer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_CallMessage.protoMessageName + ".Offer" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - 2: .same(proto: "sessionDescription"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._id) - case 2: try decoder.decodeSingularStringField(value: &self._sessionDescription) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - if let v = self._sessionDescription { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_CallMessage.Offer, rhs: SignalServiceProtos_CallMessage.Offer) -> Bool { - if lhs._id != rhs._id {return false} - if lhs._sessionDescription != rhs._sessionDescription {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_CallMessage.Answer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_CallMessage.protoMessageName + ".Answer" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - 2: .same(proto: "sessionDescription"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._id) - case 2: try decoder.decodeSingularStringField(value: &self._sessionDescription) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - if let v = self._sessionDescription { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_CallMessage.Answer, rhs: SignalServiceProtos_CallMessage.Answer) -> Bool { - if lhs._id != rhs._id {return false} - if lhs._sessionDescription != rhs._sessionDescription {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_CallMessage.IceUpdate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_CallMessage.protoMessageName + ".IceUpdate" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - 2: .same(proto: "sdpMid"), - 3: .same(proto: "sdpMLineIndex"), - 4: .same(proto: "sdp"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._id) - case 2: try decoder.decodeSingularStringField(value: &self._sdpMid) - case 3: try decoder.decodeSingularUInt32Field(value: &self._sdpMlineIndex) - case 4: try decoder.decodeSingularStringField(value: &self._sdp) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - if let v = self._sdpMid { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._sdpMlineIndex { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 3) - } - if let v = self._sdp { - try visitor.visitSingularStringField(value: v, fieldNumber: 4) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_CallMessage.IceUpdate, rhs: SignalServiceProtos_CallMessage.IceUpdate) -> Bool { - if lhs._id != rhs._id {return false} - if lhs._sdpMid != rhs._sdpMid {return false} - if lhs._sdpMlineIndex != rhs._sdpMlineIndex {return false} - if lhs._sdp != rhs._sdp {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_CallMessage.Busy: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_CallMessage.protoMessageName + ".Busy" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._id) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_CallMessage.Busy, rhs: SignalServiceProtos_CallMessage.Busy) -> Bool { - if lhs._id != rhs._id {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_CallMessage.Hangup: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_CallMessage.protoMessageName + ".Hangup" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._id) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_CallMessage.Hangup, rhs: SignalServiceProtos_CallMessage.Hangup) -> Bool { - if lhs._id != rhs._id {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_ClosedGroupCiphertextMessageWrapper: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".ClosedGroupCiphertextMessageWrapper" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "ciphertext"), - 2: .same(proto: "ephemeralPublicKey"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._ciphertext) - case 2: try decoder.decodeSingularBytesField(value: &self._ephemeralPublicKey) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._ciphertext { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - if let v = self._ephemeralPublicKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_ClosedGroupCiphertextMessageWrapper, rhs: SignalServiceProtos_ClosedGroupCiphertextMessageWrapper) -> Bool { - if lhs._ciphertext != rhs._ciphertext {return false} - if lhs._ephemeralPublicKey != rhs._ephemeralPublicKey {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".DataMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "body"), - 2: .same(proto: "attachments"), - 3: .same(proto: "group"), - 4: .same(proto: "flags"), - 5: .same(proto: "expireTimer"), - 6: .same(proto: "profileKey"), - 7: .same(proto: "timestamp"), - 8: .same(proto: "quote"), - 9: .same(proto: "contact"), - 10: .same(proto: "preview"), - 101: .same(proto: "profile"), - 103: .same(proto: "closedGroupUpdate"), - 999: .same(proto: "publicChatInfo"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._body) - case 2: try decoder.decodeRepeatedMessageField(value: &self.attachments) - case 3: try decoder.decodeSingularMessageField(value: &self._group) - case 4: try decoder.decodeSingularUInt32Field(value: &self._flags) - case 5: try decoder.decodeSingularUInt32Field(value: &self._expireTimer) - case 6: try decoder.decodeSingularBytesField(value: &self._profileKey) - case 7: try decoder.decodeSingularUInt64Field(value: &self._timestamp) - case 8: try decoder.decodeSingularMessageField(value: &self._quote) - case 9: try decoder.decodeRepeatedMessageField(value: &self.contact) - case 10: try decoder.decodeRepeatedMessageField(value: &self.preview) - case 101: try decoder.decodeSingularMessageField(value: &self._profile) - case 103: try decoder.decodeSingularMessageField(value: &self._closedGroupUpdate) - case 999: try decoder.decodeSingularMessageField(value: &self._publicChatInfo) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._body { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if !self.attachments.isEmpty { - try visitor.visitRepeatedMessageField(value: self.attachments, fieldNumber: 2) - } - if let v = self._group { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - if let v = self._flags { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 4) - } - if let v = self._expireTimer { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 5) - } - if let v = self._profileKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 6) - } - if let v = self._timestamp { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 7) - } - if let v = self._quote { - try visitor.visitSingularMessageField(value: v, fieldNumber: 8) - } - if !self.contact.isEmpty { - try visitor.visitRepeatedMessageField(value: self.contact, fieldNumber: 9) - } - if !self.preview.isEmpty { - try visitor.visitRepeatedMessageField(value: self.preview, fieldNumber: 10) - } - if let v = self._profile { - try visitor.visitSingularMessageField(value: v, fieldNumber: 101) - } - if let v = self._closedGroupUpdate { - try visitor.visitSingularMessageField(value: v, fieldNumber: 103) - } - if let v = self._publicChatInfo { - try visitor.visitSingularMessageField(value: v, fieldNumber: 999) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage, rhs: SignalServiceProtos_DataMessage) -> Bool { - if lhs._body != rhs._body {return false} - if lhs.attachments != rhs.attachments {return false} - if lhs._group != rhs._group {return false} - if lhs._flags != rhs._flags {return false} - if lhs._expireTimer != rhs._expireTimer {return false} - if lhs._profileKey != rhs._profileKey {return false} - if lhs._timestamp != rhs._timestamp {return false} - if lhs._quote != rhs._quote {return false} - if lhs.contact != rhs.contact {return false} - if lhs.preview != rhs.preview {return false} - if lhs._profile != rhs._profile {return false} - if lhs._closedGroupUpdate != rhs._closedGroupUpdate {return false} - if lhs._publicChatInfo != rhs._publicChatInfo {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Flags: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "END_SESSION"), - 2: .same(proto: "EXPIRATION_TIMER_UPDATE"), - 4: .same(proto: "PROFILE_KEY_UPDATE"), - 128: .same(proto: "UNLINK_DEVICE"), - ] -} - -extension SignalServiceProtos_DataMessage.Quote: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.protoMessageName + ".Quote" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - 2: .same(proto: "author"), - 3: .same(proto: "text"), - 4: .same(proto: "attachments"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._id) - case 2: try decoder.decodeSingularStringField(value: &self._author) - case 3: try decoder.decodeSingularStringField(value: &self._text) - case 4: try decoder.decodeRepeatedMessageField(value: &self.attachments) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - if let v = self._author { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._text { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - if !self.attachments.isEmpty { - try visitor.visitRepeatedMessageField(value: self.attachments, fieldNumber: 4) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Quote, rhs: SignalServiceProtos_DataMessage.Quote) -> Bool { - if lhs._id != rhs._id {return false} - if lhs._author != rhs._author {return false} - if lhs._text != rhs._text {return false} - if lhs.attachments != rhs.attachments {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Quote.QuotedAttachment: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.Quote.protoMessageName + ".QuotedAttachment" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "contentType"), - 2: .same(proto: "fileName"), - 3: .same(proto: "thumbnail"), - 4: .same(proto: "flags"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._contentType) - case 2: try decoder.decodeSingularStringField(value: &self._fileName) - case 3: try decoder.decodeSingularMessageField(value: &self._thumbnail) - case 4: try decoder.decodeSingularUInt32Field(value: &self._flags) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._contentType { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._fileName { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._thumbnail { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - if let v = self._flags { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 4) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Quote.QuotedAttachment, rhs: SignalServiceProtos_DataMessage.Quote.QuotedAttachment) -> Bool { - if lhs._contentType != rhs._contentType {return false} - if lhs._fileName != rhs._fileName {return false} - if lhs._thumbnail != rhs._thumbnail {return false} - if lhs._flags != rhs._flags {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Quote.QuotedAttachment.Flags: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "VOICE_MESSAGE"), - ] -} - -extension SignalServiceProtos_DataMessage.Contact: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.protoMessageName + ".Contact" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "name"), - 3: .same(proto: "number"), - 4: .same(proto: "email"), - 5: .same(proto: "address"), - 6: .same(proto: "avatar"), - 7: .same(proto: "organization"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularMessageField(value: &self._name) - case 3: try decoder.decodeRepeatedMessageField(value: &self.number) - case 4: try decoder.decodeRepeatedMessageField(value: &self.email) - case 5: try decoder.decodeRepeatedMessageField(value: &self.address) - case 6: try decoder.decodeSingularMessageField(value: &self._avatar) - case 7: try decoder.decodeSingularStringField(value: &self._organization) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._name { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } - if !self.number.isEmpty { - try visitor.visitRepeatedMessageField(value: self.number, fieldNumber: 3) - } - if !self.email.isEmpty { - try visitor.visitRepeatedMessageField(value: self.email, fieldNumber: 4) - } - if !self.address.isEmpty { - try visitor.visitRepeatedMessageField(value: self.address, fieldNumber: 5) - } - if let v = self._avatar { - try visitor.visitSingularMessageField(value: v, fieldNumber: 6) - } - if let v = self._organization { - try visitor.visitSingularStringField(value: v, fieldNumber: 7) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Contact, rhs: SignalServiceProtos_DataMessage.Contact) -> Bool { - if lhs._name != rhs._name {return false} - if lhs.number != rhs.number {return false} - if lhs.email != rhs.email {return false} - if lhs.address != rhs.address {return false} - if lhs._avatar != rhs._avatar {return false} - if lhs._organization != rhs._organization {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Contact.Name: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.Contact.protoMessageName + ".Name" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "givenName"), - 2: .same(proto: "familyName"), - 3: .same(proto: "prefix"), - 4: .same(proto: "suffix"), - 5: .same(proto: "middleName"), - 6: .same(proto: "displayName"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._givenName) - case 2: try decoder.decodeSingularStringField(value: &self._familyName) - case 3: try decoder.decodeSingularStringField(value: &self._prefix) - case 4: try decoder.decodeSingularStringField(value: &self._suffix) - case 5: try decoder.decodeSingularStringField(value: &self._middleName) - case 6: try decoder.decodeSingularStringField(value: &self._displayName) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._givenName { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._familyName { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._prefix { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - if let v = self._suffix { - try visitor.visitSingularStringField(value: v, fieldNumber: 4) - } - if let v = self._middleName { - try visitor.visitSingularStringField(value: v, fieldNumber: 5) - } - if let v = self._displayName { - try visitor.visitSingularStringField(value: v, fieldNumber: 6) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Contact.Name, rhs: SignalServiceProtos_DataMessage.Contact.Name) -> Bool { - if lhs._givenName != rhs._givenName {return false} - if lhs._familyName != rhs._familyName {return false} - if lhs._prefix != rhs._prefix {return false} - if lhs._suffix != rhs._suffix {return false} - if lhs._middleName != rhs._middleName {return false} - if lhs._displayName != rhs._displayName {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Contact.Phone: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.Contact.protoMessageName + ".Phone" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "value"), - 2: .same(proto: "type"), - 3: .same(proto: "label"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._value) - case 2: try decoder.decodeSingularEnumField(value: &self._type) - case 3: try decoder.decodeSingularStringField(value: &self._label) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._value { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 2) - } - if let v = self._label { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Contact.Phone, rhs: SignalServiceProtos_DataMessage.Contact.Phone) -> Bool { - if lhs._value != rhs._value {return false} - if lhs._type != rhs._type {return false} - if lhs._label != rhs._label {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Contact.Phone.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "HOME"), - 2: .same(proto: "MOBILE"), - 3: .same(proto: "WORK"), - 4: .same(proto: "CUSTOM"), - ] -} - -extension SignalServiceProtos_DataMessage.Contact.Email: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.Contact.protoMessageName + ".Email" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "value"), - 2: .same(proto: "type"), - 3: .same(proto: "label"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._value) - case 2: try decoder.decodeSingularEnumField(value: &self._type) - case 3: try decoder.decodeSingularStringField(value: &self._label) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._value { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 2) - } - if let v = self._label { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Contact.Email, rhs: SignalServiceProtos_DataMessage.Contact.Email) -> Bool { - if lhs._value != rhs._value {return false} - if lhs._type != rhs._type {return false} - if lhs._label != rhs._label {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Contact.Email.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "HOME"), - 2: .same(proto: "MOBILE"), - 3: .same(proto: "WORK"), - 4: .same(proto: "CUSTOM"), - ] -} - -extension SignalServiceProtos_DataMessage.Contact.PostalAddress: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.Contact.protoMessageName + ".PostalAddress" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "type"), - 2: .same(proto: "label"), - 3: .same(proto: "street"), - 4: .same(proto: "pobox"), - 5: .same(proto: "neighborhood"), - 6: .same(proto: "city"), - 7: .same(proto: "region"), - 8: .same(proto: "postcode"), - 9: .same(proto: "country"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularEnumField(value: &self._type) - case 2: try decoder.decodeSingularStringField(value: &self._label) - case 3: try decoder.decodeSingularStringField(value: &self._street) - case 4: try decoder.decodeSingularStringField(value: &self._pobox) - case 5: try decoder.decodeSingularStringField(value: &self._neighborhood) - case 6: try decoder.decodeSingularStringField(value: &self._city) - case 7: try decoder.decodeSingularStringField(value: &self._region) - case 8: try decoder.decodeSingularStringField(value: &self._postcode) - case 9: try decoder.decodeSingularStringField(value: &self._country) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 1) - } - if let v = self._label { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._street { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - if let v = self._pobox { - try visitor.visitSingularStringField(value: v, fieldNumber: 4) - } - if let v = self._neighborhood { - try visitor.visitSingularStringField(value: v, fieldNumber: 5) - } - if let v = self._city { - try visitor.visitSingularStringField(value: v, fieldNumber: 6) - } - if let v = self._region { - try visitor.visitSingularStringField(value: v, fieldNumber: 7) - } - if let v = self._postcode { - try visitor.visitSingularStringField(value: v, fieldNumber: 8) - } - if let v = self._country { - try visitor.visitSingularStringField(value: v, fieldNumber: 9) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Contact.PostalAddress, rhs: SignalServiceProtos_DataMessage.Contact.PostalAddress) -> Bool { - if lhs._type != rhs._type {return false} - if lhs._label != rhs._label {return false} - if lhs._street != rhs._street {return false} - if lhs._pobox != rhs._pobox {return false} - if lhs._neighborhood != rhs._neighborhood {return false} - if lhs._city != rhs._city {return false} - if lhs._region != rhs._region {return false} - if lhs._postcode != rhs._postcode {return false} - if lhs._country != rhs._country {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Contact.PostalAddress.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "HOME"), - 2: .same(proto: "WORK"), - 3: .same(proto: "CUSTOM"), - ] -} - -extension SignalServiceProtos_DataMessage.Contact.Avatar: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.Contact.protoMessageName + ".Avatar" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "avatar"), - 2: .same(proto: "isProfile"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularMessageField(value: &self._avatar) - case 2: try decoder.decodeSingularBoolField(value: &self._isProfile) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._avatar { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } - if let v = self._isProfile { - try visitor.visitSingularBoolField(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Contact.Avatar, rhs: SignalServiceProtos_DataMessage.Contact.Avatar) -> Bool { - if lhs._avatar != rhs._avatar {return false} - if lhs._isProfile != rhs._isProfile {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.Preview: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.protoMessageName + ".Preview" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "url"), - 2: .same(proto: "title"), - 3: .same(proto: "image"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._url) - case 2: try decoder.decodeSingularStringField(value: &self._title) - case 3: try decoder.decodeSingularMessageField(value: &self._image) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._url { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._title { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._image { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.Preview, rhs: SignalServiceProtos_DataMessage.Preview) -> Bool { - if lhs._url != rhs._url {return false} - if lhs._title != rhs._title {return false} - if lhs._image != rhs._image {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.LokiProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.protoMessageName + ".LokiProfile" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "displayName"), - 2: .same(proto: "profilePicture"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._displayName) - case 2: try decoder.decodeSingularStringField(value: &self._profilePicture) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._displayName { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._profilePicture { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.LokiProfile, rhs: SignalServiceProtos_DataMessage.LokiProfile) -> Bool { - if lhs._displayName != rhs._displayName {return false} - if lhs._profilePicture != rhs._profilePicture {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.ClosedGroupUpdate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.protoMessageName + ".ClosedGroupUpdate" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "name"), - 2: .same(proto: "groupPublicKey"), - 3: .same(proto: "groupPrivateKey"), - 4: .same(proto: "senderKeys"), - 5: .same(proto: "members"), - 6: .same(proto: "admins"), - 7: .same(proto: "type"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._name) - case 2: try decoder.decodeSingularBytesField(value: &self._groupPublicKey) - case 3: try decoder.decodeSingularBytesField(value: &self._groupPrivateKey) - case 4: try decoder.decodeRepeatedMessageField(value: &self.senderKeys) - case 5: try decoder.decodeRepeatedBytesField(value: &self.members) - case 6: try decoder.decodeRepeatedBytesField(value: &self.admins) - case 7: try decoder.decodeSingularEnumField(value: &self._type) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._name { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._groupPublicKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 2) - } - if let v = self._groupPrivateKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 3) - } - if !self.senderKeys.isEmpty { - try visitor.visitRepeatedMessageField(value: self.senderKeys, fieldNumber: 4) - } - if !self.members.isEmpty { - try visitor.visitRepeatedBytesField(value: self.members, fieldNumber: 5) - } - if !self.admins.isEmpty { - try visitor.visitRepeatedBytesField(value: self.admins, fieldNumber: 6) - } - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 7) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.ClosedGroupUpdate, rhs: SignalServiceProtos_DataMessage.ClosedGroupUpdate) -> Bool { - if lhs._name != rhs._name {return false} - if lhs._groupPublicKey != rhs._groupPublicKey {return false} - if lhs._groupPrivateKey != rhs._groupPrivateKey {return false} - if lhs.senderKeys != rhs.senderKeys {return false} - if lhs.members != rhs.members {return false} - if lhs.admins != rhs.admins {return false} - if lhs._type != rhs._type {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "NEW"), - 1: .same(proto: "INFO"), - 2: .same(proto: "SENDER_KEY_REQUEST"), - 3: .same(proto: "SENDER_KEY"), - ] -} - -extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_DataMessage.ClosedGroupUpdate.protoMessageName + ".SenderKey" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "chainKey"), - 2: .same(proto: "keyIndex"), - 3: .same(proto: "publicKey"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._chainKey) - case 2: try decoder.decodeSingularUInt32Field(value: &self._keyIndex) - case 3: try decoder.decodeSingularBytesField(value: &self._publicKey) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._chainKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - if let v = self._keyIndex { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) - } - if let v = self._publicKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 3) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey, rhs: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey) -> Bool { - if lhs._chainKey != rhs._chainKey {return false} - if lhs._keyIndex != rhs._keyIndex {return false} - if lhs._publicKey != rhs._publicKey {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_NullMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".NullMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "padding"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._padding) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._padding { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_NullMessage, rhs: SignalServiceProtos_NullMessage) -> Bool { - if lhs._padding != rhs._padding {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_ReceiptMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".ReceiptMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "type"), - 2: .same(proto: "timestamp"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularEnumField(value: &self._type) - case 2: try decoder.decodeRepeatedUInt64Field(value: &self.timestamp) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 1) - } - if !self.timestamp.isEmpty { - try visitor.visitRepeatedUInt64Field(value: self.timestamp, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_ReceiptMessage, rhs: SignalServiceProtos_ReceiptMessage) -> Bool { - if lhs._type != rhs._type {return false} - if lhs.timestamp != rhs.timestamp {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_ReceiptMessage.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "DELIVERY"), - 1: .same(proto: "READ"), - ] -} - -extension SignalServiceProtos_Verified: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".Verified" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "destination"), - 2: .same(proto: "identityKey"), - 3: .same(proto: "state"), - 4: .same(proto: "nullMessage"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._destination) - case 2: try decoder.decodeSingularBytesField(value: &self._identityKey) - case 3: try decoder.decodeSingularEnumField(value: &self._state) - case 4: try decoder.decodeSingularBytesField(value: &self._nullMessage) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._destination { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._identityKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 2) - } - if let v = self._state { - try visitor.visitSingularEnumField(value: v, fieldNumber: 3) - } - if let v = self._nullMessage { - try visitor.visitSingularBytesField(value: v, fieldNumber: 4) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_Verified, rhs: SignalServiceProtos_Verified) -> Bool { - if lhs._destination != rhs._destination {return false} - if lhs._identityKey != rhs._identityKey {return false} - if lhs._state != rhs._state {return false} - if lhs._nullMessage != rhs._nullMessage {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_Verified.State: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "DEFAULT"), - 1: .same(proto: "VERIFIED"), - 2: .same(proto: "UNVERIFIED"), - ] -} - -extension SignalServiceProtos_SyncMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".SyncMessage" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "sent"), - 2: .same(proto: "contacts"), - 3: .same(proto: "groups"), - 4: .same(proto: "request"), - 5: .same(proto: "read"), - 6: .same(proto: "blocked"), - 7: .same(proto: "verified"), - 9: .same(proto: "configuration"), - 8: .same(proto: "padding"), - 100: .same(proto: "openGroups"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularMessageField(value: &self._sent) - case 2: try decoder.decodeSingularMessageField(value: &self._contacts) - case 3: try decoder.decodeSingularMessageField(value: &self._groups) - case 4: try decoder.decodeSingularMessageField(value: &self._request) - case 5: try decoder.decodeRepeatedMessageField(value: &self.read) - case 6: try decoder.decodeSingularMessageField(value: &self._blocked) - case 7: try decoder.decodeSingularMessageField(value: &self._verified) - case 8: try decoder.decodeSingularBytesField(value: &self._padding) - case 9: try decoder.decodeSingularMessageField(value: &self._configuration) - case 100: try decoder.decodeRepeatedMessageField(value: &self.openGroups) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._sent { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } - if let v = self._contacts { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } - if let v = self._groups { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - if let v = self._request { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) - } - if !self.read.isEmpty { - try visitor.visitRepeatedMessageField(value: self.read, fieldNumber: 5) - } - if let v = self._blocked { - try visitor.visitSingularMessageField(value: v, fieldNumber: 6) - } - if let v = self._verified { - try visitor.visitSingularMessageField(value: v, fieldNumber: 7) - } - if let v = self._padding { - try visitor.visitSingularBytesField(value: v, fieldNumber: 8) - } - if let v = self._configuration { - try visitor.visitSingularMessageField(value: v, fieldNumber: 9) - } - if !self.openGroups.isEmpty { - try visitor.visitRepeatedMessageField(value: self.openGroups, fieldNumber: 100) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage, rhs: SignalServiceProtos_SyncMessage) -> Bool { - if lhs._sent != rhs._sent {return false} - if lhs._contacts != rhs._contacts {return false} - if lhs._groups != rhs._groups {return false} - if lhs._request != rhs._request {return false} - if lhs.read != rhs.read {return false} - if lhs._blocked != rhs._blocked {return false} - if lhs._verified != rhs._verified {return false} - if lhs._configuration != rhs._configuration {return false} - if lhs._padding != rhs._padding {return false} - if lhs.openGroups != rhs.openGroups {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Sent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Sent" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "destination"), - 2: .same(proto: "timestamp"), - 3: .same(proto: "message"), - 4: .same(proto: "expirationStartTimestamp"), - 5: .same(proto: "unidentifiedStatus"), - 6: .same(proto: "isRecipientUpdate"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._destination) - case 2: try decoder.decodeSingularUInt64Field(value: &self._timestamp) - case 3: try decoder.decodeSingularMessageField(value: &self._message) - case 4: try decoder.decodeSingularUInt64Field(value: &self._expirationStartTimestamp) - case 5: try decoder.decodeRepeatedMessageField(value: &self.unidentifiedStatus) - case 6: try decoder.decodeSingularBoolField(value: &self._isRecipientUpdate) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._destination { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._timestamp { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 2) - } - if let v = self._message { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - if let v = self._expirationStartTimestamp { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 4) - } - if !self.unidentifiedStatus.isEmpty { - try visitor.visitRepeatedMessageField(value: self.unidentifiedStatus, fieldNumber: 5) - } - if let v = self._isRecipientUpdate { - try visitor.visitSingularBoolField(value: v, fieldNumber: 6) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Sent, rhs: SignalServiceProtos_SyncMessage.Sent) -> Bool { - if lhs._destination != rhs._destination {return false} - if lhs._timestamp != rhs._timestamp {return false} - if lhs._message != rhs._message {return false} - if lhs._expirationStartTimestamp != rhs._expirationStartTimestamp {return false} - if lhs.unidentifiedStatus != rhs.unidentifiedStatus {return false} - if lhs._isRecipientUpdate != rhs._isRecipientUpdate {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.Sent.protoMessageName + ".UnidentifiedDeliveryStatus" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "destination"), - 2: .same(proto: "unidentified"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._destination) - case 2: try decoder.decodeSingularBoolField(value: &self._unidentified) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._destination { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._unidentified { - try visitor.visitSingularBoolField(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus, rhs: SignalServiceProtos_SyncMessage.Sent.UnidentifiedDeliveryStatus) -> Bool { - if lhs._destination != rhs._destination {return false} - if lhs._unidentified != rhs._unidentified {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Contacts: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Contacts" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "blob"), - 2: .same(proto: "isComplete"), - 101: .same(proto: "data"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularMessageField(value: &self._blob) - case 2: try decoder.decodeSingularBoolField(value: &self._isComplete) - case 101: try decoder.decodeSingularBytesField(value: &self._data) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._blob { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } - if let v = self._isComplete { - try visitor.visitSingularBoolField(value: v, fieldNumber: 2) - } - if let v = self._data { - try visitor.visitSingularBytesField(value: v, fieldNumber: 101) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Contacts, rhs: SignalServiceProtos_SyncMessage.Contacts) -> Bool { - if lhs._blob != rhs._blob {return false} - if lhs._isComplete != rhs._isComplete {return false} - if lhs._data != rhs._data {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Groups: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Groups" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "blob"), - 101: .same(proto: "data"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularMessageField(value: &self._blob) - case 101: try decoder.decodeSingularBytesField(value: &self._data) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._blob { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } - if let v = self._data { - try visitor.visitSingularBytesField(value: v, fieldNumber: 101) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Groups, rhs: SignalServiceProtos_SyncMessage.Groups) -> Bool { - if lhs._blob != rhs._blob {return false} - if lhs._data != rhs._data {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.OpenGroupDetails: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".OpenGroupDetails" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "url"), - 2: .same(proto: "channelID"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._url) - case 2: try decoder.decodeSingularUInt64Field(value: &self._channelID) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._url { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._channelID { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.OpenGroupDetails, rhs: SignalServiceProtos_SyncMessage.OpenGroupDetails) -> Bool { - if lhs._url != rhs._url {return false} - if lhs._channelID != rhs._channelID {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Blocked: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Blocked" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "numbers"), - 2: .same(proto: "groupIds"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeRepeatedStringField(value: &self.numbers) - case 2: try decoder.decodeRepeatedBytesField(value: &self.groupIds) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if !self.numbers.isEmpty { - try visitor.visitRepeatedStringField(value: self.numbers, fieldNumber: 1) - } - if !self.groupIds.isEmpty { - try visitor.visitRepeatedBytesField(value: self.groupIds, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Blocked, rhs: SignalServiceProtos_SyncMessage.Blocked) -> Bool { - if lhs.numbers != rhs.numbers {return false} - if lhs.groupIds != rhs.groupIds {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Request: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Request" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "type"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularEnumField(value: &self._type) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Request, rhs: SignalServiceProtos_SyncMessage.Request) -> Bool { - if lhs._type != rhs._type {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Request.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "UNKNOWN"), - 1: .same(proto: "CONTACTS"), - 2: .same(proto: "GROUPS"), - 3: .same(proto: "BLOCKED"), - 4: .same(proto: "CONFIGURATION"), - ] -} - -extension SignalServiceProtos_SyncMessage.Read: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Read" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "sender"), - 2: .same(proto: "timestamp"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._sender) - case 2: try decoder.decodeSingularUInt64Field(value: &self._timestamp) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._sender { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._timestamp { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Read, rhs: SignalServiceProtos_SyncMessage.Read) -> Bool { - if lhs._sender != rhs._sender {return false} - if lhs._timestamp != rhs._timestamp {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_SyncMessage.Configuration: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Configuration" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "readReceipts"), - 2: .same(proto: "unidentifiedDeliveryIndicators"), - 3: .same(proto: "typingIndicators"), - 4: .same(proto: "linkPreviews"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBoolField(value: &self._readReceipts) - case 2: try decoder.decodeSingularBoolField(value: &self._unidentifiedDeliveryIndicators) - case 3: try decoder.decodeSingularBoolField(value: &self._typingIndicators) - case 4: try decoder.decodeSingularBoolField(value: &self._linkPreviews) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._readReceipts { - try visitor.visitSingularBoolField(value: v, fieldNumber: 1) - } - if let v = self._unidentifiedDeliveryIndicators { - try visitor.visitSingularBoolField(value: v, fieldNumber: 2) - } - if let v = self._typingIndicators { - try visitor.visitSingularBoolField(value: v, fieldNumber: 3) - } - if let v = self._linkPreviews { - try visitor.visitSingularBoolField(value: v, fieldNumber: 4) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_SyncMessage.Configuration, rhs: SignalServiceProtos_SyncMessage.Configuration) -> Bool { - if lhs._readReceipts != rhs._readReceipts {return false} - if lhs._unidentifiedDeliveryIndicators != rhs._unidentifiedDeliveryIndicators {return false} - if lhs._typingIndicators != rhs._typingIndicators {return false} - if lhs._linkPreviews != rhs._linkPreviews {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_AttachmentPointer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".AttachmentPointer" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - 2: .same(proto: "contentType"), - 3: .same(proto: "key"), - 4: .same(proto: "size"), - 5: .same(proto: "thumbnail"), - 6: .same(proto: "digest"), - 7: .same(proto: "fileName"), - 8: .same(proto: "flags"), - 9: .same(proto: "width"), - 10: .same(proto: "height"), - 11: .same(proto: "caption"), - 101: .same(proto: "url"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularFixed64Field(value: &self._id) - case 2: try decoder.decodeSingularStringField(value: &self._contentType) - case 3: try decoder.decodeSingularBytesField(value: &self._key) - case 4: try decoder.decodeSingularUInt32Field(value: &self._size) - case 5: try decoder.decodeSingularBytesField(value: &self._thumbnail) - case 6: try decoder.decodeSingularBytesField(value: &self._digest) - case 7: try decoder.decodeSingularStringField(value: &self._fileName) - case 8: try decoder.decodeSingularUInt32Field(value: &self._flags) - case 9: try decoder.decodeSingularUInt32Field(value: &self._width) - case 10: try decoder.decodeSingularUInt32Field(value: &self._height) - case 11: try decoder.decodeSingularStringField(value: &self._caption) - case 101: try decoder.decodeSingularStringField(value: &self._url) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularFixed64Field(value: v, fieldNumber: 1) - } - if let v = self._contentType { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._key { - try visitor.visitSingularBytesField(value: v, fieldNumber: 3) - } - if let v = self._size { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 4) - } - if let v = self._thumbnail { - try visitor.visitSingularBytesField(value: v, fieldNumber: 5) - } - if let v = self._digest { - try visitor.visitSingularBytesField(value: v, fieldNumber: 6) - } - if let v = self._fileName { - try visitor.visitSingularStringField(value: v, fieldNumber: 7) - } - if let v = self._flags { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 8) - } - if let v = self._width { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 9) - } - if let v = self._height { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 10) - } - if let v = self._caption { - try visitor.visitSingularStringField(value: v, fieldNumber: 11) - } - if let v = self._url { - try visitor.visitSingularStringField(value: v, fieldNumber: 101) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_AttachmentPointer, rhs: SignalServiceProtos_AttachmentPointer) -> Bool { - if lhs._id != rhs._id {return false} - if lhs._contentType != rhs._contentType {return false} - if lhs._key != rhs._key {return false} - if lhs._size != rhs._size {return false} - if lhs._thumbnail != rhs._thumbnail {return false} - if lhs._digest != rhs._digest {return false} - if lhs._fileName != rhs._fileName {return false} - if lhs._flags != rhs._flags {return false} - if lhs._width != rhs._width {return false} - if lhs._height != rhs._height {return false} - if lhs._caption != rhs._caption {return false} - if lhs._url != rhs._url {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_AttachmentPointer.Flags: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "VOICE_MESSAGE"), - ] -} - -extension SignalServiceProtos_GroupContext: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".GroupContext" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - 2: .same(proto: "type"), - 3: .same(proto: "name"), - 4: .same(proto: "members"), - 5: .same(proto: "avatar"), - 6: .same(proto: "admins"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._id) - case 2: try decoder.decodeSingularEnumField(value: &self._type) - case 3: try decoder.decodeSingularStringField(value: &self._name) - case 4: try decoder.decodeRepeatedStringField(value: &self.members) - case 5: try decoder.decodeSingularMessageField(value: &self._avatar) - case 6: try decoder.decodeRepeatedStringField(value: &self.admins) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - if let v = self._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 2) - } - if let v = self._name { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } - if !self.members.isEmpty { - try visitor.visitRepeatedStringField(value: self.members, fieldNumber: 4) - } - if let v = self._avatar { - try visitor.visitSingularMessageField(value: v, fieldNumber: 5) - } - if !self.admins.isEmpty { - try visitor.visitRepeatedStringField(value: self.admins, fieldNumber: 6) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_GroupContext, rhs: SignalServiceProtos_GroupContext) -> Bool { - if lhs._id != rhs._id {return false} - if lhs._type != rhs._type {return false} - if lhs._name != rhs._name {return false} - if lhs.members != rhs.members {return false} - if lhs._avatar != rhs._avatar {return false} - if lhs.admins != rhs.admins {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_GroupContext.TypeEnum: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "UNKNOWN"), - 1: .same(proto: "UPDATE"), - 2: .same(proto: "DELIVER"), - 3: .same(proto: "QUIT"), - 4: .same(proto: "REQUEST_INFO"), - ] -} - -extension SignalServiceProtos_ContactDetails: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".ContactDetails" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "number"), - 2: .same(proto: "name"), - 3: .same(proto: "avatar"), - 4: .same(proto: "color"), - 5: .same(proto: "verified"), - 6: .same(proto: "profileKey"), - 7: .same(proto: "blocked"), - 8: .same(proto: "expireTimer"), - 101: .same(proto: "nickname"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._number) - case 2: try decoder.decodeSingularStringField(value: &self._name) - case 3: try decoder.decodeSingularMessageField(value: &self._avatar) - case 4: try decoder.decodeSingularStringField(value: &self._color) - case 5: try decoder.decodeSingularMessageField(value: &self._verified) - case 6: try decoder.decodeSingularBytesField(value: &self._profileKey) - case 7: try decoder.decodeSingularBoolField(value: &self._blocked) - case 8: try decoder.decodeSingularUInt32Field(value: &self._expireTimer) - case 101: try decoder.decodeSingularStringField(value: &self._nickname) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._number { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._name { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if let v = self._avatar { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - if let v = self._color { - try visitor.visitSingularStringField(value: v, fieldNumber: 4) - } - if let v = self._verified { - try visitor.visitSingularMessageField(value: v, fieldNumber: 5) - } - if let v = self._profileKey { - try visitor.visitSingularBytesField(value: v, fieldNumber: 6) - } - if let v = self._blocked { - try visitor.visitSingularBoolField(value: v, fieldNumber: 7) - } - if let v = self._expireTimer { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 8) - } - if let v = self._nickname { - try visitor.visitSingularStringField(value: v, fieldNumber: 101) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_ContactDetails, rhs: SignalServiceProtos_ContactDetails) -> Bool { - if lhs._number != rhs._number {return false} - if lhs._name != rhs._name {return false} - if lhs._avatar != rhs._avatar {return false} - if lhs._color != rhs._color {return false} - if lhs._verified != rhs._verified {return false} - if lhs._profileKey != rhs._profileKey {return false} - if lhs._blocked != rhs._blocked {return false} - if lhs._expireTimer != rhs._expireTimer {return false} - if lhs._nickname != rhs._nickname {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_ContactDetails.Avatar: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_ContactDetails.protoMessageName + ".Avatar" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "contentType"), - 2: .same(proto: "length"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._contentType) - case 2: try decoder.decodeSingularUInt32Field(value: &self._length) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._contentType { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._length { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_ContactDetails.Avatar, rhs: SignalServiceProtos_ContactDetails.Avatar) -> Bool { - if lhs._contentType != rhs._contentType {return false} - if lhs._length != rhs._length {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_GroupDetails: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".GroupDetails" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "id"), - 2: .same(proto: "name"), - 3: .same(proto: "members"), - 4: .same(proto: "avatar"), - 5: .same(proto: "active"), - 6: .same(proto: "expireTimer"), - 7: .same(proto: "color"), - 8: .same(proto: "blocked"), - 9: .same(proto: "admins"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularBytesField(value: &self._id) - case 2: try decoder.decodeSingularStringField(value: &self._name) - case 3: try decoder.decodeRepeatedStringField(value: &self.members) - case 4: try decoder.decodeSingularMessageField(value: &self._avatar) - case 5: try decoder.decodeSingularBoolField(value: &self._active) - case 6: try decoder.decodeSingularUInt32Field(value: &self._expireTimer) - case 7: try decoder.decodeSingularStringField(value: &self._color) - case 8: try decoder.decodeSingularBoolField(value: &self._blocked) - case 9: try decoder.decodeRepeatedStringField(value: &self.admins) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._id { - try visitor.visitSingularBytesField(value: v, fieldNumber: 1) - } - if let v = self._name { - try visitor.visitSingularStringField(value: v, fieldNumber: 2) - } - if !self.members.isEmpty { - try visitor.visitRepeatedStringField(value: self.members, fieldNumber: 3) - } - if let v = self._avatar { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) - } - if let v = self._active { - try visitor.visitSingularBoolField(value: v, fieldNumber: 5) - } - if let v = self._expireTimer { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 6) - } - if let v = self._color { - try visitor.visitSingularStringField(value: v, fieldNumber: 7) - } - if let v = self._blocked { - try visitor.visitSingularBoolField(value: v, fieldNumber: 8) - } - if !self.admins.isEmpty { - try visitor.visitRepeatedStringField(value: self.admins, fieldNumber: 9) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_GroupDetails, rhs: SignalServiceProtos_GroupDetails) -> Bool { - if lhs._id != rhs._id {return false} - if lhs._name != rhs._name {return false} - if lhs.members != rhs.members {return false} - if lhs._avatar != rhs._avatar {return false} - if lhs._active != rhs._active {return false} - if lhs._expireTimer != rhs._expireTimer {return false} - if lhs._color != rhs._color {return false} - if lhs._blocked != rhs._blocked {return false} - if lhs.admins != rhs.admins {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_GroupDetails.Avatar: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = SignalServiceProtos_GroupDetails.protoMessageName + ".Avatar" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "contentType"), - 2: .same(proto: "length"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularStringField(value: &self._contentType) - case 2: try decoder.decodeSingularUInt32Field(value: &self._length) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._contentType { - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - } - if let v = self._length { - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_GroupDetails.Avatar, rhs: SignalServiceProtos_GroupDetails.Avatar) -> Bool { - if lhs._contentType != rhs._contentType {return false} - if lhs._length != rhs._length {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension SignalServiceProtos_PublicChatInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".PublicChatInfo" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "serverID"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - switch fieldNumber { - case 1: try decoder.decodeSingularUInt64Field(value: &self._serverID) - default: break - } - } - } - - func traverse(visitor: inout V) throws { - if let v = self._serverID { - try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: SignalServiceProtos_PublicChatInfo, rhs: SignalServiceProtos_PublicChatInfo) -> Bool { - if lhs._serverID != rhs._serverID {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} diff --git a/SignalUtilitiesKit/SignalServiceProfile.swift b/SignalUtilitiesKit/SignalServiceProfile.swift deleted file mode 100644 index e1175884f..000000000 --- a/SignalUtilitiesKit/SignalServiceProfile.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -public class SignalServiceProfile: NSObject { - - public enum ValidationError: Error { - case invalid(description: String) - case invalidIdentityKey(description: String) - case invalidProfileName(description: String) - } - - public let recipientId: String - public let identityKey: Data - public let profileNameEncrypted: Data? - public let avatarUrlPath: String? - public let unidentifiedAccessVerifier: Data? - public let hasUnrestrictedUnidentifiedAccess: Bool - - public init(recipientId: String, responseObject: Any?) throws { - self.recipientId = recipientId - - guard let params = ParamParser(responseObject: responseObject) else { - throw ValidationError.invalid(description: "invalid response: \(String(describing: responseObject))") - } - - let identityKeyWithType = try params.requiredBase64EncodedData(key: "identityKey") - let kIdentityKeyLength = 33 - guard identityKeyWithType.count == kIdentityKeyLength else { - throw ValidationError.invalidIdentityKey(description: "malformed identity key \(identityKeyWithType.hexadecimalString) with decoded length: \(identityKeyWithType.count)") - } - do { - // `removeKeyType` is an objc category method only on NSData, so temporarily cast. - self.identityKey = try (identityKeyWithType as NSData).removeKeyType() as Data - } catch { - // `removeKeyType` throws an SCKExceptionWrapperError, which, typically should - // be unwrapped by any objc code calling this method. - owsFailDebug("identify key had unexpected format") - throw ValidationError.invalidIdentityKey(description: "malformed identity key \(identityKeyWithType.hexadecimalString) with data: \(identityKeyWithType)") - } - - self.profileNameEncrypted = try params.optionalBase64EncodedData(key: "name") - - let avatarUrlPath: String? = try params.optional(key: "avatar") - self.avatarUrlPath = avatarUrlPath - - self.unidentifiedAccessVerifier = try params.optionalBase64EncodedData(key: "unidentifiedAccess") - - self.hasUnrestrictedUnidentifiedAccess = try params.optional(key: "unrestrictedUnidentifiedAccess") ?? false - } -} diff --git a/SignalUtilitiesKit/Threads/TSContactThread.m b/SignalUtilitiesKit/Threads/TSContactThread.m index 9db8c904f..93efedf57 100644 --- a/SignalUtilitiesKit/Threads/TSContactThread.m +++ b/SignalUtilitiesKit/Threads/TSContactThread.m @@ -3,7 +3,6 @@ // #import "TSContactThread.h" -#import "ContactsManagerProtocol.h" #import "NotificationsProtocol.h" #import "OWSIdentityManager.h" #import "SSKEnvironment.h" diff --git a/SignalUtilitiesKit/Threads/TSGroupModel.h b/SignalUtilitiesKit/Threads/TSGroupModel.h index bf567fb81..9a3de614f 100644 --- a/SignalUtilitiesKit/Threads/TSGroupModel.h +++ b/SignalUtilitiesKit/Threads/TSGroupModel.h @@ -2,7 +2,6 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import #import #import diff --git a/SignalUtilitiesKit/ThreadUtil.h b/SignalUtilitiesKit/Threads/ThreadUtil.h similarity index 100% rename from SignalUtilitiesKit/ThreadUtil.h rename to SignalUtilitiesKit/Threads/ThreadUtil.h diff --git a/SignalUtilitiesKit/ThreadUtil.m b/SignalUtilitiesKit/Threads/ThreadUtil.m similarity index 97% rename from SignalUtilitiesKit/ThreadUtil.m rename to SignalUtilitiesKit/Threads/ThreadUtil.m index f8b4c34b6..b42ffda76 100644 --- a/SignalUtilitiesKit/ThreadUtil.m +++ b/SignalUtilitiesKit/Threads/ThreadUtil.m @@ -143,13 +143,13 @@ NS_ASSUME_NONNULL_BEGIN } + (void)ensureUnreadIndicator:(ThreadDynamicInteractions *)dynamicInteractions - thread:(TSThread *)thread - transaction:(YapDatabaseReadTransaction *)transaction - maxRangeSize:(int)maxRangeSize - blockingSafetyNumberChanges:(NSArray *)blockingSafetyNumberChanges - nonBlockingSafetyNumberChanges:(NSArray *)nonBlockingSafetyNumberChanges - hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator - firstUnseenSortId:(nullable NSNumber *)firstUnseenSortId + thread:(TSThread *)thread + transaction:(YapDatabaseReadTransaction *)transaction + maxRangeSize:(int)maxRangeSize + blockingSafetyNumberChanges:(NSArray *)blockingSafetyNumberChanges + nonBlockingSafetyNumberChanges:(NSArray *)nonBlockingSafetyNumberChanges + hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator + firstUnseenSortId:(nullable NSNumber *)firstUnseenSortId { OWSAssertDebug(dynamicInteractions); OWSAssertDebug(thread); diff --git a/SignalUtilitiesKit/FunctionalUtil.h b/SignalUtilitiesKit/Utilities/FunctionalUtil.h similarity index 100% rename from SignalUtilitiesKit/FunctionalUtil.h rename to SignalUtilitiesKit/Utilities/FunctionalUtil.h diff --git a/SignalUtilitiesKit/FunctionalUtil.m b/SignalUtilitiesKit/Utilities/FunctionalUtil.m similarity index 100% rename from SignalUtilitiesKit/FunctionalUtil.m rename to SignalUtilitiesKit/Utilities/FunctionalUtil.m diff --git a/SignalUtilitiesKit/Utilities/LKGroupUtilities.m b/SignalUtilitiesKit/Utilities/LKGroupUtilities.m index 9cced30f0..78c79b86b 100644 --- a/SignalUtilitiesKit/Utilities/LKGroupUtilities.m +++ b/SignalUtilitiesKit/Utilities/LKGroupUtilities.m @@ -37,7 +37,7 @@ return [[MMSGroupPrefix stringByAppendingString:groupID] dataUsingEncoding:NSUTF8StringEncoding]; } -+(NSString *)getEncodedGroupID: (NSData *)groupID ++(NSString *)getEncodedGroupID:(NSData *)groupID { return [[NSString alloc] initWithData:groupID encoding:NSUTF8StringEncoding]; } @@ -54,13 +54,7 @@ +(NSData *)getDecodedGroupIDAsData:(NSData *)groupID { - OWSAssertDebug(groupID.length > 0); - NSString *encodedGroupID = [[NSString alloc]initWithData:groupID encoding:NSUTF8StringEncoding]; - NSString *decodedGroupID = [encodedGroupID componentsSeparatedByString:@"!"][0]; - if ([encodedGroupID componentsSeparatedByString:@"!"].count > 1) { - decodedGroupID = [encodedGroupID componentsSeparatedByString:@"!"][1]; - } - return [decodedGroupID dataUsingEncoding:NSUTF8StringEncoding]; + return [[LKGroupUtilities getDecodedGroupID:groupID] dataUsingEncoding:NSUTF8StringEncoding]; } @end diff --git a/SignalUtilitiesKit/Notification+Loki.swift b/SignalUtilitiesKit/Utilities/Notification+Loki.swift similarity index 100% rename from SignalUtilitiesKit/Notification+Loki.swift rename to SignalUtilitiesKit/Utilities/Notification+Loki.swift diff --git a/SignalUtilitiesKit/ParamParser.swift b/SignalUtilitiesKit/Utilities/ParamParser.swift similarity index 100% rename from SignalUtilitiesKit/ParamParser.swift rename to SignalUtilitiesKit/Utilities/ParamParser.swift diff --git a/SignalUtilitiesKit/SSKIncrementingIdFinder.swift b/SignalUtilitiesKit/Utilities/SSKIncrementingIdFinder.swift similarity index 100% rename from SignalUtilitiesKit/SSKIncrementingIdFinder.swift rename to SignalUtilitiesKit/Utilities/SSKIncrementingIdFinder.swift diff --git a/SignalUtilitiesKit/SwiftSingletons.swift b/SignalUtilitiesKit/Utilities/SwiftSingletons.swift similarity index 100% rename from SignalUtilitiesKit/SwiftSingletons.swift rename to SignalUtilitiesKit/Utilities/SwiftSingletons.swift From 30370bf4d2a3c6b9281d9d036fea96f42530d890 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Nov 2020 11:16:23 +1100 Subject: [PATCH 009/177] Make basic message sending work --- Session/Signal/AppNotifications.swift | 2 +- .../ConversationViewController.m | 34 ++++++------------- .../Sending & Receiving/MessageSender.swift | 5 ++- Signal.xcodeproj/project.pbxproj | 4 +++ SignalUtilitiesKit/FullTextSearchFinder.swift | 2 +- .../Utilities/Destination+Conversion.swift | 2 +- .../Utilities/MessageSender+Utilities.swift | 6 ++++ .../TSOutgoingMessage+Conversion.swift | 19 +++++++++++ 8 files changed, 46 insertions(+), 28 deletions(-) create mode 100644 SignalUtilitiesKit/Utilities/TSOutgoingMessage+Conversion.swift diff --git a/Session/Signal/AppNotifications.swift b/Session/Signal/AppNotifications.swift index 1b6128be9..960dca597 100644 --- a/Session/Signal/AppNotifications.swift +++ b/Session/Signal/AppNotifications.swift @@ -213,7 +213,7 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { // for more details. let messageText = DisplayableText.filterNotificationText(rawMessageText) - let senderName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: incomingMessage.authorId, avoidingWriteTransaction: true)! + let senderName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: incomingMessage.authorId, avoidingWriteTransaction: true) ?? incomingMessage.authorId let notificationTitle: String? switch previewType { diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index f2a941323..982f296b5 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3823,25 +3823,17 @@ typedef enum : NSUInteger { return; } - // Limit outgoing text messages to 16kb. - // - // We convert large text messages to attachments - // which are presented as normal text messages. - - // TODO TODO TODO - -// BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - __block TSOutgoingMessage *message; -// [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { -// message = [ThreadUtil enqueueMessageWithText:text -// inThread:self.thread -// quotedReplyModel:self.inputToolbar.quotedReply -// linkPreviewDraft:self.inputToolbar.linkPreviewDraft -// transaction:transaction]; -// }]; -// [self.conversationViewModel appendUnsavedOutgoingTextMessage:message]; + SNVisibleMessage *message = [SNVisibleMessage new]; + message.text = text; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [SNMessageSender send:message inThread:self.thread usingTransaction:transaction]; + }]; - [self messageWasSent:message]; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread]; + + [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; + + [self messageWasSent:tsMessage]; // Clearing the text message is a key part of the send animation. // It takes 10-15ms, but we do it inline rather than dispatch async @@ -3867,12 +3859,6 @@ typedef enum : NSUInteger { [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.thread setDraft:@"" transaction:transaction]; }]; - - if ([self.thread isKindOfClass:TSContactThread.class]) { - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [LKSessionManagementProtocol sendSessionRequestIfNeededToPublicKey:self.thread.contactIdentifier transaction:transaction]; - }]; - } } - (void)voiceMemoGestureDidStart diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 1c2bf9dd0..d3263c174 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -2,7 +2,8 @@ import PromiseKit import SessionSnodeKit import SessionUtilitiesKit -public enum MessageSender { +@objc(SNMessageSender) +public final class MessageSender : NSObject { public enum Error : LocalizedError { case invalidMessage @@ -19,6 +20,8 @@ public enum MessageSender { } } } + + private override init() { } public static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise { switch destination { diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index b52c4960e..8abce3b20 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -238,6 +238,7 @@ B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408F239DD75000A248E7 /* RestoreVC.swift */; }; B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B4093239DF15900A248E7 /* ConversationTitleView.swift */; }; B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */; }; + B84072962565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */; }; B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; }; B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; }; @@ -1344,6 +1345,7 @@ B82B4093239DF15900A248E7 /* ConversationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationTitleView.swift; sourceTree = ""; }; B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationButtonSet.swift; sourceTree = ""; }; B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; + B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSOutgoingMessage+Conversion.swift"; sourceTree = ""; }; B84664F4235022F30083A1CD /* MentionUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionUtilities.swift; sourceTree = ""; }; B847570023D568EB00759540 /* SignalServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SignalServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedReminderView.swift; sourceTree = ""; }; @@ -3643,6 +3645,7 @@ C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */, C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */, C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, + B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */, ); path = Utilities; sourceTree = ""; @@ -4811,6 +4814,7 @@ C33FDC41255A581F00E217F9 /* TypingIndicators.swift in Sources */, C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */, C33FDC2E255A581F00E217F9 /* ClosedGroupsProtocol.swift in Sources */, + B84072962565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift in Sources */, C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */, C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */, C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */, diff --git a/SignalUtilitiesKit/FullTextSearchFinder.swift b/SignalUtilitiesKit/FullTextSearchFinder.swift index 3584ace3c..c12258a1a 100644 --- a/SignalUtilitiesKit/FullTextSearchFinder.swift +++ b/SignalUtilitiesKit/FullTextSearchFinder.swift @@ -181,7 +181,7 @@ public class FullTextSearchFinder: NSObject { } private static let recipientIndexer: SearchIndexer = SearchIndexer { (recipientId: String, transaction: YapDatabaseReadTransaction) in - let displayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true)! + let displayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true) ?? recipientId return "\(recipientId) \(displayName)" } diff --git a/SignalUtilitiesKit/Utilities/Destination+Conversion.swift b/SignalUtilitiesKit/Utilities/Destination+Conversion.swift index c7c82c223..20ca01ae2 100644 --- a/SignalUtilitiesKit/Utilities/Destination+Conversion.swift +++ b/SignalUtilitiesKit/Utilities/Destination+Conversion.swift @@ -3,7 +3,7 @@ public extension Message.Destination { static func from(_ thread: TSThread) -> Message.Destination { if let thread = thread as? TSContactThread { - return .contact(publicKey: thread.uniqueId!) + return .contact(publicKey: thread.contactIdentifier()) } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys { let groupID = thread.groupModel.groupId let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) diff --git a/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift b/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift index a0d635917..5343e447a 100644 --- a/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift +++ b/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift @@ -2,6 +2,7 @@ import PromiseKit public extension MessageSender { + @objc(send:inThread:usingTransaction:) static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { message.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) @@ -9,6 +10,11 @@ public extension MessageSender { SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } + @objc(sendNonDurably:inThread:usingTransaction:) + static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) + } + static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { message.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) diff --git a/SignalUtilitiesKit/Utilities/TSOutgoingMessage+Conversion.swift b/SignalUtilitiesKit/Utilities/TSOutgoingMessage+Conversion.swift new file mode 100644 index 000000000..eba40aaf3 --- /dev/null +++ b/SignalUtilitiesKit/Utilities/TSOutgoingMessage+Conversion.swift @@ -0,0 +1,19 @@ + +@objc public extension TSOutgoingMessage { + + @objc(from:associatedWith:) + static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread) -> TSOutgoingMessage { + var expiration: UInt32 = 0 + if let disappearingMessagesConfiguration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: thread.uniqueId!) { + expiration = disappearingMessagesConfiguration.isEnabled ? disappearingMessagesConfiguration.durationSeconds : 0 + } + return TSOutgoingMessage( + in: thread, + messageBody: visibleMessage.text, + attachmentId: nil, + expiresInSeconds: expiration, + quotedMessage: nil, + linkPreview: nil + ) + } +} From 72b4c3edafbed2e344ae85601da0e06368fb389b Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Nov 2020 15:24:09 +1100 Subject: [PATCH 010/177] WIP --- Session/AppDelegate+SharedSenderKeys.swift | 7 - .../Components/ConversationTitleView.swift | 10 +- Session/Components/PathStatusView.swift | 2 +- Session/Components/VoiceMessageView.swift | 4 +- Session/Configuration.swift | 11 +- .../Database/Storage+SessionProtocolKit.swift | 24 -- Session/Database/Storage+VolumeSamples.swift | 17 -- .../ConversationView/Cells/OWSMessageCell.m | 5 +- .../Cells/OWSQuotedMessageView.m | 2 +- .../ConversationInputToolbar.m | 5 +- .../ConversationViewController.m | 11 +- .../ConversationView/ConversationViewItem.m | 10 +- Session/Signal/MediaPageViewController.swift | 5 +- Session/Utilities/BackgroundPoller.swift | 7 +- Session/Utilities/IP2Country.swift | 2 +- Session/Utilities/MentionUtilities.swift | 3 +- Session/View Controllers/HomeVC.swift | 5 +- .../VisibleMessage+Quote.swift | 2 + .../Sending & Receiving/MessageReceiver.swift | 1 + Signal.xcodeproj/project.pbxproj | 214 ++++++++--------- .../Database/Storage+ClosedGroups.swift | 86 +++++++ .../Database/Storage+Jobs.swift | 26 +++ .../Database/Storage+Messaging.swift | 35 +++ .../Storage+OnionRequests.swift | 52 ++--- .../Database/Storage+OpenGroups.swift | 183 +++++++-------- .../Database/Storage+SessionManagement.swift | 30 +++ .../Database/Storage+Shared.swift | 6 +- .../Database/Storage+SnodeAPI.swift | 65 +----- .../Database/Storage+VolumeSamples.swift | 17 ++ .../Storage.swift | 12 +- .../ClosedGroupPoller.swift | 2 +- .../Destination+Conversion.swift | 5 +- .../Messaging/MentionsManager.swift | 15 +- .../Messaging}/MessageReceiverDelegate.swift | 26 +-- .../MessageSender+Utilities.swift | 0 .../Messaging/MessageSenderDelegate.swift | 16 ++ .../Messaging/OWSMessageUtils.m | 2 +- .../Messaging/OpenGroupAPIDelegate.swift | 31 +-- .../OpenGroupPoller.swift} | 43 ++-- .../Poller.swift | 0 .../PushNotificationManager.swift} | 30 +-- .../Messaging/Quote+Conversion.swift | 13 ++ .../SNProtoEnvelope+Conversion.swift | 0 .../TSIncomingMessage+Conversion.swift | 0 .../TSOutgoingMessage+Conversion.swift | 0 SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 1 + .../LokiDatabaseUtilities.swift | 53 ----- .../OWSPrimaryStorage+Loki.swift | 81 ------- .../Storage+ClosedGroups.swift | 79 ------- .../Move to Session/Storage+Collections.swift | 21 -- .../Move to Session/Storage+PublicChats.swift | 38 --- .../Storage+SessionManagement.swift | 31 --- .../Move to Session/Storage+SnodeAPI.swift | 58 ----- SignalUtilitiesKit/OWSAttachmentDownloads.m | 2 +- SignalUtilitiesKit/OWSUploadOperation.m | 5 +- SignalUtilitiesKit/Threads/TSThread.m | 4 +- .../ClosedGroupsProtocol.swift | 216 +----------------- .../{Remove => To Do}/ContactCellView.h | 0 .../{Remove => To Do}/ContactCellView.m | 0 .../{Remove => To Do}/ContactTableViewCell.h | 0 .../{Remove => To Do}/ContactTableViewCell.m | 0 .../DisplayNameUtilities.swift | 0 .../DisplayNameUtilities2.swift | 6 +- .../{Remove => To Do}/GroupUtilities.swift | 0 .../OWSPrimaryStorage+Loki.h | 0 .../OWSPrimaryStorage+Loki.m | 12 +- .../{Remove => To Do}/OWSProfileManager.h | 0 .../{Remove => To Do}/OWSProfileManager.m | 5 +- .../{Remove => To Do}/OWSUserProfile.h | 0 .../{Remove => To Do}/OWSUserProfile.m | 0 .../ProfileManagerProtocol.h | 0 .../PublicChatManager.swift | 38 ++- .../SessionManagementProtocol.swift | 10 +- .../SessionMetaProtocol.swift | 10 +- SignalUtilitiesKit/Utilities/Debugging.swift | 12 - .../Utilities/ECKeyPair+Hexadecimal.swift | 4 +- .../LKUserDefaults.swift | 0 77 files changed, 596 insertions(+), 1132 deletions(-) delete mode 100644 Session/AppDelegate+SharedSenderKeys.swift delete mode 100644 Session/Database/Storage+SessionProtocolKit.swift delete mode 100644 Session/Database/Storage+VolumeSamples.swift create mode 100644 SignalUtilitiesKit/Database/Storage+ClosedGroups.swift create mode 100644 SignalUtilitiesKit/Database/Storage+Jobs.swift create mode 100644 SignalUtilitiesKit/Database/Storage+Messaging.swift rename SignalUtilitiesKit/{Move to Session => Database}/Storage+OnionRequests.swift (72%) rename Session/Database/Storage+SessionMessagingKit.swift => SignalUtilitiesKit/Database/Storage+OpenGroups.swift (58%) create mode 100644 SignalUtilitiesKit/Database/Storage+SessionManagement.swift rename {Session => SignalUtilitiesKit}/Database/Storage+Shared.swift (81%) rename Session/Database/Storage+SessionSnodeKit.swift => SignalUtilitiesKit/Database/Storage+SnodeAPI.swift (61%) create mode 100644 SignalUtilitiesKit/Database/Storage+VolumeSamples.swift rename SignalUtilitiesKit/{Move to Session => Database}/Storage.swift (87%) rename SignalUtilitiesKit/{Move to Session => Messaging}/ClosedGroupPoller.swift (97%) rename SignalUtilitiesKit/{Utilities => Messaging}/Destination+Conversion.swift (79%) rename {Session => SignalUtilitiesKit/Messaging}/MessageReceiverDelegate.swift (93%) rename SignalUtilitiesKit/{Utilities => Messaging}/MessageSender+Utilities.swift (100%) create mode 100644 SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift rename Session/AppDelegate+OpenGroupAPI.swift => SignalUtilitiesKit/Messaging/OpenGroupAPIDelegate.swift (53%) rename SignalUtilitiesKit/{Move to Session/PublicChatPoller.swift => Messaging/OpenGroupPoller.swift} (85%) rename SignalUtilitiesKit/{Move to Session => Messaging}/Poller.swift (100%) rename SignalUtilitiesKit/{Move to Session/LokiPushNotificationManager.swift => Messaging/PushNotificationManager.swift} (82%) create mode 100644 SignalUtilitiesKit/Messaging/Quote+Conversion.swift rename SignalUtilitiesKit/{Utilities => Messaging}/SNProtoEnvelope+Conversion.swift (100%) rename SignalUtilitiesKit/{Utilities => Messaging}/TSIncomingMessage+Conversion.swift (100%) rename SignalUtilitiesKit/{Utilities => Messaging}/TSOutgoingMessage+Conversion.swift (100%) delete mode 100644 SignalUtilitiesKit/Move to Session/LokiDatabaseUtilities.swift delete mode 100644 SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.swift delete mode 100644 SignalUtilitiesKit/Move to Session/Storage+ClosedGroups.swift delete mode 100644 SignalUtilitiesKit/Move to Session/Storage+Collections.swift delete mode 100644 SignalUtilitiesKit/Move to Session/Storage+PublicChats.swift delete mode 100644 SignalUtilitiesKit/Move to Session/Storage+SessionManagement.swift delete mode 100644 SignalUtilitiesKit/Move to Session/Storage+SnodeAPI.swift rename SignalUtilitiesKit/{Remove => To Do}/ClosedGroupsProtocol.swift (52%) rename SignalUtilitiesKit/{Remove => To Do}/ContactCellView.h (100%) rename SignalUtilitiesKit/{Remove => To Do}/ContactCellView.m (100%) rename SignalUtilitiesKit/{Remove => To Do}/ContactTableViewCell.h (100%) rename SignalUtilitiesKit/{Remove => To Do}/ContactTableViewCell.m (100%) rename SignalUtilitiesKit/{Remove => To Do}/DisplayNameUtilities.swift (100%) rename SignalUtilitiesKit/{Remove => To Do}/DisplayNameUtilities2.swift (85%) rename SignalUtilitiesKit/{Remove => To Do}/GroupUtilities.swift (100%) rename SignalUtilitiesKit/{Move to Session => To Do}/OWSPrimaryStorage+Loki.h (100%) rename SignalUtilitiesKit/{Move to Session => To Do}/OWSPrimaryStorage+Loki.m (92%) rename SignalUtilitiesKit/{Remove => To Do}/OWSProfileManager.h (100%) rename SignalUtilitiesKit/{Remove => To Do}/OWSProfileManager.m (99%) rename SignalUtilitiesKit/{Remove => To Do}/OWSUserProfile.h (100%) rename SignalUtilitiesKit/{Remove => To Do}/OWSUserProfile.m (100%) rename SignalUtilitiesKit/{Remove => To Do}/ProfileManagerProtocol.h (100%) rename SignalUtilitiesKit/{Move to Session => To Do}/PublicChatManager.swift (76%) rename SignalUtilitiesKit/{Remove => To Do}/SessionManagementProtocol.swift (96%) rename SignalUtilitiesKit/{Remove => To Do}/SessionMetaProtocol.swift (94%) delete mode 100644 SignalUtilitiesKit/Utilities/Debugging.swift rename SignalUtilitiesKit/{Move to Session => Utilities}/LKUserDefaults.swift (100%) diff --git a/Session/AppDelegate+SharedSenderKeys.swift b/Session/AppDelegate+SharedSenderKeys.swift deleted file mode 100644 index 23bd59871..000000000 --- a/Session/AppDelegate+SharedSenderKeys.swift +++ /dev/null @@ -1,7 +0,0 @@ - -extension AppDelegate : SharedSenderKeysDelegate { - - public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { - ClosedGroupsProtocol.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction as! YapDatabaseReadWriteTransaction) - } -} diff --git a/Session/Components/ConversationTitleView.swift b/Session/Components/ConversationTitleView.swift index 2f93f729e..67ed1a24e 100644 --- a/Session/Components/ConversationTitleView.swift +++ b/Session/Components/ConversationTitleView.swift @@ -167,7 +167,8 @@ final class ConversationTitleView : UIView { } @objc func updateSubtitleForCurrentStatus() { - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } self.subtitleLabel.isHidden = false let subtitle = NSMutableAttributedString() if let muteEndDate = self.thread.mutedUntilDate, self.thread.isMuted { @@ -178,15 +179,12 @@ final class ConversationTitleView : UIView { dateFormatter.dateStyle = .medium subtitle.append(NSAttributedString(string: "Muted until " + dateFormatter.string(from: muteEndDate))) } else if let thread = self.thread as? TSGroupThread { - let storage = OWSPrimaryStorage.shared() var userCount: Int? if thread.groupModel.groupType == .closedGroup { userCount = GroupUtilities.getClosedGroupMemberCount(thread) } else if thread.groupModel.groupType == .openGroup { - storage.dbReadConnection.read { transaction in - if let publicChat = LokiDatabaseUtilities.getPublicChat(for: self.thread.uniqueId!, in: transaction) { - userCount = storage.getUserCount(for: publicChat, in: transaction) - } + if let openGroup = Storage.shared.getOpenGroup(for: self.thread.uniqueId!) { + userCount = Storage.shared.getUserCount(forOpenGroupWithID: openGroup.id) } } if let userCount = userCount { diff --git a/Session/Components/PathStatusView.swift b/Session/Components/PathStatusView.swift index 01373c862..f3413feef 100644 --- a/Session/Components/PathStatusView.swift +++ b/Session/Components/PathStatusView.swift @@ -18,7 +18,7 @@ final class PathStatusView : UIView { layer.cornerRadius = Values.pathStatusViewSize / 2 layer.masksToBounds = false if OnionRequestAPI.paths.isEmpty { - OnionRequestAPI.paths = Storage.getOnionRequestPaths() + OnionRequestAPI.paths = Storage.shared.getOnionRequestPaths() } let color = (!OnionRequestAPI.paths.isEmpty) ? Colors.accent : Colors.pathsBuilding setColor(to: color, isAnimated: false) diff --git a/Session/Components/VoiceMessageView.swift b/Session/Components/VoiceMessageView.swift index db23ba4af..42bc78aee 100644 --- a/Session/Components/VoiceMessageView.swift +++ b/Session/Components/VoiceMessageView.swift @@ -67,7 +67,7 @@ final class VoiceMessageView : UIView { guard let url = (voiceMessage as? TSAttachmentStream)?.originalMediaURL else { return print("[Loki] Couldn't get URL for voice message.") } - if let cachedVolumeSamples = Storage.getVolumeSamples(for: voiceMessage.uniqueId!), cachedVolumeSamples.count == targetSampleCount { + if let cachedVolumeSamples = Storage.shared.getVolumeSamples(for: voiceMessage.uniqueId!), cachedVolumeSamples.count == targetSampleCount { self.hideLoader() self.volumeSamples = cachedVolumeSamples } else { @@ -78,7 +78,7 @@ final class VoiceMessageView : UIView { self.isForcedAnimation = true self.volumeSamples = volumeSamples Storage.write { transaction in - Storage.setVolumeSamples(for: voiceMessageID, to: volumeSamples, using: transaction) + Storage.shared.setVolumeSamples(for: voiceMessageID, to: volumeSamples, using: transaction) } }.catch(on: DispatchQueue.main) { error in print("[Loki] Couldn't sample audio file due to error: \(error).") diff --git a/Session/Configuration.swift b/Session/Configuration.swift index 743658c20..020a53c49 100644 --- a/Session/Configuration.swift +++ b/Session/Configuration.swift @@ -5,9 +5,6 @@ import SessionSnodeKit @objc(SNConfiguration) final class Configuration : NSObject { - private static let pnServerURL = "https://live.apns.getsession.org" - private static let pnServerPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049" - @objc static func performMainSetup() { SNMessagingKit.configure( storage: Storage.shared, @@ -16,11 +13,11 @@ final class Configuration : NSObject { identityKeyStore: OWSIdentityManager.shared(), sessionRestorationImplementation: SessionRestorationImplementation(), certificateValidator: SMKCertificateDefaultValidator(trustRoot: OWSUDManagerImpl.trustRoot()), - openGroupAPIDelegate: UIApplication.shared.delegate as! AppDelegate, - pnServerURL: pnServerURL, - pnServerPublicKey: pnServerURL + openGroupAPIDelegate: OpenGroupAPIDelegate.shared, + pnServerURL: PushNotificationManager.server, + pnServerPublicKey: PushNotificationManager.serverPublicKey ) - SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: UIApplication.shared.delegate as! AppDelegate) + SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: MessageSenderDelegate.shared) SessionSnodeKit.configure(storage: Storage.shared) } } diff --git a/Session/Database/Storage+SessionProtocolKit.swift b/Session/Database/Storage+SessionProtocolKit.swift deleted file mode 100644 index 7700de54f..000000000 --- a/Session/Database/Storage+SessionProtocolKit.swift +++ /dev/null @@ -1,24 +0,0 @@ - -extension Storage : SessionProtocolKitStorageProtocol { - - private func getClosedGroupRatchetCollection(_ collection: ClosedGroupRatchetCollectionType, for groupPublicKey: String) -> String { - switch collection { - case .old: return "LokiOldClosedGroupRatchetCollection.\(groupPublicKey)" - case .current: return "LokiClosedGroupRatchetCollection.\(groupPublicKey)" - } - } - - public func getClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> ClosedGroupRatchet? { - let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) - var result: ClosedGroupRatchet? - Storage.read { transaction in - result = transaction.object(forKey: senderPublicKey, inCollection: collection) as? ClosedGroupRatchet - } - return result - } - - public func setClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, ratchet: ClosedGroupRatchet, in collection: ClosedGroupRatchetCollectionType = .current, using transaction: Any) { - let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) - (transaction as! YapDatabaseReadWriteTransaction).setObject(ratchet, forKey: senderPublicKey, inCollection: collection) - } -} diff --git a/Session/Database/Storage+VolumeSamples.swift b/Session/Database/Storage+VolumeSamples.swift deleted file mode 100644 index dce064b7e..000000000 --- a/Session/Database/Storage+VolumeSamples.swift +++ /dev/null @@ -1,17 +0,0 @@ - -extension Storage { - - static let volumeSamplesCollection = "LokiVolumeSamplesCollection" - - static func getVolumeSamples(for attachment: String) -> [Float]? { - var result: [Float]? - read { transaction in - result = transaction.object(forKey: attachment, inCollection: volumeSamplesCollection) as? [Float] - } - return result - } - - static func setVolumeSamples(for attachment: String, to volumeSamples: [Float], using transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(volumeSamples, forKey: attachment, inCollection: volumeSamplesCollection) - } -} diff --git a/Session/Signal/ConversationView/Cells/OWSMessageCell.m b/Session/Signal/ConversationView/Cells/OWSMessageCell.m index 6190bb0be..7cbafcef3 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageCell.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageCell.m @@ -286,10 +286,7 @@ NS_ASSUME_NONNULL_BEGIN // Loki: Show the moderator icon if needed if (self.viewItem.isGroupThread) { // FIXME: This logic also shouldn't apply to closed groups - __block SNOpenGroup *publicChat; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChat = [LKDatabaseUtilities getPublicChatForThreadID:self.viewItem.interaction.uniqueThreadId transaction: transaction]; - }]; + SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:self.viewItem.interaction.uniqueThreadId]; if (publicChat != nil) { BOOL isModerator = [SNOpenGroupAPI isUserModerator:incomingMessage.authorId forChannel:publicChat.channel onServer:publicChat.server]; UIImage *moderatorIcon = [UIImage imageNamed:@"Crown"]; diff --git a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m index 199d35df7..0b296a38b 100644 --- a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m @@ -553,8 +553,8 @@ const CGFloat kRemotelySourcedContentRowSpacing = 4; __block NSString *quotedAuthor = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.quotedMessage.authorId]; if (quotedAuthor == self.quotedMessage.authorId) { + SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:self.quotedMessage.threadId]; [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - SNOpenGroup *publicChat = [LKDatabaseUtilities getPublicChatForThreadID:self.quotedMessage.threadId transaction:transaction]; if (publicChat != nil) { quotedAuthor = [LKUserDisplayNameUtilities getPublicChatDisplayNameFor:self.quotedMessage.authorId in:publicChat.channel on:publicChat.server using:transaction]; } else { diff --git a/Session/Signal/ConversationView/ConversationInputToolbar.m b/Session/Signal/ConversationView/ConversationInputToolbar.m index 48e28baf3..731e3af3e 100644 --- a/Session/Signal/ConversationView/ConversationInputToolbar.m +++ b/Session/Signal/ConversationView/ConversationInputToolbar.m @@ -1089,10 +1089,7 @@ const CGFloat kMaxTextViewHeight = 120; - (void)showMentionCandidateSelectionViewFor:(NSArray *)mentionCandidates in:(TSThread *)thread { - __block SNOpenGroup *publicChat; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChat = [LKDatabaseUtilities getPublicChatForThreadID:thread.uniqueId transaction:transaction]; - }]; + SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:thread.uniqueId]; if (publicChat != nil) { self.mentionCandidateSelectionView.publicChatServer = publicChat.server; [self.mentionCandidateSelectionView setPublicChatChannel:publicChat.channel]; diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 982f296b5..44e502a37 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -605,10 +605,7 @@ typedef enum : NSUInteger { if (self.thread.isGroupThread) { TSGroupThread *thread = (TSGroupThread *)self.thread; if (!thread.isOpenGroup) { return; } - __block SNOpenGroup *publicChat; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChat = [LKDatabaseUtilities getPublicChatForThreadID:thread.uniqueId transaction:transaction]; - }]; + SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:thread.uniqueId]; [SNOpenGroupAPI getInfoForChannelWithID:publicChat.channel onServer:publicChat.server] .thenOn(dispatch_get_main_queue(), ^(id userCount) { [self.headerView updateSubtitleForCurrentStatus]; @@ -3823,8 +3820,14 @@ typedef enum : NSUInteger { return; } + // Limit outgoing text messages to 16kb. + // + // We convert large text messages to attachments + // which are presented as normal text messages. + SNVisibleMessage *message = [SNVisibleMessage new]; message.text = text; + message.quote = [SNQuote from:self.inputToolbar.quotedReply]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [SNMessageSender send:message inThread:self.thread usingTransaction:transaction]; }]; diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index 7544414b2..687094150 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -1089,10 +1089,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) TSMessage *message = (TSMessage *)self.interaction; if (!message.isOpenGroupMessage) return; - __block SNOpenGroup *publicChat; - [self.primaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChat = [LKDatabaseUtilities getPublicChatForThreadID:groupThread.uniqueId transaction: transaction]; - }]; + SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:groupThread.uniqueId]; if (publicChat == nil) return; // Delete the message @@ -1162,10 +1159,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) if (!message.isOpenGroupMessage) return true; // Ensure we have the details needed to contact the server - __block SNOpenGroup *publicChat; - [self.primaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChat = [LKDatabaseUtilities getPublicChatForThreadID:groupThread.uniqueId transaction: transaction]; - }]; + SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:groupThread.uniqueId]; if (publicChat == nil) return true; if (interationType == OWSInteractionType_IncomingMessage) { diff --git a/Session/Signal/MediaPageViewController.swift b/Session/Signal/MediaPageViewController.swift index d7138511a..d4d8206e9 100644 --- a/Session/Signal/MediaPageViewController.swift +++ b/Session/Signal/MediaPageViewController.swift @@ -674,10 +674,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou case let incomingMessage as TSIncomingMessage: let hexEncodedPublicKey = incomingMessage.authorId if incomingMessage.thread.isGroupThread() { - var publicChat: OpenGroup? - OWSPrimaryStorage.shared().dbReadConnection.read { transaction in - publicChat = LokiDatabaseUtilities.getPublicChat(for: incomingMessage.thread.uniqueId!, in: transaction) - } + let publicChat = Storage.shared.getOpenGroup(for: incomingMessage.thread.uniqueId!) if let publicChat = publicChat { return UserDisplayNameUtilities.getPublicChatDisplayName(for: hexEncodedPublicKey, in: publicChat.channel, on: publicChat.server) ?? hexEncodedPublicKey } else { diff --git a/Session/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift index 6786fd876..9ec7c4761 100644 --- a/Session/Utilities/BackgroundPoller.swift +++ b/Session/Utilities/BackgroundPoller.swift @@ -13,12 +13,9 @@ public final class BackgroundPoller : NSObject { // promises.append(AppEnvironment.shared.messageFetcherJob.run()) // FIXME: It'd be nicer to just use Poller directly closedGroupPoller = ClosedGroupPoller() promises.append(contentsOf: closedGroupPoller.pollOnce()) - var openGroups: [String:OpenGroup] = [:] - Storage.read { transaction in - openGroups = LokiDatabaseUtilities.getAllPublicChats(in: transaction) - } + let openGroups: [String:OpenGroup] = Storage.shared.getAllUserOpenGroups() openGroups.values.forEach { openGroup in - let poller = PublicChatPoller(for: openGroup) + let poller = OpenGroupPoller(for: openGroup) poller.stop() promises.append(poller.pollForNewMessages()) } diff --git a/Session/Utilities/IP2Country.swift b/Session/Utilities/IP2Country.swift index fe67cfa7c..aa6b65899 100644 --- a/Session/Utilities/IP2Country.swift +++ b/Session/Utilities/IP2Country.swift @@ -52,7 +52,7 @@ final class IP2Country { func populateCacheIfNeeded() -> Bool { if OnionRequestAPI.paths.isEmpty { - OnionRequestAPI.paths = Storage.getOnionRequestPaths() + OnionRequestAPI.paths = Storage.shared.getOnionRequestPaths() } let paths = OnionRequestAPI.paths guard !paths.isEmpty else { return false } diff --git a/Session/Utilities/MentionUtilities.swift b/Session/Utilities/MentionUtilities.swift index c0c74a945..9390d6027 100644 --- a/Session/Utilities/MentionUtilities.swift +++ b/Session/Utilities/MentionUtilities.swift @@ -10,9 +10,8 @@ public final class MentionUtilities : NSObject { @objc public static func highlightMentions(in string: String, isOutgoingMessage: Bool, threadID: String, attributes: [NSAttributedString.Key:Any]) -> NSAttributedString { let userPublicKey = getUserHexEncodedPublicKey() - var publicChat: OpenGroup? + let publicChat = Storage.shared.getOpenGroup(for: threadID) OWSPrimaryStorage.shared().dbReadConnection.read { transaction in - publicChat = LokiDatabaseUtilities.getPublicChat(for: threadID, in: transaction) MentionsManager.populateUserPublicKeyCacheIfNeeded(for: threadID, in: transaction) } var string = string diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index faa2f36e2..4e6df7b5c 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -365,10 +365,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { guard let thread = self.thread(at: indexPath.row) else { return [] } - var publicChat: OpenGroup? - OWSPrimaryStorage.shared().dbReadConnection.read { transaction in - publicChat = LokiDatabaseUtilities.getPublicChat(for: thread.uniqueId!, in: transaction) - } + let publicChat = Storage.shared.getOpenGroup(for: thread.uniqueId!) let delete = UITableViewRowAction(style: .destructive, title: NSLocalizedString("TXT_DELETE_TITLE", comment: "")) { [weak self] _, _ in let alert = UIAlertController(title: NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE", comment: ""), message: NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE", comment: ""), preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("TXT_DELETE_TITLE", comment: ""), style: .destructive) { _ in diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Quote.swift index 85065906f..74bc57d37 100644 --- a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Quote.swift @@ -10,6 +10,8 @@ public extension VisibleMessage { public var isValid: Bool { timestamp != nil && publicKey != nil && text != nil } + public override init() { super.init() } + internal init(timestamp: UInt64, publicKey: String, text: String) { self.timestamp = timestamp self.publicKey = publicKey diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index ec4b75ae5..74cf8dae9 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -4,6 +4,7 @@ import SessionUtilitiesKit // • Threads don't show up on the first message; only on the second. // • Profile pictures aren't showing up. // • Check that message expiration works. +// • Open group messages (sync messages). internal enum MessageReceiver { diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 8abce3b20..d2e8759e1 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -239,6 +239,7 @@ B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B4093239DF15900A248E7 /* ConversationTitleView.swift */; }; B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */; }; B84072962565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */; }; + B84072A02565F1670037CB17 /* Quote+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B840729F2565F1670037CB17 /* Quote+Conversion.swift */; }; B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; }; B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; }; @@ -261,6 +262,20 @@ B8CCF63723961D6D0091D419 /* NewPrivateChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */; }; B8CCF63F23975CFB0091D419 /* JoinPublicChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */; }; B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF6422397711F0091D419 /* SettingsVC.swift */; }; + B8D8F0F32565F98E0092EF10 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; + B8D8F0F42565F98E0092EF10 /* PushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationManager.swift */; }; + B8D8F12E2565FC910092EF10 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; }; + B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */; }; + B8D8F16A256615DE0092EF10 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; }; + B8D8F16B256615DE0092EF10 /* Storage+VolumeSamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */; }; + B8D8F16C256615DE0092EF10 /* Storage+SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */; }; + B8D8F17725661AFA0092EF10 /* Storage+Jobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */; }; + B8D8F18925661BA50092EF10 /* Storage+OpenGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */; }; + B8D8F19325661BF80092EF10 /* Storage+Messaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */; }; + B8D8F1BD25661C6F0092EF10 /* Storage+OnionRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */; }; + B8D8F1E6256620DD0092EF10 /* MessageReceiverDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */; }; + B8D8F1F0256621180092EF10 /* MessageSenderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */; }; + B8D8F21A25662A4D0092EF10 /* OpenGroupAPIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */; }; B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; }; B9EB5ABD1884C002007CBB57 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EB5ABC1884C002007CBB57 /* MessageUI.framework */; }; C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */; }; @@ -278,7 +293,6 @@ C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */; }; C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */; }; C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */; }; - C31F812625258FB000DD9FD9 /* Storage+VolumeSamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */; }; C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */; }; C329FEEC24F7277900B1C64C /* LightModeSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C329FEEB24F7277900B1C64C /* LightModeSheet.swift */; }; C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */; }; @@ -329,17 +343,15 @@ C33FDC33255A581F00E217F9 /* TSGroupThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA79255A57FB00E217F9 /* TSGroupThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC34255A581F00E217F9 /* NSRegularExpression+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */; }; C33FDC35255A581F00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC36255A581F00E217F9 /* Debugging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7C255A57FB00E217F9 /* Debugging.swift */; }; C33FDC38255A581F00E217F9 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7E255A57FB00E217F9 /* Mention.swift */; }; C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */; }; C33FDC3A255A581F00E217F9 /* OWSDisappearingMessagesJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA81255A57FC00E217F9 /* MentionsManager.swift */; }; - C33FDC3F255A581F00E217F9 /* OWSPrimaryStorage+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */; }; C33FDC40255A581F00E217F9 /* OWSDisappearingMessagesFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */; }; C33FDC41255A581F00E217F9 /* TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */; }; C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8B255A57FD00E217F9 /* AppVersion.m */; }; - C33FDC46255A581F00E217F9 /* PublicChatPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */; }; + C33FDC46255A581F00E217F9 /* OpenGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */; }; C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; }; C33FDC4A255A582000E217F9 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; }; C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -424,8 +436,6 @@ C33FDCEB255A582000E217F9 /* SSKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB31255A580A00E217F9 /* SSKEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */; }; C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */; }; - C33FDCF0255A582000E217F9 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; }; - C33FDCF1255A582000E217F9 /* Storage+SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */; }; C33FDCF2255A582000E217F9 /* OWSBackgroundTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCF4255A582000E217F9 /* Poller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3A255A580B00E217F9 /* Poller.swift */; }; C33FDCF5255A582000E217F9 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -461,7 +471,6 @@ C33FDD21255A582000E217F9 /* OWSMediaGalleryFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD22255A582000E217F9 /* ContentProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB68255A580F00E217F9 /* ContentProxy.swift */; }; C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB69255A580F00E217F9 /* FeatureFlags.swift */; }; - C33FDD25255A582000E217F9 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */; }; C33FDD27255A582000E217F9 /* TSPreKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */; }; @@ -487,7 +496,6 @@ C33FDD4B255A582000E217F9 /* ProtoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB91255A581200E217F9 /* ProtoUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */; }; C33FDD4E255A582000E217F9 /* TSAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB94255A581300E217F9 /* TSAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD4F255A582000E217F9 /* Storage+Collections.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB95255A581300E217F9 /* Storage+Collections.swift */; }; C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; }; C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD58255A582000E217F9 /* TSAttachmentPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */; }; @@ -521,9 +529,7 @@ C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */; }; C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */; }; C33FDD97255A582000E217F9 /* OWSDisappearingMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */; }; - C33FDD98255A582000E217F9 /* LokiPushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */; }; C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */; }; - C33FDDA2255A582000E217F9 /* Storage+OnionRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE8255A581A00E217F9 /* Storage+OnionRequests.swift */; }; C33FDDA3255A582000E217F9 /* TSInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE9255A581A00E217F9 /* TSInteraction.m */; }; C33FDDA5255A582000E217F9 /* OWSBlockingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */; }; @@ -533,14 +539,12 @@ C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB3255A582000E217F9 /* OWSError.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF9255A581C00E217F9 /* OWSError.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDB5255A582000E217F9 /* Storage+PublicChats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */; }; C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDBB255A582000E217F9 /* TSGroupThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC01255A581C00E217F9 /* TSGroupThread.m */; }; C33FDDBC255A582000E217F9 /* OWSPrimaryStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */; }; C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC03255A581D00E217F9 /* ByteParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC06255A581D00E217F9 /* SignalAccount.m */; }; - C33FDDC1255A582000E217F9 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */; }; C33FDDC5255A582000E217F9 /* OWSError.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0B255A581D00E217F9 /* OWSError.m */; }; C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */; }; C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC12255A581E00E217F9 /* TSConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -576,8 +580,6 @@ C3548F0624456447009433A8 /* PNModeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0524456447009433A8 /* PNModeVC.swift */; }; C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */; }; C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C354E75923FE2A7600CE22E3 /* BaseVC.swift */; }; - C3550A03255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3550A02255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift */; }; - C3550A1D255DD73500194B6A /* Storage+SessionMessagingKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3550A1C255DD73500194B6A /* Storage+SessionMessagingKit.swift */; }; C35E8AA82485C85800ACB629 /* GeoLite2-Country-Locations-English.csv in Resources */ = {isa = PBXBuildFile; fileRef = C35E8AA52485C85400ACB629 /* GeoLite2-Country-Locations-English.csv */; }; C35E8AA92485C85800ACB629 /* GeoLite2-Country-Blocks-IPv4.csv in Resources */ = {isa = PBXBuildFile; fileRef = C35E8AA62485C85600ACB629 /* GeoLite2-Country-Blocks-IPv4.csv */; }; C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = C35E8AAD2485E51D00ACB629 /* IP2Country.swift */; }; @@ -907,18 +909,12 @@ C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; C3D697382564DCE6004AF766 /* MessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697372564DCE6004AF766 /* MessageHandler.swift */; }; - C3D6974A2564DEDC004AF766 /* MessageReceiverDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; - C3EEA017256487B300C338BC /* LokiDatabaseUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3EEA016256487B300C338BC /* LokiDatabaseUtilities.swift */; }; C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; }; C3F0A5EC255C970D007BE2A3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5EB255C970D007BE2A3 /* Configuration.swift */; }; - C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; }; - C3F0A608255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A607255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift */; }; - C3F0A61A255C9902007BE2A3 /* Storage+SessionProtocolKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A619255C9902007BE2A3 /* Storage+SessionProtocolKit.swift */; }; - C3F0A62C255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */; }; D2179CFC16BB0B3A0006F3AB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */; }; D2179CFE16BB0B480006F3AB /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFD16BB0B480006F3AB /* SystemConfiguration.framework */; }; D221A08E169C9E5E00537ABF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D221A08D169C9E5E00537ABF /* UIKit.framework */; }; @@ -1346,6 +1342,7 @@ B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationButtonSet.swift; sourceTree = ""; }; B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSOutgoingMessage+Conversion.swift"; sourceTree = ""; }; + B840729F2565F1670037CB17 /* Quote+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Quote+Conversion.swift"; sourceTree = ""; }; B84664F4235022F30083A1CD /* MentionUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionUtilities.swift; sourceTree = ""; }; B847570023D568EB00759540 /* SignalServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SignalServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedReminderView.swift; sourceTree = ""; }; @@ -1383,6 +1380,13 @@ B8CCF638239721E20091D419 /* TabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = ""; }; B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinPublicChatVC.swift; sourceTree = ""; }; B8CCF6422397711F0091D419 /* SettingsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsVC.swift; sourceTree = ""; }; + B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = ""; }; + B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Jobs.swift"; sourceTree = ""; }; + B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = ""; }; + B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Messaging.swift"; sourceTree = ""; }; + B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OnionRequests.swift"; sourceTree = ""; }; + B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSenderDelegate.swift; sourceTree = ""; }; + B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIDelegate.swift; sourceTree = ""; }; B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = ""; }; B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = ""; }; B9EB5ABC1884C002007CBB57 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; @@ -1431,17 +1435,15 @@ C33FDA79255A57FB00E217F9 /* TSGroupThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSGroupThread.h; sourceTree = ""; }; C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+SSK.swift"; sourceTree = ""; }; C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeyReceivingErrorMessage.h; sourceTree = ""; }; - C33FDA7C255A57FB00E217F9 /* Debugging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Debugging.swift; sourceTree = ""; }; C33FDA7E255A57FB00E217F9 /* Mention.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mention.swift; sourceTree = ""; }; C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecordTranscriptJob.m; sourceTree = ""; }; C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingMessagesJob.h; sourceTree = ""; }; C33FDA81255A57FC00E217F9 /* MentionsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MentionsManager.swift; sourceTree = ""; }; - C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OWSPrimaryStorage+Loki.swift"; sourceTree = ""; }; C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesFinder.m; sourceTree = ""; }; C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicators.swift; sourceTree = ""; }; C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseTransaction+OWS.h"; sourceTree = ""; }; C33FDA8B255A57FD00E217F9 /* AppVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppVersion.m; sourceTree = ""; }; - C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicChatPoller.swift; sourceTree = ""; }; + C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroupPoller.swift; sourceTree = ""; }; C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFileSystem.m; sourceTree = ""; }; C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSYapDatabaseObject.m; sourceTree = ""; }; C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSChunkedOutputStream.h; sourceTree = ""; }; @@ -1527,7 +1529,6 @@ C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKIncrementingIdFinder.swift; sourceTree = ""; }; C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupPoller.swift; sourceTree = ""; }; C33FDB36255A580B00E217F9 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; - C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+SnodeAPI.swift"; sourceTree = ""; }; C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackgroundTask.h; sourceTree = ""; }; C33FDB3A255A580B00E217F9 /* Poller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poller.swift; sourceTree = ""; }; C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OWS.h"; sourceTree = ""; }; @@ -1589,7 +1590,6 @@ C33FDB91255A581200E217F9 /* ProtoUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProtoUtils.h; sourceTree = ""; }; C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PreKeyBundle+jsonDict.m"; sourceTree = ""; }; C33FDB94255A581300E217F9 /* TSAccountManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAccountManager.h; sourceTree = ""; }; - C33FDB95255A581300E217F9 /* Storage+Collections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+Collections.swift"; sourceTree = ""; }; C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+keyFromIntLong.m"; sourceTree = ""; }; C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSIncomingMessage.h; sourceTree = ""; }; C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentPointer.m; sourceTree = ""; }; @@ -1623,9 +1623,8 @@ C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageUtils.m; sourceTree = ""; }; C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOS.pb.swift; sourceTree = ""; }; C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesJob.m; sourceTree = ""; }; - C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiPushNotificationManager.swift; sourceTree = ""; }; + C33FDBDE255A581900E217F9 /* PushNotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationManager.swift; sourceTree = ""; }; C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = ""; }; - C33FDBE8255A581A00E217F9 /* Storage+OnionRequests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+OnionRequests.swift"; sourceTree = ""; }; C33FDBE9255A581A00E217F9 /* TSInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInteraction.m; sourceTree = ""; }; C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockingManager.h; sourceTree = ""; }; C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecipientIdentity.m; sourceTree = ""; }; @@ -1635,14 +1634,12 @@ C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLSessionDataTask+StatusCode.h"; sourceTree = ""; }; C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+OWS.h"; sourceTree = ""; }; C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = ""; }; - C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+PublicChats.swift"; sourceTree = ""; }; C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+Functional.h"; sourceTree = ""; }; C33FDC01255A581C00E217F9 /* TSGroupThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSGroupThread.m; sourceTree = ""; }; C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSPrimaryStorage.m; sourceTree = ""; }; C33FDC03255A581D00E217F9 /* ByteParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteParser.h; sourceTree = ""; }; C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisappearingMessagesFinder.h; sourceTree = ""; }; C33FDC06255A581D00E217F9 /* SignalAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalAccount.m; sourceTree = ""; }; - C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = ""; }; C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = ""; }; C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInfoMessage.m; sourceTree = ""; }; C33FDC12255A581E00E217F9 /* TSConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSConstants.h; sourceTree = ""; }; @@ -1676,8 +1673,6 @@ C3548F0524456447009433A8 /* PNModeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeVC.swift; sourceTree = ""; }; C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Wrapping.swift"; sourceTree = ""; }; C354E75923FE2A7600CE22E3 /* BaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseVC.swift; sourceTree = ""; }; - C3550A02255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+OpenGroupAPI.swift"; sourceTree = ""; }; - C3550A1C255DD73500194B6A /* Storage+SessionMessagingKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+SessionMessagingKit.swift"; sourceTree = ""; }; C35E8AA22485C72300ACB629 /* SwiftCSV.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCSV.framework; path = ThirdParty/Carthage/Build/iOS/SwiftCSV.framework; sourceTree = ""; }; C35E8AA52485C85400ACB629 /* GeoLite2-Country-Locations-English.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "GeoLite2-Country-Locations-English.csv"; sourceTree = ""; }; C35E8AA62485C85600ACB629 /* GeoLite2-Country-Blocks-IPv4.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "GeoLite2-Country-Blocks-IPv4.csv"; sourceTree = ""; }; @@ -1729,10 +1724,10 @@ C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIView+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.h; sourceTree = SOURCE_ROOT; }; C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.m; sourceTree = SOURCE_ROOT; }; - C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = SignalUtilitiesKit/Remove/OWSProfileManager.m; sourceTree = SOURCE_ROOT; }; - C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = SignalUtilitiesKit/Remove/OWSUserProfile.m; sourceTree = SOURCE_ROOT; }; - C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = SignalUtilitiesKit/Remove/OWSProfileManager.h; sourceTree = SOURCE_ROOT; }; - C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = SignalUtilitiesKit/Remove/OWSUserProfile.h; sourceTree = SOURCE_ROOT; }; + C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = "SignalUtilitiesKit/To Do/OWSProfileManager.m"; sourceTree = SOURCE_ROOT; }; + C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SignalUtilitiesKit/To Do/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; + C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = "SignalUtilitiesKit/To Do/OWSProfileManager.h"; sourceTree = SOURCE_ROOT; }; + C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = "SignalUtilitiesKit/To Do/OWSUserProfile.h"; sourceTree = SOURCE_ROOT; }; C38EF2E2255B6DB9007E1867 /* OWSScreenLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSScreenLock.swift; path = SignalUtilitiesKit/OWSScreenLock.swift; sourceTree = SOURCE_ROOT; }; C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUnreadIndicator.m; path = SignalUtilitiesKit/OWSUnreadIndicator.m; sourceTree = SOURCE_ROOT; }; C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FullTextSearcher.swift; path = SignalUtilitiesKit/FullTextSearcher.swift; sourceTree = SOURCE_ROOT; }; @@ -1817,7 +1812,7 @@ C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/Database/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSearchBar.h; path = SignalUtilitiesKit/UI/OWSSearchBar.h; sourceTree = SOURCE_ROOT; }; C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisappearingTimerConfigurationView.swift; path = SignalUtilitiesKit/UI/DisappearingTimerConfigurationView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = SignalUtilitiesKit/Remove/ContactCellView.m; sourceTree = SOURCE_ROOT; }; + C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = "SignalUtilitiesKit/To Do/ContactCellView.m"; sourceTree = SOURCE_ROOT; }; C38EF3D7255B6DF0007E1867 /* OWSTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextField.h; path = SignalUtilitiesKit/UI/OWSTextField.h; sourceTree = SOURCE_ROOT; }; C38EF3D8255B6DF0007E1867 /* OWSTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTextView.h; path = SignalUtilitiesKit/UI/OWSTextView.h; sourceTree = SOURCE_ROOT; }; C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSNavigationBar.swift; path = SignalUtilitiesKit/UI/OWSNavigationBar.swift; sourceTree = SOURCE_ROOT; }; @@ -1830,13 +1825,13 @@ C38EF3E2255B6DF3007E1867 /* GalleryRailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GalleryRailView.swift; path = SignalUtilitiesKit/UI/GalleryRailView.swift; sourceTree = SOURCE_ROOT; }; C38EF3E3255B6DF4007E1867 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoPlayerView.swift; path = SignalUtilitiesKit/UI/VideoPlayerView.swift; sourceTree = SOURCE_ROOT; }; C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CommonStrings.swift; path = SignalUtilitiesKit/CommonStrings.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E5255B6DF4007E1867 /* ContactCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactCellView.h; path = SignalUtilitiesKit/Remove/ContactCellView.h; sourceTree = SOURCE_ROOT; }; - C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactTableViewCell.h; path = SignalUtilitiesKit/Remove/ContactTableViewCell.h; sourceTree = SOURCE_ROOT; }; + C38EF3E5255B6DF4007E1867 /* ContactCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactCellView.h; path = "SignalUtilitiesKit/To Do/ContactCellView.h"; sourceTree = SOURCE_ROOT; }; + C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactTableViewCell.h; path = "SignalUtilitiesKit/To Do/ContactTableViewCell.h"; sourceTree = SOURCE_ROOT; }; C38EF3E7255B6DF5007E1867 /* OWSButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSButton.swift; path = SignalUtilitiesKit/UI/OWSButton.swift; sourceTree = SOURCE_ROOT; }; C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAlerts.swift; path = SignalUtilitiesKit/UI/OWSAlerts.swift; sourceTree = SOURCE_ROOT; }; C38EF3E9255B6DF6007E1867 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = SignalUtilitiesKit/UI/Toast.swift; sourceTree = SOURCE_ROOT; }; C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSearchBar.m; path = SignalUtilitiesKit/UI/OWSSearchBar.m; sourceTree = SOURCE_ROOT; }; - C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactTableViewCell.m; path = SignalUtilitiesKit/Remove/ContactTableViewCell.m; sourceTree = SOURCE_ROOT; }; + C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactTableViewCell.m; path = "SignalUtilitiesKit/To Do/ContactTableViewCell.m"; sourceTree = SOURCE_ROOT; }; C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSFlatButton.swift; path = SignalUtilitiesKit/UI/OWSFlatButton.swift; sourceTree = SOURCE_ROOT; }; C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = SignalUtilitiesKit/UI/TappableStackView.swift; sourceTree = SOURCE_ROOT; }; C38EF3EE255B6DF6007E1867 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = SignalUtilitiesKit/UI/GradientView.swift; sourceTree = SOURCE_ROOT; }; @@ -2017,14 +2012,11 @@ C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = ""; }; - C3EEA016256487B300C338BC /* LokiDatabaseUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiDatabaseUtilities.swift; sourceTree = ""; }; C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = ""; }; C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; C3F0A5EB255C970D007BE2A3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Shared.swift"; sourceTree = ""; }; - C3F0A607255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+SessionSnodeKit.swift"; sourceTree = ""; }; - C3F0A619255C9902007BE2A3 /* Storage+SessionProtocolKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+SessionProtocolKit.swift"; sourceTree = ""; }; - C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+SharedSenderKeys.swift"; sourceTree = ""; }; + C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+SnodeAPI.swift"; sourceTree = ""; }; C88965DE4F4EC4FC919BEC4E /* Pods-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.debug.xcconfig"; sourceTree = ""; }; CB3724C70247A916D43271FE /* Pods_Session.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Session.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; @@ -2694,18 +2686,6 @@ path = Meta; sourceTree = ""; }; - C31F812425258F9C00DD9FD9 /* Database */ = { - isa = PBXGroup; - children = ( - C3550A1C255DD73500194B6A /* Storage+SessionMessagingKit.swift */, - C3F0A619255C9902007BE2A3 /* Storage+SessionProtocolKit.swift */, - C3F0A607255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift */, - C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */, - C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */, - ); - path = Database; - sourceTree = ""; - }; C32B405424A961E1001117B5 /* Dependencies */ = { isa = PBXGroup; children = ( @@ -2777,8 +2757,7 @@ isa = PBXGroup; children = ( C33FD9B7255A54A300E217F9 /* Meta */, - C3851CE3256250FA0061EEB0 /* Remove */, - C38BBA17255E327A0041B9A3 /* Move to Session */, + C3851CE3256250FA0061EEB0 /* To Do */, C3CA3B11255CF17200F4C6D4 /* Utilities */, C3851CD225624B060061EEB0 /* UI */, C38BBA0B255E31EC0041B9A3 /* Attachments */, @@ -2934,6 +2913,7 @@ C3851CD225624B060061EEB0 /* UI */ = { isa = PBXGroup; children = ( + C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */, B8C2B2C72563685C00551B4D /* CircleView.swift */, C38EF23D255B6D66007E1867 /* UIView+OWS.h */, C38EF23E255B6D66007E1867 /* UIView+OWS.m */, @@ -3006,7 +2986,6 @@ C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */, C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */, C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */, - C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */, C38EF212255B6D3A007E1867 /* Theme.h */, C38EF214255B6D3A007E1867 /* Theme.m */, C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */, @@ -3028,7 +3007,7 @@ path = UI; sourceTree = ""; }; - C3851CE3256250FA0061EEB0 /* Remove */ = { + C3851CE3256250FA0061EEB0 /* To Do */ = { isa = PBXGroup; children = ( C33FDB19255A580900E217F9 /* GroupUtilities.swift */, @@ -3038,6 +3017,7 @@ C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */, C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */, + C33FDADF255A580400E217F9 /* PublicChatManager.swift */, C38EF3E5255B6DF4007E1867 /* ContactCellView.h */, C38EF3D6255B6DEF007E1867 /* ContactCellView.m */, C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */, @@ -3046,8 +3026,10 @@ C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */, C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */, C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */, + C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */, + C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */, ); - path = Remove; + path = "To Do"; sourceTree = ""; }; C38BBA0B255E31EC0041B9A3 /* Attachments */ = { @@ -3084,12 +3066,25 @@ C38BBA0D255E321C0041B9A3 /* Messaging */ = { isa = PBXGroup; children = ( + C33FDB3A255A580B00E217F9 /* Poller.swift */, + C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, + C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */, + C33FDBDE255A581900E217F9 /* PushNotificationManager.swift */, + C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */, + C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, + C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, + B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */, + B840729F2565F1670037CB17 /* Quote+Conversion.swift */, + B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */, + C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */, + B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */, + C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */, + C33FDA7E255A57FB00E217F9 /* Mention.swift */, + C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, - C33FDA7E255A57FB00E217F9 /* Mention.swift */, - C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, @@ -3139,6 +3134,16 @@ C38BBA0E255E32440041B9A3 /* Database */ = { isa = PBXGroup; children = ( + C33FDB36255A580B00E217F9 /* Storage.swift */, + B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */, + B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */, + B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */, + B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */, + B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */, + C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, + C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */, + C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */, + C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */, C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, @@ -3181,30 +3186,6 @@ path = Database; sourceTree = ""; }; - C38BBA17255E327A0041B9A3 /* Move to Session */ = { - isa = PBXGroup; - children = ( - C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, - C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, - C33FDBDE255A581900E217F9 /* LokiPushNotificationManager.swift */, - C33FDB3A255A580B00E217F9 /* Poller.swift */, - C33FDADF255A580400E217F9 /* PublicChatManager.swift */, - C33FDA8C255A57FD00E217F9 /* PublicChatPoller.swift */, - C3EEA016256487B300C338BC /* LokiDatabaseUtilities.swift */, - C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */, - C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */, - C33FDA85255A57FC00E217F9 /* OWSPrimaryStorage+Loki.swift */, - C33FDB36255A580B00E217F9 /* Storage.swift */, - C33FDC07255A581D00E217F9 /* Storage+ClosedGroups.swift */, - C33FDB95255A581300E217F9 /* Storage+Collections.swift */, - C33FDBE8255A581A00E217F9 /* Storage+OnionRequests.swift */, - C33FDBFB255A581C00E217F9 /* Storage+PublicChats.swift */, - C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, - C33FDB37255A580B00E217F9 /* Storage+SnodeAPI.swift */, - ); - path = "Move to Session"; - sourceTree = ""; - }; C396DAE72518407300FF6DC5 /* SwiftCSV */ = { isa = PBXGroup; children = ( @@ -3575,21 +3556,23 @@ C3CA3B11255CF17200F4C6D4 /* Utilities */ = { isa = PBXGroup; children = ( + C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, + C33FDAAF255A580000E217F9 /* String+Trimming.swift */, + C33FDB80255A581100E217F9 /* Notification+Loki.swift */, + C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, + C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, + C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */, + C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, + C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, C33FDC16255A581E00E217F9 /* FunctionalUtil.h */, C33FDB17255A580800E217F9 /* FunctionalUtil.m */, - C33FDB80255A581100E217F9 /* Notification+Loki.swift */, C33FDB8F255A581200E217F9 /* ParamParser.swift */, C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, - C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, - C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, - C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, - C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, C33FDB81255A581100E217F9 /* UIImage+OWS.m */, C33FDB49255A580C00E217F9 /* WeakTimer.swift */, C33FDB3F255A580C00E217F9 /* String+SSK.swift */, - C33FDAAF255A580000E217F9 /* String+Trimming.swift */, C33FDBC2255A581700E217F9 /* SSKAsserts.h */, C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */, C33FDB91255A581200E217F9 /* ProtoUtils.h */, @@ -3616,18 +3599,14 @@ C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */, C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */, C33FDAFD255A580600E217F9 /* LRUCache.swift */, - C33FDA7C255A57FB00E217F9 /* Debugging.swift */, C33FDC03255A581D00E217F9 /* ByteParser.h */, C33FDAE0255A580400E217F9 /* ByteParser.m */, - C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */, C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */, C38EF225255B6D5D007E1867 /* AttachmentSharing.h */, C38EF223255B6D5D007E1867 /* AttachmentSharing.m */, C38EF241255B6D67007E1867 /* Collection+OWS.swift */, C38EF2F8255B6DBC007E1867 /* DebugLogger.h */, C38EF2E6255B6DBA007E1867 /* DebugLogger.m */, - C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */, - C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */, C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */, C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */, C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */, @@ -3637,15 +3616,12 @@ C38EF305255B6DBE007E1867 /* OWSFormat.m */, C38EF281255B6D84007E1867 /* OWSAudioSession.swift */, C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */, - C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */, C38EF2EF255B6DBB007E1867 /* Weak.swift */, C38EF2FA255B6DBD007E1867 /* Bench.swift */, C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */, C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */, C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */, - C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, - B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */, ); path = Utilities; sourceTree = ""; @@ -3763,12 +3739,8 @@ isa = PBXGroup; children = ( C3F0A58F255C8E3D007BE2A3 /* Meta */, - C3550A02255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift */, - C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */, C3F0A5EB255C970D007BE2A3 /* Configuration.swift */, - C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */, B8CCF63B239757C10091D419 /* Components */, - C31F812425258F9C00DD9FD9 /* Database */, C32B405424A961E1001117B5 /* Dependencies */, 76EB03C118170B33006006FC /* Signal */, B8CCF63C239757DB0091D419 /* Utilities */, @@ -4810,7 +4782,7 @@ C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */, C33FDCA3255A582000E217F9 /* SSKMessageSenderJobRecord.m in Sources */, C38EF3C3255B6DE7007E1867 /* ImageEditorTextItem.swift in Sources */, - C33FDDB5255A582000E217F9 /* Storage+PublicChats.swift in Sources */, + B8D8F16B256615DE0092EF10 /* Storage+VolumeSamples.swift in Sources */, C33FDC41255A581F00E217F9 /* TypingIndicators.swift in Sources */, C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */, C33FDC2E255A581F00E217F9 /* ClosedGroupsProtocol.swift in Sources */, @@ -4819,6 +4791,7 @@ C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */, C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */, C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */, + B8D8F19325661BF80092EF10 /* Storage+Messaging.swift in Sources */, C38EF35F255B6DCC007E1867 /* SelectRecipientViewController.m in Sources */, C38EF3C5255B6DE7007E1867 /* OWSViewController+ImageEditor.swift in Sources */, C33FDDCD255A582000E217F9 /* OWSAttachmentDownloads.m in Sources */, @@ -4840,7 +4813,7 @@ C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */, C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */, C38EF297255B6D86007E1867 /* OWSSounds.m in Sources */, - C33FDCF1255A582000E217F9 /* Storage+SnodeAPI.swift in Sources */, + B8D8F18925661BA50092EF10 /* Storage+OpenGroups.swift in Sources */, C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */, C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */, C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, @@ -4853,16 +4826,17 @@ C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */, C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */, C33FDD42255A582000E217F9 /* TSAccountManager.m in Sources */, + B8D8F1E6256620DD0092EF10 /* MessageReceiverDelegate.swift in Sources */, C38EF3FB255B6DF7007E1867 /* UIAlertController+OWS.swift in Sources */, C33FDC53255A582000E217F9 /* OutageDetection.swift in Sources */, C38EF30C255B6DBF007E1867 /* OWSScreenLock.swift in Sources */, C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */, C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */, C33FDD00255A582000E217F9 /* TSDatabaseView.m in Sources */, - C3EEA017256487B300C338BC /* LokiDatabaseUtilities.swift in Sources */, C33FDD3B255A582000E217F9 /* UIImage+OWS.m in Sources */, C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */, C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */, + B84072A02565F1670037CB17 /* Quote+Conversion.swift in Sources */, C33FDC7E255A582000E217F9 /* TSAttachmentStream.m in Sources */, C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */, C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */, @@ -4871,7 +4845,6 @@ C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */, C33FDD3F255A582000E217F9 /* AppContext.m in Sources */, C33FDCC7255A582000E217F9 /* NSArray+OWS.m in Sources */, - C33FDD25255A582000E217F9 /* LKUserDefaults.swift in Sources */, C38EF3EF255B6DF7007E1867 /* ThreadViewHelper.m in Sources */, C33FDD72255A582000E217F9 /* TSThread.m in Sources */, C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */, @@ -4891,10 +4864,9 @@ C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */, C38EF407255B6DF7007E1867 /* Toast.swift in Sources */, C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */, - C33FDDA2255A582000E217F9 /* Storage+OnionRequests.swift in Sources */, + B8D8F0F32565F98E0092EF10 /* LKUserDefaults.swift in Sources */, C38EF409255B6DF7007E1867 /* ContactTableViewCell.m in Sources */, C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */, - C33FDC3F255A581F00E217F9 /* OWSPrimaryStorage+Loki.swift in Sources */, C38EF333255B6DBF007E1867 /* DeviceSleepManager.swift in Sources */, C33FDC52255A582000E217F9 /* RotateSignedKeyOperation.swift in Sources */, C33FDCDA255A582000E217F9 /* TSDatabaseSecondaryIndexes.m in Sources */, @@ -4911,13 +4883,15 @@ C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */, C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */, - C33FDC46255A581F00E217F9 /* PublicChatPoller.swift in Sources */, + B8D8F16A256615DE0092EF10 /* Storage+Shared.swift in Sources */, + C33FDC46255A581F00E217F9 /* OpenGroupPoller.swift in Sources */, C38EF400255B6DF7007E1867 /* GalleryRailView.swift in Sources */, C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */, C33FDC34255A581F00E217F9 /* NSRegularExpression+SSK.swift in Sources */, C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */, C38EF218255B6D3B007E1867 /* Theme.m in Sources */, C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */, + B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */, C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */, C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */, C33FDD76255A582000E217F9 /* SSKKeychainStorage.swift in Sources */, @@ -4933,8 +4907,8 @@ C33FDD05255A582000E217F9 /* OWSChunkedOutputStream.m in Sources */, C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */, C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */, + B8D8F12E2565FC910092EF10 /* Storage.swift in Sources */, C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */, - C33FDCF0255A582000E217F9 /* Storage.swift in Sources */, C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */, C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */, C38EF229255B6D5D007E1867 /* SignalAttachment.swift in Sources */, @@ -4948,17 +4922,16 @@ C38EF408255B6DF7007E1867 /* OWSSearchBar.m in Sources */, C38EF327255B6DBF007E1867 /* BlockListUIUtils.m in Sources */, C33FDCFF255A582000E217F9 /* NSString+SSK.m in Sources */, - C33FDC36255A581F00E217F9 /* Debugging.swift in Sources */, C33FDD22255A582000E217F9 /* ContentProxy.swift in Sources */, C38EF310255B6DBF007E1867 /* DebugLogger.m in Sources */, C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */, - C33FDD98255A582000E217F9 /* LokiPushNotificationManager.swift in Sources */, C33FDD70255A582000E217F9 /* DataSource.m in Sources */, C33FDD2F255A582000E217F9 /* AppReadiness.m in Sources */, C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */, C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */, C33FDC69255A582000E217F9 /* String+Trimming.swift in Sources */, C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */, + B8D8F1F0256621180092EF10 /* MessageSenderDelegate.swift in Sources */, C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */, C38EF3C4255B6DE7007E1867 /* ImageEditorContents.swift in Sources */, C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */, @@ -4969,13 +4942,13 @@ C38EF387255B6DD2007E1867 /* AttachmentItemCollection.swift in Sources */, C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */, C33FDC38255A581F00E217F9 /* Mention.swift in Sources */, - C33FDDC1255A582000E217F9 /* Storage+ClosedGroups.swift in Sources */, C38EF3BF255B6DE7007E1867 /* ImageEditorView.swift in Sources */, C38EF365255B6DCC007E1867 /* OWSTableViewController.m in Sources */, C33FDC25255A581F00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */, C38EF36B255B6DCC007E1867 /* ScreenLockViewController.m in Sources */, C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */, C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */, + B8D8F16C256615DE0092EF10 /* Storage+SnodeAPI.swift in Sources */, C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */, C3B7845D25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift in Sources */, C33FDCF4255A582000E217F9 /* Poller.swift in Sources */, @@ -4983,6 +4956,7 @@ C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */, C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */, C38EF39E255B6DDA007E1867 /* OWSQuotedReplyModel.m in Sources */, + B8D8F17725661AFA0092EF10 /* Storage+Jobs.swift in Sources */, C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, C33FDDBB255A582000E217F9 /* TSGroupThread.m in Sources */, @@ -4993,7 +4967,6 @@ C33FDD7B255A582000E217F9 /* GeneralUtilities.swift in Sources */, C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */, C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */, - C33FDD4F255A582000E217F9 /* Storage+Collections.swift in Sources */, C33FDD15255A582000E217F9 /* YapDatabaseTransaction+OWS.m in Sources */, C33FDD63255A582000E217F9 /* OWSIdentityManager.m in Sources */, C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */, @@ -5009,6 +4982,7 @@ C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */, C38EF3FE255B6DF7007E1867 /* OWSTextField.m in Sources */, C33FDC40255A581F00E217F9 /* OWSDisappearingMessagesFinder.m in Sources */, + B8D8F21A25662A4D0092EF10 /* OpenGroupAPIDelegate.swift in Sources */, C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */, @@ -5018,6 +4992,7 @@ C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */, C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */, C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */, + B8D8F0F42565F98E0092EF10 /* PushNotificationManager.swift in Sources */, C33FDC78255A582000E217F9 /* TSConstants.m in Sources */, C38EF324255B6DBF007E1867 /* Bench.swift in Sources */, C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */, @@ -5063,6 +5038,7 @@ C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */, C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */, C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */, + B8D8F1BD25661C6F0092EF10 /* Storage+OnionRequests.swift in Sources */, C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */, C33FDD2B255A582000E217F9 /* OWSMediaGalleryFinder.m in Sources */, C38EF2B4255B6D9C007E1867 /* UIView+Utilities.swift in Sources */, @@ -5228,7 +5204,6 @@ C396DAF52518408B00FF6DC5 /* CSV.swift in Sources */, B8CCF63723961D6D0091D419 /* NewPrivateChatVC.swift in Sources */, 3461293E1FD1D72B00532771 /* ExperienceUpgradeFinder.swift in Sources */, - C3F0A61A255C9902007BE2A3 /* Storage+SessionProtocolKit.swift in Sources */, 34C4E2582118957600BEA353 /* WebRTCProto.swift in Sources */, C396DAF12518408B00FF6DC5 /* EnumeratedView.swift in Sources */, 34D1F0BD1F8D108C0066283D /* AttachmentUploadView.m in Sources */, @@ -5241,7 +5216,6 @@ 3496957421A301A100DCFE74 /* OWSBackupAPI.swift in Sources */, C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */, B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */, - C3550A03255DD6D900194B6A /* AppDelegate+OpenGroupAPI.swift in Sources */, B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */, B879D449247E1BE300DB3608 /* PathVC.swift in Sources */, 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */, @@ -5303,7 +5277,6 @@ C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */, C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */, 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */, - C3F0A62C255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift in Sources */, 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */, 34D1F0881F8678AA0066283D /* ConversationViewLayout.m in Sources */, B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */, @@ -5320,17 +5293,14 @@ C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */, 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */, 34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */, - C3F0A608255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift in Sources */, 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */, 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */, 2400888E239F30A600305217 /* SessionRestorationView.swift in Sources */, - C3D6974A2564DEDC004AF766 /* MessageReceiverDelegate.swift in Sources */, B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */, 34EA69402194933900702471 /* MediaDownloadView.swift in Sources */, B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */, 4C586926224FAB83003FD070 /* AVAudioSession+OWS.m in Sources */, 3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */, - C3550A1D255DD73500194B6A /* Storage+SessionMessagingKit.swift in Sources */, C331FFF42558FF0300070591 /* PNOptionView.swift in Sources */, 4C4AE6A1224AF35700D4AF6F /* SendMediaNavigationController.swift in Sources */, 45F32C222057297A00A300D5 /* MediaDetailViewController.m in Sources */, @@ -5360,7 +5330,6 @@ B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */, 34D1F0C01F8EC1760066283D /* MessageRecipientStatusUtils.swift in Sources */, 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */, - C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */, B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */, 3488F9362191CC4000E524CC /* ConversationMediaView.swift in Sources */, 45F32C242057297A00A300D5 /* MessageDetailViewController.swift in Sources */, @@ -5391,7 +5360,6 @@ 340FC8AC204DAC8D007AEB0F /* PrivacySettingsTableViewController.m in Sources */, B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */, B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */, - C31F812625258FB000DD9FD9 /* Storage+VolumeSamples.swift in Sources */, C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */, 340FC8AE204DAC8D007AEB0F /* OWSSoundSettingsViewController.m in Sources */, 340FC8B0204DAC8D007AEB0F /* AddToBlockListViewController.m in Sources */, diff --git a/SignalUtilitiesKit/Database/Storage+ClosedGroups.swift b/SignalUtilitiesKit/Database/Storage+ClosedGroups.swift new file mode 100644 index 000000000..5aed45fc9 --- /dev/null +++ b/SignalUtilitiesKit/Database/Storage+ClosedGroups.swift @@ -0,0 +1,86 @@ + +extension Storage { + + // MARK: - Ratchets + + private static func getClosedGroupRatchetCollection(_ collection: ClosedGroupRatchetCollectionType, for groupPublicKey: String) -> String { + switch collection { + case .old: return "LokiOldClosedGroupRatchetCollection.\(groupPublicKey)" + case .current: return "LokiClosedGroupRatchetCollection.\(groupPublicKey)" + } + } + + public func getClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> ClosedGroupRatchet? { + let collection = Storage.getClosedGroupRatchetCollection(collection, for: groupPublicKey) + var result: ClosedGroupRatchet? + Storage.read { transaction in + result = transaction.object(forKey: senderPublicKey, inCollection: collection) as? ClosedGroupRatchet + } + return result + } + + public func setClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, ratchet: ClosedGroupRatchet, in collection: ClosedGroupRatchetCollectionType = .current, using transaction: Any) { + let collection = Storage.getClosedGroupRatchetCollection(collection, for: groupPublicKey) + (transaction as! YapDatabaseReadWriteTransaction).setObject(ratchet, forKey: senderPublicKey, inCollection: collection) + } + + public func getAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> [(senderPublicKey: String, ratchet: ClosedGroupRatchet)] { + let collection = Storage.getClosedGroupRatchetCollection(collection, for: groupPublicKey) + var result: [(senderPublicKey: String, ratchet: ClosedGroupRatchet)] = [] + Storage.read { transaction in + transaction.enumerateRows(inCollection: collection) { key, object, _, _ in + guard let ratchet = object as? ClosedGroupRatchet else { return } + let senderPublicKey = key + result.append((senderPublicKey: senderPublicKey, ratchet: ratchet)) + } + } + return result + } + + public func removeAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current, using transaction: Any) { + let collection = Storage.getClosedGroupRatchetCollection(collection, for: groupPublicKey) + (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: collection) + } + + // MARK: - Private Keys + + private static let closedGroupPrivateKeyCollection = "LokiClosedGroupPrivateKeyCollection" + + public func getClosedGroupPrivateKey(for publicKey: String) -> String? { + var result: String? + Storage.read { transaction in + result = transaction.object(forKey: publicKey, inCollection: Storage.closedGroupPrivateKeyCollection) as? String + } + return result + } + + public func setClosedGroupPrivateKey(_ privateKey: String, for publicKey: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(privateKey, forKey: publicKey, inCollection: Storage.closedGroupPrivateKeyCollection) + } + + public func removeClosedGroupPrivateKey(for publicKey: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: publicKey, inCollection: Storage.closedGroupPrivateKeyCollection) + } + + + + // MARK: - Convenience + + public func getAllClosedGroupSenderKeys(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> Set { + return Set(getAllClosedGroupRatchets(for: groupPublicKey, from: collection).map { senderPublicKey, ratchet in + ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: senderPublicKey)) + }) + } + + public func getUserClosedGroupPublicKeys() -> Set { + var result: Set = [] + Storage.read { transaction in + result = Set(transaction.allKeys(inCollection: Storage.closedGroupPrivateKeyCollection)) + } + return result + } + + public func isClosedGroup(_ publicKey: String) -> Bool { + getUserClosedGroupPublicKeys().contains(publicKey) + } +} diff --git a/SignalUtilitiesKit/Database/Storage+Jobs.swift b/SignalUtilitiesKit/Database/Storage+Jobs.swift new file mode 100644 index 000000000..98649f318 --- /dev/null +++ b/SignalUtilitiesKit/Database/Storage+Jobs.swift @@ -0,0 +1,26 @@ + +extension Storage { + + public func persist(_ job: Job, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(job, forKey: job.id!, inCollection: type(of: job).collection) + } + + public func markJobAsSucceeded(_ job: Job, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: type(of: job).collection) + } + + public func markJobAsFailed(_ job: Job, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: type(of: job).collection) + } + + public func getAllPendingJobs(of type: Job.Type) -> [Job] { + var result: [Job] = [] + Storage.read { transaction in + transaction.enumerateRows(inCollection: type.collection) { _, object, _, _ in + guard let job = object as? Job else { return } + result.append(job) + } + } + return result + } +} diff --git a/SignalUtilitiesKit/Database/Storage+Messaging.swift b/SignalUtilitiesKit/Database/Storage+Messaging.swift new file mode 100644 index 000000000..ed5e0034b --- /dev/null +++ b/SignalUtilitiesKit/Database/Storage+Messaging.swift @@ -0,0 +1,35 @@ +import PromiseKit + +extension Storage { + + public func getOrGenerateRegistrationID(using transaction: Any) -> UInt32 { + SSKEnvironment.shared.tsAccountManager.getOrGenerateRegistrationId(transaction as! YapDatabaseReadWriteTransaction) + } + + public func getSenderCertificate(for publicKey: String) -> SMKSenderCertificate { + let (promise, seal) = Promise.pending() + SSKEnvironment.shared.udManager.ensureSenderCertificate { senderCertificate in + seal.fulfill(senderCertificate) + } failure: { error in + // Should never fail + } + return try! promise.wait() + } + + /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. + public func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, Any)? { + let transaction = transaction as! YapDatabaseReadWriteTransaction + var threadOrNil: TSThread? + if let groupPublicKey = groupPublicKey { + guard Storage.shared.isClosedGroup(groupPublicKey) else { return nil } + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) + } else { + threadOrNil = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) + } + guard let thread = threadOrNil else { return nil } + let message = TSIncomingMessage.from(message, associatedWith: thread, using: transaction) + message.save(with: transaction) + return (thread.uniqueId!, message) + } +} diff --git a/SignalUtilitiesKit/Move to Session/Storage+OnionRequests.swift b/SignalUtilitiesKit/Database/Storage+OnionRequests.swift similarity index 72% rename from SignalUtilitiesKit/Move to Session/Storage+OnionRequests.swift rename to SignalUtilitiesKit/Database/Storage+OnionRequests.swift index 3a1e417ba..e308b96b7 100644 --- a/SignalUtilitiesKit/Move to Session/Storage+OnionRequests.swift +++ b/SignalUtilitiesKit/Database/Storage+OnionRequests.swift @@ -1,31 +1,12 @@ -public extension Storage { - - // MARK: Onion Request Paths - internal static let onionRequestPathCollection = "LokiOnionRequestPathCollection" +extension Storage { - internal static func setOnionRequestPaths(_ paths: [OnionRequestAPI.Path], using transaction: YapDatabaseReadWriteTransaction) { - let collection = onionRequestPathCollection - // FIXME: This approach assumes either 1 or 2 paths of length 3 each. We should do better than this. - clearOnionRequestPaths(using: transaction) - guard paths.count >= 1 else { return } - let path0 = paths[0] - guard path0.count == 3 else { return } - transaction.setObject(path0[0], forKey: "0-0", inCollection: collection) - transaction.setObject(path0[1], forKey: "0-1", inCollection: collection) - transaction.setObject(path0[2], forKey: "0-2", inCollection: collection) - guard paths.count >= 2 else { return } - let path1 = paths[1] - guard path1.count == 3 else { return } - transaction.setObject(path1[0], forKey: "1-0", inCollection: collection) - transaction.setObject(path1[1], forKey: "1-1", inCollection: collection) - transaction.setObject(path1[2], forKey: "1-2", inCollection: collection) - } + private static let onionRequestPathCollection = "LokiOnionRequestPathCollection" - public static func getOnionRequestPaths() -> [OnionRequestAPI.Path] { - let collection = onionRequestPathCollection + public func getOnionRequestPaths() -> [OnionRequestAPI.Path] { + let collection = Storage.onionRequestPathCollection var result: [OnionRequestAPI.Path] = [] - read { transaction in + Storage.read { transaction in if let path0Snode0 = transaction.object(forKey: "0-0", inCollection: collection) as? Snode, let path0Snode1 = transaction.object(forKey: "0-1", inCollection: collection) as? Snode, @@ -42,7 +23,26 @@ public extension Storage { return result } - internal static func clearOnionRequestPaths(using transaction: YapDatabaseReadWriteTransaction) { - transaction.removeAllObjects(inCollection: onionRequestPathCollection) + public func setOnionRequestPaths(to paths: [OnionRequestAPI.Path], using transaction: Any) { + let collection = Storage.onionRequestPathCollection + // FIXME: This approach assumes either 1 or 2 paths of length 3 each. We should do better than this. + clearOnionRequestPaths(using: transaction) + guard let transaction = transaction as? YapDatabaseReadWriteTransaction else { return } + guard paths.count >= 1 else { return } + let path0 = paths[0] + guard path0.count == 3 else { return } + transaction.setObject(path0[0], forKey: "0-0", inCollection: collection) + transaction.setObject(path0[1], forKey: "0-1", inCollection: collection) + transaction.setObject(path0[2], forKey: "0-2", inCollection: collection) + guard paths.count >= 2 else { return } + let path1 = paths[1] + guard path1.count == 3 else { return } + transaction.setObject(path1[0], forKey: "1-0", inCollection: collection) + transaction.setObject(path1[1], forKey: "1-1", inCollection: collection) + transaction.setObject(path1[2], forKey: "1-2", inCollection: collection) + } + + func clearOnionRequestPaths(using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.onionRequestPathCollection) } } diff --git a/Session/Database/Storage+SessionMessagingKit.swift b/SignalUtilitiesKit/Database/Storage+OpenGroups.swift similarity index 58% rename from Session/Database/Storage+SessionMessagingKit.swift rename to SignalUtilitiesKit/Database/Storage+OpenGroups.swift index 1e3cc5818..8fc9ebc94 100644 --- a/Session/Database/Storage+SessionMessagingKit.swift +++ b/SignalUtilitiesKit/Database/Storage+OpenGroups.swift @@ -1,87 +1,62 @@ -import Foundation -import PromiseKit -extension Storage : SessionMessagingKitStorageProtocol { - - // MARK: - Signal Protocol +extension Storage { - public func getOrGenerateRegistrationID(using transaction: Any) -> UInt32 { - SSKEnvironment.shared.tsAccountManager.getOrGenerateRegistrationId(transaction as! YapDatabaseReadWriteTransaction) - } - - public func getSenderCertificate(for publicKey: String) -> SMKSenderCertificate { - let (promise, seal) = Promise.pending() - SSKEnvironment.shared.udManager.ensureSenderCertificate { senderCertificate in - seal.fulfill(senderCertificate) - } failure: { error in - // Should never fail - } - return try! promise.wait() - } - - - - // MARK: - Shared Sender Keys - - private static let closedGroupPrivateKeyCollection = "LokiClosedGroupPrivateKeyCollection" - - public func getClosedGroupPrivateKey(for publicKey: String) -> String? { - var result: String? + // MARK: - Open Groups + + private static let openGroupCollection = "LokiPublicChatCollection" + + @objc public func getAllUserOpenGroups() -> [String:OpenGroup] { + var result = [String:OpenGroup]() Storage.read { transaction in - result = transaction.object(forKey: publicKey, inCollection: Storage.closedGroupPrivateKeyCollection) as? String - } - return result - } - - internal static func setClosedGroupPrivateKey(_ privateKey: String, for publicKey: String, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).setObject(privateKey, forKey: publicKey, inCollection: Storage.closedGroupPrivateKeyCollection) - } - - internal static func removeClosedGroupPrivateKey(for publicKey: String, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: publicKey, inCollection: Storage.closedGroupPrivateKeyCollection) - } - - func getUserClosedGroupPublicKeys() -> Set { - var result: Set = [] - Storage.read { transaction in - result = Set(transaction.allKeys(inCollection: Storage.closedGroupPrivateKeyCollection)) - } - return result - } - - public func isClosedGroup(_ publicKey: String) -> Bool { - getUserClosedGroupPublicKeys().contains(publicKey) - } - - - - // MARK: - Jobs - - public func persist(_ job: Job, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).setObject(job, forKey: job.id!, inCollection: type(of: job).collection) - } - - public func markJobAsSucceeded(_ job: Job, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: type(of: job).collection) - } - - public func markJobAsFailed(_ job: Job, using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: job.id!, inCollection: type(of: job).collection) - } - - public func getAllPendingJobs(of type: Job.Type) -> [Job] { - var result: [Job] = [] - Storage.read { transaction in - transaction.enumerateRows(inCollection: type.collection) { _, object, _, _ in - guard let job = object as? Job else { return } - result.append(job) + transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection) { threadID, object, _ in + guard let openGroup = object as? OpenGroup else { return } + result[threadID] = openGroup } } return result } + @objc(getOpenGroupForThreadID:) + public func getOpenGroup(for threadID: String) -> OpenGroup? { + var result: OpenGroup? + Storage.read { transaction in + result = transaction.object(forKey: threadID, inCollection: Storage.openGroupCollection) as? OpenGroup + } + return result + } + @objc(setOpenGroup:forThreadWithID:using:) + public func setOpenGroup(_ openGroup: OpenGroup, for threadID: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(openGroup, forKey: threadID, inCollection: Storage.openGroupCollection) + } + @objc(removeOpenGroupForThreadID:using:) + public func removeOpenGroup(for threadID: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: threadID, inCollection: Storage.openGroupCollection) + } + + + + // MARK: - Quotes + + @objc(getServerIDForQuoteWithID:quoteeHexEncodedPublicKey:threadID:transaction:) + public func getServerID(quoteID: UInt64, quoteeHexEncodedPublicKey: String, threadID: String, transaction: YapDatabaseReadTransaction) -> UInt64 { + guard let message = TSInteraction.interactions(withTimestamp: quoteID, filter: { interaction in + let senderPublicKey: String + if let message = interaction as? TSIncomingMessage { + senderPublicKey = message.authorId + } else if interaction is TSOutgoingMessage { + senderPublicKey = getUserHexEncodedPublicKey() + } else { + return false + } + return (senderPublicKey == quoteeHexEncodedPublicKey) && (interaction.uniqueThreadId == threadID) + }, with: transaction).first as! TSMessage? else { return 0 } + return message.openGroupServerMessageID + } + + + // MARK: - Authorization private static func getAuthTokenCollection(for server: String) -> String { @@ -109,7 +84,7 @@ extension Storage : SessionMessagingKitStorageProtocol { - // MARK: - Open Group Public Keys + // MARK: - Public Keys private static let openGroupPublicKeyCollection = "LokiOpenGroupPublicKeyCollection" @@ -124,12 +99,26 @@ extension Storage : SessionMessagingKitStorageProtocol { public func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: server, inCollection: Storage.openGroupPublicKeyCollection) } - + + public func removeOpenGroupPublicKey(for server: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: server, inCollection: Storage.openGroupPublicKeyCollection) + } + + + + // MARK: - Deletion + + public func clearAllData(for group: UInt64, on server: String, using transaction: Any) { + removeLastMessageServerID(for: group, on: server, using: transaction) + removeLastDeletionServerID(for: group, on: server, using: transaction) + removeOpenGroupPublicKey(for: server, using: transaction) + } + // MARK: - Last Message Server ID - private static let lastMessageServerIDCollection = "LokiGroupChatLastMessageServerIDCollection" + public static let lastMessageServerIDCollection = "LokiGroupChatLastMessageServerIDCollection" public func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64? { var result: UInt64? = nil @@ -151,7 +140,7 @@ extension Storage : SessionMessagingKitStorageProtocol { // MARK: - Last Deletion Server ID - private static let lastDeletionServerIDCollection = "LokiGroupChatLastDeletionServerIDCollection" + public static let lastDeletionServerIDCollection = "LokiGroupChatLastDeletionServerIDCollection" public func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64? { var result: UInt64? = nil @@ -171,11 +160,20 @@ extension Storage : SessionMessagingKitStorageProtocol { - // MARK: - Open Group Metadata + // MARK: - Metadata private static let openGroupUserCountCollection = "LokiPublicChatUserCountCollection" private static let openGroupMessageIDCollection = "LKMessageIDCollection" + private static let openGroupProfilePictureURLCollection = "LokiPublicChatAvatarURLCollection" + public func getUserCount(forOpenGroupWithID openGroupID: String) -> Int? { + var result: Int? + Storage.read { transaction in + result = transaction.object(forKey: openGroupID, inCollection: Storage.openGroupUserCountCollection) as? Int + } + return result + } + public func setUserCount(to newValue: Int, forOpenGroupWithID openGroupID: String, using transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: openGroupID, inCollection: Storage.openGroupUserCountCollection) } @@ -196,25 +194,16 @@ extension Storage : SessionMessagingKitStorageProtocol { public func setLastProfilePictureUploadDate(_ date: Date) { UserDefaults.standard[.lastProfilePictureUpload] = date } - - - // MARK: - Message Handling - - /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. - public func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, Any)? { - let transaction = transaction as! YapDatabaseReadWriteTransaction - var threadOrNil: TSThread? - if let groupPublicKey = groupPublicKey { - guard Storage.shared.isClosedGroup(groupPublicKey) else { return nil } - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) - } else { - threadOrNil = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) + public func getProfilePictureURL(forOpenGroupWithID openGroupID: String) -> String? { + var result: String? + Storage.read { transaction in + result = transaction.object(forKey: openGroupID, inCollection: Storage.openGroupProfilePictureURLCollection) as? String } - guard let thread = threadOrNil else { return nil } - let message = TSIncomingMessage.from(message, associatedWith: thread, using: transaction) - message.save(with: transaction) - return (thread.uniqueId!, message) + return result + } + + public func setProfilePictureURL(to profilePictureURL: String?, forOpenGroupWithID openGroupID: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(profilePictureURL, forKey: openGroupID, inCollection: Storage.openGroupProfilePictureURLCollection) } } diff --git a/SignalUtilitiesKit/Database/Storage+SessionManagement.swift b/SignalUtilitiesKit/Database/Storage+SessionManagement.swift new file mode 100644 index 000000000..45ef82c4b --- /dev/null +++ b/SignalUtilitiesKit/Database/Storage+SessionManagement.swift @@ -0,0 +1,30 @@ + +extension Storage { + + private static let sessionRequestSentTimestampCollection = "LokiSessionRequestSentTimestampCollection" + private static let sessionRequestProcessedTimestampCollection = "LokiSessionRequestProcessedTimestampCollection" + + public func getSessionRequestSentTimestamp(for publicKey: String) -> UInt64 { + var result: UInt64? + Storage.read { transaction in + result = transaction.object(forKey: publicKey, inCollection: Storage.sessionRequestSentTimestampCollection) as? UInt64 + } + return result ?? 0 + } + + public func setSessionRequestSentTimestamp(for publicKey: String, to timestamp: UInt64, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(timestamp, forKey: publicKey, inCollection: Storage.sessionRequestSentTimestampCollection) + } + + public func getSessionRequestProcessedTimestamp(for publicKey: String) -> UInt64 { + var result: UInt64? + Storage.read { transaction in + result = transaction.object(forKey: publicKey, inCollection: Storage.sessionRequestProcessedTimestampCollection) as? UInt64 + } + return result ?? 0 + } + + public func setSessionRequestProcessedTimestamp(for publicKey: String, to timestamp: UInt64, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(timestamp, forKey: publicKey, inCollection: Storage.sessionRequestProcessedTimestampCollection) + } +} diff --git a/Session/Database/Storage+Shared.swift b/SignalUtilitiesKit/Database/Storage+Shared.swift similarity index 81% rename from Session/Database/Storage+Shared.swift rename to SignalUtilitiesKit/Database/Storage+Shared.swift index 7910e7532..d2dffbac2 100644 --- a/Session/Database/Storage+Shared.swift +++ b/SignalUtilitiesKit/Database/Storage+Shared.swift @@ -1,8 +1,6 @@ extension Storage { - public static let shared = Storage() - public func with(_ work: @escaping (Any) -> Void) { Storage.writeSync { work($0) } } @@ -19,5 +17,7 @@ extension Storage { return OWSIdentityManager.shared().identityKeyPair() } - public func getUserDisplayName() -> String? { fatalError() } + public func getUserDisplayName() -> String? { + return SSKEnvironment.shared.profileManager.localProfileName() + } } diff --git a/Session/Database/Storage+SessionSnodeKit.swift b/SignalUtilitiesKit/Database/Storage+SnodeAPI.swift similarity index 61% rename from Session/Database/Storage+SessionSnodeKit.swift rename to SignalUtilitiesKit/Database/Storage+SnodeAPI.swift index 76ff86907..0c681f71b 100644 --- a/Session/Database/Storage+SessionSnodeKit.swift +++ b/SignalUtilitiesKit/Database/Storage+SnodeAPI.swift @@ -1,56 +1,9 @@ -extension Storage : SessionSnodeKitStorageProtocol { - - // MARK: - Onion Request Paths - - private static let onionRequestPathCollection = "LokiOnionRequestPathCollection" - - public func getOnionRequestPaths() -> [OnionRequestAPI.Path] { - let collection = Storage.onionRequestPathCollection - var result: [OnionRequestAPI.Path] = [] - Storage.read { transaction in - if - let path0Snode0 = transaction.object(forKey: "0-0", inCollection: collection) as? Snode, - let path0Snode1 = transaction.object(forKey: "0-1", inCollection: collection) as? Snode, - let path0Snode2 = transaction.object(forKey: "0-2", inCollection: collection) as? Snode { - result.append([ path0Snode0, path0Snode1, path0Snode2 ]) - if - let path1Snode0 = transaction.object(forKey: "1-0", inCollection: collection) as? Snode, - let path1Snode1 = transaction.object(forKey: "1-1", inCollection: collection) as? Snode, - let path1Snode2 = transaction.object(forKey: "1-2", inCollection: collection) as? Snode { - result.append([ path1Snode0, path1Snode1, path1Snode2 ]) - } - } - } - return result - } - - public func setOnionRequestPaths(to paths: [OnionRequestAPI.Path], using transaction: Any) { - let collection = Storage.onionRequestPathCollection - // FIXME: This approach assumes either 1 or 2 paths of length 3 each. We should do better than this. - clearOnionRequestPaths(using: transaction) - guard let transaction = transaction as? YapDatabaseReadWriteTransaction else { return } - guard paths.count >= 1 else { return } - let path0 = paths[0] - guard path0.count == 3 else { return } - transaction.setObject(path0[0], forKey: "0-0", inCollection: collection) - transaction.setObject(path0[1], forKey: "0-1", inCollection: collection) - transaction.setObject(path0[2], forKey: "0-2", inCollection: collection) - guard paths.count >= 2 else { return } - let path1 = paths[1] - guard path1.count == 3 else { return } - transaction.setObject(path1[0], forKey: "1-0", inCollection: collection) - transaction.setObject(path1[1], forKey: "1-1", inCollection: collection) - transaction.setObject(path1[2], forKey: "1-2", inCollection: collection) - } - - func clearOnionRequestPaths(using transaction: Any) { - (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.onionRequestPathCollection) - } - - +extension Storage { // MARK: - Snode Pool + + private static let snodePoolCollection = "LokiSnodePoolCollection" public func getSnodePool() -> Set { var result: Set = [] @@ -70,13 +23,17 @@ extension Storage : SessionSnodeKitStorageProtocol { } } - func clearSnodePool(in transaction: Any) { + public func clearSnodePool(in transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.snodePoolCollection) } // MARK: - Swarm + + private static func getSwarmCollection(for publicKey: String) -> String { + return "LokiSwarmCollection-\(publicKey)" + } public func getSwarm(for publicKey: String) -> Set { var result: Set = [] @@ -98,7 +55,7 @@ extension Storage : SessionSnodeKitStorageProtocol { } } - func clearSwarm(for publicKey: String, in transaction: Any) { + public func clearSwarm(for publicKey: String, in transaction: Any) { let collection = Storage.getSwarmCollection(for: publicKey) (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: collection) } @@ -109,7 +66,7 @@ extension Storage : SessionSnodeKitStorageProtocol { private static let lastMessageHashCollection = "LokiLastMessageHashCollection" - func getLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String) -> JSON? { + public func getLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String) -> JSON? { let key = "\(snode.address):\(snode.port).\(publicKey)" var result: JSON? Storage.read { transaction in @@ -141,7 +98,7 @@ extension Storage : SessionSnodeKitStorageProtocol { } } - func removeLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String, using transaction: Any) { + public func removeLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String, using transaction: Any) { let key = "\(snode.address):\(snode.port).\(publicKey)" (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: Storage.lastMessageHashCollection) } diff --git a/SignalUtilitiesKit/Database/Storage+VolumeSamples.swift b/SignalUtilitiesKit/Database/Storage+VolumeSamples.swift new file mode 100644 index 000000000..de82d4e5c --- /dev/null +++ b/SignalUtilitiesKit/Database/Storage+VolumeSamples.swift @@ -0,0 +1,17 @@ + +extension Storage { + + private static let volumeSamplesCollection = "LokiVolumeSamplesCollection" + + public func getVolumeSamples(for attachment: String) -> [Float]? { + var result: [Float]? + Storage.read { transaction in + result = transaction.object(forKey: attachment, inCollection: Storage.volumeSamplesCollection) as? [Float] + } + return result + } + + public func setVolumeSamples(for attachment: String, to volumeSamples: [Float], using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(volumeSamples, forKey: attachment, inCollection: Storage.volumeSamplesCollection) + } +} diff --git a/SignalUtilitiesKit/Move to Session/Storage.swift b/SignalUtilitiesKit/Database/Storage.swift similarity index 87% rename from SignalUtilitiesKit/Move to Session/Storage.swift rename to SignalUtilitiesKit/Database/Storage.swift index add543757..c0bda5868 100644 --- a/SignalUtilitiesKit/Move to Session/Storage.swift +++ b/SignalUtilitiesKit/Database/Storage.swift @@ -6,10 +6,12 @@ import PromiseKit // • Executing a write transaction from within a write transaction is NOT allowed. @objc(LKStorage) -public final class Storage : NSObject { +public final class Storage : NSObject, SessionMessagingKitStorageProtocol, SessionProtocolKitStorageProtocol, SessionSnodeKitStorageProtocol { public static let serialQueue = DispatchQueue(label: "Storage.serialQueue", qos: .userInitiated) private static var owsStorage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } + + @objc public static let shared = Storage() // MARK: Reading @@ -20,13 +22,6 @@ public final class Storage : NSObject { @objc(readWithBlock:) public static func read(with block: @escaping (YapDatabaseReadTransaction) -> Void) { - // FIXME: For some reason the code below appears to be causing crashes even though it *should* - // be in line with the YapDatabase docs - /* - let isMainThread = Thread.current.isMainThread - let connection = isMainThread ? owsStorage.uiDatabaseConnection : owsStorage.dbReadConnection - connection.read(block) - */ owsStorage.dbReadConnection.read(block) } @@ -68,7 +63,6 @@ public final class Storage : NSObject { } /// Blocks the calling thread until the write has finished. - @discardableResult @objc(writeSyncWithBlock:) public static func writeSync(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) { try! write(with: block, completion: { }).wait() // The promise returned by write(with:completion:) never rejects diff --git a/SignalUtilitiesKit/Move to Session/ClosedGroupPoller.swift b/SignalUtilitiesKit/Messaging/ClosedGroupPoller.swift similarity index 97% rename from SignalUtilitiesKit/Move to Session/ClosedGroupPoller.swift rename to SignalUtilitiesKit/Messaging/ClosedGroupPoller.swift index 01fb5f26a..afffd9bed 100644 --- a/SignalUtilitiesKit/Move to Session/ClosedGroupPoller.swift +++ b/SignalUtilitiesKit/Messaging/ClosedGroupPoller.swift @@ -45,7 +45,7 @@ public final class ClosedGroupPoller : NSObject { // MARK: Private API private func poll() -> [Promise] { guard isPolling else { return [] } - let publicKeys = Storage.getUserClosedGroupPublicKeys() + let publicKeys = Storage.shared.getUserClosedGroupPublicKeys() return publicKeys.map { publicKey in let promise = SnodeAPI.getSwarm(for: publicKey).then2 { [weak self] swarm -> Promise<[JSON]> in // randomElement() uses the system's default random generator, which is cryptographically secure diff --git a/SignalUtilitiesKit/Utilities/Destination+Conversion.swift b/SignalUtilitiesKit/Messaging/Destination+Conversion.swift similarity index 79% rename from SignalUtilitiesKit/Utilities/Destination+Conversion.swift rename to SignalUtilitiesKit/Messaging/Destination+Conversion.swift index 20ca01ae2..8e7358635 100644 --- a/SignalUtilitiesKit/Utilities/Destination+Conversion.swift +++ b/SignalUtilitiesKit/Messaging/Destination+Conversion.swift @@ -9,10 +9,7 @@ public extension Message.Destination { let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) return .closedGroup(groupPublicKey: groupPublicKey) } else if let thread = thread as? TSGroupThread, thread.isOpenGroup { - var openGroup: OpenGroup! - Storage.read { transaction in - openGroup = LokiDatabaseUtilities.getPublicChat(for: thread.uniqueId!, in: transaction) - } + let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!)! return .openGroup(channel: openGroup.channel, server: openGroup.server) } else { preconditionFailure("TODO: Handle legacy closed groups.") diff --git a/SignalUtilitiesKit/Messaging/MentionsManager.swift b/SignalUtilitiesKit/Messaging/MentionsManager.swift index 969038463..861b8522a 100644 --- a/SignalUtilitiesKit/Messaging/MentionsManager.swift +++ b/SignalUtilitiesKit/Messaging/MentionsManager.swift @@ -30,19 +30,16 @@ public final class MentionsManager : NSObject { guard let cache = userPublicKeyCache[threadID] else { return [] } var candidates: [Mention] = [] // Gather candidates - var publicChat: OpenGroup? - storage.dbReadConnection.read { transaction in - publicChat = LokiDatabaseUtilities.getPublicChat(for: threadID, in: transaction) - } + let openGroup = Storage.shared.getOpenGroup(for: threadID) storage.dbReadConnection.read { transaction in candidates = cache.compactMap { publicKey in - let uncheckedDisplayName: String? - if let publicChat = publicChat { - uncheckedDisplayName = UserDisplayNameUtilities.getPublicChatDisplayName(for: publicKey, in: publicChat.channel, on: publicChat.server) + let displayNameOrNil: String? + if let openGroup = openGroup { + displayNameOrNil = UserDisplayNameUtilities.getPublicChatDisplayName(for: publicKey, in: openGroup.channel, on: openGroup.server) } else { - uncheckedDisplayName = UserDisplayNameUtilities.getPrivateChatDisplayName(for: publicKey) + displayNameOrNil = UserDisplayNameUtilities.getPrivateChatDisplayName(for: publicKey) } - guard let displayName = uncheckedDisplayName else { return nil } + guard let displayName = displayNameOrNil else { return nil } guard !displayName.hasPrefix("Anonymous") else { return nil } return Mention(publicKey: publicKey, displayName: displayName) } diff --git a/Session/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/MessageReceiverDelegate.swift similarity index 93% rename from Session/MessageReceiverDelegate.swift rename to SignalUtilitiesKit/Messaging/MessageReceiverDelegate.swift index 9d4ed5f85..5d1b28c61 100644 --- a/Session/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/MessageReceiverDelegate.swift @@ -1,8 +1,8 @@ import SessionMessagingKit -final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegate { +public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegate { - static let shared = MessageReceiverDelegate() + public static let shared = MessageReceiverDelegate() @@ -156,7 +156,7 @@ final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegat // MARK: - Closed Groups - func handleNewGroup(_ message: ClosedGroupUpdate, using transaction: Any) { + public func handleNewGroup(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .new(groupPublicKeyAsData, name, groupPrivateKey, senderKeys, membersAsData, adminsAsData) = message.kind else { return } let transaction = transaction as! YapDatabaseReadWriteTransaction let groupPublicKey = groupPublicKeyAsData.toHexString() @@ -185,7 +185,7 @@ final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegat } } missingSenderKeys.subtracting([ userPublicKey ]).forEach { publicKey in - (UIApplication.shared.delegate as! AppDelegate).requestSenderKey(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + MessageSenderDelegate.shared.requestSenderKey(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) } // Create the group let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) @@ -200,15 +200,15 @@ final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegat thread.save(with: transaction) } // Add the group to the user's set of public keys to poll for - Storage.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction) + Storage.shared.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction) // Notify the PN server - let _ = LokiPushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) + let _ = PushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) // Notify the user let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) infoMessage.save(with: transaction) } - func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { + public func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .info(groupPublicKeyAsData, name, senderKeys, membersAsData, adminsAsData) = message.kind else { return } let transaction = transaction as! YapDatabaseReadWriteTransaction let groupPublicKey = groupPublicKeyAsData.toHexString() @@ -236,16 +236,16 @@ final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegat let userPublicKey = getUserHexEncodedPublicKey() let wasUserRemoved = !members.contains(userPublicKey) if Set(members).intersection(oldMembers) != Set(oldMembers) { - let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) + let allOldRatchets = Storage.shared.getAllClosedGroupRatchets(for: groupPublicKey) for (senderPublicKey, oldRatchet) in allOldRatchets { let collection = ClosedGroupRatchetCollectionType.old Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) } - Storage.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) + Storage.shared.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) if wasUserRemoved { - Storage.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) + Storage.shared.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) // Notify the PN server - let _ = LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + let _ = PushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) } else { let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) @@ -272,7 +272,7 @@ final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegat } } - func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) { + public func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .senderKeyRequest(groupPublicKeyAsData) = message.kind else { return } let transaction = transaction as! YapDatabaseReadWriteTransaction let userPublicKey = getUserHexEncodedPublicKey() @@ -301,7 +301,7 @@ final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegat MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } - func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) { + public func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .senderKey(groupPublicKeyAsData, senderKey) = message.kind else { return } let groupPublicKey = groupPublicKeyAsData.toHexString() guard senderKey.publicKey.toHexString() == message.sender! else { diff --git a/SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift b/SignalUtilitiesKit/Messaging/MessageSender+Utilities.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/MessageSender+Utilities.swift rename to SignalUtilitiesKit/Messaging/MessageSender+Utilities.swift diff --git a/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift new file mode 100644 index 000000000..4a7706de3 --- /dev/null +++ b/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift @@ -0,0 +1,16 @@ + +public final class MessageSenderDelegate : SharedSenderKeysDelegate { + + public static let shared = MessageSenderDelegate() + + public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { + print("[Loki] Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") + let transaction = transaction as! YapDatabaseReadWriteTransaction + let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKeyRequest(groupPublicKey: Data(hex: groupPublicKey)) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } +} diff --git a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m index 52ad56c4b..12f51b019 100644 --- a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m +++ b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m @@ -80,7 +80,7 @@ NS_ASSUME_NONNULL_BEGIN } id unread = (id)object; if (unread.read) { - [LKLogger print:@"Found an already read message in the * unread * messages list."]; + NSLog(@"Found an already read message in the * unread * messages list."); return; } count += 1; diff --git a/Session/AppDelegate+OpenGroupAPI.swift b/SignalUtilitiesKit/Messaging/OpenGroupAPIDelegate.swift similarity index 53% rename from Session/AppDelegate+OpenGroupAPI.swift rename to SignalUtilitiesKit/Messaging/OpenGroupAPIDelegate.swift index 3681ccba0..24f6ce249 100644 --- a/Session/AppDelegate+OpenGroupAPI.swift +++ b/SignalUtilitiesKit/Messaging/OpenGroupAPIDelegate.swift @@ -1,24 +1,25 @@ -extension AppDelegate : OpenGroupAPIDelegate { - +public final class OpenGroupAPIDelegate : SessionMessagingKit.OpenGroupAPIDelegate { + + public static let shared = OpenGroupAPIDelegate() + public func updateProfileIfNeeded(for channel: UInt64, on server: String, from info: OpenGroupInfo) { - let storage = OWSPrimaryStorage.shared() - let publicChatID = "\(server).\(channel)" + let openGroupID = "\(server).\(channel)" Storage.write { transaction in // Update user count - storage.setUserCount(info.memberCount, forPublicChatWithID: publicChatID, in: transaction) - let groupThread = TSGroupThread.getOrCreateThread(withGroupId: publicChatID.data(using: .utf8)!, groupType: .openGroup, transaction: transaction) + Storage.shared.setUserCount(to: info.memberCount, forOpenGroupWithID: openGroupID, using: transaction) + let thread = TSGroupThread.getOrCreateThread(withGroupId: openGroupID.data(using: .utf8)!, groupType: .openGroup, transaction: transaction) // Update display name if needed - let groupModel = groupThread.groupModel - if groupModel.groupName != info.displayName { - let newGroupModel = TSGroupModel(title: info.displayName, memberIds: groupModel.groupMemberIds, image: groupModel.groupImage, groupId: groupModel.groupId, groupType: groupModel.groupType, adminIds: groupModel.groupAdminIds) - groupThread.groupModel = newGroupModel - groupThread.save(with: transaction) + let model = thread.groupModel + if model.groupName != info.displayName { + let newGroupModel = TSGroupModel(title: info.displayName, memberIds: model.groupMemberIds, image: model.groupImage, groupId: model.groupId, groupType: model.groupType, adminIds: model.groupAdminIds) + thread.groupModel = newGroupModel + thread.save(with: transaction) } // Download and update profile picture if needed - let oldProfilePictureURL = storage.getProfilePictureURL(forPublicChatWithID: publicChatID, in: transaction) - if oldProfilePictureURL != info.profilePictureURL || groupModel.groupImage == nil { - storage.setProfilePictureURL(info.profilePictureURL, forPublicChatWithID: publicChatID, in: transaction) + let oldProfilePictureURL = Storage.shared.getProfilePictureURL(forOpenGroupWithID: openGroupID) + if oldProfilePictureURL != info.profilePictureURL || model.groupImage == nil { + Storage.shared.setProfilePictureURL(to: info.profilePictureURL, forOpenGroupWithID: openGroupID, using: transaction) if let profilePictureURL = info.profilePictureURL { var sanitizedServerURL = server var sanitizedProfilePictureURL = profilePictureURL @@ -28,7 +29,7 @@ extension AppDelegate : OpenGroupAPIDelegate { FileServerAPI.downloadAttachment(from: url).map2 { data in let attachmentStream = TSAttachmentStream(contentType: OWSMimeTypeImageJpeg, byteCount: UInt32(data.count), sourceFilename: nil, caption: nil, albumMessageId: nil) try attachmentStream.write(data) - groupThread.updateAvatar(with: attachmentStream) + thread.updateAvatar(with: attachmentStream) } } } diff --git a/SignalUtilitiesKit/Move to Session/PublicChatPoller.swift b/SignalUtilitiesKit/Messaging/OpenGroupPoller.swift similarity index 85% rename from SignalUtilitiesKit/Move to Session/PublicChatPoller.swift rename to SignalUtilitiesKit/Messaging/OpenGroupPoller.swift index 95e3aac9e..bae1a244a 100644 --- a/SignalUtilitiesKit/Move to Session/PublicChatPoller.swift +++ b/SignalUtilitiesKit/Messaging/OpenGroupPoller.swift @@ -1,8 +1,8 @@ import PromiseKit -@objc(LKPublicChatPoller) -public final class PublicChatPoller : NSObject { - private let publicChat: OpenGroup +@objc(LKOpenGroupPoller) +public final class OpenGroupPoller : NSObject { + private let openGroup: OpenGroup private var pollForNewMessagesTimer: Timer? = nil private var pollForDeletedMessagesTimer: Timer? = nil private var pollForModeratorsTimer: Timer? = nil @@ -17,9 +17,9 @@ public final class PublicChatPoller : NSObject { private let pollForDisplayNamesInterval: TimeInterval = 60 // MARK: Lifecycle - @objc(initForPublicChat:) - public init(for publicChat: OpenGroup) { - self.publicChat = publicChat + @objc(initForOpenGroup:) + public init(for openGroup: OpenGroup) { + self.openGroup = openGroup super.init() } @@ -57,24 +57,23 @@ public final class PublicChatPoller : NSObject { public func pollForNewMessages() -> Promise { guard !self.isPolling else { return Promise.value(()) } self.isPolling = true - let publicChat = self.publicChat + let openGroup = self.openGroup let userPublicKey = getUserHexEncodedPublicKey() - return OpenGroupAPI.getMessages(for: publicChat.channel, on: publicChat.server).done(on: DispatchQueue.global(qos: .default)) { messages in + return OpenGroupAPI.getMessages(for: openGroup.channel, on: openGroup.server).done(on: DispatchQueue.global(qos: .default)) { messages in self.isPolling = false - let storage = OWSPrimaryStorage.shared() // Sorting the messages by timestamp before importing them fixes an issue where messages that quote older messages can't find those older messages messages.sorted { $0.serverTimestamp < $1.serverTimestamp }.forEach { message in let senderPublicKey = message.senderPublicKey - var wasSentByCurrentUser = (senderPublicKey == getUserHexEncodedPublicKey()) + let wasSentByCurrentUser = (senderPublicKey == getUserHexEncodedPublicKey()) func generateDisplayName(from rawDisplayName: String) -> String { let endIndex = senderPublicKey.endIndex let cutoffIndex = senderPublicKey.index(endIndex, offsetBy: -8) return "\(rawDisplayName) (...\(senderPublicKey[cutoffIndex.. Promise { let hexEncodedToken = token.toHexString() let parameters = [ "token" : hexEncodedToken ] @@ -30,7 +25,7 @@ public final class LokiPushNotificationManager : NSObject { let request = TSRequest(url: url, method: "POST", parameters: parameters) request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] let promise: Promise = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { - OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: pnServerPublicKey).map2 { response in + OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in guard let json = response["body"] as? JSON else { return print("[Loki] Couldn't unregister from push notifications.") } @@ -43,20 +38,17 @@ public final class LokiPushNotificationManager : NSObject { print("[Loki] Couldn't unregister from push notifications.") } // Unsubscribe from all closed groups - Storage.getUserClosedGroupPublicKeys().forEach { closedGroup in + Storage.shared.getUserClosedGroupPublicKeys().forEach { closedGroup in performOperation(.unsubscribe, for: closedGroup, publicKey: getUserHexEncodedPublicKey()) } return promise } - /// Unregisters the user from push notifications. Only the user's device token is needed for this. @objc(unregisterWithToken:isForcedUpdate:) public static func objc_unregister(with token: Data, isForcedUpdate: Bool) -> AnyPromise { return AnyPromise.from(unregister(with: token, isForcedUpdate: isForcedUpdate)) } - /// Registers the user for push notifications. Requires the user's device - /// token and their Session ID. static func register(with token: Data, publicKey: String, isForcedUpdate: Bool) -> Promise { let hexEncodedToken = token.toHexString() let userDefaults = UserDefaults.standard @@ -67,12 +59,12 @@ public final class LokiPushNotificationManager : NSObject { print("[Loki] Device token hasn't changed or expired; no need to re-upload.") return Promise { $0.fulfill(()) } } - let parameters = [ "token" : hexEncodedToken, "pubKey" : publicKey] + let parameters = [ "token" : hexEncodedToken, "pubKey" : publicKey ] let url = URL(string: "\(server)/register")! let request = TSRequest(url: url, method: "POST", parameters: parameters) request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] let promise: Promise = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { - OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: pnServerPublicKey).map2 { response in + OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in guard let json = response["body"] as? JSON else { return print("[Loki] Couldn't register device token.") } @@ -88,14 +80,12 @@ public final class LokiPushNotificationManager : NSObject { print("[Loki] Couldn't register device token.") } // Subscribe to all closed groups - Storage.getUserClosedGroupPublicKeys().forEach { closedGroup in + Storage.shared.getUserClosedGroupPublicKeys().forEach { closedGroup in performOperation(.subscribe, for: closedGroup, publicKey: publicKey) } return promise } - /// Registers the user for push notifications. Requires the user's device - /// token and their Session ID. @objc(registerWithToken:hexEncodedPublicKey:isForcedUpdate:) public static func objc_register(with token: Data, publicKey: String, isForcedUpdate: Bool) -> AnyPromise { return AnyPromise.from(register(with: token, publicKey: publicKey, isForcedUpdate: isForcedUpdate)) @@ -105,12 +95,12 @@ public final class LokiPushNotificationManager : NSObject { public static func performOperation(_ operation: ClosedGroupOperation, for closedGroupPublicKey: String, publicKey: String) -> Promise { let isUsingFullAPNs = UserDefaults.standard[.isUsingFullAPNs] guard isUsingFullAPNs else { return Promise { $0.fulfill(()) } } - let parameters = [ "closedGroupPublicKey" : closedGroupPublicKey, "pubKey" : publicKey] + let parameters = [ "closedGroupPublicKey" : closedGroupPublicKey, "pubKey" : publicKey ] let url = URL(string: "\(server)/\(operation.rawValue)")! let request = TSRequest(url: url, method: "POST", parameters: parameters) request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] let promise: Promise = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { - OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: pnServerPublicKey).map2 { response in + OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in guard let json = response["body"] as? JSON else { return print("[Loki] Couldn't subscribe/unsubscribe closed group: \(closedGroupPublicKey).") } diff --git a/SignalUtilitiesKit/Messaging/Quote+Conversion.swift b/SignalUtilitiesKit/Messaging/Quote+Conversion.swift new file mode 100644 index 000000000..0a9973042 --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Quote+Conversion.swift @@ -0,0 +1,13 @@ + +extension VisibleMessage.Quote { + + @objc(from:) + public static func from(_ model: OWSQuotedReplyModel?) -> VisibleMessage.Quote? { + guard let model = model else { return nil } + let result = VisibleMessage.Quote() + result.timestamp = model.timestamp + result.publicKey = model.authorId + result.text = model.body + return result + } +} diff --git a/SignalUtilitiesKit/Utilities/SNProtoEnvelope+Conversion.swift b/SignalUtilitiesKit/Messaging/SNProtoEnvelope+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/SNProtoEnvelope+Conversion.swift rename to SignalUtilitiesKit/Messaging/SNProtoEnvelope+Conversion.swift diff --git a/SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift b/SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/TSIncomingMessage+Conversion.swift rename to SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift diff --git a/SignalUtilitiesKit/Utilities/TSOutgoingMessage+Conversion.swift b/SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/TSOutgoingMessage+Conversion.swift rename to SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index efc3b9b8b..e86992ce3 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -52,6 +52,7 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import +#import #import #import #import diff --git a/SignalUtilitiesKit/Move to Session/LokiDatabaseUtilities.swift b/SignalUtilitiesKit/Move to Session/LokiDatabaseUtilities.swift deleted file mode 100644 index 42d51545f..000000000 --- a/SignalUtilitiesKit/Move to Session/LokiDatabaseUtilities.swift +++ /dev/null @@ -1,53 +0,0 @@ - -@objc(LKDatabaseUtilities) -public final class LokiDatabaseUtilities : NSObject { - - private override init() { } - - // MARK: - Quotes - @objc(getServerIDForQuoteWithID:quoteeHexEncodedPublicKey:threadID:transaction:) - public static func getServerID(quoteID: UInt64, quoteeHexEncodedPublicKey: String, threadID: String, transaction: YapDatabaseReadTransaction) -> UInt64 { - guard let message = TSInteraction.interactions(withTimestamp: quoteID, filter: { interaction in - let senderHexEncodedPublicKey: String - if let message = interaction as? TSIncomingMessage { - senderHexEncodedPublicKey = message.authorId - } else if let message = interaction as? TSOutgoingMessage { - senderHexEncodedPublicKey = getUserHexEncodedPublicKey() - } else { - return false - } - return (senderHexEncodedPublicKey == quoteeHexEncodedPublicKey) && (interaction.uniqueThreadId == threadID) - }, with: transaction).first as! TSMessage? else { return 0 } - return message.openGroupServerMessageID - } - - - - // MARK: - Open Groups - private static let publicChatCollection = "LokiPublicChatCollection" - - @objc(getAllPublicChats:) - public static func getAllPublicChats(in transaction: YapDatabaseReadTransaction) -> [String:OpenGroup] { - var result = [String:OpenGroup]() - transaction.enumerateKeysAndObjects(inCollection: publicChatCollection) { threadID, object, _ in - guard let publicChat = object as? OpenGroup else { return } - result[threadID] = publicChat - } - return result - } - - @objc(getPublicChatForThreadID:transaction:) - public static func getPublicChat(for threadID: String, in transaction: YapDatabaseReadTransaction) -> OpenGroup? { - return transaction.object(forKey: threadID, inCollection: publicChatCollection) as? OpenGroup - } - - @objc(setPublicChat:threadID:transaction:) - public static func setPublicChat(_ publicChat: OpenGroup, for threadID: String, in transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(publicChat, forKey: threadID, inCollection: publicChatCollection) - } - - @objc(removePublicChatForThreadID:transaction:) - public static func removePublicChat(for threadID: String, in transaction: YapDatabaseReadWriteTransaction) { - transaction.removeObject(forKey: threadID, inCollection: publicChatCollection) - } -} diff --git a/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.swift b/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.swift deleted file mode 100644 index c46360579..000000000 --- a/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.swift +++ /dev/null @@ -1,81 +0,0 @@ - -// TODO: Make this strongly typed like LKUserDefaults - -public extension OWSPrimaryStorage { - - // MARK: Snode Pool - public func setSnodePool(_ snodePool: Set, in transaction: YapDatabaseReadWriteTransaction) { - clearSnodePool(in: transaction) - snodePool.forEach { snode in - transaction.setObject(snode, forKey: snode.description, inCollection: Storage.snodePoolCollection) - } - } - - public func clearSnodePool(in transaction: YapDatabaseReadWriteTransaction) { - transaction.removeAllObjects(inCollection: Storage.snodePoolCollection) - } - - public func getSnodePool(in transaction: YapDatabaseReadTransaction) -> Set { - var result: Set = [] - transaction.enumerateKeysAndObjects(inCollection: Storage.snodePoolCollection) { _, object, _ in - guard let snode = object as? Snode else { return } - result.insert(snode) - } - return result - } - - public func dropSnodeFromSnodePool(_ snode: Snode, in transaction: YapDatabaseReadWriteTransaction) { - transaction.removeObject(forKey: snode.description, inCollection: Storage.snodePoolCollection) - } - - // MARK: Swarm - public func setSwarm(_ swarm: [Snode], for publicKey: String, in transaction: YapDatabaseReadWriteTransaction) { - print("[Loki] Caching swarm for: \(publicKey == getUserHexEncodedPublicKey() ? "self" : publicKey).") - clearSwarm(for: publicKey, in: transaction) - let collection = Storage.getSwarmCollection(for: publicKey) - swarm.forEach { snode in - transaction.setObject(snode, forKey: snode.description, inCollection: collection) - } - } - - public func clearSwarm(for publicKey: String, in transaction: YapDatabaseReadWriteTransaction) { - let collection = Storage.getSwarmCollection(for: publicKey) - transaction.removeAllObjects(inCollection: collection) - } - - public func getSwarm(for publicKey: String, in transaction: YapDatabaseReadTransaction) -> [Snode] { - var result: [Snode] = [] - let collection = Storage.getSwarmCollection(for: publicKey) - transaction.enumerateKeysAndObjects(inCollection: collection) { _, object, _ in - guard let snode = object as? Snode else { return } - result.append(snode) - } - return result - } - - // MARK: Session Requests - public func setSessionRequestTimestamp(for publicKey: String, to timestamp: Date, in transaction: YapDatabaseReadWriteTransaction) { - transaction.setDate(timestamp, forKey: publicKey, inCollection: Storage.sessionRequestTimestampCollection) - } - - public func getSessionRequestTimestamp(for publicKey: String, in transaction: YapDatabaseReadTransaction) -> Date? { - transaction.date(forKey: publicKey, inCollection: Storage.sessionRequestTimestampCollection) - } - - // MARK: Open Groups - public func getUserCount(for publicChat: OpenGroup, in transaction: YapDatabaseReadTransaction) -> Int? { - return transaction.object(forKey: publicChat.id, inCollection: Storage.openGroupUserCountCollection) as? Int - } - - public func setUserCount(_ userCount: Int, forPublicChatWithID publicChatID: String, in transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(userCount, forKey: publicChatID, inCollection: Storage.openGroupUserCountCollection) - } - - public func getProfilePictureURL(forPublicChatWithID publicChatID: String, in transaction: YapDatabaseReadTransaction) -> String? { - return transaction.object(forKey: publicChatID, inCollection: Storage.openGroupProfilePictureURLCollection) as? String - } - - public func setProfilePictureURL(_ profilePictureURL: String?, forPublicChatWithID publicChatID: String, in transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(profilePictureURL, forKey: publicChatID, inCollection: Storage.openGroupProfilePictureURLCollection) - } -} diff --git a/SignalUtilitiesKit/Move to Session/Storage+ClosedGroups.swift b/SignalUtilitiesKit/Move to Session/Storage+ClosedGroups.swift deleted file mode 100644 index 32095d6ca..000000000 --- a/SignalUtilitiesKit/Move to Session/Storage+ClosedGroups.swift +++ /dev/null @@ -1,79 +0,0 @@ - -public extension Storage { - - // MARK: Ratchets - internal static func getClosedGroupRatchetCollection(_ collection: ClosedGroupRatchetCollectionType, for groupPublicKey: String) -> String { - switch collection { - case .old: return "LokiOldClosedGroupRatchetCollection.\(groupPublicKey)" - case .current: return "LokiClosedGroupRatchetCollection.\(groupPublicKey)" - } - } - - internal static func getClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> ClosedGroupRatchet? { - let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) - var result: ClosedGroupRatchet? - read { transaction in - result = transaction.object(forKey: senderPublicKey, inCollection: collection) as? ClosedGroupRatchet - } - return result - } - - internal static func setClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, ratchet: ClosedGroupRatchet, in collection: ClosedGroupRatchetCollectionType = .current, using transaction: YapDatabaseReadWriteTransaction) { - let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) - transaction.setObject(ratchet, forKey: senderPublicKey, inCollection: collection) - } - - public static func getAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> [(senderPublicKey: String, ratchet: ClosedGroupRatchet)] { - let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) - var result: [(senderPublicKey: String, ratchet: ClosedGroupRatchet)] = [] - read { transaction in - transaction.enumerateRows(inCollection: collection) { key, object, _, _ in - guard let senderPublicKey = key as? String, let ratchet = object as? ClosedGroupRatchet else { return } - result.append((senderPublicKey: senderPublicKey, ratchet: ratchet)) - } - } - return result - } - - internal static func getAllClosedGroupSenderKeys(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> Set { - return Set(getAllClosedGroupRatchets(for: groupPublicKey, from: collection).map { senderPublicKey, ratchet in - ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: senderPublicKey)) - }) - } - - public static func removeAllClosedGroupRatchets(for groupPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current, using transaction: YapDatabaseReadWriteTransaction) { - let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey) - transaction.removeAllObjects(inCollection: collection) - } -} - -@objc public extension Storage { - - // MARK: Private Keys - internal static let closedGroupPrivateKeyCollection = "LokiClosedGroupPrivateKeyCollection" - - public static func getUserClosedGroupPublicKeys() -> Set { - var result: Set = [] - read { transaction in - result = Set(transaction.allKeys(inCollection: closedGroupPrivateKeyCollection)) - } - return result - } - - @objc(getPrivateKeyForClosedGroupWithPublicKey:) - internal static func getClosedGroupPrivateKey(for publicKey: String) -> String? { - var result: String? - read { transaction in - result = transaction.object(forKey: publicKey, inCollection: closedGroupPrivateKeyCollection) as? String - } - return result - } - - internal static func setClosedGroupPrivateKey(_ privateKey: String, for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(privateKey, forKey: publicKey, inCollection: closedGroupPrivateKeyCollection) - } - - internal static func removeClosedGroupPrivateKey(for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - transaction.removeObject(forKey: publicKey, inCollection: closedGroupPrivateKeyCollection) - } -} diff --git a/SignalUtilitiesKit/Move to Session/Storage+Collections.swift b/SignalUtilitiesKit/Move to Session/Storage+Collections.swift deleted file mode 100644 index d017cf89d..000000000 --- a/SignalUtilitiesKit/Move to Session/Storage+Collections.swift +++ /dev/null @@ -1,21 +0,0 @@ - -// TODO: Create an extension for each category, e.g. Storage+OpenGroups, Storage+SnodePool, etc. - -@objc public extension Storage { - - // TODO: Add remaining collections - - @objc func getDeviceLinkCollection(for masterPublicKey: String) -> String { - return "LokiDeviceLinkCollection-\(masterPublicKey)" - } - - @objc public static func getSwarmCollection(for publicKey: String) -> String { - return "LokiSwarmCollection-\(publicKey)" - } - - @objc public static let openGroupCollection = "LokiPublicChatCollection" - @objc public static let openGroupProfilePictureURLCollection = "LokiPublicChatAvatarURLCollection" - @objc public static let openGroupUserCountCollection = "LokiPublicChatUserCountCollection" - @objc public static let sessionRequestTimestampCollection = "LokiSessionRequestTimestampCollection" - @objc public static let snodePoolCollection = "LokiSnodePoolCollection" -} diff --git a/SignalUtilitiesKit/Move to Session/Storage+PublicChats.swift b/SignalUtilitiesKit/Move to Session/Storage+PublicChats.swift deleted file mode 100644 index e4398308b..000000000 --- a/SignalUtilitiesKit/Move to Session/Storage+PublicChats.swift +++ /dev/null @@ -1,38 +0,0 @@ - -public extension Storage { - - // MARK: Open Group Public Keys - internal static let openGroupPublicKeyCollection = "LokiOpenGroupPublicKeyCollection" - public static let lastMessageServerIDCollection = "LokiGroupChatLastMessageServerIDCollection" - public static let lastDeletionServerIDCollection = "LokiGroupChatLastDeletionServerIDCollection" - - internal static func getOpenGroupPublicKey(for server: String) -> String? { - var result: String? = nil - read { transaction in - result = transaction.object(forKey: server, inCollection: openGroupPublicKeyCollection) as? String - } - return result - } - - internal static func setOpenGroupPublicKey(for server: String, to publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(publicKey, forKey: server, inCollection: openGroupPublicKeyCollection) - } - - internal static func removeOpenGroupPublicKey(for server: String, using transaction: YapDatabaseReadWriteTransaction) { - transaction.removeObject(forKey: server, inCollection: openGroupPublicKeyCollection) - } - - private static func removeLastMessageServerID(for group: UInt64, on server: String, using transaction: YapDatabaseReadWriteTransaction) { - transaction.removeObject(forKey: "\(server).\(group)", inCollection: lastMessageServerIDCollection) - } - - private static func removeLastDeletionServerID(for group: UInt64, on server: String, using transaction: YapDatabaseReadWriteTransaction) { - transaction.removeObject(forKey: "\(server).\(group)", inCollection: lastDeletionServerIDCollection) - } - - internal static func clearAllData(for group: UInt64, on server: String, using transaction: YapDatabaseReadWriteTransaction) { - removeLastMessageServerID(for: group, on: server, using: transaction) - removeLastDeletionServerID(for: group, on: server, using: transaction) - Storage.removeOpenGroupPublicKey(for: server, using: transaction) - } -} diff --git a/SignalUtilitiesKit/Move to Session/Storage+SessionManagement.swift b/SignalUtilitiesKit/Move to Session/Storage+SessionManagement.swift deleted file mode 100644 index 7284a9601..000000000 --- a/SignalUtilitiesKit/Move to Session/Storage+SessionManagement.swift +++ /dev/null @@ -1,31 +0,0 @@ - -public extension Storage { - - // MARK: Session Request Timestamps - internal static let sessionRequestSentTimestampCollection = "LokiSessionRequestSentTimestampCollection" - internal static let sessionRequestProcessedTimestampCollection = "LokiSessionRequestProcessedTimestampCollection" - - internal static func getSessionRequestSentTimestamp(for publicKey: String) -> UInt64 { - var result: UInt64? - read { transaction in - result = transaction.object(forKey: publicKey, inCollection: sessionRequestSentTimestampCollection) as? UInt64 - } - return result ?? 0 - } - - internal static func setSessionRequestSentTimestamp(for publicKey: String, to timestamp: UInt64, using transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(timestamp, forKey: publicKey, inCollection: sessionRequestSentTimestampCollection) - } - - internal static func getSessionRequestProcessedTimestamp(for publicKey: String) -> UInt64 { - var result: UInt64? - read { transaction in - result = transaction.object(forKey: publicKey, inCollection: sessionRequestProcessedTimestampCollection) as? UInt64 - } - return result ?? 0 - } - - internal static func setSessionRequestProcessedTimestamp(for publicKey: String, to timestamp: UInt64, using transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(timestamp, forKey: publicKey, inCollection: sessionRequestProcessedTimestampCollection) - } -} diff --git a/SignalUtilitiesKit/Move to Session/Storage+SnodeAPI.swift b/SignalUtilitiesKit/Move to Session/Storage+SnodeAPI.swift deleted file mode 100644 index b7e6aa29e..000000000 --- a/SignalUtilitiesKit/Move to Session/Storage+SnodeAPI.swift +++ /dev/null @@ -1,58 +0,0 @@ - -internal extension Storage { - - // MARK: Last Message Hash - private static let lastMessageHashCollection = "LokiLastMessageHashCollection" - - internal static func getLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String) -> JSON? { - let key = "\(snode.address):\(snode.port).\(publicKey)" - var result: JSON? - read { transaction in - result = transaction.object(forKey: key, inCollection: lastMessageHashCollection) as? JSON - } - if let result = result { - guard result["hash"] as? String != nil else { return nil } - guard result["expirationDate"] as? NSNumber != nil else { return nil } - } - return result - } - - internal static func pruneLastMessageHashInfoIfExpired(for snode: Snode, associatedWith publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - guard let lastMessageHashInfo = getLastMessageHashInfo(for: snode, associatedWith: publicKey), - let hash = lastMessageHashInfo["hash"] as? String, let expirationDate = (lastMessageHashInfo["expirationDate"] as? NSNumber)?.uint64Value else { return } - let now = NSDate.ows_millisecondTimeStamp() - if now >= expirationDate { - removeLastMessageHashInfo(for: snode, associatedWith: publicKey, using: transaction) - } - } - - internal static func getLastMessageHash(for snode: Snode, associatedWith publicKey: String) -> String? { - return getLastMessageHashInfo(for: snode, associatedWith: publicKey)?["hash"] as? String - } - - internal static func removeLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - let key = "\(snode.address):\(snode.port).\(publicKey)" - transaction.removeObject(forKey: key, inCollection: lastMessageHashCollection) - } - - internal static func setLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String, to lastMessageHashInfo: JSON, using transaction: YapDatabaseReadWriteTransaction) { - let key = "\(snode.address):\(snode.port).\(publicKey)" - guard lastMessageHashInfo.count == 2 && lastMessageHashInfo["hash"] as? String != nil && lastMessageHashInfo["expirationDate"] as? NSNumber != nil else { return } - transaction.setObject(lastMessageHashInfo, forKey: key, inCollection: lastMessageHashCollection) - } - - // MARK: Received Messages - private static let receivedMessagesCollection = "LokiReceivedMessagesCollection" - - internal static func getReceivedMessages(for publicKey: String) -> Set? { - var result: Set? - read { transaction in - result = transaction.object(forKey: publicKey, inCollection: receivedMessagesCollection) as? Set - } - return result - } - - internal static func setReceivedMessages(to receivedMessages: Set, for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(receivedMessages, forKey: publicKey, inCollection: receivedMessagesCollection) - } -} diff --git a/SignalUtilitiesKit/OWSAttachmentDownloads.m b/SignalUtilitiesKit/OWSAttachmentDownloads.m index 740a622aa..a1d02969a 100644 --- a/SignalUtilitiesKit/OWSAttachmentDownloads.m +++ b/SignalUtilitiesKit/OWSAttachmentDownloads.m @@ -338,7 +338,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error); - (void)continueDownloadIfPossible { if (self.attachmentDownloadJobQueue.count > 0) { - [LKLogger print:@"[Loki] Continuing unfinished attachment download tasks."]; + NSLog(@"[Loki] Continuing unfinished attachment download tasks."); [self startDownloadIfPossible]; } } diff --git a/SignalUtilitiesKit/OWSUploadOperation.m b/SignalUtilitiesKit/OWSUploadOperation.m index 56267ccde..cdb16a6f1 100644 --- a/SignalUtilitiesKit/OWSUploadOperation.m +++ b/SignalUtilitiesKit/OWSUploadOperation.m @@ -80,10 +80,7 @@ static const CGFloat kAttachmentUploadProgressTheta = 0.001f; [self fireNotificationWithProgress:0]; - __block SNOpenGroup *publicChat; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChat = [LKDatabaseUtilities getPublicChatForThreadID:self.threadID transaction:transaction]; - }]; + SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:self.threadID]; NSString *server = (publicChat != nil) ? publicChat.server : SNFileServerAPI.server; [[SNFileServerAPI uploadAttachment:attachmentStream withID:self.attachmentId toServer:server] diff --git a/SignalUtilitiesKit/Threads/TSThread.m b/SignalUtilitiesKit/Threads/TSThread.m index ea0577995..a142b4805 100644 --- a/SignalUtilitiesKit/Threads/TSThread.m +++ b/SignalUtilitiesKit/Threads/TSThread.m @@ -290,7 +290,7 @@ BOOL IsNoteToSelfEnabled(void) } id unread = (id)object; if (unread.read) { - [LKLogger print:@"Found an already read message in the * unseen * messages list."]; + NSLog(@"Found an already read message in the * unseen * messages list."); return; } [messages addObject:unread]; @@ -312,7 +312,7 @@ BOOL IsNoteToSelfEnabled(void) } id unread = (id)object; if (unread.read) { - [LKLogger print:@"Found an already read message in the * unread * messages list."]; + NSLog(@"Found an already read message in the * unread * messages list."); return; } count += 1; diff --git a/SignalUtilitiesKit/Remove/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift similarity index 52% rename from SignalUtilitiesKit/Remove/ClosedGroupsProtocol.swift rename to SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift index 2bf1e0566..f4c19d0ea 100644 --- a/SignalUtilitiesKit/Remove/ClosedGroupsProtocol.swift +++ b/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift @@ -73,9 +73,9 @@ public final class ClosedGroupsProtocol : NSObject { promises.append(promise) } // Add the group to the user's set of public keys to poll for - Storage.setClosedGroupPrivateKey(groupKeyPair.privateKey.toHexString(), for: groupPublicKey, using: transaction) + Storage.shared.setClosedGroupPrivateKey(groupKeyPair.privateKey.toHexString(), for: groupPublicKey, using: transaction) // Notify the PN server - promises.append(LokiPushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: userPublicKey)) + promises.append(PushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: userPublicKey)) // Notify the user let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) infoMessage.save(with: transaction) @@ -98,7 +98,7 @@ public final class ClosedGroupsProtocol : NSObject { let membersAsData = members.map { Data(hex: $0) } let admins = group.groupAdminIds let adminsAsData = admins.map { Data(hex: $0) } - guard let groupPrivateKey = Storage.getClosedGroupPrivateKey(for: groupPublicKey) else { + guard let groupPrivateKey = Storage.shared.getClosedGroupPrivateKey(for: groupPublicKey) else { print("[Loki] Couldn't get private key for closed group.") return Promise(error: Error.noPrivateKey) } @@ -126,19 +126,19 @@ public final class ClosedGroupsProtocol : NSObject { when(resolved: promises).done2 { _ in seal.fulfill(()) }.catch2 { seal.reject($0) } let _ = promise.done { Storage.writeSync { transaction in - let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) + let allOldRatchets = Storage.shared.getAllClosedGroupRatchets(for: groupPublicKey) for (senderPublicKey, oldRatchet) in allOldRatchets { let collection = ClosedGroupRatchetCollectionType.old - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) + Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) } // Delete all ratchets (it's important that this happens * after * sending out the update) - Storage.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) + Storage.shared.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) // Remove the group from the user's set of public keys to poll for if the user is leaving. Otherwise generate a new ratchet and // send it out to all members (minus the removed ones) using established channels. if isUserLeaving { - Storage.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) + Storage.shared.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) // Notify the PN server - let _ = LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + let _ = PushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) } else { // Send closed group update messages to any new members using established channels for member in newMembers { @@ -181,7 +181,7 @@ public final class ClosedGroupsProtocol : NSObject { // Establish sessions if needed establishSessionsIfNeeded(with: [String](newMembers), using: transaction) // Send closed group update messages to the new members using established channels - var allSenderKeys = Storage.getAllClosedGroupSenderKeys(for: groupPublicKey) + var allSenderKeys = Storage.shared.getAllClosedGroupSenderKeys(for: groupPublicKey) allSenderKeys.formUnion(newSenderKeys) for member in newMembers { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) @@ -194,7 +194,7 @@ public final class ClosedGroupsProtocol : NSObject { } } else { seal.fulfill(()) - let allSenderKeys = Storage.getAllClosedGroupSenderKeys(for: groupPublicKey) + let allSenderKeys = Storage.shared.getAllClosedGroupSenderKeys(for: groupPublicKey) let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) let closedGroupUpdate = ClosedGroupUpdate() @@ -245,202 +245,6 @@ public final class ClosedGroupsProtocol : NSObject { MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } - // MARK: - Receiving - - @objc(handleSharedSenderKeysUpdateIfNeeded:from:transaction:) - public static func handleSharedSenderKeysUpdateIfNeeded(_ dataMessage: SNProtoDataMessage, from publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - // Note that `publicKey` is either the public key of the group or the public key of the - // sender, depending on how the message was sent - guard let closedGroupUpdate = dataMessage.closedGroupUpdate, isValid(closedGroupUpdate) else { return } - switch closedGroupUpdate.type { - case .new: handleNewGroupMessage(closedGroupUpdate, using: transaction) - case .info: handleInfoMessage(closedGroupUpdate, from: publicKey, using: transaction) - case .senderKeyRequest: handleSenderKeyRequestMessage(closedGroupUpdate, from: publicKey, using: transaction) - case .senderKey: handleSenderKeyMessage(closedGroupUpdate, from: publicKey, using: transaction) - } - } - - private static func isValid(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate) -> Bool { - guard !closedGroupUpdate.groupPublicKey.isEmpty else { return false } - switch closedGroupUpdate.type { - case .new: return !(closedGroupUpdate.name ?? "").isEmpty && !(closedGroupUpdate.groupPrivateKey ?? Data()).isEmpty && !closedGroupUpdate.members.isEmpty - && !closedGroupUpdate.admins.isEmpty // senderKeys may be empty - case .info: return !(closedGroupUpdate.name ?? "").isEmpty && !closedGroupUpdate.members.isEmpty && !closedGroupUpdate.admins.isEmpty // senderKeys may be empty - case .senderKeyRequest: return true - case .senderKey: return !closedGroupUpdate.senderKeys.isEmpty - } - } - - private static func handleNewGroupMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, using transaction: YapDatabaseReadWriteTransaction) { - // Unwrap the message - let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() - let name = closedGroupUpdate.name - let groupPrivateKey = closedGroupUpdate.groupPrivateKey! - let senderKeys = closedGroupUpdate.senderKeys - let members = closedGroupUpdate.members.map { $0.toHexString() } - let admins = closedGroupUpdate.admins.map { $0.toHexString() } - // Persist the ratchets - senderKeys.forEach { senderKey in - guard members.contains(senderKey.publicKey.toHexString()) else { return } - let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) - } - // Sort out any discrepancies between the provided sender keys and what's required - let missingSenderKeys = Set(members).subtracting(senderKeys.map { $0.publicKey.toHexString() }) - let userPublicKey = getUserHexEncodedPublicKey() - if missingSenderKeys.contains(userPublicKey) { - establishSessionsIfNeeded(with: [String](members), using: transaction) - let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) - let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) - for member in members { - guard member != userPublicKey else { continue } - let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - } - for publicKey in missingSenderKeys.subtracting([ userPublicKey ]) { - requestSenderKey(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) - } - // Create the group - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) - let thread: TSGroupThread - if let t = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) { - thread = t - thread.setGroupModel(group, with: transaction) - } else { - thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction) - thread.usesSharedSenderKeys = true - thread.save(with: transaction) - } - // Add the group to the user's set of public keys to poll for - Storage.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction) - // Notify the PN server - let _ = LokiPushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) - // Notify the user - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) - infoMessage.save(with: transaction) - // Establish sessions if needed - establishSessionsIfNeeded(with: members, using: transaction) - } - - /// Invoked upon receiving a group update. A group update is sent out when a group's name is changed, when new users are added, when users leave or are - /// kicked, or if the group admins are changed. - private static func handleInfoMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, - using transaction: YapDatabaseReadWriteTransaction) { - // Unwrap the message - let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() - let name = closedGroupUpdate.name - let senderKeys = closedGroupUpdate.senderKeys - let members = closedGroupUpdate.members.map { $0.toHexString() } - let admins = closedGroupUpdate.admins.map { $0.toHexString() } - // Get the group - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - return print("[Loki] Ignoring closed group info message for nonexistent group.") - } - let group = thread.groupModel - // Check that the sender is a member of the group (before the update) - guard Set(group.groupMemberIds).contains(senderPublicKey) else { - return print("[Loki] Ignoring closed group info message from non-member.") - } - // Store the ratchets for any new members (it's important that this happens before the code below) - senderKeys.forEach { senderKey in - let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) - } - // Delete all ratchets and either: - // • Send out the user's new ratchet using established channels if other members of the group left or were removed - // • Remove the group from the user's set of public keys to poll for if the current user was among the members that were removed - let oldMembers = group.groupMemberIds - let userPublicKey = getUserHexEncodedPublicKey() - let wasUserRemoved = !members.contains(userPublicKey) - if Set(members).intersection(oldMembers) != Set(oldMembers) { - let allOldRatchets = Storage.getAllClosedGroupRatchets(for: groupPublicKey) - for (senderPublicKey, oldRatchet) in allOldRatchets { - let collection = ClosedGroupRatchetCollectionType.old - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) - } - Storage.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) - if wasUserRemoved { - Storage.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) - // Notify the PN server - let _ = LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) - } else { - establishSessionsIfNeeded(with: members, using: transaction) - let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) - let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) - for member in members { - guard member != userPublicKey else { continue } - let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - } - } - // Update the group - let newGroupModel = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) - thread.setGroupModel(newGroupModel, with: transaction) - // Notify the user if needed - if Set(members) != Set(oldMembers) || Set(admins) != Set(group.groupAdminIds) || name != group.groupName { - let infoMessageType: TSInfoMessageType = wasUserRemoved ? .typeGroupQuit : .typeGroupUpdate - let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel) - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: infoMessageType, customMessage: updateInfo) - infoMessage.save(with: transaction) - } - } - - private static func handleSenderKeyRequestMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - // Prepare - let userPublicKey = getUserHexEncodedPublicKey() - let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - guard let groupThread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - return print("[Loki] Ignoring closed group sender key request for nonexistent group.") - } - let group = groupThread.groupModel - // Check that the requesting user is a member of the group - let members = Set(group.groupMemberIds) - guard members.contains(senderPublicKey) else { - return print("[Loki] Ignoring closed group sender key request from non-member.") - } - // Respond to the request - print("[Loki] Responding to sender key request from: \(senderPublicKey).") - SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) - let userRatchet = Storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey) - ?? SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) - let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) - let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - - /// Invoked upon receiving a sender key from another user. - private static func handleSenderKeyMessage(_ closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - // Prepare - let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() - guard let senderKey = closedGroupUpdate.senderKeys.first else { - return print("[Loki] Ignoring invalid closed group sender key.") - } - guard senderKey.publicKey.toHexString() == senderPublicKey else { - return print("[Loki] Ignoring invalid closed group sender key.") - } - // Store the sender key - print("[Loki] Received a sender key from: \(senderPublicKey).") - let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: ratchet, using: transaction) - } - // MARK: - General @objc(establishSessionsIfNeededWithClosedGroupMembers:transaction:) diff --git a/SignalUtilitiesKit/Remove/ContactCellView.h b/SignalUtilitiesKit/To Do/ContactCellView.h similarity index 100% rename from SignalUtilitiesKit/Remove/ContactCellView.h rename to SignalUtilitiesKit/To Do/ContactCellView.h diff --git a/SignalUtilitiesKit/Remove/ContactCellView.m b/SignalUtilitiesKit/To Do/ContactCellView.m similarity index 100% rename from SignalUtilitiesKit/Remove/ContactCellView.m rename to SignalUtilitiesKit/To Do/ContactCellView.m diff --git a/SignalUtilitiesKit/Remove/ContactTableViewCell.h b/SignalUtilitiesKit/To Do/ContactTableViewCell.h similarity index 100% rename from SignalUtilitiesKit/Remove/ContactTableViewCell.h rename to SignalUtilitiesKit/To Do/ContactTableViewCell.h diff --git a/SignalUtilitiesKit/Remove/ContactTableViewCell.m b/SignalUtilitiesKit/To Do/ContactTableViewCell.m similarity index 100% rename from SignalUtilitiesKit/Remove/ContactTableViewCell.m rename to SignalUtilitiesKit/To Do/ContactTableViewCell.m diff --git a/SignalUtilitiesKit/Remove/DisplayNameUtilities.swift b/SignalUtilitiesKit/To Do/DisplayNameUtilities.swift similarity index 100% rename from SignalUtilitiesKit/Remove/DisplayNameUtilities.swift rename to SignalUtilitiesKit/To Do/DisplayNameUtilities.swift diff --git a/SignalUtilitiesKit/Remove/DisplayNameUtilities2.swift b/SignalUtilitiesKit/To Do/DisplayNameUtilities2.swift similarity index 85% rename from SignalUtilitiesKit/Remove/DisplayNameUtilities2.swift rename to SignalUtilitiesKit/To Do/DisplayNameUtilities2.swift index 728fc44a8..2d9e8d212 100644 --- a/SignalUtilitiesKit/Remove/DisplayNameUtilities2.swift +++ b/SignalUtilitiesKit/To Do/DisplayNameUtilities2.swift @@ -9,11 +9,7 @@ public final class DisplayNameUtilities2 : NSObject { // Case 1: The public key belongs to the user themselves if publicKey == getUserHexEncodedPublicKey() { return SSKEnvironment.shared.profileManager.localProfileName() ?? publicKey } // Case 2: The given thread is an open group - var openGroup: OpenGroup? = nil - Storage.read { transaction in - openGroup = LokiDatabaseUtilities.getPublicChat(for: threadID, in: transaction) - } - if let openGroup = openGroup { + if let openGroup = Storage.shared.getOpenGroup(for: threadID) { var displayName: String? = nil Storage.read { transaction in displayName = transaction.object(forKey: publicKey, inCollection: openGroup.id) as! String? diff --git a/SignalUtilitiesKit/Remove/GroupUtilities.swift b/SignalUtilitiesKit/To Do/GroupUtilities.swift similarity index 100% rename from SignalUtilitiesKit/Remove/GroupUtilities.swift rename to SignalUtilitiesKit/To Do/GroupUtilities.swift diff --git a/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.h b/SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.h similarity index 100% rename from SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.h rename to SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.h diff --git a/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.m b/SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.m similarity index 92% rename from SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.m rename to SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.m index ab8d0bc1a..7d658c73a 100644 --- a/SignalUtilitiesKit/Move to Session/OWSPrimaryStorage+Loki.m +++ b/SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.m @@ -64,7 +64,7 @@ } - (PreKeyRecord *)generateAndStorePreKeyRecordForContact:(NSString *)hexEncodedPublicKey { - [LKLogger print:[NSString stringWithFormat:@"[Loki] Generating new pre key record for: %@.", hexEncodedPublicKey]]; + NSLog([NSString stringWithFormat:@"[Loki] Generating new pre key record for: %@.", hexEncodedPublicKey]); OWSAssertDebug(hexEncodedPublicKey.length > 0); NSArray *records = [self generatePreKeyRecords:1]; @@ -94,7 +94,7 @@ [signedPreKeyRecord markAsAcceptedByService]; [self storeSignedPreKey:signedPreKeyRecord.Id signedPreKeyRecord:signedPreKeyRecord]; [self setCurrentSignedPrekeyId:signedPreKeyRecord.Id]; - [LKLogger print:@"[Loki] Signed pre key refreshed successfully."]; + NSLog(@"[Loki] Signed pre key refreshed successfully."); } SignedPreKeyRecord *_Nullable signedPreKey = self.currentSignedPreKey; @@ -127,14 +127,14 @@ data:preKeyBundle.signedPreKeyPublic]) { @throw [NSException exceptionWithName:InvalidKeyException reason:@"KeyIsNotValidlySigned" userInfo:nil]; } - [LKLogger print:[NSString stringWithFormat:@"[Loki] Generated a new pre key bundle for: %@.", hexEncodedPublicKey]]; + NSLog([NSString stringWithFormat:@"[Loki] Generated a new pre key bundle for: %@.", hexEncodedPublicKey]); return preKeyBundle; } @catch (NSException *exception) { failureCount += 1; forceClean = YES; } } - [LKLogger print:[NSString stringWithFormat:@"[Loki] Failed to generate a valid pre key bundle for: %@.", hexEncodedPublicKey]]; + NSLog([NSString stringWithFormat:@"[Loki] Failed to generate a valid pre key bundle for: %@.", hexEncodedPublicKey]); return nil; } @@ -144,14 +144,14 @@ - (void)setPreKeyBundle:(PreKeyBundle *)bundle forContact:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction { [transaction setObject:bundle forKey:hexEncodedPublicKey inCollection:LKPreKeyBundleCollection]; - [LKLogger print:[NSString stringWithFormat:@"[Loki] Stored pre key bundle from: %@.", hexEncodedPublicKey]]; + NSLog([NSString stringWithFormat:@"[Loki] Stored pre key bundle from: %@.", hexEncodedPublicKey]); // FIXME: I don't think the line below is good for anything [transaction.connection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{ }]; } - (void)removePreKeyBundleForContact:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction { [transaction removeObjectForKey:hexEncodedPublicKey inCollection:LKPreKeyBundleCollection]; - [LKLogger print:[NSString stringWithFormat:@"[Loki] Removed pre key bundle from: %@.", hexEncodedPublicKey]]; + NSLog([NSString stringWithFormat:@"[Loki] Removed pre key bundle from: %@.", hexEncodedPublicKey]); } # pragma mark - Open Groups diff --git a/SignalUtilitiesKit/Remove/OWSProfileManager.h b/SignalUtilitiesKit/To Do/OWSProfileManager.h similarity index 100% rename from SignalUtilitiesKit/Remove/OWSProfileManager.h rename to SignalUtilitiesKit/To Do/OWSProfileManager.h diff --git a/SignalUtilitiesKit/Remove/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m similarity index 99% rename from SignalUtilitiesKit/Remove/OWSProfileManager.m rename to SignalUtilitiesKit/To Do/OWSProfileManager.m index 67ef370bd..2d9ac74ef 100644 --- a/SignalUtilitiesKit/Remove/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -408,10 +408,7 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); OWSAssertDebug(successBlock); OWSAssertDebug(failureBlock); - __block NSDictionary *publicChats; - [SSKEnvironment.shared.primaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - publicChats = [LKDatabaseUtilities getAllPublicChats:transaction]; - }]; + NSDictionary *publicChats = [LKStorage.shared getAllUserOpenGroups]; NSSet *servers = [NSSet setWithArray:[publicChats.allValues map:^NSString *(SNOpenGroup *publicChat) { return publicChat.server; }]]; diff --git a/SignalUtilitiesKit/Remove/OWSUserProfile.h b/SignalUtilitiesKit/To Do/OWSUserProfile.h similarity index 100% rename from SignalUtilitiesKit/Remove/OWSUserProfile.h rename to SignalUtilitiesKit/To Do/OWSUserProfile.h diff --git a/SignalUtilitiesKit/Remove/OWSUserProfile.m b/SignalUtilitiesKit/To Do/OWSUserProfile.m similarity index 100% rename from SignalUtilitiesKit/Remove/OWSUserProfile.m rename to SignalUtilitiesKit/To Do/OWSUserProfile.m diff --git a/SignalUtilitiesKit/Remove/ProfileManagerProtocol.h b/SignalUtilitiesKit/To Do/ProfileManagerProtocol.h similarity index 100% rename from SignalUtilitiesKit/Remove/ProfileManagerProtocol.h rename to SignalUtilitiesKit/To Do/ProfileManagerProtocol.h diff --git a/SignalUtilitiesKit/Move to Session/PublicChatManager.swift b/SignalUtilitiesKit/To Do/PublicChatManager.swift similarity index 76% rename from SignalUtilitiesKit/Move to Session/PublicChatManager.swift rename to SignalUtilitiesKit/To Do/PublicChatManager.swift index d6ed42553..624ea7509 100644 --- a/SignalUtilitiesKit/Move to Session/PublicChatManager.swift +++ b/SignalUtilitiesKit/To Do/PublicChatManager.swift @@ -6,7 +6,7 @@ import PromiseKit public final class PublicChatManager : NSObject { private let storage = OWSPrimaryStorage.shared() @objc public var chats: [String:OpenGroup] = [:] - private var pollers: [String:PublicChatPoller] = [:] + private var pollers: [String:OpenGroupPoller] = [:] private var isPolling = false private var userHexEncodedPublicKey: String? { @@ -35,7 +35,7 @@ public final class PublicChatManager : NSObject { if let poller = pollers[threadID] { poller.startIfNeeded() } else { - let poller = PublicChatPoller(for: publicChat) + let poller = OpenGroupPoller(for: publicChat) poller.startIfNeeded() pollers[threadID] = poller } @@ -73,7 +73,7 @@ public final class PublicChatManager : NSObject { let thread = TSGroupThread.getOrCreateThread(with: model, transaction: transaction) // Save the group chat - LokiDatabaseUtilities.setPublicChat(chat, for: thread.uniqueId!, in: transaction) + Storage.shared.setOpenGroup(chat, for: thread.uniqueId!, using: transaction) } // Update chats and pollers @@ -88,20 +88,18 @@ public final class PublicChatManager : NSObject { } @objc func refreshChatsAndPollers() { - storage.dbReadConnection.read { transaction in - let newChats = LokiDatabaseUtilities.getAllPublicChats(in: transaction) - - // Remove any chats that don't exist in the database - let removedChatThreadIds = self.chats.keys.filter { !newChats.keys.contains($0) } - removedChatThreadIds.forEach { threadID in - let poller = self.pollers.removeValue(forKey: threadID) - poller?.stop() - } - - // Only append to chats if we have a thread for the chat - self.chats = newChats.filter { (threadID, group) in - return TSGroupThread.fetch(uniqueId: threadID, transaction: transaction) != nil - } + let newChats = Storage.shared.getAllUserOpenGroups() + + // Remove any chats that don't exist in the database + let removedChatThreadIds = self.chats.keys.filter { !newChats.keys.contains($0) } + removedChatThreadIds.forEach { threadID in + let poller = self.pollers.removeValue(forKey: threadID) + poller?.stop() + } + + // Only append to chats if we have a thread for the chat + self.chats = newChats.filter { (threadID, group) in + return TSGroupThread.fetch(uniqueId: threadID) != nil } if (isPolling) { startPollersIfNeeded() } @@ -113,13 +111,13 @@ public final class PublicChatManager : NSObject { // Reset the last message cache if let chat = self.chats[threadId] { Storage.write { transaction in - Storage.clearAllData(for: chat.channel, on: chat.server, using: transaction) + Storage.shared.clearAllData(for: chat.channel, on: chat.server, using: transaction) } } // Remove the chat from the db - Storage.writeSync { transaction in - LokiDatabaseUtilities.removePublicChat(for: threadId, in: transaction) + Storage.write { transaction in + Storage.shared.removeOpenGroup(for: threadId, using: transaction) } refreshChatsAndPollers() diff --git a/SignalUtilitiesKit/Remove/SessionManagementProtocol.swift b/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift similarity index 96% rename from SignalUtilitiesKit/Remove/SessionManagementProtocol.swift rename to SignalUtilitiesKit/To Do/SessionManagementProtocol.swift index 315c3f511..34ed9b386 100644 --- a/SignalUtilitiesKit/Remove/SessionManagementProtocol.swift +++ b/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift @@ -96,10 +96,10 @@ public final class SessionManagementProtocol : NSObject { let hasSession = storage.containsSession(publicKey, deviceId: Int32(1), protocolContext: transaction) guard !hasSession else { return } // Check that we didn't already send a session request - let hasSentSessionRequest = (Storage.getSessionRequestSentTimestamp(for: publicKey) > 0) + let hasSentSessionRequest = (Storage.shared.getSessionRequestSentTimestamp(for: publicKey) > 0) let hasSentSessionRequestExpired = SessionManagementProtocol.hasSentSessionRequestExpired(for: publicKey) if hasSentSessionRequestExpired { - Storage.setSessionRequestSentTimestamp(for: publicKey, to: 0, using: transaction) + Storage.shared.setSessionRequestSentTimestamp(for: publicKey, to: 0, using: transaction) } guard !hasSentSessionRequest || hasSentSessionRequestExpired else { return } // Create the thread if needed @@ -107,7 +107,7 @@ public final class SessionManagementProtocol : NSObject { thread.save(with: transaction) // Send the session request print("[Loki] Sending session request to: \(publicKey).") - Storage.setSessionRequestSentTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) + Storage.shared.setSessionRequestSentTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) let sessionRequest = SessionRequest() sessionRequest.preKeyBundle = storage.generatePreKeyBundle(forContact: publicKey) MessageSender.send(sessionRequest, in: thread, using: transaction) @@ -185,8 +185,8 @@ public final class SessionManagementProtocol : NSObject { } private static func shouldProcessSessionRequest(from publicKey: String, at timestamp: UInt64) -> Bool { - let sentTimestamp = Storage.getSessionRequestSentTimestamp(for: publicKey) - let processedTimestamp = Storage.getSessionRequestProcessedTimestamp(for: publicKey) + let sentTimestamp = Storage.shared.getSessionRequestSentTimestamp(for: publicKey) + let processedTimestamp = Storage.shared.getSessionRequestProcessedTimestamp(for: publicKey) let restorationTimestamp = UInt64(storage.getRestorationTime() * 1000) return timestamp > sentTimestamp && timestamp > processedTimestamp && timestamp > restorationTimestamp } diff --git a/SignalUtilitiesKit/Remove/SessionMetaProtocol.swift b/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift similarity index 94% rename from SignalUtilitiesKit/Remove/SessionMetaProtocol.swift rename to SignalUtilitiesKit/To Do/SessionMetaProtocol.swift index a89cc17f7..34db10ab7 100644 --- a/SignalUtilitiesKit/Remove/SessionMetaProtocol.swift +++ b/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift @@ -27,12 +27,10 @@ public final class SessionMetaProtocol : NSObject { guard let thread = thread as? TSGroupThread else { preconditionFailure("Can't get destinations for group message in non-group thread.") } var result: Set = [] if thread.isOpenGroup { - storage.dbReadConnection.read { transaction in - if let openGroup = LokiDatabaseUtilities.getPublicChat(for: thread.uniqueId!, in: transaction) { - result = [ openGroup.server ] // Aim the message at the open group server - } else { - // Should never occur - } + if let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!) { + result = [ openGroup.server ] // Aim the message at the open group server + } else { + // Should never occur } } else { if let groupThread = thread as? TSGroupThread, groupThread.usesSharedSenderKeys { diff --git a/SignalUtilitiesKit/Utilities/Debugging.swift b/SignalUtilitiesKit/Utilities/Debugging.swift deleted file mode 100644 index 87a709f44..000000000 --- a/SignalUtilitiesKit/Utilities/Debugging.swift +++ /dev/null @@ -1,12 +0,0 @@ - -// For some reason NSLog doesn't seem to work from SignalServiceKit. This is a workaround to still allow debugging from Obj-C. - -@objc(LKLogger) -public final class ObjC_Logger : NSObject { - - private override init() { } - - @objc public static func print(_ message: String) { - Swift.print(message) - } -} diff --git a/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift b/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift index 86a579f16..aa563044e 100644 --- a/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift +++ b/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift @@ -1,11 +1,11 @@ public extension ECKeyPair { - @objc public var hexEncodedPrivateKey: String { + @objc var hexEncodedPrivateKey: String { return privateKey.map { String(format: "%02hhx", $0) }.joined() } - @objc public var hexEncodedPublicKey: String { + @objc var hexEncodedPublicKey: String { // Prefixing with "05" is necessary for what seems to be a sort of Signal public key versioning system return "05" + publicKey.map { String(format: "%02hhx", $0) }.joined() } diff --git a/SignalUtilitiesKit/Move to Session/LKUserDefaults.swift b/SignalUtilitiesKit/Utilities/LKUserDefaults.swift similarity index 100% rename from SignalUtilitiesKit/Move to Session/LKUserDefaults.swift rename to SignalUtilitiesKit/Utilities/LKUserDefaults.swift From a48fc40aa63bf1713a0888b618909fdc1aa651c5 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Nov 2020 15:35:43 +1100 Subject: [PATCH 011/177] WIP --- SessionUtilitiesKit/String+Trimming.swift | 9 +++++++++ Signal.xcodeproj/project.pbxproj | 4 ---- SignalUtilitiesKit/Utilities/String+Trimming.swift | 9 --------- 3 files changed, 9 insertions(+), 13 deletions(-) delete mode 100644 SignalUtilitiesKit/Utilities/String+Trimming.swift diff --git a/SessionUtilitiesKit/String+Trimming.swift b/SessionUtilitiesKit/String+Trimming.swift index d95229951..997ab8e04 100644 --- a/SessionUtilitiesKit/String+Trimming.swift +++ b/SessionUtilitiesKit/String+Trimming.swift @@ -7,3 +7,12 @@ public extension String { return result } } + +@objc public extension NSString { + + @objc func removing05PrefixIfNeeded() -> NSString { + var result = self as String + if result.count == 66 && result.hasPrefix("05") { result.removeFirst(2) } + return result as NSString + } +} diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d2e8759e1..e653c010b 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -366,7 +366,6 @@ C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; - C33FDC69255A582000E217F9 /* String+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAF255A580000E217F9 /* String+Trimming.swift */; }; C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; }; C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB3255A580000E217F9 /* TSContactThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */; }; @@ -1458,7 +1457,6 @@ C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+SignedPreKeyStore.h"; sourceTree = ""; }; C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = ""; }; C33FDAAA255A580000E217F9 /* NSObject+Casting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Casting.m"; sourceTree = ""; }; - C33FDAAF255A580000E217F9 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = ""; }; C33FDAB1255A580000E217F9 /* OWSStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSStorage.m; sourceTree = ""; }; C33FDAB3255A580000E217F9 /* TSContactThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSContactThread.h; sourceTree = ""; }; C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFailedMessagesJob.m; sourceTree = ""; }; @@ -3557,7 +3555,6 @@ isa = PBXGroup; children = ( C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, - C33FDAAF255A580000E217F9 /* String+Trimming.swift */, C33FDB80255A581100E217F9 /* Notification+Loki.swift */, C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, @@ -4929,7 +4926,6 @@ C33FDD2F255A582000E217F9 /* AppReadiness.m in Sources */, C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */, C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */, - C33FDC69255A582000E217F9 /* String+Trimming.swift in Sources */, C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */, B8D8F1F0256621180092EF10 /* MessageSenderDelegate.swift in Sources */, C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */, diff --git a/SignalUtilitiesKit/Utilities/String+Trimming.swift b/SignalUtilitiesKit/Utilities/String+Trimming.swift deleted file mode 100644 index 221d66b8c..000000000 --- a/SignalUtilitiesKit/Utilities/String+Trimming.swift +++ /dev/null @@ -1,9 +0,0 @@ - -@objc extension NSString { - - @objc public func removing05PrefixIfNeeded() -> NSString { - var result = self as String - if result.count == 66 && result.hasPrefix("05") { result.removeFirst(2) } - return result as NSString - } -} From 2e85d5fb41987b713e1043168a0308454e593a59 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Nov 2020 16:21:00 +1100 Subject: [PATCH 012/177] Fix message sending status bar --- .../ConversationViewController.m | 59 ++++++------------- SessionMessagingKit/Messages/Message.swift | 5 ++ .../Sending & Receiving/MessageSender.swift | 4 +- .../TSOutgoingMessage+Conversion.swift | 6 +- 4 files changed, 32 insertions(+), 42 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 44e502a37..2536714be 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -370,12 +370,12 @@ typedef enum : NSUInteger { name:NSNotification.groupThreadUpdated object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleCalculatingPoWNotification:) - name:NSNotification.calculatingMessagePoW + selector:@selector(handleEncryptingMessageNotification:) + name:NSNotification.encryptingMessage object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleRoutingNotification:) - name:NSNotification.encryptingMessage + selector:@selector(handleCalculatingMessagePoWNotification:) + name:NSNotification.calculatingMessagePoW object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessageSendingNotification:) @@ -386,7 +386,7 @@ typedef enum : NSUInteger { name:NSNotification.messageSent object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleMessageFailedNotification:) + selector:@selector(handleMessageSendingFailedNotification:) name:NSNotification.messageSendingFailed object:nil]; } @@ -3816,47 +3816,30 @@ typedef enum : NSUInteger { text = [text ows_stripped]; - if (text.length < 1) { - return; - } - - // Limit outgoing text messages to 16kb. - // - // We convert large text messages to attachments - // which are presented as normal text messages. + if (text.length < 1) { return; } SNVisibleMessage *message = [SNVisibleMessage new]; + [message setSentTimestamp:[NSDate millisecondTimestamp]]; message.text = text; message.quote = [SNQuote from:self.inputToolbar.quotedReply]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [SNMessageSender send:message inThread:self.thread usingTransaction:transaction]; }]; - + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread]; - [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; + [tsMessage save]; + [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; + [self messageWasSent:tsMessage]; - // Clearing the text message is a key part of the send animation. - // It takes 10-15ms, but we do it inline rather than dispatch async - // since the send can't feel "complete" without it. - [BenchManager benchWithTitle:@"clearTextMessageAnimated" - block:^{ - [self.inputToolbar clearTextMessageAnimated:YES]; - [self resetMentions]; - }]; - [BenchManager completeEventWithEventId:@"fromSendUntil_clearTextMessageAnimated"]; + [self.inputToolbar clearTextMessageAnimated:YES]; + + [self resetMentions]; dispatch_async(dispatch_get_main_queue(), ^{ - // After sending we want to return from the numeric keyboard to the - // alphabetical one. Because this is so slow (40-50ms), we prefer it - // happens async, after any more essential send UI work is done. - [BenchManager benchWithTitle:@"toggleDefaultKeyboard" - block:^{ - [self.inputToolbar toggleDefaultKeyboard]; - }]; - [BenchManager completeEventWithEventId:@"fromSendUntil_toggleDefaultKeyboard"]; + [self.inputToolbar toggleDefaultKeyboard]; }); [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { @@ -4554,13 +4537,13 @@ typedef enum : NSUInteger { [self updateScrollDownButtonLayout]; } -- (void)handleCalculatingPoWNotification:(NSNotification *)notification +- (void)handleEncryptingMessageNotification:(NSNotification *)notification { NSNumber *timestamp = (NSNumber *)notification.object; [self setProgressIfNeededTo:0.25f forMessageWithTimestamp:timestamp]; } -- (void)handleRoutingNotification:(NSNotification *)notification +- (void)handleCalculatingMessagePoWNotification:(NSNotification *)notification { NSNumber *timestamp = (NSNumber *)notification.object; [self setProgressIfNeededTo:0.50f forMessageWithTimestamp:timestamp]; @@ -4582,7 +4565,7 @@ typedef enum : NSUInteger { }); } -- (void)handleMessageFailedNotification:(NSNotification *)notification +- (void)handleMessageSendingFailedNotification:(NSNotification *)notification { NSNumber *timestamp = (NSNumber *)notification.object; [self hideProgressIndicatorViewForMessageWithTimestamp:timestamp]; @@ -4590,11 +4573,7 @@ typedef enum : NSUInteger { - (void)setProgressIfNeededTo:(float)progress forMessageWithTimestamp:(NSNumber *)timestamp { - if ([self.handledMessageTimestamps contains:^BOOL(NSNumber *t) { - return [t isEqual:timestamp]; - }]) { - return; - } + if ([self.handledMessageTimestamps containsObject:timestamp]) { return; } dispatch_async(dispatch_get_main_queue(), ^{ __block TSInteraction *targetInteraction; [LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) { diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index 59a8acd17..abfd2887a 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -47,4 +47,9 @@ public class Message : NSObject, NSCoding { // NSObject/NSCoding conformance is public func toProto() -> SNProtoContent? { preconditionFailure("toProto() is abstract and must be overridden.") } + + // MARK: General + @objc public func setSentTimestamp(_ sentTimestamp: UInt64) { + self.sentTimestamp = sentTimestamp + } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index d3263c174..dcb9858dc 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -31,7 +31,9 @@ public final class MessageSender : NSObject { } internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { - message.sentTimestamp = NSDate.millisecondTimestamp() + if message.sentTimestamp == nil { // Visible messages will already have the sent timestamp set + message.sentTimestamp = NSDate.millisecondTimestamp() + } message.sender = Configuration.shared.storage.getUserPublicKey() switch destination { case .contact(let publicKey): message.recipient = publicKey diff --git a/SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift b/SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift index eba40aaf3..3a9d87941 100644 --- a/SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift +++ b/SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift @@ -8,10 +8,14 @@ expiration = disappearingMessagesConfiguration.isEnabled ? disappearingMessagesConfiguration.durationSeconds : 0 } return TSOutgoingMessage( + outgoingMessageWithTimestamp: visibleMessage.sentTimestamp!, in: thread, messageBody: visibleMessage.text, - attachmentId: nil, + attachmentIds: NSMutableArray(), expiresInSeconds: expiration, + expireStartedAt: 0, + isVoiceMessage: false, + groupMetaMessage: .unspecified, quotedMessage: nil, linkPreview: nil ) From 9242f971fd626cf9a0114543c3d5d2dd81aa2e12 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Nov 2020 16:28:30 +1100 Subject: [PATCH 013/177] Fix timestamp handling --- SessionMessagingKit/Sending & Receiving/MessageReceiver.swift | 1 + SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 74cf8dae9..2f9b3b4cc 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -85,6 +85,7 @@ internal enum MessageReceiver { if let message = message { message.sender = sender message.recipient = Configuration.shared.storage.getUserPublicKey() + message.sentTimestamp = envelope.timestamp message.receivedTimestamp = NSDate.millisecondTimestamp() message.groupPublicKey = groupPublicKey message.openGroupServerMessageID = messageServerID diff --git a/SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift b/SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift index bd21269d6..b337d210b 100644 --- a/SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift +++ b/SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift @@ -4,7 +4,7 @@ public extension TSIncomingMessage { static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage { let sender = visibleMessage.sender! let result = TSIncomingMessage( - timestamp: visibleMessage.receivedTimestamp!, + timestamp: visibleMessage.sentTimestamp!, in: thread, authorId: sender, sourceDeviceId: 1, From 4a31a84daa783a864225aecf4ec1339b2b5724c9 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Nov 2020 16:51:08 +1100 Subject: [PATCH 014/177] Fix messages showing up as failed --- Session/Configuration.swift | 1 + SessionMessagingKit/Configuration.swift | 3 +++ ...ndler.swift => MessageReceiverDelegate.swift} | 0 .../Sending & Receiving/MessageSender.swift | 6 +++++- .../MessageSenderDelegate.swift | 5 +++++ Signal.xcodeproj/project.pbxproj | 12 ++++++++---- .../Messaging/MessageSenderDelegate.swift | 7 ++++++- SignalUtilitiesKit/Messaging/TSIncomingMessage.m | 1 - SignalUtilitiesKit/Messaging/TSOutgoingMessage.h | 3 ++- SignalUtilitiesKit/Messaging/TSOutgoingMessage.m | 16 +++++++++++++++- 10 files changed, 45 insertions(+), 9 deletions(-) rename SessionMessagingKit/Sending & Receiving/{MessageHandler.swift => MessageReceiverDelegate.swift} (100%) create mode 100644 SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift diff --git a/Session/Configuration.swift b/Session/Configuration.swift index 020a53c49..0a03a6e0b 100644 --- a/Session/Configuration.swift +++ b/Session/Configuration.swift @@ -8,6 +8,7 @@ final class Configuration : NSObject { @objc static func performMainSetup() { SNMessagingKit.configure( storage: Storage.shared, + messageSenderDelegate: MessageSenderDelegate.shared, messageReceiverDelegate: MessageReceiverDelegate.shared, signalStorage: OWSPrimaryStorage.shared(), identityKeyStore: OWSIdentityManager.shared(), diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index 0994ad56c..f514bc6aa 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -2,6 +2,7 @@ import SessionProtocolKit public struct Configuration { public let storage: SessionMessagingKitStorageProtocol + public let messageSenderDelegate: MessageSenderDelegate public let messageReceiverDelegate: MessageReceiverDelegate public let signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore public let identityKeyStore: IdentityKeyStore @@ -18,6 +19,7 @@ public enum SNMessagingKit { // Just to make the external API nice public static func configure( storage: SessionMessagingKitStorageProtocol, + messageSenderDelegate: MessageSenderDelegate, messageReceiverDelegate: MessageReceiverDelegate, signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore, identityKeyStore: IdentityKeyStore, @@ -29,6 +31,7 @@ public enum SNMessagingKit { // Just to make the external API nice ) { Configuration.shared = Configuration( storage: storage, + messageSenderDelegate: messageSenderDelegate, messageReceiverDelegate: messageReceiverDelegate, signalStorage: signalStorage, identityKeyStore: identityKeyStore, diff --git a/SessionMessagingKit/Sending & Receiving/MessageHandler.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift similarity index 100% rename from SessionMessagingKit/Sending & Receiving/MessageHandler.swift rename to SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index dcb9858dc..870193b0e 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -130,11 +130,15 @@ public final class MessageSender : NSObject { seal.reject(error) } let _ = promise.done(on: DispatchQueue.main) { + let storage = Configuration.shared.storage + storage.withAsync({ transaction in + Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) + }, completion: { }) if case .contact(_) = destination { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) } let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) - Configuration.shared.storage.with { transaction in + storage.with { transaction in JobQueue.shared.add(notifyPNServerJob, using: transaction) } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift new file mode 100644 index 000000000..0b6b91ea0 --- /dev/null +++ b/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift @@ -0,0 +1,5 @@ + +public protocol MessageSenderDelegate { + + func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) +} diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index e653c010b..620b29787 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -244,6 +244,7 @@ B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; }; B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */; }; + B867665825663BBA00B197C5 /* MessageSenderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B867665725663BBA00B197C5 /* MessageSenderDelegate.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; @@ -907,7 +908,7 @@ C3CA3B1D255CF3C800F4C6D4 /* MessageSender+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */; }; C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; - C3D697382564DCE6004AF766 /* MessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697372564DCE6004AF766 /* MessageHandler.swift */; }; + C3D697382564DCE6004AF766 /* MessageReceiverDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; @@ -1348,6 +1349,7 @@ B85357C223A1BD1200AAF6CD /* SeedVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedVC.swift; sourceTree = ""; }; B8544E3023D16CA500299F14 /* DeviceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceUtilities.swift; sourceTree = ""; }; B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceUtilities.swift; sourceTree = ""; }; + B867665725663BBA00B197C5 /* MessageSenderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSenderDelegate.swift; sourceTree = ""; }; B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = ""; }; B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; @@ -2004,7 +2006,7 @@ C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Utilities.swift"; sourceTree = ""; }; C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NullMessage.swift; sourceTree = ""; }; C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = ""; }; - C3D697372564DCE6004AF766 /* MessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageHandler.swift; sourceTree = ""; }; + C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverDelegate.swift; sourceTree = ""; }; C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverDelegate.swift; sourceTree = ""; }; C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = ""; }; C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; @@ -2657,9 +2659,10 @@ C3471FA32555439E00297E91 /* Notification+MessageSender.swift */, C300A5F12554B09800555489 /* MessageSender.swift */, C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */, + B867665725663BBA00B197C5 /* MessageSenderDelegate.swift */, C300A5FB2554B0A000555489 /* MessageReceiver.swift */, C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */, - C3D697372564DCE6004AF766 /* MessageHandler.swift */, + C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */, ); path = "Sending & Receiving"; sourceTree = ""; @@ -5112,6 +5115,7 @@ C3C2A7682553A3D900C340D1 /* VisibleMessage+Contact.swift in Sources */, C3A721392558BDFA0043A11F /* OpenGroupAPI.swift in Sources */, C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */, + B867665825663BBA00B197C5 /* MessageSenderDelegate.swift in Sources */, C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */, C3A721382558BDFA0043A11F /* OpenGroupMessage.swift in Sources */, C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */, @@ -5126,7 +5130,7 @@ C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */, C352A30925574D8500338F3E /* Message+Destination.swift in Sources */, C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */, - C3D697382564DCE6004AF766 /* MessageHandler.swift in Sources */, + C3D697382564DCE6004AF766 /* MessageReceiverDelegate.swift in Sources */, C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */, C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */, C3C2A74425539EB700C340D1 /* Message.swift in Sources */, diff --git a/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift index 4a7706de3..4ddc84b2d 100644 --- a/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift @@ -1,8 +1,13 @@ -public final class MessageSenderDelegate : SharedSenderKeysDelegate { +public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDelegate, SharedSenderKeysDelegate { public static let shared = MessageSenderDelegate() + public func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) + } + public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { print("[Loki] Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") let transaction = transaction as! YapDatabaseReadWriteTransaction diff --git a/SignalUtilitiesKit/Messaging/TSIncomingMessage.m b/SignalUtilitiesKit/Messaging/TSIncomingMessage.m index a2d30d92a..40092305c 100644 --- a/SignalUtilitiesKit/Messaging/TSIncomingMessage.m +++ b/SignalUtilitiesKit/Messaging/TSIncomingMessage.m @@ -106,7 +106,6 @@ NS_ASSUME_NONNULL_BEGIN return foundMessage; } - - (OWSInteractionType)interactionType { return OWSInteractionType_IncomingMessage; diff --git a/SignalUtilitiesKit/Messaging/TSOutgoingMessage.h b/SignalUtilitiesKit/Messaging/TSOutgoingMessage.h index f5d9e340b..dfd9d73e2 100644 --- a/SignalUtilitiesKit/Messaging/TSOutgoingMessage.h +++ b/SignalUtilitiesKit/Messaging/TSOutgoingMessage.h @@ -140,9 +140,10 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { @property (nonatomic, readonly) BOOL isOnline; -/// Loki: Time to live for the message in milliseconds. @property (nonatomic, readonly) uint ttl; ++ (nullable instancetype)findMessageWithTimestamp:(uint64_t)timestamp; + /** * The data representation of this message, to be encrypted, before being sent. */ diff --git a/SignalUtilitiesKit/Messaging/TSOutgoingMessage.m b/SignalUtilitiesKit/Messaging/TSOutgoingMessage.m index 58a0bdb64..5b2449b23 100644 --- a/SignalUtilitiesKit/Messaging/TSOutgoingMessage.m +++ b/SignalUtilitiesKit/Messaging/TSOutgoingMessage.m @@ -6,7 +6,7 @@ #import "TSOutgoingMessage.h" #import "NSString+SSK.h" - +#import "TSDatabaseSecondaryIndexes.h" #import "OWSPrimaryStorage.h" #import "ProfileManagerProtocol.h" #import "ProtoUtils.h" @@ -502,6 +502,20 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt return NO; } ++ (nullable instancetype)findMessageWithTimestamp:(uint64_t)timestamp +{ + __block TSOutgoingMessage *result; + [LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [TSDatabaseSecondaryIndexes enumerateMessagesWithTimestamp:timestamp withBlock:^(NSString *collection, NSString *key, BOOL *stop) { + TSInteraction *interaction = [TSInteraction fetchObjectWithUniqueID:key transaction:transaction]; + if ([interaction isKindOfClass:[TSOutgoingMessage class]]) { + result = (TSOutgoingMessage *)interaction; + } + } usingTransaction:transaction]; + }]; + return result; +} + - (OWSInteractionType)interactionType { return OWSInteractionType_OutgoingMessage; From 9f4d72f2f558640234b22a2e8d0451e809fbf34d Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 20 Nov 2020 10:07:36 +1100 Subject: [PATCH 015/177] Make quotes work again Also organize files --- Session/Configuration.swift | 4 +- Session/Signal/AppDelegate.m | 6 +- .../Cells/OWSQuotedMessageView.m | 10 +- .../Control Message/SessionRequest.swift | 18 +- Signal.xcodeproj/project.pbxproj | 228 ++++++++++++------ .../Database/Storage+Messaging.swift | 2 +- .../Attachments/SignalAttachment.swift | 0 .../Attachments/TSAttachment.h | 0 .../Attachments/TSAttachment.m | 0 .../Attachments/TSAttachmentPointer.h | 0 .../Attachments/TSAttachmentPointer.m | 0 .../Attachments/TSAttachmentStream.h | 0 .../Attachments/TSAttachmentStream.m | 0 .../{ => Blocking}/OWSBlockingManager.h | 0 .../{ => Blocking}/OWSBlockingManager.m | 0 .../{ => Core Messages}/TSErrorMessage.h | 0 .../{ => Core Messages}/TSErrorMessage.m | 0 .../TSErrorMessage_privateConstructor.h | 0 .../TSIncomingMessage+Conversion.swift | 4 +- .../{ => Core Messages}/TSIncomingMessage.h | 0 .../{ => Core Messages}/TSIncomingMessage.m | 0 .../{ => Core Messages}/TSInfoMessage.h | 0 .../{ => Core Messages}/TSInfoMessage.m | 0 .../{ => Core Messages}/TSInteraction.h | 0 .../{ => Core Messages}/TSInteraction.m | 0 .../TSInvalidIdentityKeyErrorMessage.h | 0 .../TSInvalidIdentityKeyErrorMessage.m | 0 ...SInvalidIdentityKeyReceivingErrorMessage.h | 0 ...SInvalidIdentityKeyReceivingErrorMessage.m | 0 .../TSInvalidIdentityKeySendingErrorMessage.h | 0 .../TSInvalidIdentityKeySendingErrorMessage.m | 0 .../Messaging/{ => Core Messages}/TSMessage.h | 0 .../Messaging/{ => Core Messages}/TSMessage.m | 0 .../TSOutgoingMessage+Conversion.swift | 2 +- .../{ => Core Messages}/TSOutgoingMessage.h | 0 .../{ => Core Messages}/TSOutgoingMessage.m | 0 ...sappearingConfigurationUpdateInfoMessage.h | 0 ...sappearingConfigurationUpdateInfoMessage.m | 0 .../OWSDisappearingMessagesConfiguration.h | 0 .../OWSDisappearingMessagesConfiguration.m | 0 .../OWSDisappearingMessagesFinder.h | 0 .../OWSDisappearingMessagesFinder.m | 0 .../OWSDisappearingMessagesJob.h | 0 .../OWSDisappearingMessagesJob.m | 0 .../{ => Link Previews}/OWSLinkPreview.swift | 0 .../Messaging/{ => Mentions}/Mention.swift | 0 .../{ => Mentions}/MentionsManager.swift | 0 .../PushNotificationAPI.swift} | 4 +- .../Messaging/Quote+Conversion.swift | 13 - .../{ => Quotes}/OWSQuotedReplyModel.h | 0 .../{ => Quotes}/OWSQuotedReplyModel.m | 0 .../Messaging/Quotes/Quote+Conversion.swift | 27 +++ .../Messaging/{ => Quotes}/TSQuotedMessage.h | 0 .../Messaging/{ => Quotes}/TSQuotedMessage.m | 0 .../OWSOutgoingReceiptManager.h | 0 .../OWSOutgoingReceiptManager.m | 0 .../OWSReadReceiptManager.h | 0 .../OWSReadReceiptManager.m | 0 .../{ => Read Tracking}/OWSReadTracking.h | 0 .../TSUnreadIndicatorInteraction.h | 0 .../TSUnreadIndicatorInteraction.m | 0 .../ClosedGroupPoller.swift | 0 .../Destination+Conversion.swift | 0 .../MessageReceiverDelegate.swift | 4 +- .../MessageSender+Utilities.swift | 0 .../MessageSenderDelegate.swift | 0 .../OpenGroupAPIDelegate.swift | 0 .../OpenGroupPoller.swift | 0 .../{ => Sending & Receiving}/Poller.swift | 0 .../SNProtoEnvelope+Conversion.swift | 0 .../TypingIndicators.swift | 0 .../OWSIncomingMessageFinder.h | 0 .../OWSIncomingMessageFinder.m | 0 .../{ => Utilities}/OWSMessageUtils.h | 0 .../{ => Utilities}/OWSMessageUtils.m | 0 SignalUtilitiesKit/TSAccountManager.m | 4 +- .../To Do/ClosedGroupsProtocol.swift | 4 +- 77 files changed, 216 insertions(+), 114 deletions(-) rename SignalUtilitiesKit/{ => Messaging}/Attachments/SignalAttachment.swift (100%) rename SignalUtilitiesKit/{ => Messaging}/Attachments/TSAttachment.h (100%) rename SignalUtilitiesKit/{ => Messaging}/Attachments/TSAttachment.m (100%) rename SignalUtilitiesKit/{ => Messaging}/Attachments/TSAttachmentPointer.h (100%) rename SignalUtilitiesKit/{ => Messaging}/Attachments/TSAttachmentPointer.m (100%) rename SignalUtilitiesKit/{ => Messaging}/Attachments/TSAttachmentStream.h (100%) rename SignalUtilitiesKit/{ => Messaging}/Attachments/TSAttachmentStream.m (100%) rename SignalUtilitiesKit/Messaging/{ => Blocking}/OWSBlockingManager.h (100%) rename SignalUtilitiesKit/Messaging/{ => Blocking}/OWSBlockingManager.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSErrorMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSErrorMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSErrorMessage_privateConstructor.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSIncomingMessage+Conversion.swift (83%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSIncomingMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSIncomingMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInfoMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInfoMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInteraction.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInteraction.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInvalidIdentityKeyErrorMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInvalidIdentityKeyErrorMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInvalidIdentityKeyReceivingErrorMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInvalidIdentityKeyReceivingErrorMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInvalidIdentityKeySendingErrorMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSInvalidIdentityKeySendingErrorMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSOutgoingMessage+Conversion.swift (92%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSOutgoingMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Core Messages}/TSOutgoingMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingConfigurationUpdateInfoMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingConfigurationUpdateInfoMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingMessagesConfiguration.h (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingMessagesConfiguration.m (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingMessagesFinder.h (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingMessagesFinder.m (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingMessagesJob.h (100%) rename SignalUtilitiesKit/Messaging/{ => Disappearing Messages}/OWSDisappearingMessagesJob.m (100%) rename SignalUtilitiesKit/Messaging/{ => Link Previews}/OWSLinkPreview.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Mentions}/Mention.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Mentions}/MentionsManager.swift (100%) rename SignalUtilitiesKit/Messaging/{PushNotificationManager.swift => Notifications/PushNotificationAPI.swift} (98%) delete mode 100644 SignalUtilitiesKit/Messaging/Quote+Conversion.swift rename SignalUtilitiesKit/Messaging/{ => Quotes}/OWSQuotedReplyModel.h (100%) rename SignalUtilitiesKit/Messaging/{ => Quotes}/OWSQuotedReplyModel.m (100%) create mode 100644 SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift rename SignalUtilitiesKit/Messaging/{ => Quotes}/TSQuotedMessage.h (100%) rename SignalUtilitiesKit/Messaging/{ => Quotes}/TSQuotedMessage.m (100%) rename SignalUtilitiesKit/Messaging/{ => Read Tracking}/OWSOutgoingReceiptManager.h (100%) rename SignalUtilitiesKit/Messaging/{ => Read Tracking}/OWSOutgoingReceiptManager.m (100%) rename SignalUtilitiesKit/Messaging/{ => Read Tracking}/OWSReadReceiptManager.h (100%) rename SignalUtilitiesKit/Messaging/{ => Read Tracking}/OWSReadReceiptManager.m (100%) rename SignalUtilitiesKit/Messaging/{ => Read Tracking}/OWSReadTracking.h (100%) rename SignalUtilitiesKit/Messaging/{ => Read Tracking}/TSUnreadIndicatorInteraction.h (100%) rename SignalUtilitiesKit/Messaging/{ => Read Tracking}/TSUnreadIndicatorInteraction.m (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/ClosedGroupPoller.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/Destination+Conversion.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/MessageReceiverDelegate.swift (98%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/MessageSender+Utilities.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/MessageSenderDelegate.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/OpenGroupAPIDelegate.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/OpenGroupPoller.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/Poller.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Sending & Receiving}/SNProtoEnvelope+Conversion.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Typing Indicators}/TypingIndicators.swift (100%) rename SignalUtilitiesKit/Messaging/{ => Utilities}/OWSIncomingMessageFinder.h (100%) rename SignalUtilitiesKit/Messaging/{ => Utilities}/OWSIncomingMessageFinder.m (100%) rename SignalUtilitiesKit/Messaging/{ => Utilities}/OWSMessageUtils.h (100%) rename SignalUtilitiesKit/Messaging/{ => Utilities}/OWSMessageUtils.m (100%) diff --git a/Session/Configuration.swift b/Session/Configuration.swift index 0a03a6e0b..68f2373cc 100644 --- a/Session/Configuration.swift +++ b/Session/Configuration.swift @@ -15,8 +15,8 @@ final class Configuration : NSObject { sessionRestorationImplementation: SessionRestorationImplementation(), certificateValidator: SMKCertificateDefaultValidator(trustRoot: OWSUDManagerImpl.trustRoot()), openGroupAPIDelegate: OpenGroupAPIDelegate.shared, - pnServerURL: PushNotificationManager.server, - pnServerPublicKey: PushNotificationManager.serverPublicKey + pnServerURL: PushNotificationAPI.server, + pnServerPublicKey: PushNotificationAPI.serverPublicKey ) SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: MessageSenderDelegate.shared) SessionSnodeKit.configure(storage: Storage.shared) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 9d8454de5..338fac2b4 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -669,9 +669,9 @@ static NSTimeInterval launchStartedAt; OWSLogInfo(@"Registering for push notifications with token: %@.", deviceToken); BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"]; if (isUsingFullAPNs) { - __unused AnyPromise *promise = [LKPushNotificationManager registerWithToken:deviceToken hexEncodedPublicKey:self.tsAccountManager.localNumber isForcedUpdate:NO]; + __unused AnyPromise *promise = [LKPushNotificationAPI registerWithToken:deviceToken hexEncodedPublicKey:self.tsAccountManager.localNumber isForcedUpdate:NO]; } else { - __unused AnyPromise *promise = [LKPushNotificationManager unregisterWithToken:deviceToken isForcedUpdate:NO]; + __unused AnyPromise *promise = [LKPushNotificationAPI unregisterWithToken:deviceToken isForcedUpdate:NO]; } } @@ -857,7 +857,7 @@ static NSTimeInterval launchStartedAt; NSString *hexEncodedDeviceToken = [userDefaults stringForKey:@"deviceToken"]; if (isUsingFullAPNs && hexEncodedDeviceToken != nil) { NSData *deviceToken = [NSData dataFromHexString:hexEncodedDeviceToken]; - [[LKPushNotificationManager unregisterWithToken:deviceToken isForcedUpdate:YES] retainUntilComplete]; + [[LKPushNotificationAPI unregisterWithToken:deviceToken isForcedUpdate:YES] retainUntilComplete]; } [ThreadUtil deleteAllContent]; [SSKEnvironment.shared.identityManager clearIdentityKey]; diff --git a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m index 0b296a38b..6ef78ab2c 100644 --- a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m @@ -550,15 +550,13 @@ const CGFloat kRemotelySourcedContentRowSpacing = 4; quotedAuthorText = NSLocalizedString(@"You", @""); } } else { - __block NSString *quotedAuthor = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.quotedMessage.authorId]; + __block NSString *quotedAuthor = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.quotedMessage.authorId] ?: self.quotedMessage.authorId; if (quotedAuthor == self.quotedMessage.authorId) { - SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:self.quotedMessage.threadId]; + SNOpenGroup *openGroup = [LKStorage.shared getOpenGroupForThreadID:self.quotedMessage.threadId]; [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - if (publicChat != nil) { - quotedAuthor = [LKUserDisplayNameUtilities getPublicChatDisplayNameFor:self.quotedMessage.authorId in:publicChat.channel on:publicChat.server using:transaction]; - } else { - quotedAuthor = [LKUserDisplayNameUtilities getPrivateChatDisplayNameFor:self.quotedMessage.authorId]; + if (openGroup != nil) { + quotedAuthor = [LKUserDisplayNameUtilities getPublicChatDisplayNameFor:self.quotedMessage.authorId in:openGroup.channel on:openGroup.server using:transaction]; } }]; } diff --git a/SessionMessagingKit/Messages/Control Message/SessionRequest.swift b/SessionMessagingKit/Messages/Control Message/SessionRequest.swift index ac2e05046..0d7c5d05f 100644 --- a/SessionMessagingKit/Messages/Control Message/SessionRequest.swift +++ b/SessionMessagingKit/Messages/Control Message/SessionRequest.swift @@ -37,14 +37,16 @@ public final class SessionRequest : ControlMessage { Configuration.shared.storage.with { transaction in registrationID = Configuration.shared.storage.getOrGenerateRegistrationID(using: transaction) } - guard let preKeyBundle = PreKeyBundle(registrationId: Int32(registrationID), - deviceId: 1, - preKeyId: Int32(preKeyBundleProto.prekeyID), - preKeyPublic: preKeyBundleProto.prekey, - signedPreKeyPublic: preKeyBundleProto.signedKey, - signedPreKeyId: Int32(preKeyBundleProto.signedKeyID), - signedPreKeySignature: preKeyBundleProto.signature, - identityKey: preKeyBundleProto.identityKey) else { return nil } + guard let preKeyBundle = PreKeyBundle( + registrationId: Int32(registrationID), + deviceId: 1, + preKeyId: Int32(preKeyBundleProto.prekeyID), + preKeyPublic: preKeyBundleProto.prekey, + signedPreKeyPublic: preKeyBundleProto.signedKey, + signedPreKeyId: Int32(preKeyBundleProto.signedKeyID), + signedPreKeySignature: preKeyBundleProto.signature, + identityKey: preKeyBundleProto.identityKey + ) else { return nil } return SessionRequest(preKeyBundle: preKeyBundle) } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 620b29787..86642be94 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -264,7 +264,7 @@ B8CCF63F23975CFB0091D419 /* JoinPublicChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */; }; B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF6422397711F0091D419 /* SettingsVC.swift */; }; B8D8F0F32565F98E0092EF10 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; - B8D8F0F42565F98E0092EF10 /* PushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationManager.swift */; }; + B8D8F0F42565F98E0092EF10 /* PushNotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */; }; B8D8F12E2565FC910092EF10 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; }; B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */; }; B8D8F16A256615DE0092EF10 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; }; @@ -1623,7 +1623,7 @@ C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageUtils.m; sourceTree = ""; }; C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOS.pb.swift; sourceTree = ""; }; C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesJob.m; sourceTree = ""; }; - C33FDBDE255A581900E217F9 /* PushNotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationManager.swift; sourceTree = ""; }; + C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationAPI.swift; sourceTree = ""; }; C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = ""; }; C33FDBE9255A581A00E217F9 /* TSInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInteraction.m; sourceTree = ""; }; C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockingManager.h; sourceTree = ""; }; @@ -1685,7 +1685,7 @@ C38EF212255B6D3A007E1867 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Theme.h; path = SignalUtilitiesKit/UI/Theme.h; sourceTree = SOURCE_ROOT; }; C38EF214255B6D3A007E1867 /* Theme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Theme.m; path = SignalUtilitiesKit/UI/Theme.m; sourceTree = SOURCE_ROOT; }; C38EF223255B6D5D007E1867 /* AttachmentSharing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AttachmentSharing.m; path = SignalUtilitiesKit/Utilities/AttachmentSharing.m; sourceTree = SOURCE_ROOT; }; - C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = SignalUtilitiesKit/Attachments/SignalAttachment.swift; sourceTree = SOURCE_ROOT; }; + C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = SignalUtilitiesKit/Messaging/Attachments/SignalAttachment.swift; sourceTree = SOURCE_ROOT; }; C38EF225255B6D5D007E1867 /* AttachmentSharing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AttachmentSharing.h; path = SignalUtilitiesKit/Utilities/AttachmentSharing.h; sourceTree = SOURCE_ROOT; }; C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewDelegate.swift; path = SignalUtilitiesKit/Utilities/ShareViewDelegate.swift; sourceTree = SOURCE_ROOT; }; C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSVideoPlayer.swift; path = SignalUtilitiesKit/Utilities/OWSVideoPlayer.swift; sourceTree = SOURCE_ROOT; }; @@ -1722,8 +1722,8 @@ C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SignalUtilitiesKit/UI/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; }; C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIView+Utilities.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.h; sourceTree = SOURCE_ROOT; }; - C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.m; sourceTree = SOURCE_ROOT; }; + C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = "SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.h"; sourceTree = SOURCE_ROOT; }; + C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = "SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.m"; sourceTree = SOURCE_ROOT; }; C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = "SignalUtilitiesKit/To Do/OWSProfileManager.m"; sourceTree = SOURCE_ROOT; }; C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SignalUtilitiesKit/To Do/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = "SignalUtilitiesKit/To Do/OWSProfileManager.h"; sourceTree = SOURCE_ROOT; }; @@ -1790,8 +1790,8 @@ C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ApprovalRailCellView.swift; path = SignalUtilitiesKit/UI/ApprovalRailCellView.swift; sourceTree = SOURCE_ROOT; }; C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift; sourceTree = SOURCE_ROOT; }; C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadViewModel.swift; path = SignalUtilitiesKit/ThreadViewModel.swift; sourceTree = SOURCE_ROOT; }; - C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.h; sourceTree = SOURCE_ROOT; }; - C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.m; sourceTree = SOURCE_ROOT; }; + C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h; sourceTree = SOURCE_ROOT; }; + C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m; sourceTree = SOURCE_ROOT; }; C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorTextViewController.swift; sourceTree = SOURCE_ROOT; }; C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = SignalUtilitiesKit/UI/ImageEditorItem.swift; sourceTree = SOURCE_ROOT; }; @@ -2761,7 +2761,6 @@ C3851CE3256250FA0061EEB0 /* To Do */, C3CA3B11255CF17200F4C6D4 /* Utilities */, C3851CD225624B060061EEB0 /* UI */, - C38BBA0B255E31EC0041B9A3 /* Attachments */, C38BBA0C255E32020041B9A3 /* Threads */, C38BBA0D255E321C0041B9A3 /* Messaging */, C38BBA0E255E32440041B9A3 /* Database */, @@ -2911,6 +2910,144 @@ path = CSV; sourceTree = ""; }; + C379DC6825672B5E0002D4EB /* Notifications */ = { + isa = PBXGroup; + children = ( + C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */, + ); + path = Notifications; + sourceTree = ""; + }; + C379DC7125672B8F0002D4EB /* Utilities */ = { + isa = PBXGroup; + children = ( + C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, + C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, + C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, + C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */, + ); + path = Utilities; + sourceTree = ""; + }; + C379DC7A25672BDB0002D4EB /* Sending & Receiving */ = { + isa = PBXGroup; + children = ( + C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, + C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */, + C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */, + B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */, + C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */, + B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */, + C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */, + C33FDB3A255A580B00E217F9 /* Poller.swift */, + C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, + ); + path = "Sending & Receiving"; + sourceTree = ""; + }; + C379DC7B25672C020002D4EB /* Mentions */ = { + isa = PBXGroup; + children = ( + C33FDA7E255A57FB00E217F9 /* Mention.swift */, + C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, + ); + path = Mentions; + sourceTree = ""; + }; + C379DC8425672C3E0002D4EB /* Quotes */ = { + isa = PBXGroup; + children = ( + C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, + C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, + B840729F2565F1670037CB17 /* Quote+Conversion.swift */, + C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */, + C33FDB83255A581100E217F9 /* TSQuotedMessage.m */, + ); + path = Quotes; + sourceTree = ""; + }; + C379DC8525672C790002D4EB /* Disappearing Messages */ = { + isa = PBXGroup; + children = ( + C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, + C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, + C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, + C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, + C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, + C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */, + C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */, + C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */, + ); + path = "Disappearing Messages"; + sourceTree = ""; + }; + C379DC8625672CAF0002D4EB /* Link Previews */ = { + isa = PBXGroup; + children = ( + C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, + ); + path = "Link Previews"; + sourceTree = ""; + }; + C379DC8725672CD30002D4EB /* Read Tracking */ = { + isa = PBXGroup; + children = ( + C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */, + C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */, + C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */, + C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */, + C33FDAE1255A580400E217F9 /* OWSReadTracking.h */, + C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, + C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, + ); + path = "Read Tracking"; + sourceTree = ""; + }; + C379DC9025672D490002D4EB /* Blocking */ = { + isa = PBXGroup; + children = ( + C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, + C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, + ); + path = Blocking; + sourceTree = ""; + }; + C379DCA925672DBD0002D4EB /* Typing Indicators */ = { + isa = PBXGroup; + children = ( + C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */, + ); + path = "Typing Indicators"; + sourceTree = ""; + }; + C379DCAA25672E7B0002D4EB /* Core Messages */ = { + isa = PBXGroup; + children = ( + C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, + C33FDBB0255A581500E217F9 /* TSErrorMessage.h */, + C33FDAE7255A580500E217F9 /* TSErrorMessage.m */, + C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */, + C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */, + C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, + C33FDADD255A580400E217F9 /* TSInfoMessage.h */, + C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */, + C33FDAE6255A580400E217F9 /* TSInteraction.h */, + C33FDBE9255A581A00E217F9 /* TSInteraction.m */, + C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */, + C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */, + C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */, + C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */, + C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */, + C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */, + C33FDA70255A57FA00E217F9 /* TSMessage.h */, + C33FDB60255A580E00E217F9 /* TSMessage.m */, + C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */, + C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */, + B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */, + ); + path = "Core Messages"; + sourceTree = ""; + }; C3851CD225624B060061EEB0 /* UI */ = { isa = PBXGroup; children = ( @@ -3067,67 +3204,18 @@ C38BBA0D255E321C0041B9A3 /* Messaging */ = { isa = PBXGroup; children = ( - C33FDB3A255A580B00E217F9 /* Poller.swift */, - C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, - C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */, - C33FDBDE255A581900E217F9 /* PushNotificationManager.swift */, - C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */, - C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, - C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, - B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */, - B840729F2565F1670037CB17 /* Quote+Conversion.swift */, - B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */, - C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */, - B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */, - C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */, - C33FDA7E255A57FB00E217F9 /* Mention.swift */, - C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, - C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, - C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, - C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, - C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, - C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, - C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, - C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, - C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */, - C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */, - C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */, - C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, - C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, - C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, - C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, - C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, - C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, - C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */, - C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */, - C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */, - C33FDAE1255A580400E217F9 /* OWSReadTracking.h */, - C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */, - C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */, - C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */, - C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, - C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, - C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, - C33FDBB0255A581500E217F9 /* TSErrorMessage.h */, - C33FDAE7255A580500E217F9 /* TSErrorMessage.m */, - C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */, - C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */, - C33FDADD255A580400E217F9 /* TSInfoMessage.h */, - C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */, - C33FDAE6255A580400E217F9 /* TSInteraction.h */, - C33FDBE9255A581A00E217F9 /* TSInteraction.m */, - C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */, - C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */, - C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */, - C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */, - C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */, - C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */, - C33FDA70255A57FA00E217F9 /* TSMessage.h */, - C33FDB60255A580E00E217F9 /* TSMessage.m */, - C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */, - C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */, - C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */, - C33FDB83255A581100E217F9 /* TSQuotedMessage.m */, + C38BBA0B255E31EC0041B9A3 /* Attachments */, + C379DC9025672D490002D4EB /* Blocking */, + C379DCAA25672E7B0002D4EB /* Core Messages */, + C379DC8525672C790002D4EB /* Disappearing Messages */, + C379DC8625672CAF0002D4EB /* Link Previews */, + C379DC7B25672C020002D4EB /* Mentions */, + C379DC6825672B5E0002D4EB /* Notifications */, + C379DC8425672C3E0002D4EB /* Quotes */, + C379DC8725672CD30002D4EB /* Read Tracking */, + C379DC7A25672BDB0002D4EB /* Sending & Receiving */, + C379DCA925672DBD0002D4EB /* Typing Indicators */, + C379DC7125672B8F0002D4EB /* Utilities */, ); path = Messaging; sourceTree = ""; @@ -4991,7 +5079,7 @@ C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */, C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */, C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */, - B8D8F0F42565F98E0092EF10 /* PushNotificationManager.swift in Sources */, + B8D8F0F42565F98E0092EF10 /* PushNotificationAPI.swift in Sources */, C33FDC78255A582000E217F9 /* TSConstants.m in Sources */, C38EF324255B6DBF007E1867 /* Bench.swift in Sources */, C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */, diff --git a/SignalUtilitiesKit/Database/Storage+Messaging.swift b/SignalUtilitiesKit/Database/Storage+Messaging.swift index ed5e0034b..50a4fe4bb 100644 --- a/SignalUtilitiesKit/Database/Storage+Messaging.swift +++ b/SignalUtilitiesKit/Database/Storage+Messaging.swift @@ -28,7 +28,7 @@ extension Storage { threadOrNil = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) } guard let thread = threadOrNil else { return nil } - let message = TSIncomingMessage.from(message, associatedWith: thread, using: transaction) + let message = TSIncomingMessage.from(message, associatedWith: thread) message.save(with: transaction) return (thread.uniqueId!, message) } diff --git a/SignalUtilitiesKit/Attachments/SignalAttachment.swift b/SignalUtilitiesKit/Messaging/Attachments/SignalAttachment.swift similarity index 100% rename from SignalUtilitiesKit/Attachments/SignalAttachment.swift rename to SignalUtilitiesKit/Messaging/Attachments/SignalAttachment.swift diff --git a/SignalUtilitiesKit/Attachments/TSAttachment.h b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment.h similarity index 100% rename from SignalUtilitiesKit/Attachments/TSAttachment.h rename to SignalUtilitiesKit/Messaging/Attachments/TSAttachment.h diff --git a/SignalUtilitiesKit/Attachments/TSAttachment.m b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment.m similarity index 100% rename from SignalUtilitiesKit/Attachments/TSAttachment.m rename to SignalUtilitiesKit/Messaging/Attachments/TSAttachment.m diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentPointer.h b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.h similarity index 100% rename from SignalUtilitiesKit/Attachments/TSAttachmentPointer.h rename to SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.h diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentPointer.m b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.m similarity index 100% rename from SignalUtilitiesKit/Attachments/TSAttachmentPointer.m rename to SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.m diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentStream.h b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.h similarity index 100% rename from SignalUtilitiesKit/Attachments/TSAttachmentStream.h rename to SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.h diff --git a/SignalUtilitiesKit/Attachments/TSAttachmentStream.m b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.m similarity index 100% rename from SignalUtilitiesKit/Attachments/TSAttachmentStream.m rename to SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.m diff --git a/SignalUtilitiesKit/Messaging/OWSBlockingManager.h b/SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSBlockingManager.h rename to SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.h diff --git a/SignalUtilitiesKit/Messaging/OWSBlockingManager.m b/SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSBlockingManager.m rename to SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.m diff --git a/SignalUtilitiesKit/Messaging/TSErrorMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSErrorMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSErrorMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSErrorMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.m diff --git a/SignalUtilitiesKit/Messaging/TSErrorMessage_privateConstructor.h b/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage_privateConstructor.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSErrorMessage_privateConstructor.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage_privateConstructor.h diff --git a/SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift b/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift similarity index 83% rename from SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift rename to SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift index b337d210b..6917b7235 100644 --- a/SignalUtilitiesKit/Messaging/TSIncomingMessage+Conversion.swift +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift @@ -1,7 +1,7 @@ public extension TSIncomingMessage { - static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage { + static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread) -> TSIncomingMessage { let sender = visibleMessage.sender! let result = TSIncomingMessage( timestamp: visibleMessage.sentTimestamp!, @@ -11,7 +11,7 @@ public extension TSIncomingMessage { messageBody: visibleMessage.text!, attachmentIds: [], expiresInSeconds: 0, - quotedMessage: nil, + quotedMessage: TSQuotedMessage.from(visibleMessage.quote), linkPreview: nil, serverTimestamp: nil, wasReceivedByUD: true diff --git a/SignalUtilitiesKit/Messaging/TSIncomingMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSIncomingMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSIncomingMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSIncomingMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.m diff --git a/SignalUtilitiesKit/Messaging/TSInfoMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInfoMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSInfoMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInfoMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.m diff --git a/SignalUtilitiesKit/Messaging/TSInteraction.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInteraction.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h diff --git a/SignalUtilitiesKit/Messaging/TSInteraction.m b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInteraction.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m diff --git a/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyErrorMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.m diff --git a/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInvalidIdentityKeyReceivingErrorMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.m diff --git a/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.m diff --git a/SignalUtilitiesKit/Messaging/TSMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m diff --git a/SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift b/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage+Conversion.swift similarity index 92% rename from SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift rename to SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage+Conversion.swift index 3a9d87941..3f0ec8d85 100644 --- a/SignalUtilitiesKit/Messaging/TSOutgoingMessage+Conversion.swift +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage+Conversion.swift @@ -16,7 +16,7 @@ expireStartedAt: 0, isVoiceMessage: false, groupMetaMessage: .unspecified, - quotedMessage: nil, + quotedMessage: TSQuotedMessage.from(visibleMessage.quote), linkPreview: nil ) } diff --git a/SignalUtilitiesKit/Messaging/TSOutgoingMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSOutgoingMessage.h rename to SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSOutgoingMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSOutgoingMessage.m rename to SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.h b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.h rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.h diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.m b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingConfigurationUpdateInfoMessage.m rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.m diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.h b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.h rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.m b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingMessagesConfiguration.m rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.m diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.h b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.h rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.h diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.m b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingMessagesFinder.m rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.m diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.h b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.h rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.h diff --git a/SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.m b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSDisappearingMessagesJob.m rename to SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.m diff --git a/SignalUtilitiesKit/Messaging/OWSLinkPreview.swift b/SignalUtilitiesKit/Messaging/Link Previews/OWSLinkPreview.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSLinkPreview.swift rename to SignalUtilitiesKit/Messaging/Link Previews/OWSLinkPreview.swift diff --git a/SignalUtilitiesKit/Messaging/Mention.swift b/SignalUtilitiesKit/Messaging/Mentions/Mention.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Mention.swift rename to SignalUtilitiesKit/Messaging/Mentions/Mention.swift diff --git a/SignalUtilitiesKit/Messaging/MentionsManager.swift b/SignalUtilitiesKit/Messaging/Mentions/MentionsManager.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/MentionsManager.swift rename to SignalUtilitiesKit/Messaging/Mentions/MentionsManager.swift diff --git a/SignalUtilitiesKit/Messaging/PushNotificationManager.swift b/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift similarity index 98% rename from SignalUtilitiesKit/Messaging/PushNotificationManager.swift rename to SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift index a00313a6d..6e6274307 100644 --- a/SignalUtilitiesKit/Messaging/PushNotificationManager.swift +++ b/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift @@ -1,7 +1,7 @@ import PromiseKit -@objc(LKPushNotificationManager) -public final class PushNotificationManager : NSObject { +@objc(LKPushNotificationAPI) +public final class PushNotificationAPI : NSObject { // MARK: Settings public static let server = "https://live.apns.getsession.org" diff --git a/SignalUtilitiesKit/Messaging/Quote+Conversion.swift b/SignalUtilitiesKit/Messaging/Quote+Conversion.swift deleted file mode 100644 index 0a9973042..000000000 --- a/SignalUtilitiesKit/Messaging/Quote+Conversion.swift +++ /dev/null @@ -1,13 +0,0 @@ - -extension VisibleMessage.Quote { - - @objc(from:) - public static func from(_ model: OWSQuotedReplyModel?) -> VisibleMessage.Quote? { - guard let model = model else { return nil } - let result = VisibleMessage.Quote() - result.timestamp = model.timestamp - result.publicKey = model.authorId - result.text = model.body - return result - } -} diff --git a/SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.h b/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.h rename to SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h diff --git a/SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.m b/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSQuotedReplyModel.m rename to SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m diff --git a/SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift b/SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift new file mode 100644 index 000000000..e7bee2c4c --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift @@ -0,0 +1,27 @@ + +extension VisibleMessage.Quote { + + @objc(from:) + public static func from(_ quote: OWSQuotedReplyModel?) -> VisibleMessage.Quote? { + guard let quote = quote else { return nil } + let result = VisibleMessage.Quote() + result.timestamp = quote.timestamp + result.publicKey = quote.authorId + result.text = quote.body + return result + } +} + +extension TSQuotedMessage { + + @objc(from:) + public static func from(_ quote: VisibleMessage.Quote?) -> TSQuotedMessage? { + guard let quote = quote else { return nil } + return TSQuotedMessage( + timestamp: quote.timestamp!, + authorId: quote.publicKey!, + body: quote.text, bodySource: .local, + receivedQuotedAttachmentInfos: [] + ) + } +} diff --git a/SignalUtilitiesKit/Messaging/TSQuotedMessage.h b/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSQuotedMessage.h rename to SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h diff --git a/SignalUtilitiesKit/Messaging/TSQuotedMessage.m b/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSQuotedMessage.m rename to SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.m diff --git a/SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.h b/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.h rename to SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.h diff --git a/SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.m b/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSOutgoingReceiptManager.m rename to SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m diff --git a/SignalUtilitiesKit/Messaging/OWSReadReceiptManager.h b/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSReadReceiptManager.h rename to SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.h diff --git a/SignalUtilitiesKit/Messaging/OWSReadReceiptManager.m b/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSReadReceiptManager.m rename to SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.m diff --git a/SignalUtilitiesKit/Messaging/OWSReadTracking.h b/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadTracking.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSReadTracking.h rename to SignalUtilitiesKit/Messaging/Read Tracking/OWSReadTracking.h diff --git a/SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.h b/SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.h similarity index 100% rename from SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.h rename to SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.h diff --git a/SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.m b/SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.m similarity index 100% rename from SignalUtilitiesKit/Messaging/TSUnreadIndicatorInteraction.m rename to SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.m diff --git a/SignalUtilitiesKit/Messaging/ClosedGroupPoller.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/ClosedGroupPoller.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift diff --git a/SignalUtilitiesKit/Messaging/Destination+Conversion.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/Destination+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Destination+Conversion.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/Destination+Conversion.swift diff --git a/SignalUtilitiesKit/Messaging/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift similarity index 98% rename from SignalUtilitiesKit/Messaging/MessageReceiverDelegate.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift index 5d1b28c61..bcdac1a30 100644 --- a/SignalUtilitiesKit/Messaging/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift @@ -202,7 +202,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver // Add the group to the user's set of public keys to poll for Storage.shared.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction) // Notify the PN server - let _ = PushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) + let _ = PushNotificationAPI.performOperation(.subscribe, for: groupPublicKey, publicKey: getUserHexEncodedPublicKey()) // Notify the user let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) infoMessage.save(with: transaction) @@ -245,7 +245,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver if wasUserRemoved { Storage.shared.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) // Notify the PN server - let _ = PushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + let _ = PushNotificationAPI.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) } else { let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) diff --git a/SignalUtilitiesKit/Messaging/MessageSender+Utilities.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/MessageSender+Utilities.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift diff --git a/SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/MessageSenderDelegate.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift diff --git a/SignalUtilitiesKit/Messaging/OpenGroupAPIDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/OpenGroupAPIDelegate.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift diff --git a/SignalUtilitiesKit/Messaging/OpenGroupPoller.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupPoller.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/OpenGroupPoller.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupPoller.swift diff --git a/SignalUtilitiesKit/Messaging/Poller.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Poller.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift diff --git a/SignalUtilitiesKit/Messaging/SNProtoEnvelope+Conversion.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/SNProtoEnvelope+Conversion.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift diff --git a/SignalUtilitiesKit/Messaging/TypingIndicators.swift b/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/TypingIndicators.swift rename to SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift diff --git a/SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.h b/SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.h rename to SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.h diff --git a/SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.m b/SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSIncomingMessageFinder.m rename to SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.m diff --git a/SignalUtilitiesKit/Messaging/OWSMessageUtils.h b/SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.h similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSMessageUtils.h rename to SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.h diff --git a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m b/SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.m similarity index 100% rename from SignalUtilitiesKit/Messaging/OWSMessageUtils.m rename to SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.m diff --git a/SignalUtilitiesKit/TSAccountManager.m b/SignalUtilitiesKit/TSAccountManager.m index 685b76fb5..4114a65fb 100644 --- a/SignalUtilitiesKit/TSAccountManager.m +++ b/SignalUtilitiesKit/TSAccountManager.m @@ -295,8 +295,8 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa { BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"]; NSData *pushTokenAsData = [NSData dataFromHexString:pushToken]; - AnyPromise *promise = isUsingFullAPNs ? [LKPushNotificationManager registerWithToken:pushTokenAsData hexEncodedPublicKey:self.localNumber isForcedUpdate:isForcedUpdate] - : [LKPushNotificationManager unregisterWithToken:pushTokenAsData isForcedUpdate:isForcedUpdate]; + AnyPromise *promise = isUsingFullAPNs ? [LKPushNotificationAPI registerWithToken:pushTokenAsData hexEncodedPublicKey:self.localNumber isForcedUpdate:isForcedUpdate] + : [LKPushNotificationAPI unregisterWithToken:pushTokenAsData isForcedUpdate:isForcedUpdate]; promise .then(^() { successHandler(); diff --git a/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift index f4c19d0ea..7e8bd651d 100644 --- a/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift +++ b/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift @@ -75,7 +75,7 @@ public final class ClosedGroupsProtocol : NSObject { // Add the group to the user's set of public keys to poll for Storage.shared.setClosedGroupPrivateKey(groupKeyPair.privateKey.toHexString(), for: groupPublicKey, using: transaction) // Notify the PN server - promises.append(PushNotificationManager.performOperation(.subscribe, for: groupPublicKey, publicKey: userPublicKey)) + promises.append(PushNotificationAPI.performOperation(.subscribe, for: groupPublicKey, publicKey: userPublicKey)) // Notify the user let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) infoMessage.save(with: transaction) @@ -138,7 +138,7 @@ public final class ClosedGroupsProtocol : NSObject { if isUserLeaving { Storage.shared.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) // Notify the PN server - let _ = PushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + let _ = PushNotificationAPI.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) } else { // Send closed group update messages to any new members using established channels for member in newMembers { From 7d207ddfb782a044949aec383db371f92dff6d3c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 20 Nov 2020 10:14:35 +1100 Subject: [PATCH 016/177] Organize files --- Session/Components/VoiceMessageView.swift | 4 +- Session/Signal/SessionResetJob.swift | 2 +- Session/Utilities/IP2Country.swift | 2 +- .../NotificationServiceExtensionContext.swift | 2 +- Signal.xcodeproj/project.pbxproj | 272 +++++++++++------- .../CreatePreKeysOperation.swift | 2 +- .../{ => Keychain}/SSKKeychainStorage.swift | 0 .../{ => Migration}/OWSDatabaseMigration.h | 0 .../{ => Migration}/OWSDatabaseMigration.m | 0 .../OWSDatabaseMigrationRunner.h | 0 .../OWSDatabaseMigrationRunner.m | 0 .../OWSResaveCollectionDBMigration.h | 0 .../OWSResaveCollectionDBMigration.m | 0 .../OWSPrimaryStorage+PreKeyStore.h | 0 .../OWSPrimaryStorage+PreKeyStore.m | 0 .../OWSPrimaryStorage+SessionStore.h | 0 .../OWSPrimaryStorage+SessionStore.m | 0 .../OWSPrimaryStorage+SignedPreKeyStore.h | 0 .../OWSPrimaryStorage+SignedPreKeyStore.m | 0 .../OWSPrimaryStorage+keyFromIntLong.h | 0 .../OWSPrimaryStorage+keyFromIntLong.m | 0 .../{ => OWSStorage}/OWSPrimaryStorage.h | 0 .../{ => OWSStorage}/OWSPrimaryStorage.m | 0 .../Database/{ => OWSStorage}/OWSStorage.h | 0 .../Database/{ => OWSStorage}/OWSStorage.m | 0 .../{ => Storage}/Storage+ClosedGroups.swift | 0 .../Database/{ => Storage}/Storage+Jobs.swift | 0 .../{ => Storage}/Storage+Messaging.swift | 0 .../{ => Storage}/Storage+OnionRequests.swift | 0 .../{ => Storage}/Storage+OpenGroups.swift | 0 .../Storage+SessionManagement.swift | 0 .../{ => Storage}/Storage+Shared.swift | 0 .../{ => Storage}/Storage+SnodeAPI.swift | 0 .../{ => Storage}/Storage+VolumeSamples.swift | 0 .../Database/{ => Storage}/Storage.swift | 0 .../{ => Utilities}/OWSStorage+Subclass.h | 0 .../{ => Utilities}/SSKPreferences.swift | 0 .../{ => Utilities}/SignalKeyingStorage.h | 0 .../{ => Utilities}/SignalKeyingStorage.m | 0 .../TSDatabaseSecondaryIndexes.h | 0 .../TSDatabaseSecondaryIndexes.m | 0 .../Database/{ => Utilities}/TSDatabaseView.h | 0 .../Database/{ => Utilities}/TSDatabaseView.m | 0 .../{ => Utilities}/TSStorageHeaders.h | 0 .../Database/{ => Utilities}/TSStorageKeys.h | 0 .../{ => Utilities}/ThreadViewHelper.h | 0 .../{ => Utilities}/ThreadViewHelper.m | 0 .../{ => YapDatabase}/TSYapDatabaseObject.h | 0 .../{ => YapDatabase}/TSYapDatabaseObject.m | 0 .../YapDatabase+Promise.swift | 0 .../YapDatabaseConnection+OWS.h | 0 .../YapDatabaseConnection+OWS.m | 0 .../YapDatabaseTransaction+OWS.h | 0 .../YapDatabaseTransaction+OWS.m | 0 ...LokiSessionRestorationImplementation.swift | 6 +- .../Notifications/PushNotificationAPI.swift | 20 +- .../ClosedGroupPoller.swift | 6 +- .../MessageReceiverDelegate.swift | 14 +- .../MessageSenderDelegate.swift | 2 +- .../Sending & Receiving/Poller.swift | 10 +- .../SNProtoEnvelope+Conversion.swift | 4 +- SignalUtilitiesKit/OWSUDManager.swift | 2 +- .../PreKeyRefreshOperation.swift | 2 +- .../RotateSignedKeyOperation.swift | 2 +- .../{Utilities => Threads}/LKGroupUtilities.h | 0 .../{Utilities => Threads}/LKGroupUtilities.m | 0 .../To Do/ClosedGroupsProtocol.swift | 10 +- .../To Do/SessionManagementProtocol.swift | 18 +- .../To Do/SessionMetaProtocol.swift | 2 +- ...AttachmentApprovalInputAccessoryView.swift | 0 .../AttachmentApprovalViewController.swift | 0 .../AttachmentCaptionToolbar.swift | 0 .../AttachmentCaptionViewController.swift | 0 .../AttachmentItemCollection.swift | 0 .../AttachmentPrepViewController.swift | 0 .../AttachmentTextToolbar.swift | 0 .../AttachmentTextView.swift | 0 .../ImageEditorBrushViewController.swift | 0 .../ImageEditorCanvasView.swift | 0 .../ImageEditorContents.swift | 0 .../ImageEditorCropViewController.swift | 0 .../{ => Image Editing}/ImageEditorItem.swift | 0 .../ImageEditorModel.swift | 0 .../ImageEditorPaletteView.swift | 0 .../ImageEditorPanGestureRecognizer.swift | 0 .../ImageEditorPinchGestureRecognizer.swift | 0 .../ImageEditorStrokeItem.swift | 0 .../ImageEditorTextItem.swift | 0 .../ImageEditorTextViewController.swift | 0 .../ImageEditorTransform.swift | 0 .../{ => Image Editing}/ImageEditorView.swift | 0 91 files changed, 223 insertions(+), 159 deletions(-) rename SignalUtilitiesKit/Database/{ => Keychain}/SSKKeychainStorage.swift (100%) rename SignalUtilitiesKit/Database/{ => Migration}/OWSDatabaseMigration.h (100%) rename SignalUtilitiesKit/Database/{ => Migration}/OWSDatabaseMigration.m (100%) rename SignalUtilitiesKit/Database/{ => Migration}/OWSDatabaseMigrationRunner.h (100%) rename SignalUtilitiesKit/Database/{ => Migration}/OWSDatabaseMigrationRunner.m (100%) rename SignalUtilitiesKit/Database/{ => Migration}/OWSResaveCollectionDBMigration.h (100%) rename SignalUtilitiesKit/Database/{ => Migration}/OWSResaveCollectionDBMigration.m (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+PreKeyStore.h (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+PreKeyStore.m (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+SessionStore.h (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+SessionStore.m (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+SignedPreKeyStore.h (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+SignedPreKeyStore.m (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+keyFromIntLong.h (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage+keyFromIntLong.m (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage.h (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSPrimaryStorage.m (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSStorage.h (100%) rename SignalUtilitiesKit/Database/{ => OWSStorage}/OWSStorage.m (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+ClosedGroups.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+Jobs.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+Messaging.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+OnionRequests.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+OpenGroups.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+SessionManagement.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+Shared.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+SnodeAPI.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage+VolumeSamples.swift (100%) rename SignalUtilitiesKit/Database/{ => Storage}/Storage.swift (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/OWSStorage+Subclass.h (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/SSKPreferences.swift (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/SignalKeyingStorage.h (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/SignalKeyingStorage.m (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/TSDatabaseSecondaryIndexes.h (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/TSDatabaseSecondaryIndexes.m (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/TSDatabaseView.h (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/TSDatabaseView.m (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/TSStorageHeaders.h (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/TSStorageKeys.h (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/ThreadViewHelper.h (100%) rename SignalUtilitiesKit/Database/{ => Utilities}/ThreadViewHelper.m (100%) rename SignalUtilitiesKit/Database/{ => YapDatabase}/TSYapDatabaseObject.h (100%) rename SignalUtilitiesKit/Database/{ => YapDatabase}/TSYapDatabaseObject.m (100%) rename SignalUtilitiesKit/Database/{ => YapDatabase}/YapDatabase+Promise.swift (100%) rename SignalUtilitiesKit/Database/{ => YapDatabase}/YapDatabaseConnection+OWS.h (100%) rename SignalUtilitiesKit/Database/{ => YapDatabase}/YapDatabaseConnection+OWS.m (100%) rename SignalUtilitiesKit/Database/{ => YapDatabase}/YapDatabaseTransaction+OWS.h (100%) rename SignalUtilitiesKit/Database/{ => YapDatabase}/YapDatabaseTransaction+OWS.m (100%) rename SignalUtilitiesKit/{Utilities => Threads}/LKGroupUtilities.h (100%) rename SignalUtilitiesKit/{Utilities => Threads}/LKGroupUtilities.m (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentApprovalInputAccessoryView.swift (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentApprovalViewController.swift (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentCaptionToolbar.swift (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentCaptionViewController.swift (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentItemCollection.swift (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentPrepViewController.swift (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentTextToolbar.swift (100%) rename SignalUtilitiesKit/UI/{ => Attachment Approval}/AttachmentTextView.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorBrushViewController.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorCanvasView.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorContents.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorCropViewController.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorItem.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorModel.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorPaletteView.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorPanGestureRecognizer.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorPinchGestureRecognizer.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorStrokeItem.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorTextItem.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorTextViewController.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorTransform.swift (100%) rename SignalUtilitiesKit/UI/{ => Image Editing}/ImageEditorView.swift (100%) diff --git a/Session/Components/VoiceMessageView.swift b/Session/Components/VoiceMessageView.swift index 42bc78aee..85f69a7af 100644 --- a/Session/Components/VoiceMessageView.swift +++ b/Session/Components/VoiceMessageView.swift @@ -65,7 +65,7 @@ final class VoiceMessageView : UIView { setUpViewHierarchy() if voiceMessage.isDownloaded { guard let url = (voiceMessage as? TSAttachmentStream)?.originalMediaURL else { - return print("[Loki] Couldn't get URL for voice message.") + return SNLog("Couldn't get URL for voice message.") } if let cachedVolumeSamples = Storage.shared.getVolumeSamples(for: voiceMessage.uniqueId!), cachedVolumeSamples.count == targetSampleCount { self.hideLoader() @@ -81,7 +81,7 @@ final class VoiceMessageView : UIView { Storage.shared.setVolumeSamples(for: voiceMessageID, to: volumeSamples, using: transaction) } }.catch(on: DispatchQueue.main) { error in - print("[Loki] Couldn't sample audio file due to error: \(error).") + SNLog("Couldn't sample audio file due to error: \(error).") } } } else { diff --git a/Session/Signal/SessionResetJob.swift b/Session/Signal/SessionResetJob.swift index 19df92994..163926c1d 100644 --- a/Session/Signal/SessionResetJob.swift +++ b/Session/Signal/SessionResetJob.swift @@ -131,7 +131,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation { message.save(with: transaction) // Loki: We have initiated a session reset - print("[Loki] Session reset initiated.") + SNLog("Session reset initiated.") self.contactThread.sessionResetStatus = .initiated self.contactThread.save(with: transaction) } diff --git a/Session/Utilities/IP2Country.swift b/Session/Utilities/IP2Country.swift index aa6b65899..caf0e865d 100644 --- a/Session/Utilities/IP2Country.swift +++ b/Session/Utilities/IP2Country.swift @@ -64,7 +64,7 @@ final class IP2Country { IP2Country.isInitialized = true NotificationCenter.default.post(name: .onionRequestPathCountriesLoaded, object: nil) } - print("[Loki] Finished preloading onion request path countries.") + SNLog("Finished preloading onion request path countries.") return true } } diff --git a/SessionPushNotificationExtension/NotificationServiceExtensionContext.swift b/SessionPushNotificationExtension/NotificationServiceExtensionContext.swift index a28af8af5..b5b4dfe50 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtensionContext.swift +++ b/SessionPushNotificationExtension/NotificationServiceExtensionContext.swift @@ -17,7 +17,7 @@ final class NotificationServiceExtensionContext : NSObject, AppContext { lazy var buildTime: Date = { guard let buildTimestamp = Bundle.main.object(forInfoDictionaryKey: "BuildTimestamp") as? TimeInterval, buildTimestamp > 0 else { - print("[Loki] No build timestamp; assuming app never expires.") + SNLog("No build timestamp; assuming app never expires.") return .distantFuture } return .init(timeIntervalSince1970: buildTimestamp) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 86642be94..59f0a69de 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -1702,17 +1702,17 @@ C38EF240255B6D67007E1867 /* UIView+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+OWS.swift"; path = "SignalUtilitiesKit/UI/UIView+OWS.swift"; sourceTree = SOURCE_ROOT; }; C38EF241255B6D67007E1867 /* Collection+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Collection+OWS.swift"; path = "SignalUtilitiesKit/Utilities/Collection+OWS.swift"; sourceTree = SOURCE_ROOT; }; C38EF242255B6D67007E1867 /* UIColor+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIColor+OWS.m"; path = "SignalUtilitiesKit/UI/UIColor+OWS.m"; sourceTree = SOURCE_ROOT; }; - C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSResaveCollectionDBMigration.m; path = SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.m; sourceTree = SOURCE_ROOT; }; - C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigrationRunner.m; path = SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.m; sourceTree = SOURCE_ROOT; }; - C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSResaveCollectionDBMigration.h; path = SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.h; sourceTree = SOURCE_ROOT; }; - C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigrationRunner.h; path = SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.h; sourceTree = SOURCE_ROOT; }; - C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; - C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; + C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSResaveCollectionDBMigration.m; path = SignalUtilitiesKit/Database/Migration/OWSResaveCollectionDBMigration.m; sourceTree = SOURCE_ROOT; }; + C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigrationRunner.m; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m; sourceTree = SOURCE_ROOT; }; + C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSResaveCollectionDBMigration.h; path = SignalUtilitiesKit/Database/Migration/OWSResaveCollectionDBMigration.h; sourceTree = SOURCE_ROOT; }; + C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigrationRunner.h; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.h; sourceTree = SOURCE_ROOT; }; + C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; + C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SignalUtilitiesKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; - C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/Database/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; + C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; C38EF283255B6D84007E1867 /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VersionMigrations.h; path = SignalUtilitiesKit/VersionMigrations.h; sourceTree = SOURCE_ROOT; }; C38EF284255B6D84007E1867 /* AppSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppSetup.h; path = SignalUtilitiesKit/AppSetup.h; sourceTree = SOURCE_ROOT; }; - C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalKeyingStorage.h; path = SignalUtilitiesKit/Database/SignalKeyingStorage.h; sourceTree = SOURCE_ROOT; }; + C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalKeyingStorage.h; path = SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.h; sourceTree = SOURCE_ROOT; }; C38EF286255B6D85007E1867 /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VersionMigrations.m; path = SignalUtilitiesKit/VersionMigrations.m; sourceTree = SOURCE_ROOT; }; C38EF287255B6D85007E1867 /* AppSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppSetup.m; path = SignalUtilitiesKit/AppSetup.m; sourceTree = SOURCE_ROOT; }; C38EF288255B6D85007E1867 /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSounds.h; path = SignalUtilitiesKit/OWSSounds.h; sourceTree = SOURCE_ROOT; }; @@ -1780,36 +1780,36 @@ C38EF356255B6DCB007E1867 /* OWSNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSNavigationController.m; path = SignalUtilitiesKit/UI/OWSNavigationController.m; sourceTree = SOURCE_ROOT; }; C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageApprovalViewController.swift; path = SignalUtilitiesKit/UI/MessageApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; C38EF358255B6DCC007E1867 /* MediaMessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaMessageView.swift; path = SignalUtilitiesKit/UI/MediaMessageView.swift; sourceTree = SOURCE_ROOT; }; - C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextToolbar.swift; path = SignalUtilitiesKit/UI/AttachmentTextToolbar.swift; sourceTree = SOURCE_ROOT; }; - C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalInputAccessoryView.swift; path = SignalUtilitiesKit/UI/AttachmentApprovalInputAccessoryView.swift; sourceTree = SOURCE_ROOT; }; - C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentItemCollection.swift; path = SignalUtilitiesKit/UI/AttachmentItemCollection.swift; sourceTree = SOURCE_ROOT; }; - C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalViewController.swift; path = SignalUtilitiesKit/UI/AttachmentApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextView.swift; path = SignalUtilitiesKit/UI/AttachmentTextView.swift; sourceTree = SOURCE_ROOT; }; - C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionToolbar.swift; path = SignalUtilitiesKit/UI/AttachmentCaptionToolbar.swift; sourceTree = SOURCE_ROOT; }; - C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentPrepViewController.swift; path = SignalUtilitiesKit/UI/AttachmentPrepViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextToolbar.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentTextToolbar.swift"; sourceTree = SOURCE_ROOT; }; + C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalInputAccessoryView.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalInputAccessoryView.swift"; sourceTree = SOURCE_ROOT; }; + C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentItemCollection.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentItemCollection.swift"; sourceTree = SOURCE_ROOT; }; + C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalViewController.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalViewController.swift"; sourceTree = SOURCE_ROOT; }; + C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentTextView.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentTextView.swift"; sourceTree = SOURCE_ROOT; }; + C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionToolbar.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentCaptionToolbar.swift"; sourceTree = SOURCE_ROOT; }; + C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentPrepViewController.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentPrepViewController.swift"; sourceTree = SOURCE_ROOT; }; C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ApprovalRailCellView.swift; path = SignalUtilitiesKit/UI/ApprovalRailCellView.swift; sourceTree = SOURCE_ROOT; }; - C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift; sourceTree = SOURCE_ROOT; }; + C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentCaptionViewController.swift"; sourceTree = SOURCE_ROOT; }; C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadViewModel.swift; path = SignalUtilitiesKit/ThreadViewModel.swift; sourceTree = SOURCE_ROOT; }; C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h; sourceTree = SOURCE_ROOT; }; C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m; sourceTree = SOURCE_ROOT; }; - C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorTextViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = SignalUtilitiesKit/UI/ImageEditorItem.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorStrokeItem.swift; path = SignalUtilitiesKit/UI/ImageEditorStrokeItem.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPanGestureRecognizer.swift; path = SignalUtilitiesKit/UI/ImageEditorPanGestureRecognizer.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTransform.swift; path = SignalUtilitiesKit/UI/ImageEditorTransform.swift; sourceTree = SOURCE_ROOT; }; + C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorTextViewController.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorPinchGestureRecognizer.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorItem.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorStrokeItem.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorStrokeItem.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPanGestureRecognizer.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorPanGestureRecognizer.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTransform.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorTransform.swift"; sourceTree = SOURCE_ROOT; }; C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrderedDictionary.swift; path = SignalUtilitiesKit/Utilities/OrderedDictionary.swift; sourceTree = SOURCE_ROOT; }; - C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorView.swift; path = SignalUtilitiesKit/UI/ImageEditorView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCropViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorCropViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorBrushViewController.swift; path = SignalUtilitiesKit/UI/ImageEditorBrushViewController.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPaletteView.swift; path = SignalUtilitiesKit/UI/ImageEditorPaletteView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextItem.swift; path = SignalUtilitiesKit/UI/ImageEditorTextItem.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorContents.swift; path = SignalUtilitiesKit/UI/ImageEditorContents.swift; sourceTree = SOURCE_ROOT; }; + C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorView.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorView.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCropViewController.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorCropViewController.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorBrushViewController.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorBrushViewController.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPaletteView.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorPaletteView.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextItem.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorTextItem.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorContents.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorContents.swift"; sourceTree = SOURCE_ROOT; }; C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "OWSViewController+ImageEditor.swift"; path = "SignalUtilitiesKit/UI/OWSViewController+ImageEditor.swift"; sourceTree = SOURCE_ROOT; }; - C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorModel.swift; path = SignalUtilitiesKit/UI/ImageEditorModel.swift; sourceTree = SOURCE_ROOT; }; - C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCanvasView.swift; path = SignalUtilitiesKit/UI/ImageEditorCanvasView.swift; sourceTree = SOURCE_ROOT; }; - C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadViewHelper.m; path = SignalUtilitiesKit/Database/ThreadViewHelper.m; sourceTree = SOURCE_ROOT; }; - C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/Database/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; + C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorModel.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorModel.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCanvasView.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorCanvasView.swift"; sourceTree = SOURCE_ROOT; }; + C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadViewHelper.m; path = SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m; sourceTree = SOURCE_ROOT; }; + C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSearchBar.h; path = SignalUtilitiesKit/UI/OWSSearchBar.h; sourceTree = SOURCE_ROOT; }; C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisappearingTimerConfigurationView.swift; path = SignalUtilitiesKit/UI/DisappearingTimerConfigurationView.swift; sourceTree = SOURCE_ROOT; }; C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = "SignalUtilitiesKit/To Do/ContactCellView.m"; sourceTree = SOURCE_ROOT; }; @@ -3048,9 +3048,137 @@ path = "Core Messages"; sourceTree = ""; }; + C379DCC3256732800002D4EB /* Storage */ = { + isa = PBXGroup; + children = ( + C33FDB36255A580B00E217F9 /* Storage.swift */, + B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */, + B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */, + B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */, + B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */, + B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */, + C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, + C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */, + C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */, + C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */, + ); + path = Storage; + sourceTree = ""; + }; + C379DCC4256732980002D4EB /* YapDatabase */ = { + isa = PBXGroup; + children = ( + C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */, + C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */, + C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, + C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, + C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, + C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */, + C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */, + ); + path = YapDatabase; + sourceTree = ""; + }; + C379DCC5256732B00002D4EB /* OWSStorage */ = { + isa = PBXGroup; + children = ( + C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, + C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, + C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */, + C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */, + C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */, + C33FDB50255A580D00E217F9 /* OWSPrimaryStorage+PreKeyStore.m */, + C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */, + C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */, + C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */, + C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */, + C33FDAFE255A580600E217F9 /* OWSStorage.h */, + C33FDAB1255A580000E217F9 /* OWSStorage.m */, + ); + path = OWSStorage; + sourceTree = ""; + }; + C379DCD6256732CE0002D4EB /* Keychain */ = { + isa = PBXGroup; + children = ( + C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, + ); + path = Keychain; + sourceTree = ""; + }; + C379DCE7256732EF0002D4EB /* Utilities */ = { + isa = PBXGroup; + children = ( + C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, + C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, + C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, + C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, + C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, + C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, + C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, + C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */, + C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */, + C33FDB46255A580C00E217F9 /* TSDatabaseView.m */, + C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, + C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, + ); + path = Utilities; + sourceTree = ""; + }; + C379DCE82567330E0002D4EB /* Migration */ = { + isa = PBXGroup; + children = ( + C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, + C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, + C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */, + C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */, + C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */, + C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */, + ); + path = Migration; + sourceTree = ""; + }; + C379DCE9256733390002D4EB /* Image Editing */ = { + isa = PBXGroup; + children = ( + C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */, + C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */, + C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */, + C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */, + C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */, + C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */, + C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */, + C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */, + C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */, + C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */, + C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */, + C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */, + C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */, + C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */, + ); + path = "Image Editing"; + sourceTree = ""; + }; + C379DCEA2567334F0002D4EB /* Attachment Approval */ = { + isa = PBXGroup; + children = ( + C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */, + C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */, + C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */, + C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */, + C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */, + C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */, + C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */, + C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */, + ); + path = "Attachment Approval"; + sourceTree = ""; + }; C3851CD225624B060061EEB0 /* UI */ = { isa = PBXGroup; children = ( + C379DCEA2567334F0002D4EB /* Attachment Approval */, + C379DCE9256733390002D4EB /* Image Editing */, C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */, B8C2B2C72563685C00551B4D /* CircleView.swift */, C38EF23D255B6D66007E1867 /* UIView+OWS.h */, @@ -3061,14 +3189,6 @@ C38EF23C255B6D66007E1867 /* UIColor+OWS.h */, C38EF242255B6D67007E1867 /* UIColor+OWS.m */, C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */, - C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */, - C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */, - C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */, - C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */, - C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */, - C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */, - C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */, - C38EF380255B6DD0007E1867 /* AttachmentTextView.swift */, C38EF358255B6DCC007E1867 /* MediaMessageView.swift */, C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */, C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */, @@ -3101,20 +3221,6 @@ C38EF3D8255B6DF0007E1867 /* OWSTextView.h */, C38EF3DF255B6DF2007E1867 /* OWSTextView.m */, C38EF3E9255B6DF6007E1867 /* Toast.swift */, - C38EF3B1255B6DE5007E1867 /* ImageEditorBrushViewController.swift */, - C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */, - C38EF3B4255B6DE6007E1867 /* ImageEditorContents.swift */, - C38EF3B0255B6DE5007E1867 /* ImageEditorCropViewController.swift */, - C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */, - C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */, - C38EF3B2255B6DE5007E1867 /* ImageEditorPaletteView.swift */, - C38EF3AC255B6DE4007E1867 /* ImageEditorPanGestureRecognizer.swift */, - C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */, - C38EF3AB255B6DE4007E1867 /* ImageEditorStrokeItem.swift */, - C38EF3B3255B6DE6007E1867 /* ImageEditorTextItem.swift */, - C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */, - C38EF3AD255B6DE4007E1867 /* ImageEditorTransform.swift */, - C38EF3AF255B6DE5007E1867 /* ImageEditorView.swift */, C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */, C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */, C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */, @@ -3187,6 +3293,8 @@ C38BBA0C255E32020041B9A3 /* Threads */ = { isa = PBXGroup; children = ( + C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, + C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, B8C2B33B2563770800551B4D /* ThreadUtil.h */, B8C2B331256376F000551B4D /* ThreadUtil.m */, C33FDAB3255A580000E217F9 /* TSContactThread.h */, @@ -3223,54 +3331,12 @@ C38BBA0E255E32440041B9A3 /* Database */ = { isa = PBXGroup; children = ( - C33FDB36255A580B00E217F9 /* Storage.swift */, - B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */, - B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */, - B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */, - B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */, - B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */, - C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, - C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */, - C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */, - C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */, - C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, - C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, - C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, - C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, - C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, - C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, - C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, - C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */, - C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */, - C33FDB46255A580C00E217F9 /* TSDatabaseView.m */, - C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, - C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, - C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, - C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, - C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, - C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */, - C38EF26D255B6D79007E1867 /* OWSDatabaseMigrationRunner.m */, - C38EF26E255B6D79007E1867 /* OWSResaveCollectionDBMigration.h */, - C38EF26C255B6D79007E1867 /* OWSResaveCollectionDBMigration.m */, - C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, - C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, - C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */, - C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */, - C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */, - C33FDB50255A580D00E217F9 /* OWSPrimaryStorage+PreKeyStore.m */, - C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */, - C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */, - C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */, - C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */, - C33FDAFE255A580600E217F9 /* OWSStorage.h */, - C33FDAB1255A580000E217F9 /* OWSStorage.m */, - C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */, - C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */, - C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, - C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, - C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, - C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */, - C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */, + C379DCD6256732CE0002D4EB /* Keychain */, + C379DCE82567330E0002D4EB /* Migration */, + C379DCC5256732B00002D4EB /* OWSStorage */, + C379DCC3256732800002D4EB /* Storage */, + C379DCE7256732EF0002D4EB /* Utilities */, + C379DCC4256732980002D4EB /* YapDatabase */, ); path = Database; sourceTree = ""; @@ -3650,8 +3716,6 @@ C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */, - C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, - C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, C33FDC16255A581E00E217F9 /* FunctionalUtil.h */, C33FDB17255A580800E217F9 /* FunctionalUtil.m */, C33FDB8F255A581200E217F9 /* ParamParser.swift */, diff --git a/SignalUtilitiesKit/CreatePreKeysOperation.swift b/SignalUtilitiesKit/CreatePreKeysOperation.swift index cda43567c..aa342c29e 100644 --- a/SignalUtilitiesKit/CreatePreKeysOperation.swift +++ b/SignalUtilitiesKit/CreatePreKeysOperation.swift @@ -27,7 +27,7 @@ public class CreatePreKeysOperation: OWSOperation { signedPreKeyRecord.markAsAcceptedByService() storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - print("[Loki] Pre keys created successfully.") + SNLog("Pre keys created successfully.") reportSuccess() } } diff --git a/SignalUtilitiesKit/Database/SSKKeychainStorage.swift b/SignalUtilitiesKit/Database/Keychain/SSKKeychainStorage.swift similarity index 100% rename from SignalUtilitiesKit/Database/SSKKeychainStorage.swift rename to SignalUtilitiesKit/Database/Keychain/SSKKeychainStorage.swift diff --git a/SignalUtilitiesKit/Database/OWSDatabaseMigration.h b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSDatabaseMigration.h rename to SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h diff --git a/SignalUtilitiesKit/Database/OWSDatabaseMigration.m b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSDatabaseMigration.m rename to SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m diff --git a/SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.h b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.h rename to SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.h diff --git a/SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSDatabaseMigrationRunner.m rename to SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m diff --git a/SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.h b/SignalUtilitiesKit/Database/Migration/OWSResaveCollectionDBMigration.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.h rename to SignalUtilitiesKit/Database/Migration/OWSResaveCollectionDBMigration.h diff --git a/SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.m b/SignalUtilitiesKit/Database/Migration/OWSResaveCollectionDBMigration.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSResaveCollectionDBMigration.m rename to SignalUtilitiesKit/Database/Migration/OWSResaveCollectionDBMigration.m diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.h b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.h rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.h diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.m b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.m rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.m diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.h diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.m b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.m rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.m diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.h b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.h rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.h diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.m b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.m rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.m diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.h b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.h rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.h diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.m b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.m rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.m diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage.h b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage.h rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.h diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage.m b/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSPrimaryStorage.m rename to SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.m diff --git a/SignalUtilitiesKit/Database/OWSStorage.h b/SignalUtilitiesKit/Database/OWSStorage/OWSStorage.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage.h rename to SignalUtilitiesKit/Database/OWSStorage/OWSStorage.h diff --git a/SignalUtilitiesKit/Database/OWSStorage.m b/SignalUtilitiesKit/Database/OWSStorage/OWSStorage.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage.m rename to SignalUtilitiesKit/Database/OWSStorage/OWSStorage.m diff --git a/SignalUtilitiesKit/Database/Storage+ClosedGroups.swift b/SignalUtilitiesKit/Database/Storage/Storage+ClosedGroups.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+ClosedGroups.swift rename to SignalUtilitiesKit/Database/Storage/Storage+ClosedGroups.swift diff --git a/SignalUtilitiesKit/Database/Storage+Jobs.swift b/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+Jobs.swift rename to SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift diff --git a/SignalUtilitiesKit/Database/Storage+Messaging.swift b/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+Messaging.swift rename to SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift diff --git a/SignalUtilitiesKit/Database/Storage+OnionRequests.swift b/SignalUtilitiesKit/Database/Storage/Storage+OnionRequests.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+OnionRequests.swift rename to SignalUtilitiesKit/Database/Storage/Storage+OnionRequests.swift diff --git a/SignalUtilitiesKit/Database/Storage+OpenGroups.swift b/SignalUtilitiesKit/Database/Storage/Storage+OpenGroups.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+OpenGroups.swift rename to SignalUtilitiesKit/Database/Storage/Storage+OpenGroups.swift diff --git a/SignalUtilitiesKit/Database/Storage+SessionManagement.swift b/SignalUtilitiesKit/Database/Storage/Storage+SessionManagement.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+SessionManagement.swift rename to SignalUtilitiesKit/Database/Storage/Storage+SessionManagement.swift diff --git a/SignalUtilitiesKit/Database/Storage+Shared.swift b/SignalUtilitiesKit/Database/Storage/Storage+Shared.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+Shared.swift rename to SignalUtilitiesKit/Database/Storage/Storage+Shared.swift diff --git a/SignalUtilitiesKit/Database/Storage+SnodeAPI.swift b/SignalUtilitiesKit/Database/Storage/Storage+SnodeAPI.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+SnodeAPI.swift rename to SignalUtilitiesKit/Database/Storage/Storage+SnodeAPI.swift diff --git a/SignalUtilitiesKit/Database/Storage+VolumeSamples.swift b/SignalUtilitiesKit/Database/Storage/Storage+VolumeSamples.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage+VolumeSamples.swift rename to SignalUtilitiesKit/Database/Storage/Storage+VolumeSamples.swift diff --git a/SignalUtilitiesKit/Database/Storage.swift b/SignalUtilitiesKit/Database/Storage/Storage.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage.swift rename to SignalUtilitiesKit/Database/Storage/Storage.swift diff --git a/SignalUtilitiesKit/Database/OWSStorage+Subclass.h b/SignalUtilitiesKit/Database/Utilities/OWSStorage+Subclass.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage+Subclass.h rename to SignalUtilitiesKit/Database/Utilities/OWSStorage+Subclass.h diff --git a/SignalUtilitiesKit/Database/SSKPreferences.swift b/SignalUtilitiesKit/Database/Utilities/SSKPreferences.swift similarity index 100% rename from SignalUtilitiesKit/Database/SSKPreferences.swift rename to SignalUtilitiesKit/Database/Utilities/SSKPreferences.swift diff --git a/SignalUtilitiesKit/Database/SignalKeyingStorage.h b/SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.h similarity index 100% rename from SignalUtilitiesKit/Database/SignalKeyingStorage.h rename to SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.h diff --git a/SignalUtilitiesKit/Database/SignalKeyingStorage.m b/SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.m similarity index 100% rename from SignalUtilitiesKit/Database/SignalKeyingStorage.m rename to SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.m diff --git a/SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.h b/SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.h similarity index 100% rename from SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.h rename to SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.h diff --git a/SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.m b/SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.m similarity index 100% rename from SignalUtilitiesKit/Database/TSDatabaseSecondaryIndexes.m rename to SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.m diff --git a/SignalUtilitiesKit/Database/TSDatabaseView.h b/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.h similarity index 100% rename from SignalUtilitiesKit/Database/TSDatabaseView.h rename to SignalUtilitiesKit/Database/Utilities/TSDatabaseView.h diff --git a/SignalUtilitiesKit/Database/TSDatabaseView.m b/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m similarity index 100% rename from SignalUtilitiesKit/Database/TSDatabaseView.m rename to SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m diff --git a/SignalUtilitiesKit/Database/TSStorageHeaders.h b/SignalUtilitiesKit/Database/Utilities/TSStorageHeaders.h similarity index 100% rename from SignalUtilitiesKit/Database/TSStorageHeaders.h rename to SignalUtilitiesKit/Database/Utilities/TSStorageHeaders.h diff --git a/SignalUtilitiesKit/Database/TSStorageKeys.h b/SignalUtilitiesKit/Database/Utilities/TSStorageKeys.h similarity index 100% rename from SignalUtilitiesKit/Database/TSStorageKeys.h rename to SignalUtilitiesKit/Database/Utilities/TSStorageKeys.h diff --git a/SignalUtilitiesKit/Database/ThreadViewHelper.h b/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.h similarity index 100% rename from SignalUtilitiesKit/Database/ThreadViewHelper.h rename to SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.h diff --git a/SignalUtilitiesKit/Database/ThreadViewHelper.m b/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m similarity index 100% rename from SignalUtilitiesKit/Database/ThreadViewHelper.m rename to SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m diff --git a/SignalUtilitiesKit/Database/TSYapDatabaseObject.h b/SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.h similarity index 100% rename from SignalUtilitiesKit/Database/TSYapDatabaseObject.h rename to SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.h diff --git a/SignalUtilitiesKit/Database/TSYapDatabaseObject.m b/SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.m similarity index 100% rename from SignalUtilitiesKit/Database/TSYapDatabaseObject.m rename to SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.m diff --git a/SignalUtilitiesKit/Database/YapDatabase+Promise.swift b/SignalUtilitiesKit/Database/YapDatabase/YapDatabase+Promise.swift similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabase+Promise.swift rename to SignalUtilitiesKit/Database/YapDatabase/YapDatabase+Promise.swift diff --git a/SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.h b/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.h similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.h rename to SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.h diff --git a/SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.m b/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.m similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabaseConnection+OWS.m rename to SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.m diff --git a/SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.h b/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.h similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.h rename to SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.h diff --git a/SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.m b/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.m similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabaseTransaction+OWS.m rename to SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.m diff --git a/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift b/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift index 50271146c..720723ca9 100644 --- a/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift +++ b/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift @@ -15,11 +15,11 @@ public final class SessionRestorationImplementation : NSObject, SessionRestorati public func validatePreKeyWhisperMessage(for publicKey: String, preKeyWhisperMessage: PreKeyWhisperMessage, using transaction: Any) throws { guard let transaction = transaction as? YapDatabaseReadTransaction else { return } guard let storedPreKey = storage.getPreKeyRecord(forContact: publicKey, transaction: transaction) else { - print("[Loki] Missing pre key bundle.") + SNLog("Missing pre key bundle.") throw Error.missingPreKey } guard storedPreKey.id == preKeyWhisperMessage.prekeyID else { - print("[Loki] Received a PreKeyWhisperMessage from an unknown source.") + SNLog("Received a PreKeyWhisperMessage from an unknown source.") throw Error.invalidPreKeyID } } @@ -36,7 +36,7 @@ public final class SessionRestorationImplementation : NSObject, SessionRestorati guard let transaction = transaction as? YapDatabaseReadWriteTransaction else { return } guard !publicKey.isEmpty else { return } guard let thread = TSContactThread.getWithContactId(publicKey, transaction: transaction) else { - return print("[Loki] A new session was adopted but the thread couldn't be found for: \(publicKey).") + return SNLog("A new session was adopted but the thread couldn't be found for: \(publicKey).") } // Notify the user let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetDone) diff --git a/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift b/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift index 6e6274307..560440b66 100644 --- a/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift +++ b/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift @@ -27,15 +27,15 @@ public final class PushNotificationAPI : NSObject { let promise: Promise = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in guard let json = response["body"] as? JSON else { - return print("[Loki] Couldn't unregister from push notifications.") + return SNLog("Couldn't unregister from push notifications.") } guard json["code"] as? Int != 0 else { - return print("[Loki] Couldn't unregister from push notifications due to error: \(json["message"] as? String ?? "nil").") + return SNLog("Couldn't unregister from push notifications due to error: \(json["message"] as? String ?? "nil").") } } } promise.catch2 { error in - print("[Loki] Couldn't unregister from push notifications.") + SNLog("Couldn't unregister from push notifications.") } // Unsubscribe from all closed groups Storage.shared.getUserClosedGroupPublicKeys().forEach { closedGroup in @@ -56,7 +56,7 @@ public final class PushNotificationAPI : NSObject { let lastUploadTime = userDefaults[.lastDeviceTokenUpload] let now = Date().timeIntervalSince1970 guard isForcedUpdate || hexEncodedToken != oldToken || now - lastUploadTime > tokenExpirationInterval else { - print("[Loki] Device token hasn't changed or expired; no need to re-upload.") + SNLog("Device token hasn't changed or expired; no need to re-upload.") return Promise { $0.fulfill(()) } } let parameters = [ "token" : hexEncodedToken, "pubKey" : publicKey ] @@ -66,10 +66,10 @@ public final class PushNotificationAPI : NSObject { let promise: Promise = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in guard let json = response["body"] as? JSON else { - return print("[Loki] Couldn't register device token.") + return SNLog("Couldn't register device token.") } guard json["code"] as? Int != 0 else { - return print("[Loki] Couldn't register device token due to error: \(json["message"] as? String ?? "nil").") + return SNLog("Couldn't register device token due to error: \(json["message"] as? String ?? "nil").") } userDefaults[.deviceToken] = hexEncodedToken userDefaults[.lastDeviceTokenUpload] = now @@ -77,7 +77,7 @@ public final class PushNotificationAPI : NSObject { } } promise.catch2 { error in - print("[Loki] Couldn't register device token.") + SNLog("Couldn't register device token.") } // Subscribe to all closed groups Storage.shared.getUserClosedGroupPublicKeys().forEach { closedGroup in @@ -102,15 +102,15 @@ public final class PushNotificationAPI : NSObject { let promise: Promise = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in guard let json = response["body"] as? JSON else { - return print("[Loki] Couldn't subscribe/unsubscribe closed group: \(closedGroupPublicKey).") + return SNLog("Couldn't subscribe/unsubscribe closed group: \(closedGroupPublicKey).") } guard json["code"] as? Int != 0 else { - return print("[Loki] Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey) due to error: \(json["message"] as? String ?? "nil").") + return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey) due to error: \(json["message"] as? String ?? "nil").") } } } promise.catch2 { error in - print("[Loki] Couldn't subscribe/unsubscribe closed group: \(closedGroupPublicKey).") + SNLog("Couldn't subscribe/unsubscribe closed group: \(closedGroupPublicKey).") } return promise } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift index afffd9bed..d8effed4e 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift @@ -58,7 +58,7 @@ public final class ClosedGroupPoller : NSObject { promise.done2 { [weak self] messages in guard let self = self, self.isPolling else { return } if !messages.isEmpty { - print("[Loki] Received \(messages.count) new message(s) in closed group with public key: \(publicKey).") + SNLog("Received \(messages.count) new message(s) in closed group with public key: \(publicKey).") } messages.forEach { json in guard let envelope = SNProtoEnvelope.from(json) else { return } @@ -69,12 +69,12 @@ public final class ClosedGroupPoller : NSObject { SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } } catch { - print("[Loki] Failed to deserialize envelope due to error: \(error).") + SNLog("Failed to deserialize envelope due to error: \(error).") } } } promise.catch2 { error in - print("[Loki] Polling failed for closed group with public key: \(publicKey) due to error: \(error).") + SNLog("Polling failed for closed group with public key: \(publicKey) due to error: \(error).") } return promise.map { _ in } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift index bcdac1a30..84eb02a3f 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift @@ -217,12 +217,12 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver // Get the group let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - return print("[Loki] Ignoring closed group info message for nonexistent group.") + return SNLog("Ignoring closed group info message for nonexistent group.") } let group = thread.groupModel // Check that the sender is a member of the group (before the update) guard Set(group.groupMemberIds).contains(message.sender!) else { - return print("[Loki] Ignoring closed group info message from non-member.") + return SNLog("Ignoring closed group info message from non-member.") } // Store the ratchets for any new members (it's important that this happens before the code below) senderKeys.forEach { senderKey in @@ -279,16 +279,16 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver let groupPublicKey = groupPublicKeyAsData.toHexString() let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) guard let groupThread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - return print("[Loki] Ignoring closed group sender key request for nonexistent group.") + return SNLog("Ignoring closed group sender key request for nonexistent group.") } let group = groupThread.groupModel // Check that the requesting user is a member of the group let members = Set(group.groupMemberIds) guard members.contains(message.sender!) else { - return print("[Loki] Ignoring closed group sender key request from non-member.") + return SNLog("Ignoring closed group sender key request from non-member.") } // Respond to the request - print("[Loki] Responding to sender key request from: \(message.sender!).") + SNLog("Responding to sender key request from: \(message.sender!).") SessionManagementProtocol.sendSessionRequestIfNeeded(to: message.sender!, using: transaction) let userRatchet = Storage.shared.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey) ?? SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) @@ -305,10 +305,10 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver guard case let .senderKey(groupPublicKeyAsData, senderKey) = message.kind else { return } let groupPublicKey = groupPublicKeyAsData.toHexString() guard senderKey.publicKey.toHexString() == message.sender! else { - return print("[Loki] Ignoring invalid closed group sender key.") + return SNLog("Ignoring invalid closed group sender key.") } // Store the sender key - print("[Loki] Received a sender key from: \(message.sender!).") + SNLog("Received a sender key from: \(message.sender!).") let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: message.sender!, ratchet: ratchet, using: transaction) } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index 4ddc84b2d..affbd632f 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -9,7 +9,7 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele } public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { - print("[Loki] Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") + SNLog("Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") let transaction = transaction as! YapDatabaseReadWriteTransaction let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) thread.save(with: transaction) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift index 9a819c981..c02223ceb 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift @@ -30,13 +30,13 @@ public final class Poller : NSObject { // MARK: Public API @objc public func startIfNeeded() { guard !isPolling else { return } - print("[Loki] Started polling.") + SNLog("Started polling.") isPolling = true setUpPolling() } @objc public func stop() { - print("[Loki] Stopped polling.") + SNLog("Stopped polling.") isPolling = false usedSnodes.removeAll() } @@ -73,7 +73,7 @@ public final class Poller : NSObject { if let error = error as? Error, error == .pollLimitReached { self?.pollCount = 0 } else { - print("[Loki] Polling \(nextSnode) failed; dropping it and switching to next snode.") + SNLog("Polling \(nextSnode) failed; dropping it and switching to next snode.") SnodeAPI.dropSnodeFromSwarmIfNeeded(nextSnode, publicKey: userPublicKey) } self?.pollNextSnode(seal: seal) @@ -90,7 +90,7 @@ public final class Poller : NSObject { guard let strongSelf = self, strongSelf.isPolling else { return Promise { $0.fulfill(()) } } let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: userPublicKey) if !messages.isEmpty { - print("[Loki] Received \(messages.count) new message(s).") + SNLog("Received \(messages.count) new message(s).") } messages.forEach { json in guard let envelope = SNProtoEnvelope.from(json) else { return } @@ -101,7 +101,7 @@ public final class Poller : NSObject { SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } } catch { - print("[Loki] Failed to deserialize envelope due to error: \(error).") + SNLog("Failed to deserialize envelope due to error: \(error).") } } strongSelf.pollCount += 1 diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift index 724b2698f..b186b8cf5 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift @@ -3,11 +3,11 @@ public extension SNProtoEnvelope { static func from(_ json: JSON) -> SNProtoEnvelope? { guard let base64EncodedData = json["data"] as? String, let data = Data(base64Encoded: base64EncodedData) else { - print("[Loki] Failed to decode data for message: \(json).") + SNLog("Failed to decode data for message: \(json).") return nil } guard let result = try? MessageWrapper.unwrap(data: data) else { - print("[Loki] Failed to unwrap data for message: \(json).") + SNLog("Failed to unwrap data for message: \(json).") return nil } return result diff --git a/SignalUtilitiesKit/OWSUDManager.swift b/SignalUtilitiesKit/OWSUDManager.swift index 8dc897062..3e46d010f 100644 --- a/SignalUtilitiesKit/OWSUDManager.swift +++ b/SignalUtilitiesKit/OWSUDManager.swift @@ -446,7 +446,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { } return certificate } catch { - print("[Loki] Couldn't get UD sender certificate due to error: \(error).") + SNLog("Couldn't get UD sender certificate due to error: \(error).") return nil } } diff --git a/SignalUtilitiesKit/PreKeyRefreshOperation.swift b/SignalUtilitiesKit/PreKeyRefreshOperation.swift index 077dd841b..d313dbe30 100644 --- a/SignalUtilitiesKit/PreKeyRefreshOperation.swift +++ b/SignalUtilitiesKit/PreKeyRefreshOperation.swift @@ -37,7 +37,7 @@ public class RefreshPreKeysOperation: OWSOperation { storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) TSPreKeyManager.clearPreKeyUpdateFailureCount() TSPreKeyManager.clearSignedPreKeyRecords() - print("[Loki] Signed pre key refreshed successfully.") + SNLog("Signed pre key refreshed successfully.") self.reportSuccess() } } diff --git a/SignalUtilitiesKit/RotateSignedKeyOperation.swift b/SignalUtilitiesKit/RotateSignedKeyOperation.swift index 0142e69d7..c92d86453 100644 --- a/SignalUtilitiesKit/RotateSignedKeyOperation.swift +++ b/SignalUtilitiesKit/RotateSignedKeyOperation.swift @@ -27,7 +27,7 @@ public class RotateSignedPreKeyOperation: OWSOperation { storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) TSPreKeyManager.clearPreKeyUpdateFailureCount() TSPreKeyManager.clearSignedPreKeyRecords() - print("[Loki] Signed pre key rotated successfully.") + SNLog("Signed pre key rotated successfully.") self.reportSuccess() } } diff --git a/SignalUtilitiesKit/Utilities/LKGroupUtilities.h b/SignalUtilitiesKit/Threads/LKGroupUtilities.h similarity index 100% rename from SignalUtilitiesKit/Utilities/LKGroupUtilities.h rename to SignalUtilitiesKit/Threads/LKGroupUtilities.h diff --git a/SignalUtilitiesKit/Utilities/LKGroupUtilities.m b/SignalUtilitiesKit/Threads/LKGroupUtilities.m similarity index 100% rename from SignalUtilitiesKit/Utilities/LKGroupUtilities.m rename to SignalUtilitiesKit/Threads/LKGroupUtilities.m diff --git a/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift index 7e8bd651d..04acd3ead 100644 --- a/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift +++ b/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift @@ -89,7 +89,7 @@ public final class ClosedGroupsProtocol : NSObject { let userPublicKey = getUserHexEncodedPublicKey() let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - print("[Loki] Can't update nonexistent closed group.") + SNLog("Can't update nonexistent closed group.") return Promise(error: Error.noThread) } let group = thread.groupModel @@ -99,7 +99,7 @@ public final class ClosedGroupsProtocol : NSObject { let admins = group.groupAdminIds let adminsAsData = admins.map { Data(hex: $0) } guard let groupPrivateKey = Storage.shared.getClosedGroupPrivateKey(for: groupPublicKey) else { - print("[Loki] Couldn't get private key for closed group.") + SNLog("Couldn't get private key for closed group.") return Promise(error: Error.noPrivateKey) } let wasAnyUserRemoved = Set(members).intersection(oldMembers) != oldMembers @@ -108,7 +108,7 @@ public final class ClosedGroupsProtocol : NSObject { var newSenderKeys: [ClosedGroupSenderKey] = [] if wasAnyUserRemoved { if isUserLeaving && removedMembers.count != 1 { - print("[Loki] Can't remove self and others simultaneously.") + SNLog("Can't remove self and others simultaneously.") return Promise(error: Error.invalidUpdate) } // Establish sessions if needed @@ -223,7 +223,7 @@ public final class ClosedGroupsProtocol : NSObject { let userPublicKey = getUserHexEncodedPublicKey() let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - print("[Loki] Can't leave nonexistent closed group.") + SNLog("Can't leave nonexistent closed group.") return Promise(error: Error.noThread) } let group = thread.groupModel @@ -233,7 +233,7 @@ public final class ClosedGroupsProtocol : NSObject { } public static func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - print("[Loki] Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") + SNLog("Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") // Establish session if needed SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) // Send the request diff --git a/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift b/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift index 34ed9b386..bb0df42fd 100644 --- a/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift +++ b/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift @@ -26,7 +26,7 @@ public final class SessionManagementProtocol : NSObject { signedPreKeyRecord.markAsAcceptedByService() storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - print("[Loki] Pre keys created successfully.") + SNLog("Pre keys created successfully.") } @objc(refreshSignedPreKey) @@ -42,7 +42,7 @@ public final class SessionManagementProtocol : NSObject { storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) TSPreKeyManager.clearPreKeyUpdateFailureCount() TSPreKeyManager.clearSignedPreKeyRecords() - print("[Loki] Signed pre key refreshed successfully.") + SNLog("Signed pre key refreshed successfully.") } @objc(rotateSignedPreKey) @@ -55,7 +55,7 @@ public final class SessionManagementProtocol : NSObject { storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) TSPreKeyManager.clearPreKeyUpdateFailureCount() TSPreKeyManager.clearSignedPreKeyRecords() - print("[Loki] Signed pre key rotated successfully.") + SNLog("Signed pre key rotated successfully.") } // MARK: - Sending @@ -106,7 +106,7 @@ public final class SessionManagementProtocol : NSObject { let thread = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) thread.save(with: transaction) // Send the session request - print("[Loki] Sending session request to: \(publicKey).") + SNLog("Sending session request to: \(publicKey).") Storage.shared.setSessionRequestSentTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) let sessionRequest = SessionRequest() sessionRequest.preKeyBundle = storage.generatePreKeyBundle(forContact: publicKey) @@ -139,7 +139,7 @@ public final class SessionManagementProtocol : NSObject { public static func startSessionReset(in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { // // Check preconditions // guard let thread = thread as? TSContactThread else { -// return print("[Loki] Can't restore session for non contact thread.") +// return SNLog("Can't restore session for non contact thread.") // } // // Send end session messages to the devices requiring session restoration // let devices = thread.sessionRestoreDevices // TODO: Rename this to something that reads better @@ -195,12 +195,12 @@ public final class SessionManagementProtocol : NSObject { public static func handlePreKeyBundleMessageIfNeeded(_ protoContent: SNProtoContent, wrappedIn envelope: SNProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { // let publicKey = envelope.source! // Set during UD decryption // guard let preKeyBundleMessage = protoContent.prekeyBundleMessage else { return } -// print("[Loki] Received a pre key bundle message from: \(publicKey).") +// SNLog("Received a pre key bundle message from: \(publicKey).") // guard let preKeyBundle = preKeyBundleMessage.getPreKeyBundle(with: transaction) else { -// return print("[Loki] Couldn't parse pre key bundle received from: \(publicKey).") +// return SNLog("Couldn't parse pre key bundle received from: \(publicKey).") // } // if !shouldProcessSessionRequest(from: publicKey, at: envelope.timestamp) { -// return print("[Loki] Ignoring session request from: \(publicKey).") +// return SNLog("Ignoring session request from: \(publicKey).") // } // storage.setPreKeyBundle(preKeyBundle, forContact: publicKey, transaction: transaction) // Storage.setSessionRequestProcessedTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) @@ -210,7 +210,7 @@ public final class SessionManagementProtocol : NSObject { @objc(handleEndSessionMessageReceivedInThread:using:) public static func handleEndSessionMessageReceived(in thread: TSContactThread, using transaction: YapDatabaseReadWriteTransaction) { // let publicKey = thread.contactIdentifier() -// print("[Loki] End session message received from: \(publicKey).") +// SNLog("End session message received from: \(publicKey).") // // Notify the user // let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) // infoMessage.save(with: transaction) diff --git a/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift b/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift index 34db10ab7..a47c8e5ee 100644 --- a/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift +++ b/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift @@ -110,7 +110,7 @@ public final class SessionMetaProtocol : NSObject { public static func updateProfileKeyIfNeeded(for publicKey: String, using dataMessage: SNProtoDataMessage) { guard dataMessage.hasProfileKey, let profileKey = dataMessage.profileKey else { return } guard profileKey.count == kAES256_KeyByteLength else { - return print("[Loki] Unexpected profile key size: \(profileKey.count).") + return SNLog("Unexpected profile key size: \(profileKey.count).") } let profilePictureURL = dataMessage.profile?.profilePicture let profileManager = SSKEnvironment.shared.profileManager diff --git a/SignalUtilitiesKit/UI/AttachmentApprovalInputAccessoryView.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalInputAccessoryView.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentApprovalInputAccessoryView.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalInputAccessoryView.swift diff --git a/SignalUtilitiesKit/UI/AttachmentApprovalViewController.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalViewController.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentApprovalViewController.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalViewController.swift diff --git a/SignalUtilitiesKit/UI/AttachmentCaptionToolbar.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentCaptionToolbar.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentCaptionToolbar.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentCaptionToolbar.swift diff --git a/SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentCaptionViewController.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentCaptionViewController.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentCaptionViewController.swift diff --git a/SignalUtilitiesKit/UI/AttachmentItemCollection.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentItemCollection.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentItemCollection.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentItemCollection.swift diff --git a/SignalUtilitiesKit/UI/AttachmentPrepViewController.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentPrepViewController.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentPrepViewController.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentPrepViewController.swift diff --git a/SignalUtilitiesKit/UI/AttachmentTextToolbar.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentTextToolbar.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentTextToolbar.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentTextToolbar.swift diff --git a/SignalUtilitiesKit/UI/AttachmentTextView.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentTextView.swift similarity index 100% rename from SignalUtilitiesKit/UI/AttachmentTextView.swift rename to SignalUtilitiesKit/UI/Attachment Approval/AttachmentTextView.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorBrushViewController.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorBrushViewController.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorBrushViewController.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorBrushViewController.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorCanvasView.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorCanvasView.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorCanvasView.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorCanvasView.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorContents.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorContents.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorContents.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorContents.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorCropViewController.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorCropViewController.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorCropViewController.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorCropViewController.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorItem.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorItem.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorItem.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorItem.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorModel.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorModel.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorModel.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorModel.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorPaletteView.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorPaletteView.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorPaletteView.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorPaletteView.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorPanGestureRecognizer.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorPanGestureRecognizer.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorPanGestureRecognizer.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorPanGestureRecognizer.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorPinchGestureRecognizer.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorPinchGestureRecognizer.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorPinchGestureRecognizer.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorStrokeItem.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorStrokeItem.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorStrokeItem.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorStrokeItem.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorTextItem.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorTextItem.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorTextItem.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorTextItem.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorTextViewController.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorTextViewController.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorTextViewController.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorTextViewController.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorTransform.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorTransform.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorTransform.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorTransform.swift diff --git a/SignalUtilitiesKit/UI/ImageEditorView.swift b/SignalUtilitiesKit/UI/Image Editing/ImageEditorView.swift similarity index 100% rename from SignalUtilitiesKit/UI/ImageEditorView.swift rename to SignalUtilitiesKit/UI/Image Editing/ImageEditorView.swift From 961878f74c0d2680938ab44b233e60c07b463be6 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 20 Nov 2020 11:10:53 +1100 Subject: [PATCH 017/177] Parse attachment pointers --- .../Jobs/MessageReceiveJob.swift | 4 +- .../VisibleMessage+Attachment.swift | 60 +++++++++++++++++++ .../Visible Message/VisibleMessage.swift | 2 +- .../Sending & Receiving/MessageReceiver.swift | 16 +++-- .../MessageReceiverDelegate.swift | 1 + SessionMessagingKit/Storage.swift | 3 +- Signal.xcodeproj/project.pbxproj | 8 +++ .../Database/Storage/Storage+Messaging.swift | 8 +++ .../Attachments/Attachment+Conversion.swift | 22 +++++++ .../MessageReceiverDelegate.swift | 36 +++++++++++ 10 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 SessionMessagingKit/Messages/Visible Message/VisibleMessage+Attachment.swift create mode 100644 SignalUtilitiesKit/Messaging/Attachments/Attachment+Conversion.swift diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 13d8ee713..1049b8a11 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -39,8 +39,8 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self Threading.workQueue.async { do { - let message = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) - try MessageReceiver.handle(message, using: transaction) + let (message, proto) = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) + try MessageReceiver.handle(message, associatedWithProto: proto, using: transaction) self.handleSuccess() } catch { SNLog("Couldn't parse message due to error: \(error).") diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Attachment.swift b/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Attachment.swift new file mode 100644 index 000000000..96d180e68 --- /dev/null +++ b/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Attachment.swift @@ -0,0 +1,60 @@ +import CoreGraphics +import SessionUtilitiesKit + +public extension VisibleMessage { + + @objc(SNAttachment) + class Attachment : NSObject, NSCoding { + public var fileName: String? + public var contentType: String? + public var key: Data? + public var digest: Data? + public var kind: Kind? + public var caption: String? + public var size: CGSize? + public var sizeInBytes: UInt? + public var url: String? + + public var isValid: Bool { + fileName != nil && contentType != nil && key != nil && digest != nil && kind != nil && size != nil && sizeInBytes != nil && url != nil + } + + public enum Kind : String { + case voiceMessage, generic + } + + public override init() { super.init() } + + public required init?(coder: NSCoder) { + if let fileName = coder.decodeObject(forKey: "fileName") as! String? { self.fileName = fileName } + if let contentType = coder.decodeObject(forKey: "contentType") as! String? { self.contentType = contentType } + if let key = coder.decodeObject(forKey: "key") as! Data? { self.key = key } + if let digest = coder.decodeObject(forKey: "digest") as! Data? { self.digest = digest } + if let rawKind = coder.decodeObject(forKey: "kind") as! String? { self.kind = Kind(rawValue: rawKind) } + if let caption = coder.decodeObject(forKey: "caption") as! String? { self.caption = caption } + if let size = coder.decodeObject(forKey: "size") as! CGSize? { self.size = size } + if let sizeInBytes = coder.decodeObject(forKey: "sizeInBytes") as! UInt? { self.sizeInBytes = sizeInBytes } + if let url = coder.decodeObject(forKey: "url") as! String? { self.url = url } + } + + public func encode(with coder: NSCoder) { + coder.encode(fileName, forKey: "fileName") + coder.encode(contentType, forKey: "contentType") + coder.encode(key, forKey: "key") + coder.encode(digest, forKey: "digest") + coder.encode(kind?.rawValue, forKey: "kind") + coder.encode(caption, forKey: "caption") + coder.encode(size, forKey: "size") + coder.encode(sizeInBytes, forKey: "sizeInBytes") + coder.encode(url, forKey: "url") + } + + public static func fromProto(_ proto: SNProtoAttachmentPointer) -> Attachment? { + preconditionFailure("Use MessageReceiverDelegate.parseAttachments(from:) instead.") + } + + public func toProto() -> SNProtoDataMessageQuote? { + fatalError("Not implemented.") + } + } +} diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift index 05f6839d4..e0339d25f 100644 --- a/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift @@ -38,7 +38,7 @@ public final class VisibleMessage : Message { guard let dataMessage = proto.dataMessage else { return nil } let result = VisibleMessage() result.text = dataMessage.body - result.attachmentIDs = [] // TODO: Attachments + // Attachments are handled in MessageReceiver if let quoteProto = dataMessage.quote, let quote = Quote.fromProto(quoteProto) { result.quote = quote } if let linkPreviewProto = dataMessage.preview.first, let linkPreview = LinkPreview.fromProto(linkPreviewProto) { result.linkPreview = linkPreview } // TODO: Contact diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 2f9b3b4cc..b8917dd72 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -47,7 +47,7 @@ internal enum MessageReceiver { } } - internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> Message { + internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) // Decrypt the contents @@ -90,13 +90,13 @@ internal enum MessageReceiver { message.groupPublicKey = groupPublicKey message.openGroupServerMessageID = messageServerID guard message.isValid else { throw Error.invalidMessage } - return message + return (message, proto) } else { throw Error.unknownMessage } } - internal static func handle(_ message: Message, using transaction: Any) throws { + internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) case let message as SessionRequest: handleSessionRequest(message, using: transaction) @@ -104,7 +104,7 @@ internal enum MessageReceiver { case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) - case let message as VisibleMessage: try handleVisibleMessage(message, using: transaction) + case let message as VisibleMessage: try handleVisibleMessage(message, associatedWithProto: proto, using: transaction) default: fatalError() } } @@ -148,14 +148,18 @@ internal enum MessageReceiver { } } - private static func handleVisibleMessage(_ message: VisibleMessage, using transaction: Any) throws { + private static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { let delegate = Configuration.shared.messageReceiverDelegate + let storage = Configuration.shared.storage + // Handle attachments + let attachments = delegate.parseAttachments(from: proto.dataMessage!.attachments) + message.attachmentIDs = storage.save(attachments, using: transaction) // Update profile if needed if let profile = message.profile { delegate.updateProfile(for: message.sender!, from: profile, using: transaction) } // Persist the message - guard let (threadID, tsIncomingMessage) = Configuration.shared.storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + guard let (threadID, tsIncomingMessage) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } message.threadID = threadID // Cancel any typing indicators delegate.cancelTypingIndicatorsIfNeeded(for: message.sender!) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift index cba87224d..34e289e41 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift @@ -14,4 +14,5 @@ public protocol MessageReceiverDelegate { func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) + func parseAttachments(from protos: [SNProtoAttachmentPointer]) -> [VisibleMessage.Attachment] } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 42ce0351f..71b0d3fab 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -42,7 +42,6 @@ public protocol SessionMessagingKitStorageProtocol { func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any) // MARK: - Last Message Server ID - func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64? func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) func removeLastMessageServerID(for group: UInt64, on server: String, using transaction: Any) @@ -64,4 +63,6 @@ public protocol SessionMessagingKitStorageProtocol { /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, Any)? + /// Returns the IDs of the saved attachments. + func save(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 59f0a69de..ab725d155 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -585,6 +585,8 @@ C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = C35E8AAD2485E51D00ACB629 /* IP2Country.swift */; }; C3645350252449260045C478 /* VoiceMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C364534F252449260045C478 /* VoiceMessageView.swift */; }; C364535C252467900045C478 /* AudioUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C364535B252467900045C478 /* AudioUtilities.swift */; }; + C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */; }; + C379DCFE25673DBC0002D4EB /* Attachment+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */; }; C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F53A7255B96E0002AEA92 /* OWSAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1679,6 +1681,8 @@ C35E8AAD2485E51D00ACB629 /* IP2Country.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IP2Country.swift; sourceTree = ""; }; C364534F252449260045C478 /* VoiceMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageView.swift; sourceTree = ""; }; C364535B252467900045C478 /* AudioUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUtilities.swift; sourceTree = ""; }; + C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Attachment.swift"; sourceTree = ""; }; + C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Attachment+Conversion.swift"; sourceTree = ""; }; C37F53E8255BA9BB002AEA92 /* Environment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = ""; }; C37F5402255BA9ED002AEA92 /* Environment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = ""; }; C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SNProtoEnvelope+Conversion.swift"; sourceTree = ""; }; @@ -2631,6 +2635,7 @@ isa = PBXGroup; children = ( C3C2A74C2553A39700C340D1 /* VisibleMessage.swift */, + C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */, C3C2A7552553A3AB00C340D1 /* VisibleMessage+Quote.swift */, C3C2A75E2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift */, C3C2A7672553A3D900C340D1 /* VisibleMessage+Contact.swift */, @@ -3279,6 +3284,7 @@ C38BBA0B255E31EC0041B9A3 /* Attachments */ = { isa = PBXGroup; children = ( + C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */, C38EF224255B6D5D007E1867 /* SignalAttachment.swift */, C33FDC15255A581E00E217F9 /* TSAttachment.h */, C33FDAC2255A580200E217F9 /* TSAttachment.m */, @@ -4957,6 +4963,7 @@ C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */, C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */, C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */, + C379DCFE25673DBC0002D4EB /* Attachment+Conversion.swift in Sources */, C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */, C33FDCFB255A582000E217F9 /* MIMETypeUtil.m in Sources */, C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */, @@ -5263,6 +5270,7 @@ C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */, C3A721902558C0CD0043A11F /* FileServerAPI.swift in Sources */, C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */, + C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */, C3C2A7842553AAF300C340D1 /* SNProto.swift in Sources */, C3C2A7682553A3D900C340D1 /* VisibleMessage+Contact.swift in Sources */, C3A721392558BDFA0043A11F /* OpenGroupAPI.swift in Sources */, diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift b/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift index 50a4fe4bb..ca05b565c 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift +++ b/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift @@ -32,4 +32,12 @@ extension Storage { message.save(with: transaction) return (thread.uniqueId!, message) } + + public func save(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] { + return attachments.map { attachment in + let tsAttachment = TSAttachmentPointer.from(attachment) + tsAttachment.save(with: transaction as! YapDatabaseReadWriteTransaction) + return tsAttachment.uniqueId! + } + } } diff --git a/SignalUtilitiesKit/Messaging/Attachments/Attachment+Conversion.swift b/SignalUtilitiesKit/Messaging/Attachments/Attachment+Conversion.swift new file mode 100644 index 000000000..c4b595f90 --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Attachments/Attachment+Conversion.swift @@ -0,0 +1,22 @@ + +extension TSAttachmentPointer { + + public static func from(_ attachment: VisibleMessage.Attachment) -> TSAttachmentPointer { + let kind: TSAttachmentType + switch attachment.kind! { + case .generic: kind = .default + case .voiceMessage: kind = .voiceMessage + } + return TSAttachmentPointer( + serverId: 0, + key: attachment.key, + digest: attachment.digest, + byteCount: UInt32(attachment.sizeInBytes!), + contentType: attachment.contentType!, + sourceFilename: attachment.fileName, + caption: attachment.caption, + albumMessageId: nil, + attachmentType: kind, + mediaSize: attachment.size!) + } +} diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift index 84eb02a3f..a8efdb92a 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift @@ -312,4 +312,40 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: message.sender!, ratchet: ratchet, using: transaction) } + + + + // MARK: - Attachments + + public func parseAttachments(from protos: [SNProtoAttachmentPointer]) -> [VisibleMessage.Attachment] { + return protos.compactMap { proto in + let result = VisibleMessage.Attachment() + result.fileName = proto.fileName + func inferContentType() -> String { + guard let fileName = result.fileName, let fileExtension = URL(string: fileName)?.pathExtension else { return OWSMimeTypeApplicationOctetStream } + return MIMETypeUtil.mimeType(forFileExtension: fileExtension) ?? OWSMimeTypeApplicationOctetStream + } + result.contentType = proto.contentType ?? inferContentType() + result.key = proto.key + result.digest = proto.digest + let kind: VisibleMessage.Attachment.Kind + if proto.hasFlags && (proto.flags & UInt32(SNProtoAttachmentPointer.SNProtoAttachmentPointerFlags.voiceMessage.rawValue)) > 0 { + kind = .voiceMessage + } else { + kind = .generic + } + result.kind = kind + result.caption = proto.hasCaption ? proto.caption : nil + let size: CGSize + if proto.hasWidth && proto.width > 0 && proto.hasHeight && proto.height > 0 { + size = CGSize(width: Int(proto.width), height: Int(proto.height)) + } else { + size = CGSize.zero + } + result.size = size + result.sizeInBytes = proto.size > 0 ? UInt(proto.size) : nil + result.url = proto.url + return result.isValid ? result : nil + } + } } From b218a16b05d72e2e581e847b05aa48d4291953d3 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 20 Nov 2020 14:04:56 +1100 Subject: [PATCH 018/177] Implement attachment downloading --- Podfile | 4 + Podfile.lock | 2 +- Session/Meta/Signal-Bridging-Header.h | 4 +- .../Cells/AttachmentUploadView.m | 2 +- .../Cells/OWSGenericAttachmentView.m | 2 +- .../ConversationViewController.m | 2 +- Session/Signal/MainAppContext.h | 2 +- Session/Signal/OWSBackupExportJob.m | 2 +- Session/Signal/OWSBackupIO.m | 2 +- Session/Signal/OWSBackupImportJob.m | 2 +- .../Signal/OWSBackupSettingsViewController.m | 2 +- Session/Signal/OWSOrphanDataCleaner.m | 2 +- .../Jobs/AttachmentDownloadJob.swift | 70 ++++++- SessionMessagingKit/Jobs/JobQueue.swift | 6 +- .../ClosedGroupUpdate.swift | 0 .../ControlMessage.swift | 0 .../ExpirationTimerUpdate.swift | 0 .../ReadReceipt.swift | 0 .../TypingIndicator.swift | 0 .../Unused}/NullMessage.swift | 0 .../Unused}/SessionRequest.swift | 0 .../Attachments}/OWSThumbnailService.swift | 10 - .../Attachments/TSAttachment.h | 8 +- .../Attachments/TSAttachment.m | 48 +---- .../Attachments/TSAttachmentPointer.h | 15 +- .../Attachments/TSAttachmentPointer.m | 86 +------- .../Attachments/TSAttachmentStream.h | 10 +- .../Attachments/TSAttachmentStream.m | 86 +------- .../VisibleMessage+Attachment.swift | 31 ++- .../VisibleMessage+Contact.swift | 0 .../VisibleMessage+LinkPreview.swift | 0 .../VisibleMessage+Profile.swift | 0 .../VisibleMessage+Quote.swift | 0 .../VisibleMessage.swift | 0 .../Meta/SessionMessagingKit.h | 4 + .../Sending & Receiving/MessageReceiver.swift | 30 +-- .../MessageReceiverDelegate.swift | 1 - .../MessageSender+Encryption.swift | 6 +- .../Sending & Receiving/MessageSender.swift | 7 +- .../MessageSenderDelegate.swift | 1 + .../Utilities/AttachmentStream.swift | 12 -- SessionMessagingKit/Utilities/DotNetAPI.swift | 4 +- .../SignalShareExtension-Bridging-Header.h | 2 +- .../SAEScreenLockViewController.m | 2 +- .../ShareAppExtensionContext.h | 2 +- .../AppContext.h | 4 - .../AppContext.m | 10 - SessionUtilitiesKit/Configuration.swift | 20 ++ .../DataSource.h | 4 - .../DataSource.m | 69 +------ .../MIMETypeUtil.h | 4 - .../MIMETypeUtil.m | 15 +- .../Meta/SessionUtilitiesKit.h | 8 + .../NSData+Image.h | 4 - .../NSData+Image.m | 28 +-- .../OWSFileSystem.h | 6 +- .../OWSFileSystem.m | 99 ++------- .../OWSMediaUtils.swift | 32 ++- .../OWSPrimaryStorageProtocol.swift | 7 + .../Storage.swift | 5 +- .../TSYapDatabaseObject.h | 5 +- .../TSYapDatabaseObject.m | 25 +-- .../UIImage+OWS.h | 4 - .../UIImage+OWS.m | 22 -- Signal.xcodeproj/project.pbxproj | 192 ++++++++++-------- .../Migration/OWSDatabaseMigrationRunner.m | 2 +- .../Storage/Storage+Conformances.swift | 2 + .../Database/Utilities/ThreadViewHelper.m | 2 +- .../Messaging/Quotes/OWSQuotedReplyModel.m | 2 +- .../MessageReceiverDelegate.swift | 36 ---- .../MessageSenderDelegate.swift | 4 + SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 3 - SignalUtilitiesKit/OWSPreferences.m | 2 +- SignalUtilitiesKit/OWSSounds.m | 2 +- SignalUtilitiesKit/To Do/OWSProfileManager.m | 6 +- SignalUtilitiesKit/To Do/OWSUserProfile.m | 4 +- .../UI/SelectRecipientViewController.m | 2 +- SignalUtilitiesKit/UI/UIUtil.h | 2 +- SignalUtilitiesKit/UI/UIUtil.m | 2 +- SignalUtilitiesKit/UI/UIView+OWS.m | 2 +- SignalUtilitiesKit/UI/UIViewController+OWS.m | 2 +- .../Utilities/AttachmentSharing.m | 2 +- SignalUtilitiesKit/Utilities/DebugLogger.m | 4 +- .../Utilities/NSAttributedString+OWS.m | 2 +- SignalUtilitiesKit/Utilities/SSKAsserts.h | 2 +- SignalUtilitiesKit/VersionMigrations.m | 2 +- 86 files changed, 373 insertions(+), 746 deletions(-) rename SessionMessagingKit/Messages/{Control Message => Control Messages}/ClosedGroupUpdate.swift (100%) rename SessionMessagingKit/Messages/{Control Message => Control Messages}/ControlMessage.swift (100%) rename SessionMessagingKit/Messages/{Control Message => Control Messages}/ExpirationTimerUpdate.swift (100%) rename SessionMessagingKit/Messages/{Control Message => Control Messages}/ReadReceipt.swift (100%) rename SessionMessagingKit/Messages/{Control Message => Control Messages}/TypingIndicator.swift (100%) rename SessionMessagingKit/Messages/{Control Message => Control Messages/Unused}/NullMessage.swift (100%) rename SessionMessagingKit/Messages/{Control Message => Control Messages/Unused}/SessionRequest.swift (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Messages/Visible Messages/Attachments}/OWSThumbnailService.swift (96%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Messages/Visible Messages}/Attachments/TSAttachment.h (94%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Messages/Visible Messages}/Attachments/TSAttachment.m (80%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Messages/Visible Messages}/Attachments/TSAttachmentPointer.h (82%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Messages/Visible Messages}/Attachments/TSAttachmentPointer.m (72%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Messages/Visible Messages}/Attachments/TSAttachmentStream.h (94%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Messages/Visible Messages}/Attachments/TSAttachmentStream.m (87%) rename SessionMessagingKit/Messages/{Visible Message => Visible Messages/Attachments}/VisibleMessage+Attachment.swift (60%) rename SessionMessagingKit/Messages/{Visible Message => Visible Messages}/VisibleMessage+Contact.swift (100%) rename SessionMessagingKit/Messages/{Visible Message => Visible Messages}/VisibleMessage+LinkPreview.swift (100%) rename SessionMessagingKit/Messages/{Visible Message => Visible Messages}/VisibleMessage+Profile.swift (100%) rename SessionMessagingKit/Messages/{Visible Message => Visible Messages}/VisibleMessage+Quote.swift (100%) rename SessionMessagingKit/Messages/{Visible Message => Visible Messages}/VisibleMessage.swift (100%) delete mode 100644 SessionMessagingKit/Utilities/AttachmentStream.swift rename {SignalUtilitiesKit => SessionUtilitiesKit}/AppContext.h (98%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/AppContext.m (84%) create mode 100644 SessionUtilitiesKit/Configuration.swift rename {SignalUtilitiesKit => SessionUtilitiesKit}/DataSource.h (95%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/DataSource.m (76%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/MIMETypeUtil.h (97%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/MIMETypeUtil.m (99%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSData+Image.h (90%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSData+Image.m (90%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/OWSFileSystem.h (92%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/OWSFileSystem.m (71%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/OWSMediaUtils.swift (76%) create mode 100644 SessionUtilitiesKit/OWSPrimaryStorageProtocol.swift rename {SignalUtilitiesKit/Database/Storage => SessionUtilitiesKit}/Storage.swift (92%) rename {SignalUtilitiesKit/Database/YapDatabase => SessionUtilitiesKit}/TSYapDatabaseObject.h (98%) rename {SignalUtilitiesKit/Database/YapDatabase => SessionUtilitiesKit}/TSYapDatabaseObject.m (92%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/UIImage+OWS.h (88%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/UIImage+OWS.m (91%) create mode 100644 SignalUtilitiesKit/Database/Storage/Storage+Conformances.swift diff --git a/Podfile b/Podfile index caf6d4ca6..ea1aa18d9 100644 --- a/Podfile +++ b/Podfile @@ -69,9 +69,11 @@ target 'SessionMessagingKit' do pod 'AFNetworking', inhibit_warnings: true pod 'CryptoSwift', :inhibit_warnings => true pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true + pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'SwiftProtobuf', '~> 1.5.0', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true end target 'SessionProtocolKit' do @@ -95,8 +97,10 @@ end target 'SessionUtilitiesKit' do pod 'CryptoSwift', :inhibit_warnings => true pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true + pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true end post_install do |installer| diff --git a/Podfile.lock b/Podfile.lock index 54a6863c1..4f46bd158 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 3489ed70ea51f2bf705bf99703efc71d697de373 +PODFILE CHECKSUM: 62df79698293257648cb6e60724f720f8477bd0f COCOAPODS: 1.10.0.rc.1 diff --git a/Session/Meta/Signal-Bridging-Header.h b/Session/Meta/Signal-Bridging-Header.h index 54ffdc4b2..a22e34763 100644 --- a/Session/Meta/Signal-Bridging-Header.h +++ b/Session/Meta/Signal-Bridging-Header.h @@ -64,7 +64,7 @@ #import #import #import -#import +#import #import #import #import @@ -72,7 +72,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/ConversationView/Cells/AttachmentUploadView.m b/Session/Signal/ConversationView/Cells/AttachmentUploadView.m index 96c1b1223..4b74b21ef 100644 --- a/Session/Signal/ConversationView/Cells/AttachmentUploadView.m +++ b/Session/Signal/ConversationView/Cells/AttachmentUploadView.m @@ -7,7 +7,7 @@ #import "OWSProgressView.h" #import #import -#import +#import #import #import diff --git a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m index 5782c329d..b80503e03 100644 --- a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m +++ b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m @@ -10,7 +10,7 @@ #import #import -#import +#import #import #import #import diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 2536714be..3917855a8 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -50,7 +50,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/MainAppContext.h b/Session/Signal/MainAppContext.h index 039b069ef..a5c0ac97e 100644 --- a/Session/Signal/MainAppContext.h +++ b/Session/Signal/MainAppContext.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSBackupExportJob.m b/Session/Signal/OWSBackupExportJob.m index 46dcb1b99..fdcba1c38 100644 --- a/Session/Signal/OWSBackupExportJob.m +++ b/Session/Signal/OWSBackupExportJob.m @@ -12,7 +12,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/OWSBackupIO.m b/Session/Signal/OWSBackupIO.m index ed581e2dd..ef95733e0 100644 --- a/Session/Signal/OWSBackupIO.m +++ b/Session/Signal/OWSBackupIO.m @@ -4,7 +4,7 @@ #import "OWSBackupIO.h" #import -#import +#import @import Compression; diff --git a/Session/Signal/OWSBackupImportJob.m b/Session/Signal/OWSBackupImportJob.m index 17c857fa5..6c58e9d07 100644 --- a/Session/Signal/OWSBackupImportJob.m +++ b/Session/Signal/OWSBackupImportJob.m @@ -10,7 +10,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/OWSBackupSettingsViewController.m b/Session/Signal/OWSBackupSettingsViewController.m index d00b30a4d..1d27fff3e 100644 --- a/Session/Signal/OWSBackupSettingsViewController.m +++ b/Session/Signal/OWSBackupSettingsViewController.m @@ -13,7 +13,7 @@ #import #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSOrphanDataCleaner.m b/Session/Signal/OWSOrphanDataCleaner.m index 6d6e1e909..0ed5cc8b0 100644 --- a/Session/Signal/OWSOrphanDataCleaner.m +++ b/Session/Signal/OWSOrphanDataCleaner.m @@ -10,7 +10,7 @@ #import #import -#import +#import #import #import #import diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 58fb1758e..f7c6e4dad 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -1,29 +1,85 @@ +import Foundation import SessionUtilitiesKit - -// TODO: Implementation +import SignalCoreKit public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? + private let attachmentID: String public var id: String? public var failureCount: UInt = 0 + public enum Error : LocalizedError { + case noAttachment + + public var errorDescription: String? { + switch self { + case .noAttachment: return "No such attachment." + } + } + } + // MARK: Settings public class var collection: String { return "AttachmentDownloadJobCollection" } public static let maxFailureCount: UInt = 20 - // MARK: Coding - public init?(coder: NSCoder) { } + // MARK: Initialization + public init(attachmentID: String) { + self.attachmentID = attachmentID + } - public func encode(with coder: NSCoder) { } + // MARK: Coding + public init?(coder: NSCoder) { + guard let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String? else { return nil } + self.attachmentID = attachmentID + } + + public func encode(with coder: NSCoder) { + coder.encode(attachmentID, forKey: "attachmentID") + } // MARK: Running - public func execute() { } + public func execute() { + guard let pointer = TSAttachmentPointer.fetch(uniqueId: attachmentID) else { + return handleFailure(error: Error.noAttachment) + } + let temporaryFilePath = URL(fileURLWithPath: OWSTemporaryDirectoryAccessibleAfterFirstAuth() + UUID().uuidString) + FileServerAPI.downloadAttachment(from: pointer.downloadURL).done(on: DispatchQueue.global(qos: .userInitiated)) { data in // Intentionally capture self + do { + try data.write(to: temporaryFilePath, options: .atomic) + } catch { + return self.handleFailure(error: error) + } + let plaintext: Data + if let key = pointer.encryptionKey, let digest = pointer.digest { + do { + plaintext = try Cryptography.decryptAttachment(data, withKey: key, digest: digest, unpaddedSize: pointer.byteCount) + } catch { + return self.handleFailure(error: error) + } + } else { + plaintext = data // Open group attachments are unencrypted + } + let stream = TSAttachmentStream(pointer: pointer) + do { + try stream.write(plaintext) + } catch { + return self.handleFailure(error: error) + } + OWSFileSystem.deleteFile(temporaryFilePath.absoluteString) + Configuration.shared.storage.withAsync({ transaction in + stream.save(with: transaction as! YapDatabaseReadWriteTransaction) + // TODO: Update the message + }, completion: { }) + }.catch(on: DispatchQueue.global()) { error in + self.handleFailure(error: error) + } + } private func handleSuccess() { delegate?.handleJobSucceeded(self) } - private func handleFailure(error: Error) { + private func handleFailure(error: Swift.Error) { delegate?.handleJobFailed(self, with: error) } } diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 8b97a725a..f02dc971e 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -6,10 +6,14 @@ public final class JobQueue : NSObject, JobDelegate { @objc public static let shared = JobQueue() @objc public func add(_ job: Job, using transaction: Any) { + addWithoutExecuting(job, using: transaction) + job.execute() + } + + @objc public func addWithoutExecuting(_ job: Job, using transaction: Any) { job.id = String(NSDate.millisecondTimestamp()) Configuration.shared.storage.persist(job, using: transaction) job.delegate = self - job.execute() } @objc public func resumePendingJobs() { diff --git a/SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift similarity index 100% rename from SessionMessagingKit/Messages/Control Message/ClosedGroupUpdate.swift rename to SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift diff --git a/SessionMessagingKit/Messages/Control Message/ControlMessage.swift b/SessionMessagingKit/Messages/Control Messages/ControlMessage.swift similarity index 100% rename from SessionMessagingKit/Messages/Control Message/ControlMessage.swift rename to SessionMessagingKit/Messages/Control Messages/ControlMessage.swift diff --git a/SessionMessagingKit/Messages/Control Message/ExpirationTimerUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift similarity index 100% rename from SessionMessagingKit/Messages/Control Message/ExpirationTimerUpdate.swift rename to SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift diff --git a/SessionMessagingKit/Messages/Control Message/ReadReceipt.swift b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift similarity index 100% rename from SessionMessagingKit/Messages/Control Message/ReadReceipt.swift rename to SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift diff --git a/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift b/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift similarity index 100% rename from SessionMessagingKit/Messages/Control Message/TypingIndicator.swift rename to SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift diff --git a/SessionMessagingKit/Messages/Control Message/NullMessage.swift b/SessionMessagingKit/Messages/Control Messages/Unused/NullMessage.swift similarity index 100% rename from SessionMessagingKit/Messages/Control Message/NullMessage.swift rename to SessionMessagingKit/Messages/Control Messages/Unused/NullMessage.swift diff --git a/SessionMessagingKit/Messages/Control Message/SessionRequest.swift b/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift similarity index 100% rename from SessionMessagingKit/Messages/Control Message/SessionRequest.swift rename to SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift diff --git a/SignalUtilitiesKit/OWSThumbnailService.swift b/SessionMessagingKit/Messages/Visible Messages/Attachments/OWSThumbnailService.swift similarity index 96% rename from SignalUtilitiesKit/OWSThumbnailService.swift rename to SessionMessagingKit/Messages/Visible Messages/Attachments/OWSThumbnailService.swift index d65a502d5..0b6601fc2 100644 --- a/SignalUtilitiesKit/OWSThumbnailService.swift +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/OWSThumbnailService.swift @@ -75,12 +75,6 @@ private struct OWSThumbnailRequest { // arrive so that we prioritize the most recent view state. private var thumbnailRequestStack = [OWSThumbnailRequest]() - private override init() { - super.init() - - SwiftSingletons.register(self) - } - private func canThumbnailAttachment(attachment: TSAttachmentStream) -> Bool { return attachment.isImage || attachment.isAnimated || attachment.isVideo } @@ -117,8 +111,6 @@ private struct OWSThumbnailRequest { thumbnailRequest.success(loadedThumbnail) } } catch { - Logger.error("Could not create thumbnail: \(error)") - DispatchQueue.global().async { thumbnailRequest.failure(error) } @@ -146,8 +138,6 @@ private struct OWSThumbnailRequest { return OWSLoadedThumbnail(image: image, filePath: thumbnailPath) } - Logger.verbose("Creating thumbnail of size: \(thumbnailRequest.thumbnailDimensionPoints)") - let thumbnailDirPath = (thumbnailPath as NSString).deletingLastPathComponent guard OWSFileSystem.ensureDirectoryExists(thumbnailDirPath) else { throw OWSThumbnailError.failure(description: "Could not create attachment's thumbnail directory.") diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment.h b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h similarity index 94% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachment.h rename to SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h index 2beefa705..3e67f5f08 100644 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment.h +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h @@ -1,13 +1,8 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import +#import NS_ASSUME_NONNULL_BEGIN @class TSAttachmentPointer; -@class TSMessage; typedef NS_ENUM(NSUInteger, TSAttachmentType) { TSAttachmentTypeDefault = 0, @@ -45,7 +40,6 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { @property (nonatomic, readonly, nullable) NSString *caption; @property (nonatomic, nullable) NSString *albumMessageId; -- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction; // `migrateAlbumMessageId` is only used in the migration to the new multi-attachment message scheme, // and shouldn't be used as a general purpose setter. Instead, `albumMessageId` should be passed as diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment.m b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m similarity index 80% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachment.m rename to SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m index fcb08527f..43c7139b5 100644 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment.m +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m @@ -1,13 +1,7 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import "TSAttachment.h" #import "MIMETypeUtil.h" -#import "NSString+SSK.h" #import "TSAttachmentPointer.h" -#import "TSMessage.h" -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -16,9 +10,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; @interface TSAttachment () @property (nonatomic, readonly) NSUInteger attachmentSchemaVersion; - @property (nonatomic, nullable) NSString *sourceFilename; - @property (nonatomic) NSString *contentType; @end @@ -35,17 +27,9 @@ NSUInteger const TSAttachmentSchemaVersion = 4; caption:(nullable NSString *)caption albumMessageId:(nullable NSString *)albumMessageId { - OWSAssertDebug(serverId > 0); - if (byteCount <= 0) { - // This will fail with legacy iOS clients which don't upload attachment size. - OWSLogWarn(@"Missing byteCount for attachment with serverId: %lld", serverId); - } if (contentType.length < 1) { - OWSLogWarn(@"incoming attachment has invalid content type"); - contentType = OWSMimeTypeApplicationOctetStream; } - OWSAssertDebug(contentType.length > 0); self = [super init]; if (!self) { @@ -73,13 +57,9 @@ NSUInteger const TSAttachmentSchemaVersion = 4; caption:(nullable NSString *)caption albumMessageId:(nullable NSString *)albumMessageId { - OWSAssertDebug(uniqueId.length > 0); if (contentType.length < 1) { - OWSLogWarn(@"incoming attachment has invalid content type"); - contentType = OWSMimeTypeApplicationOctetStream; } - OWSAssertDebug(contentType.length > 0); // If saved, this AttachmentPointer would replace the AttachmentStream in the attachments collection. // However we only use this AttachmentPointer should only be used during the export process so it @@ -108,17 +88,13 @@ NSUInteger const TSAttachmentSchemaVersion = 4; albumMessageId:(nullable NSString *)albumMessageId { if (contentType.length < 1) { - OWSLogWarn(@"outgoing attachment has invalid content type"); - contentType = OWSMimeTypeApplicationOctetStream; } - OWSAssertDebug(contentType.length > 0); self = [super init]; if (!self) { return self; } - OWSLogVerbose(@"init attachment with uniqueId: %@", self.uniqueId); _contentType = contentType; _byteCount = byteCount; @@ -135,15 +111,6 @@ NSUInteger const TSAttachmentSchemaVersion = 4; // that represent downloaded incoming attachments. - (instancetype)initWithPointer:(TSAttachmentPointer *)pointer { - if (!pointer.lazyRestoreFragment) { - OWSAssertDebug(pointer.serverId > 0); - if (pointer.byteCount <= 0) { - // This will fail with legacy iOS clients which don't upload attachment size. - OWSLogWarn(@"Missing pointer.byteCount for attachment with serverId: %lld", pointer.serverId); - } - } - OWSAssertDebug(pointer.contentType.length > 0); - // Once saved, this AttachmentStream will replace the AttachmentPointer in the attachments collection. self = [super initWithUniqueId:pointer.uniqueId]; if (!self) { @@ -156,8 +123,6 @@ NSUInteger const TSAttachmentSchemaVersion = 4; _sourceFilename = pointer.sourceFilename; NSString *contentType = pointer.contentType; if (contentType.length < 1) { - OWSLogWarn(@"incoming attachment has invalid content type"); - contentType = OWSMimeTypeApplicationOctetStream; } _contentType = contentType; @@ -184,12 +149,9 @@ NSUInteger const TSAttachmentSchemaVersion = 4; if (!_sourceFilename) { // renamed _filename to _sourceFilename _sourceFilename = [coder decodeObjectForKey:@"filename"]; - OWSAssertDebug(!_sourceFilename || [_sourceFilename isKindOfClass:[NSString class]]); } if (_contentType.length < 1) { - OWSLogWarn(@"legacy attachment has invalid content type"); - _contentType = OWSMimeTypeApplicationOctetStream; } @@ -284,14 +246,6 @@ NSUInteger const TSAttachmentSchemaVersion = 4; #pragma mark - Relationships -- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - if (self.albumMessageId == nil) { - return nil; - } - return [TSMessage fetchObjectWithUniqueID:self.albumMessageId transaction:transaction]; -} - - (void)migrateAlbumMessageId:(NSString *)albumMesssageId { _albumMessageId = albumMesssageId; diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.h b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h similarity index 82% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.h rename to SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h index 8820b2c70..f8f8e6276 100644 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.h +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h @@ -1,8 +1,4 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -39,9 +35,6 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { @property (nonatomic, readonly) CGSize mediaSize; -// Non-nil for attachments which need "lazy backup restore." -- (nullable OWSBackupFragment *)lazyRestoreFragment; - - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - (instancetype)initWithServerId:(UInt64)serverId @@ -64,12 +57,6 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { (NSArray *)attachmentProtos albumMessage:(TSMessage *)message; -#pragma mark - Update With... Methods - -// Marks attachment as needing "lazy backup restore." -- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment - transaction:(YapDatabaseReadWriteTransaction *)transaction; - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.m b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m similarity index 72% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.m rename to SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m index 88f9f9788..c7bad6658 100644 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer.m +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m @@ -1,14 +1,9 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import "TSAttachmentPointer.h" -#import "OWSBackupFragment.h" #import "TSAttachmentStream.h" -#import -#import +#import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -86,8 +81,6 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initForRestoreWithAttachmentStream:(TSAttachmentStream *)attachmentStream { - OWSAssertDebug(attachmentStream); - self = [super initForRestoreWithUniqueId:attachmentStream.uniqueId contentType:attachmentStream.contentType sourceFilename:attachmentStream.sourceFilename @@ -109,21 +102,14 @@ NS_ASSUME_NONNULL_BEGIN albumMessage:(nullable TSMessage *)albumMessage { if (attachmentProto.id < 1) { - OWSFailDebug(@"Invalid attachment id."); return nil; } - /* - if (attachmentProto.key.length < 1) { - OWSFailDebug(@"Invalid attachment key."); - return nil; - } - */ + NSString *_Nullable fileName = attachmentProto.fileName; NSString *_Nullable contentType = attachmentProto.contentType; if (contentType.length < 1) { // Content type might not set if the sending client can't // infer a MIME type from the file extension. - OWSLogWarn(@"Invalid attachment content type."); NSString *_Nullable fileExtension = [fileName pathExtension].lowercaseString; if (fileExtension.length > 0) { contentType = [MIMETypeUtil mimeTypeForFileExtension:fileExtension]; @@ -148,11 +134,6 @@ NS_ASSUME_NONNULL_BEGIN caption = attachmentProto.caption; } - NSString *_Nullable albumMessageId; - if (albumMessage != nil) { - albumMessageId = albumMessage.uniqueId; - } - CGSize mediaSize = CGSizeZero; if (attachmentProto.hasWidth && attachmentProto.hasHeight && attachmentProto.width > 0 && attachmentProto.height > 0) { @@ -166,22 +147,17 @@ NS_ASSUME_NONNULL_BEGIN contentType:contentType sourceFilename:fileName caption:caption - albumMessageId:albumMessageId + albumMessageId:0 attachmentType:attachmentType mediaSize:mediaSize]; - - pointer.downloadURL = attachmentProto.url; // Loki + pointer.downloadURL = attachmentProto.url; return pointer; } -+ (NSArray *)attachmentPointersFromProtos: - (NSArray *)attachmentProtos ++ (NSArray *)attachmentPointersFromProtos:(NSArray *)attachmentProtos albumMessage:(TSMessage *)albumMessage { - OWSAssertDebug(attachmentProtos); - OWSAssertDebug(albumMessage); - NSMutableArray *attachmentPointers = [NSMutableArray new]; for (SNProtoAttachmentPointer *attachmentProto in attachmentProtos) { TSAttachmentPointer *_Nullable attachmentPointer = @@ -203,63 +179,13 @@ NS_ASSUME_NONNULL_BEGIN // Legacy instances of TSAttachmentPointer apparently used the serverId as their // uniqueId. if (attachmentSchemaVersion < 2 && self.serverId == 0) { - OWSAssertDebug([self isDecimalNumberText:self.uniqueId]); if ([self isDecimalNumberText:self.uniqueId]) { // For legacy instances, try to parse the serverId from the uniqueId. self.serverId = (UInt64)[self.uniqueId integerValue]; - } else { - OWSLogError(@"invalid legacy attachment uniqueId: %@.", self.uniqueId); } } } -- (nullable OWSBackupFragment *)lazyRestoreFragment -{ - if (!self.lazyRestoreFragmentId) { - return nil; - } - OWSBackupFragment *_Nullable backupFragment = - [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId]; - OWSAssertDebug(backupFragment); - return backupFragment; -} - -#pragma mark - Update With... Methods - -- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(lazyRestoreFragment); - OWSAssertDebug(transaction); - - if (!lazyRestoreFragment.uniqueId) { - // If metadata hasn't been saved yet, save now. - [lazyRestoreFragment saveWithTransaction:transaction]; - - OWSAssertDebug(lazyRestoreFragment.uniqueId); - } - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSAttachmentPointer *attachment) { - [attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId]; - }]; -} - -- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ -#ifdef DEBUG - if (self.uniqueId.length > 0) { - id _Nullable oldObject = [transaction objectForKey:self.uniqueId inCollection:TSAttachment.collection]; - if ([oldObject isKindOfClass:[TSAttachmentStream class]]) { - OWSFailDebug(@"We should never overwrite a TSAttachmentStream with a TSAttachmentPointer."); - } - } else { - OWSFailDebug(@"Missing uniqueId."); - } -#endif - - [super saveWithTransaction:transaction]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.h b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.h similarity index 94% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.h rename to SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.h index 76496107b..a663f8eaf 100644 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.h +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.h @@ -1,9 +1,5 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import +#import +#import #if TARGET_OS_IPHONE #import @@ -19,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN typedef void (^OWSThumbnailSuccess)(UIImage *image); typedef void (^OWSThumbnailFailure)(void); -@interface TSAttachmentStream : TSAttachment +@interface TSAttachmentStream : TSAttachment - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithContentType:(NSString *)contentType diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.m b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.m similarity index 87% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.m rename to SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.m index e5a6037b0..8b3d94a30 100644 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentStream.m +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.m @@ -1,16 +1,11 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import "TSAttachmentStream.h" -#import "MIMETypeUtil.h" #import "NSData+Image.h" -#import "OWSFileSystem.h" #import "TSAttachmentPointer.h" #import #import -#import #import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -149,21 +144,17 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); sourceFilename:self.sourceFilename inFolder:attachmentsFolder]; if (!filePath) { - OWSFailDebug(@"Could not generate path for attachment."); return; } if (![filePath hasPrefix:attachmentsFolder]) { - OWSFailDebug(@"Attachment paths should all be in the attachments folder."); return; } NSString *localRelativeFilePath = [filePath substringFromIndex:attachmentsFolder.length]; if (localRelativeFilePath.length < 1) { - OWSFailDebug(@"Empty local relative attachment paths."); return; } self.localRelativeFilePath = localRelativeFilePath; - OWSAssertDebug(self.originalFilePath); } #pragma mark - File Management @@ -173,7 +164,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); *error = nil; NSString *_Nullable filePath = self.originalFilePath; if (!filePath) { - OWSFailDebug(@"Missing path for attachment."); return nil; } return [NSData dataWithContentsOfFile:filePath options:0 error:error]; @@ -181,28 +171,20 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (BOOL)writeData:(NSData *)data error:(NSError **)error { - OWSAssertDebug(data); - *error = nil; NSString *_Nullable filePath = self.originalFilePath; if (!filePath) { - OWSFailDebug(@"Missing path for attachment."); return NO; } - OWSLogDebug(@"Writing attachment to file: %@", filePath); return [data writeToFile:filePath options:0 error:error]; } - (BOOL)writeDataSource:(DataSource *)dataSource { - OWSAssertDebug(dataSource); - NSString *_Nullable filePath = self.originalFilePath; if (!filePath) { - OWSFailDebug(@"Missing path for attachment."); return NO; } - OWSLogDebug(@"Writing attachment to file: %@", filePath); return [dataSource writeToPath:filePath]; } @@ -218,8 +200,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); + (nullable NSError *)migrateToSharedData { - OWSLogInfo(@""); - return [OWSFileSystem moveAppFilePath:self.legacyAttachmentsDirPath sharedDataFilePath:self.sharedDataAttachmentsDirPath]; } @@ -239,7 +219,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (nullable NSString *)originalFilePath { if (!self.localRelativeFilePath) { - OWSFailDebug(@"Attachment missing local file path."); return nil; } @@ -250,7 +229,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); { NSString *filePath = self.originalFilePath; if (!filePath) { - OWSFailDebug(@"Attachment missing local file path."); return nil; } @@ -268,7 +246,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (NSString *)thumbnailsDirPath { if (!self.localRelativeFilePath) { - OWSFailDebug(@"Attachment missing local file path."); return nil; } @@ -288,7 +265,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); { NSString *_Nullable filePath = self.originalFilePath; if (!filePath) { - OWSFailDebug(@"Missing path for attachment."); return nil; } return [NSURL fileURLWithPath:filePath]; @@ -300,30 +276,19 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); NSString *thumbnailsDirPath = self.thumbnailsDirPath; if ([[NSFileManager defaultManager] fileExistsAtPath:thumbnailsDirPath]) { - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:thumbnailsDirPath error:&error]; - if (error || !success) { - OWSLogError(@"remove thumbnails dir failed with: %@", error); - } + [[NSFileManager defaultManager] removeItemAtPath:thumbnailsDirPath error:&error]; } NSString *_Nullable legacyThumbnailPath = self.legacyThumbnailPath; if (legacyThumbnailPath) { - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:legacyThumbnailPath error:&error]; - - if (error || !success) { - OWSLogError(@"remove legacy thumbnail failed with: %@", error); - } + [[NSFileManager defaultManager] removeItemAtPath:legacyThumbnailPath error:&error]; } NSString *_Nullable filePath = self.originalFilePath; if (!filePath) { - OWSFailDebug(@"Missing path for attachment."); return; } - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; - if (error || !success) { - OWSLogError(@"remove file failed with: %@", error); - } + [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; } - (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction @@ -353,13 +318,10 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (BOOL)isValidImage { - OWSAssertDebug(self.isImage || self.isAnimated); - BOOL result; BOOL didUpdateCache = NO; @synchronized(self) { if (!self.isValidImageCached) { - OWSLogVerbose(@"Updating isValidImageCached."); self.isValidImageCached = @([NSData ows_isValidImageAtPath:self.originalFilePath mimeType:self.contentType]); didUpdateCache = YES; @@ -378,13 +340,10 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (BOOL)isValidVideo { - OWSAssertDebug(self.isVideo); - BOOL result; BOOL didUpdateCache = NO; @synchronized(self) { if (!self.isValidVideoCached) { - OWSLogVerbose(@"Updating isValidVideoCached."); self.isValidVideoCached = @([OWSMediaUtils isValidVideoWithPath:self.originalFilePath]); didUpdateCache = YES; } @@ -423,16 +382,13 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (nullable NSData *)validStillImageData { if ([self isVideo]) { - OWSFailDebug(@"isVideo was unexpectedly true"); return nil; } if ([self isAnimated]) { - OWSFailDebug(@"isAnimated was unexpectedly true"); return nil; } if (![NSData ows_isValidImageAtPath:self.originalFilePath mimeType:self.contentType]) { - OWSFailDebug(@"skipping invalid image"); return nil; } @@ -452,7 +408,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); maxDimension:ThumbnailDimensionPointsLarge() error:&error]; if (error || !image) { - OWSLogError(@"Could not create video still: %@.", error); return nil; } return image; @@ -468,15 +423,11 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); [fileManager contentsOfDirectoryAtURL:fileURL includingPropertiesForKeys:nil options:0 error:&error]; if (error) { - OWSFailDebug(@"failed to get contents of attachments folder: %@ with error: %@", self.attachmentsFolder, error); return; } for (NSURL *url in contents) { [fileManager removeItemAtURL:url error:&error]; - if (error) { - OWSFailDebug(@"failed to remove item at path: %@ with error: %@", url, error); - } } } @@ -529,8 +480,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (CGSize)cachedMediaSize { - OWSAssertDebug(self.shouldHaveImageSize); - @synchronized(self) { if (self.cachedImageWidth && self.cachedImageHeight) { return CGSizeMake(self.cachedImageWidth.floatValue, self.cachedImageHeight.floatValue); @@ -544,8 +493,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (void)applyChangeAsyncToLatestCopyWithChangeBlock:(void (^)(TSAttachmentStream *))changeBlock { - OWSAssertDebug(changeBlock); - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { NSString *collection = [TSAttachmentStream collection]; TSAttachmentStream *latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection]; @@ -555,9 +502,8 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); // _very_ rare. // // An exception is incoming group avatar updates which we don't ever save. - OWSLogWarn(@"Attachment not yet saved."); } else if (![latestInstance isKindOfClass:[TSAttachmentStream class]]) { - OWSFailDebug(@"Attachment has unexpected type: %@", latestInstance.class); + // Shouldn't occur } else { changeBlock(latestInstance); @@ -570,9 +516,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (CGFloat)calculateAudioDurationSeconds { - OWSAssertIsOnMainThread(); - OWSAssertDebug([self isAudio]); - NSError *error; AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.originalMediaURL error:&error]; if (error && [error.domain isEqualToString:NSOSStatusErrorDomain] @@ -583,15 +526,12 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); if (!error) { return (CGFloat)[audioPlayer duration]; } else { - OWSLogError(@"Could not find audio duration: %@", self.originalMediaURL); return 0; } } - (CGFloat)audioDurationSeconds { - OWSAssertIsOnMainThread(); - if (self.cachedAudioDurationSeconds) { return self.cachedAudioDurationSeconds.floatValue; } @@ -686,7 +626,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); if ([[NSFileManager defaultManager] fileExistsAtPath:thumbnailPath]) { UIImage *_Nullable image = [UIImage imageWithContentsOfFile:thumbnailPath]; if (!image) { - OWSFailDebug(@"couldn't load image."); // Any time we return nil from this method we have to call the failure handler // or else the caller waits for an async thumbnail failure(); @@ -699,7 +638,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); thumbnailDimensionPoints:thumbnailDimensionPoints success:success failure:^(NSError *error) { - OWSLogError(@"Failed to create thumbnail: %@", error); failure(); }]; return nil; @@ -737,7 +675,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); { OWSLoadedThumbnail *_Nullable loadedThumbnail = [self loadedThumbnailSmallSync]; if (!loadedThumbnail) { - OWSLogInfo(@"Couldn't load small thumbnail sync."); return nil; } return loadedThumbnail.image; @@ -747,13 +684,11 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); { OWSLoadedThumbnail *_Nullable loadedThumbnail = [self loadedThumbnailSmallSync]; if (!loadedThumbnail) { - OWSLogInfo(@"Couldn't load small thumbnail sync."); return nil; } NSError *error; NSData *_Nullable data = [loadedThumbnail dataAndReturnError:&error]; if (error || !data) { - OWSFailDebug(@"Couldn't load thumbnail data: %@", error); return nil; } return data; @@ -769,7 +704,7 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); NSArray *_Nullable fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:thumbnailsDirPath error:&error]; if (error || !fileNames) { - OWSFailDebug(@"contentsOfDirectoryAtPath failed with error: %@", error); + // Do nothing } else { for (NSString *fileName in fileNames) { NSString *filePath = [thumbnailsDirPath stringByAppendingPathComponent:fileName]; @@ -812,7 +747,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); NSError *error; BOOL success = [thumbnailAttachment writeData:thumbnailData error:&error]; if (!success || error) { - OWSLogError(@"Couldn't copy attachment data for message sent to self: %@.", error); return nil; } @@ -823,14 +757,11 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); + (nullable SNProtoAttachmentPointer *)buildProtoForAttachmentId:(nullable NSString *)attachmentId { - OWSAssertDebug(attachmentId.length > 0); - // TODO we should past in a transaction, rather than sneakily generate one in `fetch...` to make sure we're // getting a consistent view in the message sending process. A brief glance shows it touches quite a bit of code, // but should be straight forward. TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; if (![attachment isKindOfClass:[TSAttachmentStream class]]) { - OWSLogError(@"Unexpected type for attachment builder: %@", attachment); return nil; } @@ -843,10 +774,8 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); { SNProtoAttachmentPointerBuilder *builder = [SNProtoAttachmentPointer builderWithId:self.serverId]; - OWSAssertDebug(self.contentType.length > 0); builder.contentType = self.contentType; - OWSLogVerbose(@"Sending attachment with filename: '%@'", self.sourceFilename); if (self.sourceFilename.length > 0) { builder.fileName = self.sourceFilename; } @@ -876,7 +805,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); NSError *error; SNProtoAttachmentPointer *_Nullable attachmentProto = [builder buildAndReturnError:&error]; if (error || !attachmentProto) { - OWSFailDebug(@"could not build protobuf: %@", error); return nil; } return attachmentProto; diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Attachment.swift b/SessionMessagingKit/Messages/Visible Messages/Attachments/VisibleMessage+Attachment.swift similarity index 60% rename from SessionMessagingKit/Messages/Visible Message/VisibleMessage+Attachment.swift rename to SessionMessagingKit/Messages/Visible Messages/Attachments/VisibleMessage+Attachment.swift index 96d180e68..998875a35 100644 --- a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Attachment.swift +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/VisibleMessage+Attachment.swift @@ -16,7 +16,8 @@ public extension VisibleMessage { public var url: String? public var isValid: Bool { - fileName != nil && contentType != nil && key != nil && digest != nil && kind != nil && size != nil && sizeInBytes != nil && url != nil + // key and digest can be nil for open group attachments + fileName != nil && contentType != nil && kind != nil && size != nil && sizeInBytes != nil && url != nil } public enum Kind : String { @@ -50,7 +51,33 @@ public extension VisibleMessage { } public static func fromProto(_ proto: SNProtoAttachmentPointer) -> Attachment? { - preconditionFailure("Use MessageReceiverDelegate.parseAttachments(from:) instead.") + let result = Attachment() + result.fileName = proto.fileName + func inferContentType() -> String { + guard let fileName = result.fileName, let fileExtension = URL(string: fileName)?.pathExtension else { return OWSMimeTypeApplicationOctetStream } + return MIMETypeUtil.mimeType(forFileExtension: fileExtension) ?? OWSMimeTypeApplicationOctetStream + } + result.contentType = proto.contentType ?? inferContentType() + result.key = proto.key + result.digest = proto.digest + let kind: VisibleMessage.Attachment.Kind + if proto.hasFlags && (proto.flags & UInt32(SNProtoAttachmentPointer.SNProtoAttachmentPointerFlags.voiceMessage.rawValue)) > 0 { + kind = .voiceMessage + } else { + kind = .generic + } + result.kind = kind + result.caption = proto.hasCaption ? proto.caption : nil + let size: CGSize + if proto.hasWidth && proto.width > 0 && proto.hasHeight && proto.height > 0 { + size = CGSize(width: Int(proto.width), height: Int(proto.height)) + } else { + size = CGSize.zero + } + result.size = size + result.sizeInBytes = proto.size > 0 ? UInt(proto.size) : nil + result.url = proto.url + return result } public func toProto() -> SNProtoDataMessageQuote? { diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Contact.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Contact.swift similarity index 100% rename from SessionMessagingKit/Messages/Visible Message/VisibleMessage+Contact.swift rename to SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Contact.swift diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+LinkPreview.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift similarity index 100% rename from SessionMessagingKit/Messages/Visible Message/VisibleMessage+LinkPreview.swift rename to SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Profile.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift similarity index 100% rename from SessionMessagingKit/Messages/Visible Message/VisibleMessage+Profile.swift rename to SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift similarity index 100% rename from SessionMessagingKit/Messages/Visible Message/VisibleMessage+Quote.swift rename to SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift similarity index 100% rename from SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift rename to SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index 6a1fd0adf..0665b4812 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -2,3 +2,7 @@ FOUNDATION_EXPORT double SessionMessagingKitVersionNumber; FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; + +#import +#import +#import diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index b8917dd72..8f6caf6f2 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -74,8 +74,6 @@ internal enum MessageReceiver { // Parse the message let message: Message? = { if let readReceipt = ReadReceipt.fromProto(proto) { return readReceipt } - if let sessionRequest = SessionRequest.fromProto(proto) { return sessionRequest } - if let nullMessage = NullMessage.fromProto(proto) { return nullMessage } if let typingIndicator = TypingIndicator.fromProto(proto) { return typingIndicator } if let closedGroupUpdate = ClosedGroupUpdate.fromProto(proto) { return closedGroupUpdate } if let expirationTimerUpdate = ExpirationTimerUpdate.fromProto(proto) { return expirationTimerUpdate } @@ -99,8 +97,6 @@ internal enum MessageReceiver { internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) - case let message as SessionRequest: handleSessionRequest(message, using: transaction) - case let message as NullMessage: handleNullMessage(message, using: transaction) case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) @@ -113,14 +109,6 @@ internal enum MessageReceiver { Configuration.shared.messageReceiverDelegate.markMessagesAsRead(message.timestamps!, from: message.sender!, at: message.receivedTimestamp!) } - private static func handleSessionRequest(_ message: SessionRequest, using transaction: Any) { - // We might not need this anymore - } - - private static func handleNullMessage(_ message: NullMessage, using transaction: Any) { - // We might not need this anymore - } - private static func handleTypingIndicator(_ message: TypingIndicator, using transaction: Any) { let delegate = Configuration.shared.messageReceiverDelegate switch message.kind! { @@ -152,8 +140,22 @@ internal enum MessageReceiver { let delegate = Configuration.shared.messageReceiverDelegate let storage = Configuration.shared.storage // Handle attachments - let attachments = delegate.parseAttachments(from: proto.dataMessage!.attachments) - message.attachmentIDs = storage.save(attachments, using: transaction) + let attachments: [VisibleMessage.Attachment] = proto.dataMessage!.attachments.compactMap { proto in + guard let attachment = VisibleMessage.Attachment.fromProto(proto) else { return nil } + return attachment.isValid ? attachment : nil + } + let attachmentIDs = storage.save(attachments, using: transaction) + message.attachmentIDs = attachmentIDs + storage.withAsync({ transaction in + attachmentIDs.forEach { attachmentID in + let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID) + if CurrentAppContext().isMainAppAndActive { + JobQueue.shared.add(downloadJob, using: transaction) + } else { + JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) + } + } + }, completion: { }) // Update profile if needed if let profile = message.profile { delegate.updateProfile(for: message.sender!, from: profile, using: transaction) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift index 34e289e41..cba87224d 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift @@ -14,5 +14,4 @@ public protocol MessageReceiverDelegate { func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) - func parseAttachments(from protos: [SNProtoAttachmentPointer]) -> [VisibleMessage.Attachment] } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift index 44bea6225..3a07bd7ae 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift @@ -7,13 +7,9 @@ internal extension MessageSender { let storage = Configuration.shared.signalStorage let cipher = try SMKSecretSessionCipher(sessionResetImplementation: Configuration.shared.sessionRestorationImplementation, sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: Configuration.shared.identityKeyStore) - let useFallbackEncryption: Bool = { - if (message is SessionRequest) { return true } - return !storage.containsSession(publicKey, deviceId: 1, protocolContext: transaction) - }() let certificate = Configuration.shared.storage.getSenderCertificate(for: publicKey) return try cipher.throwswrapped_encryptMessage(recipientPublicKey: publicKey, deviceID: 1, paddedPlaintext: (plaintext as NSData).paddedMessageBody(), - senderCertificate: certificate, protocolContext: transaction, useFallbackSessionCipher: useFallbackEncryption) + senderCertificate: certificate, protocolContext: transaction, useFallbackSessionCipher: true) } static func encryptWithSharedSenderKeys(_ plaintext: Data, for groupPublicKey: String, using transaction: Any) throws -> Data { diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 870193b0e..c7cf38752 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -138,11 +138,14 @@ public final class MessageSender : NSObject { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) } let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) - storage.with { transaction in + storage.withAsync({ transaction in JobQueue.shared.add(notifyPNServerJob, using: transaction) - } + }, completion: { }) } let _ = promise.catch(on: DispatchQueue.main) { _ in + Configuration.shared.storage.withAsync({ transaction in + Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, using: transaction) + }, completion: { }) if case .contact(_) = destination { NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift index 0b6b91ea0..dac0ecc66 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift @@ -2,4 +2,5 @@ public protocol MessageSenderDelegate { func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) + func handleFailedMessageSend(_ message: Message, using transaction: Any) } diff --git a/SessionMessagingKit/Utilities/AttachmentStream.swift b/SessionMessagingKit/Utilities/AttachmentStream.swift deleted file mode 100644 index b5cd00cf1..000000000 --- a/SessionMessagingKit/Utilities/AttachmentStream.swift +++ /dev/null @@ -1,12 +0,0 @@ - -@objc(SNAttachmentStream) -public protocol AttachmentStream { - @objc var encryptionKey: Data { get set } - @objc var digest: Data { get set } - @objc var serverId: UInt64 { get set } - @objc var isUploaded: Bool { get set } - @objc var downloadURL: String { get set } - - @objc func readDataFromFile() throws -> Data - @objc func save() -} diff --git a/SessionMessagingKit/Utilities/DotNetAPI.swift b/SessionMessagingKit/Utilities/DotNetAPI.swift index 82f11d125..36fcdba1e 100644 --- a/SessionMessagingKit/Utilities/DotNetAPI.swift +++ b/SessionMessagingKit/Utilities/DotNetAPI.swift @@ -133,11 +133,11 @@ public class DotNetAPI : NSObject { } @objc(uploadAttachment:withID:toServer:) - public static func objc_uploadAttachment(_ attachment: AttachmentStream, with attachmentID: String, to server: String) -> AnyPromise { + public static func objc_uploadAttachment(_ attachment: TSAttachmentStream, with attachmentID: String, to server: String) -> AnyPromise { return AnyPromise.from(uploadAttachment(attachment, with: attachmentID, to: server)) } - public static func uploadAttachment(_ attachment: AttachmentStream, with attachmentID: String, to server: String) -> Promise { + public static func uploadAttachment(_ attachment: TSAttachmentStream, with attachmentID: String, to server: String) -> Promise { let isEncryptionRequired = (server == FileServerAPI.server) return Promise() { seal in func proceed(with token: String) { diff --git a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h index cd60f743f..7ec01ed1e 100644 --- a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h +++ b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h @@ -19,7 +19,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/SessionShareExtension/SAEScreenLockViewController.m b/SessionShareExtension/SAEScreenLockViewController.m index 92c70fc36..70d5e6696 100644 --- a/SessionShareExtension/SAEScreenLockViewController.m +++ b/SessionShareExtension/SAEScreenLockViewController.m @@ -5,7 +5,7 @@ #import "SAEScreenLockViewController.h" #import "UIColor+OWS.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SessionShareExtension/ShareAppExtensionContext.h b/SessionShareExtension/ShareAppExtensionContext.h index 4398ea941..8e53d724d 100644 --- a/SessionShareExtension/ShareAppExtensionContext.h +++ b/SessionShareExtension/ShareAppExtensionContext.h @@ -2,7 +2,7 @@ // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/AppContext.h b/SessionUtilitiesKit/AppContext.h similarity index 98% rename from SignalUtilitiesKit/AppContext.h rename to SessionUtilitiesKit/AppContext.h index f9327db8a..50305e99e 100755 --- a/SignalUtilitiesKit/AppContext.h +++ b/SessionUtilitiesKit/AppContext.h @@ -1,7 +1,3 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/AppContext.m b/SessionUtilitiesKit/AppContext.m similarity index 84% rename from SignalUtilitiesKit/AppContext.m rename to SessionUtilitiesKit/AppContext.m index 39423c3cc..b99a3093b 100755 --- a/SignalUtilitiesKit/AppContext.m +++ b/SessionUtilitiesKit/AppContext.m @@ -1,7 +1,3 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - #import "AppContext.h" NS_ASSUME_NONNULL_BEGIN @@ -27,8 +23,6 @@ static id currentAppContext = nil; id CurrentAppContext(void) { - OWSCAssertDebug(currentAppContext); - return currentAppContext; } @@ -38,8 +32,6 @@ void SetCurrentAppContext(id appContext) // // App extensions may be opened multiple times in the same process, // so statics will persist. - OWSCAssertDebug(!currentAppContext || !currentAppContext.isMainApp); - currentAppContext = appContext; } @@ -52,8 +44,6 @@ void ClearCurrentAppContextForTests() void ExitShareExtension(void) { - OWSLogInfo(@"ExitShareExtension"); - [DDLog flushLog]; exit(0); } diff --git a/SessionUtilitiesKit/Configuration.swift b/SessionUtilitiesKit/Configuration.swift new file mode 100644 index 000000000..2e3699ab3 --- /dev/null +++ b/SessionUtilitiesKit/Configuration.swift @@ -0,0 +1,20 @@ + +@objc(SNConfiguration) +public final class Configuration : NSObject { + @objc public let owsPrimaryStorage: OWSPrimaryStorageProtocol + public let maxFileSize: UInt + + @objc public static var shared: Configuration! + + fileprivate init(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) { + self.owsPrimaryStorage = owsPrimaryStorage + self.maxFileSize = maxFileSize + } +} + +public enum SessionUtilitiesKit { // Just to make the external API nice + + public static func configure(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) { + Configuration.shared = Configuration(owsPrimaryStorage: owsPrimaryStorage, maxFileSize: maxFileSize) + } +} diff --git a/SignalUtilitiesKit/DataSource.h b/SessionUtilitiesKit/DataSource.h similarity index 95% rename from SignalUtilitiesKit/DataSource.h rename to SessionUtilitiesKit/DataSource.h index 5401c4c35..a999ed7ff 100755 --- a/SignalUtilitiesKit/DataSource.h +++ b/SessionUtilitiesKit/DataSource.h @@ -1,7 +1,3 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/DataSource.m b/SessionUtilitiesKit/DataSource.m similarity index 76% rename from SignalUtilitiesKit/DataSource.m rename to SessionUtilitiesKit/DataSource.m index 723983b55..43b22c895 100755 --- a/SignalUtilitiesKit/DataSource.m +++ b/SessionUtilitiesKit/DataSource.m @@ -1,13 +1,9 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import "DataSource.h" #import "MIMETypeUtil.h" #import "NSData+Image.h" #import "OWSFileSystem.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -33,31 +29,26 @@ NS_ASSUME_NONNULL_BEGIN - (NSData *)data { - OWSAbstractMethod(); return nil; } - (nullable NSURL *)dataUrl { - OWSAbstractMethod(); return nil; } - (nullable NSString *)dataPathIfOnDisk { - OWSAbstractMethod(); return nil; } - (NSUInteger)dataLength { - OWSAbstractMethod(); return 0; } - (BOOL)writeToPath:(NSString *)dstFilePath { - OWSAbstractMethod(); return NO; } @@ -87,8 +78,6 @@ NS_ASSUME_NONNULL_BEGIN // Returns the MIME type, if known. - (nullable NSString *)mimeType { - OWSAbstractMethod(); - return nil; } @@ -118,10 +107,7 @@ NS_ASSUME_NONNULL_BEGIN if (filePath) { dispatch_async(dispatch_get_main_queue(), ^{ NSError *error; - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; - if (!success || error) { - OWSCFailDebug(@"DataSourceValue could not delete file: %@, %@", filePath, error); - } + [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; }); } } @@ -130,8 +116,6 @@ NS_ASSUME_NONNULL_BEGIN + (nullable DataSource *)dataSourceWithData:(NSData *)data fileExtension:(NSString *)fileExtension { - OWSAssertDebug(data); - if (!data) { return nil; } @@ -172,8 +156,6 @@ NS_ASSUME_NONNULL_BEGIN - (NSData *)data { - OWSAssertDebug(self.dataValue); - return self.dataValue; } @@ -185,17 +167,12 @@ NS_ASSUME_NONNULL_BEGIN - (nullable NSString *)dataPath { - OWSAssertDebug(self.dataValue); - @synchronized(self) { if (!self.cachedFilePath) { NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:self.fileExtension]; if ([self writeToPath:filePath]) { self.cachedFilePath = filePath; - } else { - OWSLogDebug(@"Could not write data to disk: %@", self.fileExtension); - OWSFailDebug(@"Could not write data to disk."); } } @@ -210,21 +187,15 @@ NS_ASSUME_NONNULL_BEGIN - (NSUInteger)dataLength { - OWSAssertDebug(self.dataValue); - return self.dataValue.length; } - (BOOL)writeToPath:(NSString *)dstFilePath { - OWSAssertDebug(self.dataValue); - NSData *dataCopy = self.dataValue; BOOL success = [dataCopy writeToFile:dstFilePath atomically:YES]; if (!success) { - OWSLogDebug(@"Could not write data to disk: %@", dstFilePath); - OWSFailDebug(@"Could not write data to disk."); return NO; } else { return YES; @@ -261,10 +232,7 @@ NS_ASSUME_NONNULL_BEGIN if (filePath) { dispatch_async(dispatch_get_main_queue(), ^{ NSError *error; - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; - if (!success || error) { - OWSCFailDebug(@"DataSourcePath could not delete file: %@, %@", filePath, error); - } + [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; }); } } @@ -272,8 +240,6 @@ NS_ASSUME_NONNULL_BEGIN + (nullable DataSource *)dataSourceWithURL:(NSURL *)fileUrl shouldDeleteOnDeallocation:(BOOL)shouldDeleteOnDeallocation { - OWSAssertDebug(fileUrl); - if (!fileUrl || ![fileUrl isFileURL]) { return nil; } @@ -286,8 +252,6 @@ NS_ASSUME_NONNULL_BEGIN + (nullable DataSource *)dataSourceWithFilePath:(NSString *)filePath shouldDeleteOnDeallocation:(BOOL)shouldDeleteOnDeallocation { - OWSAssertDebug(filePath); - if (!filePath) { return nil; } @@ -300,30 +264,17 @@ NS_ASSUME_NONNULL_BEGIN - (void)setFilePath:(NSString *)filePath { - OWSAssertDebug(filePath.length > 0); - -#ifdef DEBUG - BOOL isDirectory; - BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory]; - OWSAssertDebug(exists); - OWSAssertDebug(!isDirectory); -#endif - _filePath = filePath; } - (NSData *)data { - OWSAssertDebug(self.filePath); - @synchronized(self) { if (!self.cachedData) { self.cachedData = [NSData dataWithContentsOfFile:self.filePath]; } if (!self.cachedData) { - OWSLogDebug(@"Could not read data from disk: %@", self.filePath); - OWSFailDebug(@"Could not read data from disk."); self.cachedData = [NSData new]; } return self.cachedData; @@ -332,29 +283,21 @@ NS_ASSUME_NONNULL_BEGIN - (nullable NSURL *)dataUrl { - OWSAssertDebug(self.filePath); - return [NSURL fileURLWithPath:self.filePath]; } - (nullable NSString *)dataPath { - OWSAssertDebug(self.filePath); - return self.filePath; } - (nullable NSString *)dataPathIfOnDisk { - OWSAssertDebug(self.filePath); - return self.filePath; } - (NSUInteger)dataLength { - OWSAssertDebug(self.filePath); - @synchronized(self) { if (!self.cachedDataLength) { @@ -362,8 +305,6 @@ NS_ASSUME_NONNULL_BEGIN NSDictionary *_Nullable attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:&error]; if (!attributes || error) { - OWSLogDebug(@"Could not read data length from disk: %@, %@", self.filePath, error); - OWSFailDebug(@"Could not read data length from disk with error: %@", error); self.cachedDataLength = @(0); } else { uint64_t fileSize = [attributes fileSize]; @@ -376,13 +317,9 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)writeToPath:(NSString *)dstFilePath { - OWSAssertDebug(self.filePath); - NSError *error; BOOL success = [[NSFileManager defaultManager] copyItemAtPath:self.filePath toPath:dstFilePath error:&error]; if (!success || error) { - OWSLogDebug(@"Could not write data from path: %@, to path: %@, %@", self.filePath, dstFilePath, error); - OWSFailDebug(@"Could not write data with error: %@", error); return NO; } else { return YES; diff --git a/SignalUtilitiesKit/Utilities/MIMETypeUtil.h b/SessionUtilitiesKit/MIMETypeUtil.h similarity index 97% rename from SignalUtilitiesKit/Utilities/MIMETypeUtil.h rename to SessionUtilitiesKit/MIMETypeUtil.h index 899eb4be8..1c12bc7fa 100644 --- a/SignalUtilitiesKit/Utilities/MIMETypeUtil.h +++ b/SessionUtilitiesKit/MIMETypeUtil.h @@ -1,7 +1,3 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Utilities/MIMETypeUtil.m b/SessionUtilitiesKit/MIMETypeUtil.m similarity index 99% rename from SignalUtilitiesKit/Utilities/MIMETypeUtil.m rename to SessionUtilitiesKit/MIMETypeUtil.m index ecbf5f5fe..e15e918b9 100644 --- a/SignalUtilitiesKit/Utilities/MIMETypeUtil.m +++ b/SessionUtilitiesKit/MIMETypeUtil.m @@ -1,10 +1,5 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - #import "MIMETypeUtil.h" #import "OWSFileSystem.h" -#import #if TARGET_OS_IPHONE #import @@ -382,7 +377,6 @@ NSString *const kSyncMessageFileExtension = @"bin"; return [self filePathForData:uniqueId withFileExtension:fileExtension inFolder:folder]; } - OWSLogError(@"Got asked for path of file %@ which is unsupported", contentType); // Use a fallback file extension. return [self filePathForData:uniqueId withFileExtension:kDefaultFileExtension inFolder:folder]; } @@ -475,10 +469,7 @@ NSString *const kSyncMessageFileExtension = @"bin"; NSMutableSet *result = [NSMutableSet new]; for (NSString *mimeType in mimeTypes) { NSString *_Nullable utiType = [self utiTypeForMIMEType:mimeType]; - if (!utiType) { - OWSFailDebug(@"unknown utiType for mimetype: %@", mimeType); - continue; - } + if (!utiType) { continue; } [result addObject:utiType]; } return result; @@ -1593,8 +1584,6 @@ NSString *const kSyncMessageFileExtension = @"bin"; + (nullable NSString *)mimeTypeForFileExtension:(NSString *)fileExtension { - OWSAssertDebug(fileExtension.length > 0); - return [self genericExtensionTypesToMIMETypes][fileExtension]; } @@ -2614,8 +2603,6 @@ NSString *const kSyncMessageFileExtension = @"bin"; + (nullable NSString *)utiTypeForFileExtension:(NSString *)fileExtension { - OWSAssertDebug(fileExtension.length > 0); - NSString *_Nullable utiType = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL); return utiType; diff --git a/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h b/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h index 8ecbab311..672951858 100644 --- a/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h +++ b/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h @@ -3,6 +3,14 @@ FOUNDATION_EXPORT double SessionUtilitiesKitVersionNumber; FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[]; +#import +#import +#import +#import #import #import +#import #import +#import +#import + diff --git a/SignalUtilitiesKit/Utilities/NSData+Image.h b/SessionUtilitiesKit/NSData+Image.h similarity index 90% rename from SignalUtilitiesKit/Utilities/NSData+Image.h rename to SessionUtilitiesKit/NSData+Image.h index 07d0899b0..900730caa 100644 --- a/SignalUtilitiesKit/Utilities/NSData+Image.h +++ b/SessionUtilitiesKit/NSData+Image.h @@ -1,7 +1,3 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Utilities/NSData+Image.m b/SessionUtilitiesKit/NSData+Image.m similarity index 90% rename from SignalUtilitiesKit/Utilities/NSData+Image.m rename to SessionUtilitiesKit/NSData+Image.m index 07f9be595..49f8639af 100644 --- a/SignalUtilitiesKit/Utilities/NSData+Image.m +++ b/SessionUtilitiesKit/NSData+Image.m @@ -1,12 +1,8 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import "NSData+Image.h" #import "MIMETypeUtil.h" #import "OWSFileSystem.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -36,7 +32,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { = (isAnimated ? OWSMediaUtils.kMaxFileSizeAnimatedImage : OWSMediaUtils.kMaxFileSizeImage); NSUInteger fileSize = self.length; if (fileSize > kMaxFileSize) { - OWSLogWarn(@"Oversize image."); return NO; } @@ -58,35 +53,29 @@ typedef NS_ENUM(NSInteger, ImageFormat) { mimeType = [MIMETypeUtil mimeTypeForFileExtension:fileExtension]; } if (mimeType.length < 1) { - OWSLogError(@"Image has unknown MIME type."); return NO; } NSNumber *_Nullable fileSize = [OWSFileSystem fileSizeOfPath:filePath]; if (!fileSize) { - OWSLogError(@"Could not determine file size."); return NO; } BOOL isAnimated = [MIMETypeUtil isSupportedAnimatedMIMEType:mimeType]; if (isAnimated) { if (fileSize.unsignedIntegerValue > OWSMediaUtils.kMaxFileSizeAnimatedImage) { - OWSLogWarn(@"Oversize animated image."); return NO; } } else if ([MIMETypeUtil isSupportedImageMIMEType:mimeType]) { if (fileSize.unsignedIntegerValue > OWSMediaUtils.kMaxFileSizeImage) { - OWSLogWarn(@"Oversize still image."); return NO; } } else { - OWSLogError(@"Image has unsupported MIME type."); return NO; } NSError *error = nil; NSData *_Nullable data = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error]; if (!data || error) { - OWSLogError(@"Could not read image data: %@", error); return NO; } @@ -95,7 +84,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { } if (![self ows_hasValidImageDimensionsAtPath:filePath isAnimated:isAnimated]) { - OWSLogError(@"%@ image had invalid dimensions.", self.logTag); return NO; } @@ -131,8 +119,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { + (BOOL)ows_hasValidImageDimensionWithImageSource:(CGImageSourceRef)imageSource isAnimated:(BOOL)isAnimated { - OWSAssertDebug(imageSource); - NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); @@ -142,14 +128,12 @@ typedef NS_ENUM(NSInteger, ImageFormat) { NSNumber *widthNumber = imageProperties[(__bridge NSString *)kCGImagePropertyPixelWidth]; if (!widthNumber) { - OWSLogError(@"widthNumber was unexpectedly nil"); return NO; } CGFloat width = widthNumber.floatValue; NSNumber *heightNumber = imageProperties[(__bridge NSString *)kCGImagePropertyPixelHeight]; if (!heightNumber) { - OWSLogError(@"heightNumber was unexpectedly nil"); return NO; } CGFloat height = heightNumber.floatValue; @@ -158,7 +142,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { * key is a CFNumberRef. */ NSNumber *depthNumber = imageProperties[(__bridge NSString *)kCGImagePropertyDepth]; if (!depthNumber) { - OWSLogError(@"depthNumber was unexpectedly nil"); return NO; } NSUInteger depthBits = depthNumber.unsignedIntegerValue; @@ -169,12 +152,10 @@ typedef NS_ENUM(NSInteger, ImageFormat) { * The value of this key is CFStringRef. */ NSString *colorModel = imageProperties[(__bridge NSString *)kCGImagePropertyColorModel]; if (!colorModel) { - OWSLogError(@"colorModel was unexpectedly nil"); return NO; } if (![colorModel isEqualToString:(__bridge NSString *)kCGImagePropertyColorModelRGB] && ![colorModel isEqualToString:(__bridge NSString *)kCGImagePropertyColorModelGray]) { - OWSLogError(@"Invalid colorModel: %@", colorModel); return NO; } @@ -188,7 +169,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { CGFloat kMaxBytes = kMaxValidImageDimension * kMaxValidImageDimension * kExpectedBytePerPixel; CGFloat actualBytes = width * height * bytesPerPixel; if (actualBytes > kMaxBytes) { - OWSLogWarn(@"invalid dimensions width: %f, height %f, bytesPerPixel: %f", width, height, bytesPerPixel); return NO; } @@ -328,7 +308,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { + (CGSize)imageSizeForFilePath:(NSString *)filePath mimeType:(NSString *)mimeType { if (![NSData ows_isValidImageAtPath:filePath mimeType:mimeType]) { - OWSLogError(@"Invalid image."); return CGSizeZero; } NSURL *url = [NSURL fileURLWithPath:filePath]; @@ -336,7 +315,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { // With CGImageSource we avoid loading the whole image into memory. CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL); if (!source) { - OWSFailDebug(@"Could not load image: %@", url); return CGSizeZero; } @@ -357,8 +335,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { if (orientation) { imageSize = [self applyImageOrientation:(UIImageOrientation)orientation.intValue toImageSize:imageSize]; } - } else { - OWSFailDebug(@"Could not determine size of image: %@", url); } } CFRelease(source); @@ -390,7 +366,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { // With CGImageSource we avoid loading the whole image into memory. CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL); if (!source) { - OWSFailDebug(@"Could not load image: %@", url); return NO; } @@ -407,7 +382,6 @@ typedef NS_ENUM(NSInteger, ImageFormat) { } else { // This is not an error; kCGImagePropertyHasAlpha is an optional // property. - OWSLogWarn(@"Could not determine transparency of image: %@", url); result = NO; } } diff --git a/SignalUtilitiesKit/OWSFileSystem.h b/SessionUtilitiesKit/OWSFileSystem.h similarity index 92% rename from SignalUtilitiesKit/OWSFileSystem.h rename to SessionUtilitiesKit/OWSFileSystem.h index 7e059c0a3..74b7f0383 100644 --- a/SignalUtilitiesKit/OWSFileSystem.h +++ b/SessionUtilitiesKit/OWSFileSystem.h @@ -1,7 +1,3 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import NS_ASSUME_NONNULL_BEGIN @@ -12,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN NSString *OWSTemporaryDirectory(void); NSString *OWSTemporaryDirectoryAccessibleAfterFirstAuth(void); void ClearOldTemporaryDirectories(void); +void ClearOldTemporaryDirectoriesSync(void); @interface OWSFileSystem : NSObject @@ -52,7 +49,6 @@ void ClearOldTemporaryDirectories(void); + (nullable NSString *)writeDataToTemporaryFile:(NSData *)data fileExtension:(NSString *_Nullable)fileExtension; + (nullable NSNumber *)fileSizeOfPath:(NSString *)filePath; -+ (void)logAttributesOfItemAtPathRecursively:(NSString *)path; @end diff --git a/SignalUtilitiesKit/OWSFileSystem.m b/SessionUtilitiesKit/OWSFileSystem.m similarity index 71% rename from SignalUtilitiesKit/OWSFileSystem.m rename to SessionUtilitiesKit/OWSFileSystem.m index 63415221e..1534f7a0b 100644 --- a/SignalUtilitiesKit/OWSFileSystem.m +++ b/SessionUtilitiesKit/OWSFileSystem.m @@ -1,12 +1,5 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import "OWSFileSystem.h" -#import "OWSError.h" -#import "TSConstants.h" #import "AppContext.h" -#import NS_ASSUME_NONNULL_BEGIN @@ -29,12 +22,10 @@ NS_ASSUME_NONNULL_BEGIN for (NSString *relativePath in directoryEnumerator) { NSString *filePath = [dirPath stringByAppendingPathComponent:relativePath]; - OWSLogDebug(@"path: %@ had attributes: %@", filePath, directoryEnumerator.fileAttributes); success = success && [self protectFileOrFolderAtPath:filePath]; } - OWSLogInfo(@"protected contents at path: %@", path); return success; } @@ -46,7 +37,6 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)protectFileOrFolderAtPath:(NSString *)path fileProtectionType:(NSFileProtectionType)fileProtectionType { - OWSLogVerbose(@"protecting file at path: %@", path); if (![NSFileManager.defaultManager fileExistsAtPath:path]) { return NO; } @@ -61,38 +51,11 @@ NS_ASSUME_NONNULL_BEGIN BOOL success = [ressourceURL setResourceValues:resourcesAttrs error:&error]; if (error || !success) { - OWSFailDebug(@"Could not protect file or folder: %@", error); return NO; } return YES; } -+ (void)logAttributesOfItemAtPathRecursively:(NSString *)path -{ - BOOL isDirectory; - BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]; - if (!exists) { - OWSFailDebug(@"error retrieving file attributes for missing file"); - return; - } - - if (isDirectory) { - NSDirectoryEnumerator *directoryEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:(NSString *)path]; - for (NSString *path in directoryEnumerator) { - OWSLogDebug(@"path: %@ has attributes: %@", path, directoryEnumerator.fileAttributes); - } - } else { - NSError *error; - NSDictionary *_Nullable attributes = - [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error]; - if (error) { - OWSFailDebug(@"error retrieving file attributes: %@", error); - } else { - OWSLogDebug(@"path: %@ has attributes: %@", path, attributes); - } - } -} - + (NSString *)appLibraryDirectoryPath { NSFileManager *fileManager = [NSFileManager defaultManager]; @@ -114,7 +77,6 @@ NS_ASSUME_NONNULL_BEGIN + (NSString *)cachesDirectoryPath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - OWSAssertDebug(paths.count >= 1); return paths[0]; } @@ -128,13 +90,10 @@ NS_ASSUME_NONNULL_BEGIN NSString *newFilePath = [[oldFilePath stringByAppendingString:@"."] stringByAppendingString:[NSUUID UUID].UUIDString]; - OWSLogInfo(@"Moving file or directory from: %@ to: %@", oldFilePath, newFilePath); NSError *_Nullable error; BOOL success = [fileManager moveItemAtPath:oldFilePath toPath:newFilePath error:&error]; if (!success || error) { - OWSLogDebug(@"Could not move file or directory from: %@ to: %@, error: %@", oldFilePath, newFilePath, error); - OWSFailDebug(@"Could not move file or directory with error: %@", error); return error; } return nil; @@ -147,8 +106,6 @@ NS_ASSUME_NONNULL_BEGIN return nil; } - OWSLogInfo(@"Moving file or directory from: %@ to: %@", oldFilePath, newFilePath); - if ([fileManager fileExistsAtPath:newFilePath]) { // If a file/directory already exists at the destination, // try to move it "aside" by renaming it with an extension. @@ -159,29 +116,17 @@ NS_ASSUME_NONNULL_BEGIN } if ([fileManager fileExistsAtPath:newFilePath]) { - OWSLogDebug( - @"Can't move file or directory from: %@ to: %@; destination already exists.", oldFilePath, newFilePath); - OWSFailDebug(@"Can't move file or directory; destination already exists."); - return OWSErrorWithCodeDescription( - OWSErrorCodeMoveFileToSharedDataContainerError, @"Can't move file; destination already exists."); + return [NSError errorWithDomain:@"OWSSignalServiceKitErrorDomain" + code:777412 + userInfo:@{ NSLocalizedDescriptionKey : @"Can't move file; destination already exists." }]; } - - NSDate *startDate = [NSDate new]; - + NSError *_Nullable error; BOOL success = [fileManager moveItemAtPath:oldFilePath toPath:newFilePath error:&error]; if (!success || error) { - OWSLogDebug(@"Could not move file or directory from: %@ to: %@, error: %@", oldFilePath, newFilePath, error); - OWSFailDebug(@"Could not move file or directory with error: %@", error); return error; } - OWSLogInfo(@"Moved file or directory in: %f", fabs([startDate timeIntervalSinceNow])); - OWSLogDebug(@"Moved file or directory from: %@ to: %@ in: %f", - oldFilePath, - newFilePath, - fabs([startDate timeIntervalSinceNow])); - // Ensure all files moved have the proper data protection class. // On large directories this can take a while, so we dispatch async // since we're in the launch path. @@ -202,11 +147,8 @@ NS_ASSUME_NONNULL_BEGIN BOOL isDirectory; BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:dirPath isDirectory:&isDirectory]; if (exists) { - OWSAssertDebug(isDirectory); - return [self protectFileOrFolderAtPath:dirPath fileProtectionType:fileProtectionType]; } else { - OWSLogInfo(@"Creating directory at: %@", dirPath); NSError *error = nil; [[NSFileManager defaultManager] createDirectoryAtPath:dirPath @@ -214,7 +156,6 @@ NS_ASSUME_NONNULL_BEGIN attributes:nil error:&error]; if (error) { - OWSFailDebug(@"Failed to create directory: %@, error: %@", dirPath, error); return NO; } return [self protectFileOrFolderAtPath:dirPath fileProtectionType:fileProtectionType]; @@ -229,7 +170,6 @@ NS_ASSUME_NONNULL_BEGIN } else { BOOL success = [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]; if (!success) { - OWSFailDebug(@"Failed to create file."); return NO; } return [self protectFileOrFolderAtPath:filePath]; @@ -241,7 +181,6 @@ NS_ASSUME_NONNULL_BEGIN NSError *error; BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; if (!success || error) { - OWSLogError(@"Failed to delete file: %@", error.description); return NO; } return YES; @@ -257,13 +196,10 @@ NS_ASSUME_NONNULL_BEGIN + (NSArray *_Nullable)allFilesInDirectoryRecursive:(NSString *)dirPath error:(NSError **)error { - OWSAssertDebug(dirPath.length > 0); - *error = nil; NSArray *filenames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dirPath error:error]; if (*error) { - OWSFailDebug(@"could not find files in directory: %@", *error); return nil; } @@ -306,13 +242,10 @@ NS_ASSUME_NONNULL_BEGIN + (nullable NSString *)writeDataToTemporaryFile:(NSData *)data fileExtension:(NSString *_Nullable)fileExtension { - OWSAssertDebug(data); - NSString *tempFilePath = [self temporaryFilePathWithFileExtension:fileExtension]; NSError *error; BOOL success = [data writeToFile:tempFilePath options:NSDataWritingAtomic error:&error]; if (!success || error) { - OWSFailDebug(@"could not write to temporary file: %@", error); return nil; } @@ -328,7 +261,6 @@ NS_ASSUME_NONNULL_BEGIN unsigned long long fileSize = [[fileManager attributesOfItemAtPath:filePath error:&error][NSFileSize] unsignedLongLongValue]; if (error) { - OWSLogError(@"Couldn't fetch file size[%@]: %@", filePath, error); return nil; } else { return @(fileSize); @@ -346,8 +278,7 @@ NSString *OWSTemporaryDirectory(void) dispatch_once(&onceToken, ^{ NSString *dirName = [NSString stringWithFormat:@"ows_temp_%@", NSUUID.UUID.UUIDString]; dirPath = [NSTemporaryDirectory() stringByAppendingPathComponent:dirName]; - BOOL success = [OWSFileSystem ensureDirectoryExists:dirPath fileProtectionType:NSFileProtectionComplete]; - OWSCAssert(success); + [OWSFileSystem ensureDirectoryExists:dirPath fileProtectionType:NSFileProtectionComplete]; }); return dirPath; } @@ -355,9 +286,8 @@ NSString *OWSTemporaryDirectory(void) NSString *OWSTemporaryDirectoryAccessibleAfterFirstAuth(void) { NSString *dirPath = NSTemporaryDirectory(); - BOOL success = [OWSFileSystem ensureDirectoryExists:dirPath - fileProtectionType:NSFileProtectionCompleteUntilFirstUserAuthentication]; - OWSCAssert(success); + [OWSFileSystem ensureDirectoryExists:dirPath + fileProtectionType:NSFileProtectionCompleteUntilFirstUserAuthentication]; return dirPath; } @@ -371,7 +301,6 @@ void ClearOldTemporaryDirectoriesSync(void) NSError *error; NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dirPath error:&error]; if (error) { - OWSCFailDebug(@"contentsOfDirectoryAtPath error: %@", error); return; } for (NSString *fileName in fileNames) { @@ -390,32 +319,28 @@ void ClearOldTemporaryDirectoriesSync(void) // a) "ows_temp" name prefix. // b) modified time before app launch time. if (![fileName hasPrefix:@"ows_temp"]) { - NSError *error; - NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; - if (!attributes || error) { + NSError *e; + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&e]; + if (!attributes || e) { // This is fine; the file may have been deleted since we found it. - OWSLogError(@"Could not get attributes of file or directory at: %@", filePath); continue; } // Don't delete files which were created in the last N minutes. NSDate *creationDate = attributes.fileModificationDate; - if ([creationDate isAfterDate:thresholdDate]) { - OWSLogInfo(@"Skipping file due to age: %f", fabs([creationDate timeIntervalSinceNow])); + if (creationDate.timeIntervalSince1970 > thresholdDate.timeIntervalSince1970) { continue; } } - OWSLogVerbose(@"Removing temp file or directory: %@", filePath); if (![OWSFileSystem deleteFile:filePath]) { // This can happen if the app launches before the phone is unlocked. // Clean up will occur when app becomes active. - OWSLogWarn(@"Could not delete old temp directory: %@", filePath); } } } // NOTE: We need to call this method on launch _and_ every time the app becomes active, -// since file protection may prevent it from succeeding in the background. +// since file protection may prevent it from succeeding in the background. void ClearOldTemporaryDirectories(void) { // We use the lowest priority queue for this, and wait N seconds diff --git a/SignalUtilitiesKit/Utilities/OWSMediaUtils.swift b/SessionUtilitiesKit/OWSMediaUtils.swift similarity index 76% rename from SignalUtilitiesKit/Utilities/OWSMediaUtils.swift rename to SessionUtilitiesKit/OWSMediaUtils.swift index c74223e9a..59e064cee 100644 --- a/SignalUtilitiesKit/Utilities/OWSMediaUtils.swift +++ b/SessionUtilitiesKit/OWSMediaUtils.swift @@ -1,7 +1,3 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - import Foundation import AVFoundation @@ -16,7 +12,7 @@ public enum OWSMediaError: Error { } @objc public class func thumbnail(forImageAtPath path: String, maxDimension: CGFloat) throws -> UIImage { - Logger.verbose("thumbnailing image: \(path)") + SNLog("thumbnailing image: \(path)") guard FileManager.default.fileExists(atPath: path) else { throw OWSMediaError.failure(description: "Media file missing.") @@ -34,7 +30,7 @@ public enum OWSMediaError: Error { } @objc public class func thumbnail(forVideoAtPath path: String, maxDimension: CGFloat) throws -> UIImage { - Logger.verbose("thumbnailing video: \(path)") + SNLog("thumbnailing video: \(path)") guard isVideoOfValidContentTypeAndSize(path: path) else { throw OWSMediaError.failure(description: "Media file has missing or invalid length.") @@ -58,7 +54,7 @@ public enum OWSMediaError: Error { @objc public class func isValidVideo(path: String) -> Bool { guard isVideoOfValidContentTypeAndSize(path: path) else { - Logger.error("Media file has missing or invalid length.") + SNLog("Media file has missing or invalid length.") return false } @@ -69,21 +65,21 @@ public enum OWSMediaError: Error { private class func isVideoOfValidContentTypeAndSize(path: String) -> Bool { guard FileManager.default.fileExists(atPath: path) else { - Logger.error("Media file missing.") + SNLog("Media file missing.") return false } let fileExtension = URL(fileURLWithPath: path).pathExtension guard let contentType = MIMETypeUtil.mimeType(forFileExtension: fileExtension) else { - Logger.error("Media file has unknown content type.") + SNLog("Media file has unknown content type.") return false } guard MIMETypeUtil.isSupportedVideoMIMEType(contentType) else { - Logger.error("Media file has invalid content type.") + SNLog("Media file has invalid content type.") return false } guard let fileSize = OWSFileSystem.fileSize(ofPath: path) else { - Logger.error("Media file has unknown length.") + SNLog("Media file has unknown length.") return false } return fileSize.uintValue <= kMaxFileSizeVideo @@ -97,11 +93,11 @@ public enum OWSMediaError: Error { maxTrackSize.height = max(maxTrackSize.height, trackSize.height) } if maxTrackSize.width < 1.0 || maxTrackSize.height < 1.0 { - Logger.error("Invalid video size: \(maxTrackSize)") + SNLog("Invalid video size: \(maxTrackSize)") return false } if maxTrackSize.width > kMaxVideoDimensions || maxTrackSize.height > kMaxVideoDimensions { - Logger.error("Invalid video dimensions: \(maxTrackSize)") + SNLog("Invalid video dimensions: \(maxTrackSize)") return false } return true @@ -115,15 +111,15 @@ public enum OWSMediaError: Error { * https://github.com/signalapp/Signal-Android/blob/master/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java */ @objc - public static var kMaxFileSizeAnimatedImage: UInt { UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier) } + public static var kMaxFileSizeAnimatedImage: UInt { Configuration.shared.maxFileSize } @objc - public static var kMaxFileSizeImage: UInt { UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier) } + public static var kMaxFileSizeImage: UInt { Configuration.shared.maxFileSize } @objc - public static var kMaxFileSizeVideo: UInt { UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier) } + public static var kMaxFileSizeVideo: UInt { Configuration.shared.maxFileSize } @objc - public static var kMaxFileSizeAudio: UInt { UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier) } + public static var kMaxFileSizeAudio: UInt { Configuration.shared.maxFileSize } @objc - public static var kMaxFileSizeGeneric: UInt { UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier) } + public static var kMaxFileSizeGeneric: UInt { Configuration.shared.maxFileSize } @objc public static let kMaxVideoDimensions: CGFloat = 3 * 1024 diff --git a/SessionUtilitiesKit/OWSPrimaryStorageProtocol.swift b/SessionUtilitiesKit/OWSPrimaryStorageProtocol.swift new file mode 100644 index 000000000..49f6b327c --- /dev/null +++ b/SessionUtilitiesKit/OWSPrimaryStorageProtocol.swift @@ -0,0 +1,7 @@ +import YapDatabase + +@objc public protocol OWSPrimaryStorageProtocol { + + var dbReadConnection: YapDatabaseConnection { get } + var dbReadWriteConnection: YapDatabaseConnection { get } +} diff --git a/SignalUtilitiesKit/Database/Storage/Storage.swift b/SessionUtilitiesKit/Storage.swift similarity index 92% rename from SignalUtilitiesKit/Database/Storage/Storage.swift rename to SessionUtilitiesKit/Storage.swift index c0bda5868..b294bafdf 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage.swift +++ b/SessionUtilitiesKit/Storage.swift @@ -1,4 +1,5 @@ import PromiseKit +import YapDatabase // Some important notes about YapDatabase: // @@ -6,10 +7,10 @@ import PromiseKit // • Executing a write transaction from within a write transaction is NOT allowed. @objc(LKStorage) -public final class Storage : NSObject, SessionMessagingKitStorageProtocol, SessionProtocolKitStorageProtocol, SessionSnodeKitStorageProtocol { +public final class Storage : NSObject { public static let serialQueue = DispatchQueue(label: "Storage.serialQueue", qos: .userInitiated) - private static var owsStorage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } + private static var owsStorage: OWSPrimaryStorageProtocol { Configuration.shared.owsPrimaryStorage } @objc public static let shared = Storage() diff --git a/SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.h b/SessionUtilitiesKit/TSYapDatabaseObject.h similarity index 98% rename from SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.h rename to SessionUtilitiesKit/TSYapDatabaseObject.h index cb95b2ee4..4ddcdcedd 100644 --- a/SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.h +++ b/SessionUtilitiesKit/TSYapDatabaseObject.h @@ -2,6 +2,8 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +#import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -71,9 +73,6 @@ NS_ASSUME_NONNULL_BEGIN - (YapDatabaseConnection *)dbReadWriteConnection; + (YapDatabaseConnection *)dbReadWriteConnection; -- (OWSPrimaryStorage *)primaryStorage; -+ (OWSPrimaryStorage *)primaryStorage; - /** * Fetches the object with the provided identifier * diff --git a/SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.m b/SessionUtilitiesKit/TSYapDatabaseObject.m similarity index 92% rename from SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.m rename to SessionUtilitiesKit/TSYapDatabaseObject.m index 21c313b61..ce9aa7f73 100644 --- a/SignalUtilitiesKit/Database/YapDatabase/TSYapDatabaseObject.m +++ b/SessionUtilitiesKit/TSYapDatabaseObject.m @@ -3,10 +3,8 @@ // #import "TSYapDatabaseObject.h" -#import "OWSPrimaryStorage.h" -#import "SSKEnvironment.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -92,11 +90,6 @@ NS_ASSUME_NONNULL_BEGIN return [[self class] dbReadWriteConnection]; } -- (OWSPrimaryStorage *)primaryStorage -{ - return [[self class] primaryStorage]; -} - #pragma mark Class Methods + (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey @@ -110,8 +103,6 @@ NS_ASSUME_NONNULL_BEGIN + (YapDatabaseConnection *)dbReadConnection { - OWSJanksUI(); - // We use TSYapDatabaseObject's dbReadWriteConnection (not OWSPrimaryStorage's // dbReadConnection) for consistency, since we tend to [TSYapDatabaseObject // save] and want to write to the same connection we read from. To get true @@ -122,14 +113,7 @@ NS_ASSUME_NONNULL_BEGIN + (YapDatabaseConnection *)dbReadWriteConnection { - OWSJanksUI(); - - return SSKEnvironment.shared.objectReadWriteConnection; -} - -+ (OWSPrimaryStorage *)primaryStorage -{ - return [OWSPrimaryStorage sharedManager]; + return SNConfiguration.shared.owsPrimaryStorage.dbReadWriteConnection; } + (NSString *)collection @@ -206,8 +190,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)applyChangeToSelfAndLatestCopy:(YapDatabaseReadWriteTransaction *)transaction changeBlock:(void (^)(id))changeBlock { - OWSAssertDebug(transaction); - changeBlock(self); NSString *collection = [[self class] collection]; @@ -236,9 +218,6 @@ NS_ASSUME_NONNULL_BEGIN { TSYapDatabaseObject *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction]; if (!latest) { - if (!ignoreMissing) { - OWSFailDebug(@"`latest` was unexpectedly nil"); - } return; } diff --git a/SignalUtilitiesKit/Utilities/UIImage+OWS.h b/SessionUtilitiesKit/UIImage+OWS.h similarity index 88% rename from SignalUtilitiesKit/Utilities/UIImage+OWS.h rename to SessionUtilitiesKit/UIImage+OWS.h index c193c9fd2..d4f823513 100644 --- a/SignalUtilitiesKit/Utilities/UIImage+OWS.h +++ b/SessionUtilitiesKit/UIImage+OWS.h @@ -1,7 +1,3 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Utilities/UIImage+OWS.m b/SessionUtilitiesKit/UIImage+OWS.m similarity index 91% rename from SignalUtilitiesKit/Utilities/UIImage+OWS.m rename to SessionUtilitiesKit/UIImage+OWS.m index 2c852100a..9de401082 100644 --- a/SignalUtilitiesKit/Utilities/UIImage+OWS.m +++ b/SessionUtilitiesKit/UIImage+OWS.m @@ -1,9 +1,4 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - #import "UIImage+OWS.h" -#import NS_ASSUME_NONNULL_BEGIN @@ -42,7 +37,6 @@ NS_ASSUME_NONNULL_BEGIN { CGSize originalSize = self.size; if (originalSize.width < 1 || originalSize.height < 1) { - OWSLogError(@"Invalid original size: %@", NSStringFromCGSize(originalSize)); return nil; } @@ -61,14 +55,12 @@ NS_ASSUME_NONNULL_BEGIN thumbnailSize.height = maxDimensionPoints; } if (thumbnailSize.width < 1 || thumbnailSize.height < 1) { - OWSLogError(@"Invalid thumbnail size: %@", NSStringFromCGSize(thumbnailSize)); return nil; } UIGraphicsBeginImageContext(CGSizeMake(thumbnailSize.width, thumbnailSize.height)); CGContextRef _Nullable context = UIGraphicsGetCurrentContext(); if (context == NULL) { - OWSLogError(@"Couldn't create context."); return nil; } CGContextSetInterpolationQuality(context, kCGInterpolationHigh); @@ -141,7 +133,6 @@ NS_ASSUME_NONNULL_BEGIN break; default: - OWSFailDebug(@"Invalid image orientation"); return nil; } @@ -176,15 +167,10 @@ NS_ASSUME_NONNULL_BEGIN - (UIImage *)resizedImageToFillPixelSize:(CGSize)dstSize { - OWSAssertDebug(dstSize.width > 0); - OWSAssertDebug(dstSize.height > 0); - UIImage *normalized = [self normalizedImage]; // Get the size in pixels, not points. CGSize srcSize = CGSizeMake(CGImageGetWidth(normalized.CGImage), CGImageGetHeight(normalized.CGImage)); - OWSAssertDebug(srcSize.width > 0); - OWSAssertDebug(srcSize.height > 0); CGFloat widthRatio = srcSize.width / dstSize.width; CGFloat heightRatio = srcSize.height / dstSize.height; @@ -193,13 +179,11 @@ NS_ASSUME_NONNULL_BEGIN drawRect.origin.y = 0; drawRect.size.height = dstSize.height; drawRect.size.width = dstSize.height * srcSize.width / srcSize.height; - OWSAssertDebug(drawRect.size.width > dstSize.width); drawRect.origin.x = (drawRect.size.width - dstSize.width) * -0.5f; } else { drawRect.origin.x = 0; drawRect.size.width = dstSize.width; drawRect.size.height = dstSize.width * srcSize.height / srcSize.width; - OWSAssertDebug(drawRect.size.height >= dstSize.height); drawRect.origin.y = (drawRect.size.height - dstSize.height) * -0.5f; } @@ -214,17 +198,11 @@ NS_ASSUME_NONNULL_BEGIN + (UIImage *)imageWithColor:(UIColor *)color { - OWSAssertIsOnMainThread(); - OWSAssertDebug(color); - return [self imageWithColor:color size:CGSizeMake(1.f, 1.f)]; } + (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size { - OWSAssertIsOnMainThread(); - OWSAssertDebug(color); - CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); UIGraphicsBeginImageContextWithOptions(rect.size, NO, 1.f); CGContextRef context = UIGraphicsGetCurrentContext(); diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index ab725d155..05c2cdedf 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -265,7 +265,6 @@ B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF6422397711F0091D419 /* SettingsVC.swift */; }; B8D8F0F32565F98E0092EF10 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; B8D8F0F42565F98E0092EF10 /* PushNotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */; }; - B8D8F12E2565FC910092EF10 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; }; B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */; }; B8D8F16A256615DE0092EF10 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; }; B8D8F16B256615DE0092EF10 /* Storage+VolumeSamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */; }; @@ -353,8 +352,6 @@ C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8B255A57FD00E217F9 /* AppVersion.m */; }; C33FDC46255A581F00E217F9 /* OpenGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */; }; - C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; }; - C33FDC4A255A582000E217F9 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; }; C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA96255A57FE00E217F9 /* OWSDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */; }; @@ -363,7 +360,6 @@ C33FDC57255A582000E217F9 /* OWSContactsOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */; }; C33FDC5A255A582000E217F9 /* OWSRecipientIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC5B255A582000E217F9 /* TSYapDatabaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; @@ -377,9 +373,7 @@ C33FDC78255A582000E217F9 /* TSConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDABE255A580100E217F9 /* TSConstants.m */; }; C33FDC7A255A582000E217F9 /* OWSIncomingMessageFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC1255A580100E217F9 /* NSSet+Functional.m */; }; - C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC2255A580200E217F9 /* TSAttachment.m */; }; C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC3255A580200E217F9 /* OWSDispatch.m */; }; - C33FDC7E255A582000E217F9 /* TSAttachmentStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */; }; C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; }; C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC8D255A582000E217F9 /* TSThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD3255A580300E217F9 /* TSThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -394,7 +388,6 @@ C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDADF255A580400E217F9 /* PublicChatManager.swift */; }; C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE0255A580400E217F9 /* ByteParser.m */; }; C33FDC9B255A582000E217F9 /* OWSReadTracking.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE1255A580400E217F9 /* OWSReadTracking.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC9E255A582000E217F9 /* TSAttachmentStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE6255A580400E217F9 /* TSInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA1255A582000E217F9 /* TSErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE7255A580500E217F9 /* TSErrorMessage.m */; }; C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -402,15 +395,12 @@ C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEC255A580500E217F9 /* SignalRecipient.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCA9255A582000E217F9 /* NSData+Image.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAEF255A580500E217F9 /* NSData+Image.m */; }; - C33FDCAB255A582000E217F9 /* OWSThumbnailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */; }; C33FDCAC255A582000E217F9 /* ProxiedContentDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */; }; C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */; }; C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF4255A580600E217F9 /* SSKEnvironment.m */; }; C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */; }; C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF9255A580600E217F9 /* TSContactThread.m */; }; C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */; }; - C33FDCB6255A582000E217F9 /* MIMETypeUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; }; C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */; }; @@ -425,13 +415,10 @@ C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB17255A580800E217F9 /* FunctionalUtil.m */; }; C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB19255A580900E217F9 /* GroupUtilities.swift */; }; - C33FDCD6255A582000E217F9 /* UIImage+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1C255A580900E217F9 /* UIImage+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD7255A582000E217F9 /* OWSReadReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD8255A582000E217F9 /* OWSIncomingMessageFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */; }; C33FDCDA255A582000E217F9 /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; }; - C33FDCDC255A582000E217F9 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; }; C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE3255A582000E217F9 /* NSData+Image.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB29255A580A00E217F9 /* NSData+Image.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCE6255A582000E217F9 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCEB255A582000E217F9 /* SSKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB31255A580A00E217F9 /* SSKEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */; }; @@ -441,7 +428,6 @@ C33FDCF5255A582000E217F9 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3F255A580C00E217F9 /* String+SSK.swift */; }; C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */; }; - C33FDCFB255A582000E217F9 /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */; }; C33FDCFD255A582000E217F9 /* YapDatabaseConnection+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */; }; C33FDCFE255A582000E217F9 /* OWSContactsOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */; }; C33FDCFF255A582000E217F9 /* NSString+SSK.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB45255A580C00E217F9 /* NSString+SSK.m */; }; @@ -456,7 +442,6 @@ C33FDD0B255A582000E217F9 /* NSUserDefaults+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0C255A582000E217F9 /* OWSHTTPSecurityPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB52255A580D00E217F9 /* OWSHTTPSecurityPolicy.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0D255A582000E217F9 /* PreKeyBundle+jsonDict.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB53255A580D00E217F9 /* PreKeyBundle+jsonDict.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD0E255A582000E217F9 /* DataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB54255A580D00E217F9 /* DataSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0F255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */; }; C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */; }; C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */; }; @@ -484,12 +469,9 @@ C33FDD38255A582000E217F9 /* TSPreKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */; }; C33FDD39255A582000E217F9 /* FullTextSearchFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */; }; C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB80255A581100E217F9 /* Notification+Loki.swift */; }; - C33FDD3B255A582000E217F9 /* UIImage+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB81255A581100E217F9 /* UIImage+OWS.m */; }; C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB83255A581100E217F9 /* TSQuotedMessage.m */; }; - C33FDD3F255A582000E217F9 /* AppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB85255A581100E217F9 /* AppContext.m */; }; C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB87255A581100E217F9 /* JobQueue.swift */; }; C33FDD42255A582000E217F9 /* TSAccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB88255A581200E217F9 /* TSAccountManager.m */; }; - C33FDD44255A582000E217F9 /* AppContext.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8A255A581200E217F9 /* AppContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */; }; C33FDD46255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; }; @@ -498,7 +480,6 @@ C33FDD4E255A582000E217F9 /* TSAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB94255A581300E217F9 /* TSAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; }; C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD58255A582000E217F9 /* TSAttachmentPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */; }; C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */; }; @@ -506,12 +487,10 @@ C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */; }; C33FDD63255A582000E217F9 /* OWSIdentityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */; }; - C33FDD65255A582000E217F9 /* OWSFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAB255A581500E217F9 /* OWSFileSystem.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD67255A582000E217F9 /* OWSRecordTranscriptJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD68255A582000E217F9 /* SignalAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAE255A581500E217F9 /* SignalAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD6A255A582000E217F9 /* TSErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB0255A581500E217F9 /* TSErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */; }; - C33FDD70255A582000E217F9 /* DataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB6255A581600E217F9 /* DataSource.m */; }; C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB7255A581600E217F9 /* SignalRecipient.m */; }; C33FDD72255A582000E217F9 /* TSThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB8255A581600E217F9 /* TSThread.m */; }; C33FDD73255A582000E217F9 /* ProfileManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -549,9 +528,7 @@ C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */; }; C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC12255A581E00E217F9 /* TSConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDCD255A582000E217F9 /* OWSAttachmentDownloads.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */; }; - C33FDDCF255A582000E217F9 /* TSAttachment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC15255A581E00E217F9 /* TSAttachment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC16255A581E00E217F9 /* FunctionalUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDD2255A582000E217F9 /* TSAttachmentPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC19255A581F00E217F9 /* OWSQueues.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */; }; C33FDDD8255A582000E217F9 /* OWSUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */; }; @@ -586,7 +563,6 @@ C3645350252449260045C478 /* VoiceMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C364534F252449260045C478 /* VoiceMessageView.swift */; }; C364535C252467900045C478 /* AudioUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C364535B252467900045C478 /* AudioUtilities.swift */; }; C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */; }; - C379DCFE25673DBC0002D4EB /* Attachment+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */; }; C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F53A7255B96E0002AEA92 /* OWSAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -787,7 +763,6 @@ C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */; }; C3A7222A2558C1E40043A11F /* DotNetAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A722292558C1E40043A11F /* DotNetAPI.swift */; }; C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */; }; - C3A722802558C4E10043A11F /* AttachmentStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7227F2558C4E10043A11F /* AttachmentStream.swift */; }; C3A722922558C8940043A11F /* OpenGroupAPIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */; }; C3A7229C2558E4310043A11F /* OpenGroupMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */; }; C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Description.swift */; }; @@ -911,6 +886,33 @@ C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; C3D697382564DCE6004AF766 /* MessageReceiverDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */; }; + C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */; }; + C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; }; + C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAB255A581500E217F9 /* OWSFileSystem.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E39B256763C20040E4F3 /* AppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB85255A581100E217F9 /* AppContext.m */; }; + C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8A255A581200E217F9 /* AppContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */; }; + C3D9E3BF25676AD70040E4F3 /* TSAttachmentStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */; }; + C3D9E3C025676AD70040E4F3 /* TSAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC2255A580200E217F9 /* TSAttachment.m */; }; + C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; }; + C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E40C25676C100040E4F3 /* Storage+Conformances.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E40B25676C100040E4F3 /* Storage+Conformances.swift */; }; + C3D9E41525676C320040E4F3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; }; + C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */; }; + C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E43025676D3D0040E4F3 /* Configuration.swift */; }; + C3D9E485256775D20040E4F3 /* TSAttachment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC15255A581E00E217F9 /* TSAttachment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E486256775D20040E4F3 /* TSAttachmentPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E487256775D20040E4F3 /* TSAttachmentStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB6255A581600E217F9 /* DataSource.m */; }; + C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; }; + C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB81255A581100E217F9 /* UIImage+OWS.m */; }; + C3D9E4E3256778720040E4F3 /* UIImage+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1C255A580900E217F9 /* UIImage+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E4F4256778AF0040E4F3 /* NSData+Image.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAEF255A580500E217F9 /* NSData+Image.m */; }; + C3D9E4FD256778E30040E4F3 /* NSData+Image.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB29255A580A00E217F9 /* NSData+Image.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB54255A580D00E217F9 /* DataSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */; }; + C3D9E53925677F5E0040E4F3 /* Attachment+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; @@ -1881,7 +1883,6 @@ C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AnyPromise+Conversion.swift"; sourceTree = ""; }; C3A722292558C1E40043A11F /* DotNetAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotNetAPI.swift; sourceTree = ""; }; C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Retaining.swift"; sourceTree = ""; }; - C3A7227F2558C4E10043A11F /* AttachmentStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentStream.swift; sourceTree = ""; }; C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIDelegate.swift; sourceTree = ""; }; C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupMessage+Conversion.swift"; sourceTree = ""; }; C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = "Migrating Translations from Android.md"; path = "Meta/Translations/Migrating Translations from Android.md"; sourceTree = ""; }; @@ -2012,6 +2013,9 @@ C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = ""; }; C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverDelegate.swift; sourceTree = ""; }; C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverDelegate.swift; sourceTree = ""; }; + C3D9E40B25676C100040E4F3 /* Storage+Conformances.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Conformances.swift"; sourceTree = ""; }; + C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSPrimaryStorageProtocol.swift; sourceTree = ""; }; + C3D9E43025676D3D0040E4F3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = ""; }; C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; @@ -2625,37 +2629,36 @@ children = ( C3C2A74325539EB700C340D1 /* Message.swift */, C352A30825574D8400338F3E /* Message+Destination.swift */, - C300A5C62554B02D00555489 /* Visible Message */, - C300A5C72554B03900555489 /* Control Message */, + C300A5C62554B02D00555489 /* Visible Messages */, + C300A5C72554B03900555489 /* Control Messages */, ); path = Messages; sourceTree = ""; }; - C300A5C62554B02D00555489 /* Visible Message */ = { + C300A5C62554B02D00555489 /* Visible Messages */ = { isa = PBXGroup; children = ( + C3D9E3B52567685D0040E4F3 /* Attachments */, C3C2A74C2553A39700C340D1 /* VisibleMessage.swift */, - C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */, C3C2A7552553A3AB00C340D1 /* VisibleMessage+Quote.swift */, C3C2A75E2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift */, C3C2A7672553A3D900C340D1 /* VisibleMessage+Contact.swift */, C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */, ); - path = "Visible Message"; + path = "Visible Messages"; sourceTree = ""; }; - C300A5C72554B03900555489 /* Control Message */ = { + C300A5C72554B03900555489 /* Control Messages */ = { isa = PBXGroup; children = ( + C379DD172567458A0002D4EB /* Unused */, C3C2A7702553A41E00C340D1 /* ControlMessage.swift */, C300A5BC2554B00D00555489 /* ReadReceipt.swift */, - C300A5C82554B04E00555489 /* SessionRequest.swift */, - C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */, C300A5D22554B05A00555489 /* TypingIndicator.swift */, C300A5DC2554B06600555489 /* ClosedGroupUpdate.swift */, C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */, ); - path = "Control Message"; + path = "Control Messages"; sourceTree = ""; }; C300A5F02554B08500555489 /* Sending & Receiving */ = { @@ -2769,8 +2772,6 @@ C38BBA0C255E32020041B9A3 /* Threads */, C38BBA0D255E321C0041B9A3 /* Messaging */, C38BBA0E255E32440041B9A3 /* Database */, - C33FDB8A255A581200E217F9 /* AppContext.h */, - C33FDB85255A581100E217F9 /* AppContext.m */, C33FDB01255A580700E217F9 /* AppReadiness.h */, C33FDB75255A581000E217F9 /* AppReadiness.m */, C33FDB4C255A580D00E217F9 /* AppVersion.h */, @@ -2799,8 +2800,6 @@ C33FDA8B255A57FD00E217F9 /* AppVersion.m */, C33FDB68255A580F00E217F9 /* ContentProxy.swift */, C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */, - C33FDB54255A580D00E217F9 /* DataSource.h */, - C33FDBB6255A581600E217F9 /* DataSource.m */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, C33FDB87255A581100E217F9 /* JobQueue.swift */, @@ -2828,8 +2827,6 @@ C33FDB59255A580E00E217F9 /* OWSFailedAttachmentDownloadsJob.m */, C33FDADB255A580400E217F9 /* OWSFailedMessagesJob.h */, C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */, - C33FDBAB255A581500E217F9 /* OWSFileSystem.h */, - C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */, C33FDABB255A580100E217F9 /* OWSGroupsOutputStream.h */, C33FDAD8255A580300E217F9 /* OWSGroupsOutputStream.m */, C33FDB52255A580D00E217F9 /* OWSHTTPSecurityPolicy.h */, @@ -2847,7 +2844,6 @@ C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */, C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */, C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */, - C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */, C33FDB5A255A580E00E217F9 /* OWSUDManager.swift */, C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */, C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */, @@ -3056,7 +3052,7 @@ C379DCC3256732800002D4EB /* Storage */ = { isa = PBXGroup; children = ( - C33FDB36255A580B00E217F9 /* Storage.swift */, + C3D9E40B25676C100040E4F3 /* Storage+Conformances.swift */, B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */, B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */, B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */, @@ -3073,8 +3069,6 @@ C379DCC4256732980002D4EB /* YapDatabase */ = { isa = PBXGroup; children = ( - C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */, - C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */, C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, @@ -3179,6 +3173,15 @@ path = "Attachment Approval"; sourceTree = ""; }; + C379DD172567458A0002D4EB /* Unused */ = { + isa = PBXGroup; + children = ( + C300A5C82554B04E00555489 /* SessionRequest.swift */, + C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */, + ); + path = Unused; + sourceTree = ""; + }; C3851CD225624B060061EEB0 /* UI */ = { isa = PBXGroup; children = ( @@ -3286,12 +3289,6 @@ children = ( C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */, C38EF224255B6D5D007E1867 /* SignalAttachment.swift */, - C33FDC15255A581E00E217F9 /* TSAttachment.h */, - C33FDAC2255A580200E217F9 /* TSAttachment.m */, - C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */, - C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */, - C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */, - C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */, ); path = Attachments; sourceTree = ""; @@ -3406,7 +3403,6 @@ C3BBE0B32554F0D30050F1E3 /* Utilities */ = { isa = PBXGroup; children = ( - C3A7227F2558C4E10043A11F /* AttachmentStream.swift */, C3A722292558C1E40043A11F /* DotNetAPI.swift */, C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */, C3A71D0A2558989C0043A11F /* MessageWrapper.swift */, @@ -3460,24 +3456,42 @@ C3C2A68B255388D500C340D1 /* Meta */, C3C2A5D72553860B00C340D1 /* AESGCM.swift */, C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */, + C33FDB8A255A581200E217F9 /* AppContext.h */, + C33FDB85255A581100E217F9 /* AppContext.m */, C3C2A5D12553860800C340D1 /* Array+Description.swift */, + C3D9E43025676D3D0040E4F3 /* Configuration.swift */, + C33FDB54255A580D00E217F9 /* DataSource.h */, + C33FDBB6255A581600E217F9 /* DataSource.m */, C3C2ABD12553C6C900C340D1 /* Data+SecureRandom.swift */, C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */, C3A71D662558A0170043A11F /* DiffieHellman.swift */, C3C2A5BC255385EE00C340D1 /* HTTP.swift */, C3C2A5D92553860B00C340D1 /* JSON.swift */, C3C2A5CE2553860700C340D1 /* Logging.swift */, + C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */, + C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */, C3A71F882558BA9F0043A11F /* Mnemonic.swift */, + C33FDB29255A580A00E217F9 /* NSData+Image.h */, + C33FDAEF255A580500E217F9 /* NSData+Image.m */, C300A6302554B68200555489 /* NSDate+Timestamp.h */, C300A6312554B6D100555489 /* NSDate+Timestamp.mm */, C352A3762557859C00338F3E /* NSTimer+Proxying.h */, C352A36C2557858D00338F3E /* NSTimer+Proxying.m */, + C33FDBAB255A581500E217F9 /* OWSFileSystem.h */, + C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */, + C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */, + C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */, C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */, C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */, C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */, + C33FDB36255A580B00E217F9 /* Storage.swift */, C3C2AC2D2553CBEB00C340D1 /* String+Trimming.swift */, C352A3A42557B5F000338F3E /* TSRequest.h */, C352A3A52557B60D00338F3E /* TSRequest.m */, + C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */, + C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */, + C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, + C33FDB81255A581100E217F9 /* UIImage+OWS.m */, ); path = SessionUtilitiesKit; sourceTree = ""; @@ -3727,15 +3741,12 @@ C33FDB8F255A581200E217F9 /* ParamParser.swift */, C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, - C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, - C33FDB81255A581100E217F9 /* UIImage+OWS.m */, C33FDB49255A580C00E217F9 /* WeakTimer.swift */, C33FDB3F255A580C00E217F9 /* String+SSK.swift */, C33FDBC2255A581700E217F9 /* SSKAsserts.h */, C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */, C33FDB91255A581200E217F9 /* ProtoUtils.h */, C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, - C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */, C33FDB14255A580800E217F9 /* OWSMath.h */, C33FDADC255A580400E217F9 /* NSObject+Casting.h */, C33FDAAA255A580000E217F9 /* NSObject+Casting.m */, @@ -3752,10 +3763,6 @@ C33FDAB8255A580100E217F9 /* NSArray+Functional.m */, C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */, C33FDB0D255A580800E217F9 /* NSArray+OWS.m */, - C33FDB29255A580A00E217F9 /* NSData+Image.h */, - C33FDAEF255A580500E217F9 /* NSData+Image.m */, - C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */, - C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */, C33FDAFD255A580600E217F9 /* LRUCache.swift */, C33FDC03255A581D00E217F9 /* ByteParser.h */, C33FDAE0255A580400E217F9 /* ByteParser.m */, @@ -3784,6 +3791,21 @@ path = Utilities; sourceTree = ""; }; + C3D9E3B52567685D0040E4F3 /* Attachments */ = { + isa = PBXGroup; + children = ( + C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */, + C33FDC15255A581E00E217F9 /* TSAttachment.h */, + C33FDAC2255A580200E217F9 /* TSAttachment.m */, + C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */, + C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */, + C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */, + C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */, + C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */, + ); + path = Attachments; + sourceTree = ""; + }; C3F0A58F255C8E3D007BE2A3 /* Meta */ = { isa = PBXGroup; children = ( @@ -3927,7 +3949,6 @@ C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */, C33FDD46255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.h in Headers */, C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */, - C33FDCE3255A582000E217F9 /* NSData+Image.h in Headers */, C38EF311255B6DBF007E1867 /* OWSScrubbingLogFormatter.h in Headers */, C33FDC77255A582000E217F9 /* OWSOutgoingReceiptManager.h in Headers */, B8C2B3442563782400551B4D /* ThreadUtil.h in Headers */, @@ -3939,7 +3960,6 @@ C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */, C33FDD73255A582000E217F9 /* ProfileManagerProtocol.h in Headers */, C38EF2D8255B6DAF007E1867 /* OWSUserProfile.h in Headers */, - C33FDCB6255A582000E217F9 /* MIMETypeUtil.h in Headers */, C33FDD17255A582000E217F9 /* TSErrorMessage_privateConstructor.h in Headers */, C33FDC93255A582000E217F9 /* OWSDisappearingMessagesConfiguration.h in Headers */, C38EF2C2255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h in Headers */, @@ -3947,10 +3967,7 @@ C38EF313255B6DBF007E1867 /* OWSUnreadIndicator.h in Headers */, C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, C33FDC9B255A582000E217F9 /* OWSReadTracking.h in Headers */, - C33FDD44255A582000E217F9 /* AppContext.h in Headers */, C33FDC97255A582000E217F9 /* TSInfoMessage.h in Headers */, - C33FDD65255A582000E217F9 /* OWSFileSystem.h in Headers */, - C33FDCD6255A582000E217F9 /* UIImage+OWS.h in Headers */, C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */, C33FDC3A255A581F00E217F9 /* OWSDisappearingMessagesJob.h in Headers */, C33FDD6A255A582000E217F9 /* TSErrorMessage.h in Headers */, @@ -3965,7 +3982,6 @@ C33FDC2C255A581F00E217F9 /* OWSFailedAttachmentDownloadsJob.h in Headers */, C38EF22A255B6D5D007E1867 /* AttachmentSharing.h in Headers */, C33FDD67255A582000E217F9 /* OWSRecordTranscriptJob.h in Headers */, - C33FDDCF255A582000E217F9 /* TSAttachment.h in Headers */, C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */, C33FDC2F255A581F00E217F9 /* OWSSyncManagerProtocol.h in Headers */, C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */, @@ -3973,7 +3989,6 @@ C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */, C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */, C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */, - C33FDC5B255A582000E217F9 /* TSYapDatabaseObject.h in Headers */, C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */, C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */, C33FDCC4255A582000E217F9 /* TSGroupModel.h in Headers */, @@ -3985,7 +4000,6 @@ C33FDD0C255A582000E217F9 /* OWSHTTPSecurityPolicy.h in Headers */, C33FDC57255A582000E217F9 /* OWSContactsOutputStream.h in Headers */, C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */, - C33FDDD2255A582000E217F9 /* TSAttachmentPointer.h in Headers */, C38EF3F0255B6DF7007E1867 /* ThreadViewHelper.h in Headers */, C33FDCD7255A582000E217F9 /* OWSReadReceiptManager.h in Headers */, C33FDD21255A582000E217F9 /* OWSMediaGalleryFinder.h in Headers */, @@ -4000,7 +4014,6 @@ C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */, C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */, C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */, - C33FDC9E255A582000E217F9 /* TSAttachmentStream.h in Headers */, C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */, C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */, C33FDD84255A582000E217F9 /* LKGroupUtilities.h in Headers */, @@ -4020,7 +4033,6 @@ C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */, C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */, C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */, - C33FDD0E255A582000E217F9 /* DataSource.h in Headers */, C38EF325255B6DBF007E1867 /* OWSWindowManager.h in Headers */, C33FDCF2255A582000E217F9 /* OWSBackgroundTask.h in Headers */, C38EF39C255B6DDA007E1867 /* OWSQuotedReplyModel.h in Headers */, @@ -4077,8 +4089,15 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */, + C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */, + C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */, C352A3B72557B6ED00338F3E /* TSRequest.h in Headers */, + C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */, + C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */, + C3D9E4FD256778E30040E4F3 /* NSData+Image.h in Headers */, C300A63B2554B72200555489 /* NSDate+Timestamp.h in Headers */, + C3D9E4E3256778720040E4F3 /* UIImage+OWS.h in Headers */, C352A3772557864000338F3E /* NSTimer+Proxying.h in Headers */, C3C2A67D255388CC00C340D1 /* SessionUtilitiesKit.h in Headers */, ); @@ -4088,7 +4107,10 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + C3D9E485256775D20040E4F3 /* TSAttachment.h in Headers */, C3C2A6F425539DE700C340D1 /* SessionMessagingKit.h in Headers */, + C3D9E487256775D20040E4F3 /* TSAttachmentStream.h in Headers */, + C3D9E486256775D20040E4F3 /* TSAttachmentPointer.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4933,7 +4955,6 @@ files = ( C38EF30D255B6DBF007E1867 /* OWSUnreadIndicator.m in Sources */, C38EF3FD255B6DF7007E1867 /* OWSTextView.m in Sources */, - C33FDCA9255A582000E217F9 /* NSData+Image.m in Sources */, C38EF3C6255B6DE7007E1867 /* ImageEditorModel.swift in Sources */, C38EF317255B6DBF007E1867 /* DisplayableText.swift in Sources */, C38EF30F255B6DBF007E1867 /* AppPreferences.swift in Sources */, @@ -4963,9 +4984,8 @@ C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */, C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */, C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */, - C379DCFE25673DBC0002D4EB /* Attachment+Conversion.swift in Sources */, + C3D9E40C25676C100040E4F3 /* Storage+Conformances.swift in Sources */, C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */, - C33FDCFB255A582000E217F9 /* MIMETypeUtil.m in Sources */, C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */, C38EF244255B6D67007E1867 /* UIDevice+featureSupport.swift in Sources */, C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */, @@ -4992,23 +5012,19 @@ C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */, C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */, C33FDD00255A582000E217F9 /* TSDatabaseView.m in Sources */, - C33FDD3B255A582000E217F9 /* UIImage+OWS.m in Sources */, C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */, C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */, B84072A02565F1670037CB17 /* Quote+Conversion.swift in Sources */, - C33FDC7E255A582000E217F9 /* TSAttachmentStream.m in Sources */, C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */, C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */, C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */, C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */, C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */, - C33FDD3F255A582000E217F9 /* AppContext.m in Sources */, C33FDCC7255A582000E217F9 /* NSArray+OWS.m in Sources */, C38EF3EF255B6DF7007E1867 /* ThreadViewHelper.m in Sources */, C33FDD72255A582000E217F9 /* TSThread.m in Sources */, C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */, C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */, - C33FDC4A255A582000E217F9 /* TSYapDatabaseObject.m in Sources */, C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */, C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */, C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */, @@ -5034,13 +5050,11 @@ C38EF316255B6DBF007E1867 /* ProximityMonitoringManager.swift in Sources */, C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */, C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */, - C33FDD58255A582000E217F9 /* TSAttachmentPointer.m in Sources */, C33FDD39255A582000E217F9 /* FullTextSearchFinder.swift in Sources */, C38EEF0A255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift in Sources */, C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */, C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */, C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, - C33FDC7C255A582000E217F9 /* TSAttachment.m in Sources */, C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */, B8D8F16A256615DE0092EF10 /* Storage+Shared.swift in Sources */, C33FDC46255A581F00E217F9 /* OpenGroupPoller.swift in Sources */, @@ -5066,7 +5080,6 @@ C33FDD05255A582000E217F9 /* OWSChunkedOutputStream.m in Sources */, C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */, C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */, - B8D8F12E2565FC910092EF10 /* Storage.swift in Sources */, C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */, C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */, C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */, @@ -5084,7 +5097,6 @@ C33FDD22255A582000E217F9 /* ContentProxy.swift in Sources */, C38EF310255B6DBF007E1867 /* DebugLogger.m in Sources */, C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */, - C33FDD70255A582000E217F9 /* DataSource.m in Sources */, C33FDD2F255A582000E217F9 /* AppReadiness.m in Sources */, C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */, C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */, @@ -5112,7 +5124,6 @@ C33FDCF4255A582000E217F9 /* Poller.swift in Sources */, C38EF332255B6DBF007E1867 /* OWSPreferences.m in Sources */, C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */, - C33FDC48255A581F00E217F9 /* OWSFileSystem.m in Sources */, C38EF39E255B6DDA007E1867 /* OWSQuotedReplyModel.m in Sources */, B8D8F17725661AFA0092EF10 /* Storage+Jobs.swift in Sources */, C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, @@ -5148,6 +5159,7 @@ C38EF293255B6D86007E1867 /* AppSetup.m in Sources */, C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */, C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */, + C3D9E53925677F5E0040E4F3 /* Attachment+Conversion.swift in Sources */, C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */, C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */, B8D8F0F42565F98E0092EF10 /* PushNotificationAPI.swift in Sources */, @@ -5160,7 +5172,6 @@ C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, C33FDCAC255A582000E217F9 /* ProxiedContentDownloader.swift in Sources */, C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */, - C33FDCDC255A582000E217F9 /* OWSMediaUtils.swift in Sources */, C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */, C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */, C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */, @@ -5188,7 +5199,6 @@ C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */, C33FDDD8255A582000E217F9 /* OWSUploadOperation.m in Sources */, C33FDDC5255A582000E217F9 /* OWSError.m in Sources */, - C33FDCAB255A582000E217F9 /* OWSThumbnailService.swift in Sources */, C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */, C33FDC2D255A581F00E217F9 /* ECKeyPair+Hexadecimal.swift in Sources */, C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */, @@ -5228,20 +5238,31 @@ buildActionMask = 2147483647; files = ( C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */, + C3D9E41525676C320040E4F3 /* Storage.swift in Sources */, + C3D9E39B256763C20040E4F3 /* AppContext.m in Sources */, C3BBE0A82554D4DE0050F1E3 /* JSON.swift in Sources */, C352A36D2557858E00338F3E /* NSTimer+Proxying.m in Sources */, C3C2ABD22553C6C900C340D1 /* Data+SecureRandom.swift in Sources */, + C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */, + C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */, C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */, C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */, + C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */, C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Description.swift in Sources */, + C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */, + C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */, C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */, + C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */, C352A3A62557B60D00338F3E /* TSRequest.m in Sources */, C3471ED42555386B00297E91 /* AESGCM.swift in Sources */, C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */, C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */, + C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */, C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */, + C3D9E4F4256778AF0040E4F3 /* NSData+Image.m in Sources */, C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */, C300A60D2554B31900555489 /* Logging.swift in Sources */, + C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */, C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */, C300A6322554B6D100555489 /* NSDate+Timestamp.mm in Sources */, ); @@ -5253,7 +5274,6 @@ files = ( C3A7229C2558E4310043A11F /* OpenGroupMessage+Conversion.swift in Sources */, C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */, - C3A722802558C4E10043A11F /* AttachmentStream.swift in Sources */, C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */, C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */, C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */, @@ -5262,6 +5282,7 @@ C3C2A74D2553A39700C340D1 /* VisibleMessage.swift in Sources */, C352A3932557883D00338F3E /* JobDelegate.swift in Sources */, C352A31325574F5200338F3E /* MessageReceiveJob.swift in Sources */, + C3D9E3BF25676AD70040E4F3 /* TSAttachmentStream.m in Sources */, C3A722922558C8940043A11F /* OpenGroupAPIDelegate.swift in Sources */, C3C2A7562553A3AB00C340D1 /* VisibleMessage+Quote.swift in Sources */, C300A5FC2554B0A000555489 /* MessageReceiver.swift in Sources */, @@ -5269,6 +5290,7 @@ C352A3892557876500338F3E /* JobQueue.swift in Sources */, C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */, C3A721902558C0CD0043A11F /* FileServerAPI.swift in Sources */, + C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */, C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */, C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */, C3C2A7842553AAF300C340D1 /* SNProto.swift in Sources */, @@ -5282,6 +5304,7 @@ C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */, C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */, C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */, + C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */, C3471F4225553A4D00297E91 /* Threading.swift in Sources */, C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */, C3471FA42555439E00297E91 /* Notification+MessageSender.swift in Sources */, @@ -5290,6 +5313,7 @@ C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */, C352A30925574D8500338F3E /* Message+Destination.swift in Sources */, C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */, + C3D9E3C025676AD70040E4F3 /* TSAttachment.m in Sources */, C3D697382564DCE6004AF766 /* MessageReceiverDelegate.swift in Sources */, C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */, C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */, diff --git a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m index cb270323e..bdc905703 100644 --- a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m +++ b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m @@ -5,7 +5,7 @@ #import "OWSDatabaseMigrationRunner.h" #import "OWSDatabaseMigration.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Conformances.swift b/SignalUtilitiesKit/Database/Storage/Storage+Conformances.swift new file mode 100644 index 000000000..c42dcc40f --- /dev/null +++ b/SignalUtilitiesKit/Database/Storage/Storage+Conformances.swift @@ -0,0 +1,2 @@ + +extension Storage : SessionMessagingKitStorageProtocol, SessionProtocolKitStorageProtocol, SessionSnodeKitStorageProtocol { } diff --git a/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m b/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m index 54dede175..970b55803 100644 --- a/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m +++ b/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m @@ -3,7 +3,7 @@ // #import "ThreadViewHelper.h" -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m b/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m index 18a1aed67..29d9f5e32 100644 --- a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m +++ b/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m @@ -5,7 +5,7 @@ #import "OWSQuotedReplyModel.h" #import "ConversationViewItem.h" #import -#import +#import #import #import diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift index a8efdb92a..84eb02a3f 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift @@ -312,40 +312,4 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: message.sender!, ratchet: ratchet, using: transaction) } - - - - // MARK: - Attachments - - public func parseAttachments(from protos: [SNProtoAttachmentPointer]) -> [VisibleMessage.Attachment] { - return protos.compactMap { proto in - let result = VisibleMessage.Attachment() - result.fileName = proto.fileName - func inferContentType() -> String { - guard let fileName = result.fileName, let fileExtension = URL(string: fileName)?.pathExtension else { return OWSMimeTypeApplicationOctetStream } - return MIMETypeUtil.mimeType(forFileExtension: fileExtension) ?? OWSMimeTypeApplicationOctetStream - } - result.contentType = proto.contentType ?? inferContentType() - result.key = proto.key - result.digest = proto.digest - let kind: VisibleMessage.Attachment.Kind - if proto.hasFlags && (proto.flags & UInt32(SNProtoAttachmentPointer.SNProtoAttachmentPointerFlags.voiceMessage.rawValue)) > 0 { - kind = .voiceMessage - } else { - kind = .generic - } - result.kind = kind - result.caption = proto.hasCaption ? proto.caption : nil - let size: CGSize - if proto.hasWidth && proto.width > 0 && proto.hasHeight && proto.height > 0 { - size = CGSize(width: Int(proto.width), height: Int(proto.height)) - } else { - size = CGSize.zero - } - result.size = size - result.sizeInBytes = proto.size > 0 ? UInt(proto.size) : nil - result.url = proto.url - return result.isValid ? result : nil - } - } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index affbd632f..aa26c37a6 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -7,6 +7,10 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) } + + public func handleFailedMessageSend(_ message: Message, using transaction: Any) { + // TODO: Implement + } public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { SNLog("Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index e86992ce3..ec10aed87 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -8,7 +8,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; @import SessionSnodeKit; @import SessionUtilitiesKit; -#import #import #import #import @@ -17,7 +16,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import @@ -38,7 +36,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import diff --git a/SignalUtilitiesKit/OWSPreferences.m b/SignalUtilitiesKit/OWSPreferences.m index c72f9ecd1..c1bf374ec 100644 --- a/SignalUtilitiesKit/OWSPreferences.m +++ b/SignalUtilitiesKit/OWSPreferences.m @@ -3,7 +3,7 @@ // #import "OWSPreferences.h" -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/OWSSounds.m b/SignalUtilitiesKit/OWSSounds.m index f50e5e9e6..edff6751d 100644 --- a/SignalUtilitiesKit/OWSSounds.m +++ b/SignalUtilitiesKit/OWSSounds.m @@ -6,7 +6,7 @@ #import "Environment.h" #import "OWSAudioPlayer.h" #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m index 2d9ac74ef..8e99e6925 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -8,14 +8,14 @@ #import #import #import "UIUtil.h" -#import +#import #import -#import +#import #import #import #import #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/To Do/OWSUserProfile.m b/SignalUtilitiesKit/To Do/OWSUserProfile.m index bedb81b7d..36113d034 100644 --- a/SignalUtilitiesKit/To Do/OWSUserProfile.m +++ b/SignalUtilitiesKit/To Do/OWSUserProfile.m @@ -6,10 +6,10 @@ #import -#import +#import #import #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/UI/SelectRecipientViewController.m b/SignalUtilitiesKit/UI/SelectRecipientViewController.m index a592b7e1e..35571e317 100644 --- a/SignalUtilitiesKit/UI/SelectRecipientViewController.m +++ b/SignalUtilitiesKit/UI/SelectRecipientViewController.m @@ -10,7 +10,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/UI/UIUtil.h b/SignalUtilitiesKit/UI/UIUtil.h index 73db5cb3e..96983e675 100644 --- a/SignalUtilitiesKit/UI/UIUtil.h +++ b/SignalUtilitiesKit/UI/UIUtil.h @@ -4,7 +4,7 @@ #import #import -#import +#import #import #define ACCESSIBILITY_IDENTIFIER_WITH_NAME(_root_view, _variable_name) \ diff --git a/SignalUtilitiesKit/UI/UIUtil.m b/SignalUtilitiesKit/UI/UIUtil.m index 2390c03be..940657363 100644 --- a/SignalUtilitiesKit/UI/UIUtil.m +++ b/SignalUtilitiesKit/UI/UIUtil.m @@ -5,7 +5,7 @@ #import "UIUtil.h" #import "Theme.h" #import "UIColor+OWS.h" -#import +#import #import diff --git a/SignalUtilitiesKit/UI/UIView+OWS.m b/SignalUtilitiesKit/UI/UIView+OWS.m index 7101d2d25..79fe83339 100644 --- a/SignalUtilitiesKit/UI/UIView+OWS.m +++ b/SignalUtilitiesKit/UI/UIView+OWS.m @@ -5,7 +5,7 @@ #import "UIView+OWS.h" #import "OWSMath.h" -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/UI/UIViewController+OWS.m b/SignalUtilitiesKit/UI/UIViewController+OWS.m index a8fb4a33d..18ed7599f 100644 --- a/SignalUtilitiesKit/UI/UIViewController+OWS.m +++ b/SignalUtilitiesKit/UI/UIViewController+OWS.m @@ -11,7 +11,7 @@ #import "UIViewController+OWS.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Utilities/AttachmentSharing.m b/SignalUtilitiesKit/Utilities/AttachmentSharing.m index d1b883d9c..aada8799c 100644 --- a/SignalUtilitiesKit/Utilities/AttachmentSharing.m +++ b/SignalUtilitiesKit/Utilities/AttachmentSharing.m @@ -4,7 +4,7 @@ #import "AttachmentSharing.h" #import "UIUtil.h" -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Utilities/DebugLogger.m b/SignalUtilitiesKit/Utilities/DebugLogger.m index 42984cd24..0e8f8e0c4 100644 --- a/SignalUtilitiesKit/Utilities/DebugLogger.m +++ b/SignalUtilitiesKit/Utilities/DebugLogger.m @@ -5,8 +5,8 @@ #import "DebugLogger.h" #import "OWSScrubbingLogFormatter.h" -#import -#import +#import +#import #pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging. #import diff --git a/SignalUtilitiesKit/Utilities/NSAttributedString+OWS.m b/SignalUtilitiesKit/Utilities/NSAttributedString+OWS.m index 84ea2a773..936a15b2f 100644 --- a/SignalUtilitiesKit/Utilities/NSAttributedString+OWS.m +++ b/SignalUtilitiesKit/Utilities/NSAttributedString+OWS.m @@ -4,7 +4,7 @@ #import "NSAttributedString+OWS.h" #import "UIView+OWS.h" -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Utilities/SSKAsserts.h b/SignalUtilitiesKit/Utilities/SSKAsserts.h index 93e5d2a73..8fcbd48eb 100755 --- a/SignalUtilitiesKit/Utilities/SSKAsserts.h +++ b/SignalUtilitiesKit/Utilities/SSKAsserts.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import #import #import diff --git a/SignalUtilitiesKit/VersionMigrations.m b/SignalUtilitiesKit/VersionMigrations.m index 18b71738b..53d4fe530 100644 --- a/SignalUtilitiesKit/VersionMigrations.m +++ b/SignalUtilitiesKit/VersionMigrations.m @@ -5,7 +5,7 @@ #import "VersionMigrations.h" #import "OWSDatabaseMigrationRunner.h" #import "SignalKeyingStorage.h" -#import +#import #import #import #import From d7c71a8c06f02ee264a4bacde2c959050c4eddb8 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 23 Nov 2020 10:24:40 +1100 Subject: [PATCH 019/177] Make things compile again --- Session/Configuration.swift | 3 ++ Session/Meta/Signal-Bridging-Header.h | 12 +++---- .../Cells/AttachmentUploadView.m | 2 +- .../Cells/OWSGenericAttachmentView.m | 2 +- .../Cells/OWSQuotedMessageView.m | 2 +- .../ConversationView/ConversationViewItem.m | 2 +- Session/Signal/MediaDetailViewController.m | 2 +- Session/Signal/OWSBackupExportJob.m | 4 +-- Session/Signal/OWSBackupImportJob.m | 2 +- Session/Signal/OWSOrphanDataCleaner.m | 4 +-- Session/Signal/SessionResetJob.swift | 2 +- .../Jobs/AttachmentDownloadJob.swift | 35 +++++++++++++------ .../Attachments/TSAttachment.h | 5 --- .../Attachments/TSAttachment.m | 7 ---- .../Attachments/TSAttachmentPointer.h | 3 ++ .../Attachments/TSAttachmentPointer.m | 10 ------ .../Sending & Receiving/MessageReceiver.swift | 23 ++++++------ .../MessageReceiverDelegate.swift | 2 +- SessionMessagingKit/Storage.swift | 10 ++++-- SessionUtilitiesKit/Configuration.swift | 2 +- SessionUtilitiesKit/TSYapDatabaseObject.m | 2 +- Signal.xcodeproj/project.pbxproj | 16 +++++++++ .../Database/Migration/OWSDatabaseMigration.h | 2 +- .../Database/Storage/Storage+Messaging.swift | 26 +++++++++++--- .../Database/Utilities/TSDatabaseView.m | 2 +- .../Attachments/TSAttachment+Albums.h | 18 ++++++++++ .../Attachments/TSAttachment+Albums.m | 18 ++++++++++ .../Attachments/TSAttachmentPointer+Backups.h | 19 ++++++++++ .../Attachments/TSAttachmentPointer+Backups.m | 34 ++++++++++++++++++ .../Messaging/Core Messages/TSInteraction.h | 2 +- .../OWSDisappearingMessagesConfiguration.h | 2 +- .../Messaging/Quotes/OWSQuotedReplyModel.m | 5 ++- .../Messaging/Quotes/TSQuotedMessage.h | 2 +- .../MessageReceiverDelegate.swift | 6 ++-- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 7 ++-- SignalUtilitiesKit/OWSBackupFragment.h | 2 +- SignalUtilitiesKit/OWSMediaGalleryFinder.m | 1 + SignalUtilitiesKit/OWSRecipientIdentity.h | 2 +- SignalUtilitiesKit/SSKJobRecord.h | 2 +- SignalUtilitiesKit/SignalAccount.h | 2 +- SignalUtilitiesKit/SignalRecipient.h | 2 +- SignalUtilitiesKit/Threads/TSGroupModel.h | 2 +- SignalUtilitiesKit/Threads/TSThread.h | 2 +- SignalUtilitiesKit/To Do/OWSProfileManager.m | 6 ++-- SignalUtilitiesKit/To Do/OWSUserProfile.h | 2 +- SignalUtilitiesKit/UI/UIUtil.h | 2 +- .../Utilities/AttachmentSharing.m | 2 +- 47 files changed, 223 insertions(+), 99 deletions(-) create mode 100644 SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h create mode 100644 SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m create mode 100644 SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.h create mode 100644 SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.m diff --git a/Session/Configuration.swift b/Session/Configuration.swift index 68f2373cc..c100c7d96 100644 --- a/Session/Configuration.swift +++ b/Session/Configuration.swift @@ -2,6 +2,8 @@ import SessionMessagingKit import SessionProtocolKit import SessionSnodeKit +extension OWSPrimaryStorage : OWSPrimaryStorageProtocol { } + @objc(SNConfiguration) final class Configuration : NSObject { @@ -20,5 +22,6 @@ final class Configuration : NSObject { ) SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: MessageSenderDelegate.shared) SessionSnodeKit.configure(storage: Storage.shared) + SessionUtilitiesKit.configure(owsPrimaryStorage: OWSPrimaryStorage.shared(), maxFileSize: UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier)) } } diff --git a/Session/Meta/Signal-Bridging-Header.h b/Session/Meta/Signal-Bridging-Header.h index a22e34763..578c0f2e7 100644 --- a/Session/Meta/Signal-Bridging-Header.h +++ b/Session/Meta/Signal-Bridging-Header.h @@ -63,9 +63,9 @@ #import #import #import -#import +#import #import -#import +#import #import #import #import @@ -80,9 +80,9 @@ #import #import #import -#import -#import -#import +#import +#import +#import #import #import #import @@ -92,7 +92,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/ConversationView/Cells/AttachmentUploadView.m b/Session/Signal/ConversationView/Cells/AttachmentUploadView.m index 4b74b21ef..6672ffa8e 100644 --- a/Session/Signal/ConversationView/Cells/AttachmentUploadView.m +++ b/Session/Signal/ConversationView/Cells/AttachmentUploadView.m @@ -9,7 +9,7 @@ #import #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m index b80503e03..55ea4cd7d 100644 --- a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m +++ b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m @@ -12,7 +12,7 @@ #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m index 6ef78ab2c..9ae9cdd14 100644 --- a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m @@ -12,7 +12,7 @@ #import #import #import -#import +#import #import #import diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index 687094150..0d9b25ee6 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -11,7 +11,7 @@ #import "Session-Swift.h" #import "AnyPromise.h" #import -#import +#import #import #import diff --git a/Session/Signal/MediaDetailViewController.m b/Session/Signal/MediaDetailViewController.m index 1d7845a62..825660050 100644 --- a/Session/Signal/MediaDetailViewController.m +++ b/Session/Signal/MediaDetailViewController.m @@ -17,7 +17,7 @@ #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSBackupExportJob.m b/Session/Signal/OWSBackupExportJob.m index fdcba1c38..0d0593483 100644 --- a/Session/Signal/OWSBackupExportJob.m +++ b/Session/Signal/OWSBackupExportJob.m @@ -13,8 +13,8 @@ #import #import #import -#import -#import +#import +#import #import #import diff --git a/Session/Signal/OWSBackupImportJob.m b/Session/Signal/OWSBackupImportJob.m index 6c58e9d07..024f47e56 100644 --- a/Session/Signal/OWSBackupImportJob.m +++ b/Session/Signal/OWSBackupImportJob.m @@ -11,7 +11,7 @@ #import #import #import -#import +#import #import #import diff --git a/Session/Signal/OWSOrphanDataCleaner.m b/Session/Signal/OWSOrphanDataCleaner.m index 0ed5cc8b0..5da139091 100644 --- a/Session/Signal/OWSOrphanDataCleaner.m +++ b/Session/Signal/OWSOrphanDataCleaner.m @@ -9,10 +9,10 @@ #import #import #import - +#import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/SessionResetJob.swift b/Session/Signal/SessionResetJob.swift index 163926c1d..a35f8418c 100644 --- a/Session/Signal/SessionResetJob.swift +++ b/Session/Signal/SessionResetJob.swift @@ -7,7 +7,7 @@ import PromiseKit import SignalUtilitiesKit @objc(OWSSessionResetJobQueue) -public class SessionResetJobQueue: NSObject, JobQueue { +public class SessionResetJobQueue: NSObject, SignalUtilitiesKit.JobQueue { @objc(addContactThread:transaction:) public func add(contactThread: TSContactThread, transaction: YapDatabaseReadWriteTransaction) { diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index f7c6e4dad..1ebb22422 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -5,6 +5,7 @@ import SignalCoreKit public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? private let attachmentID: String + private let tsIncomingMessageID: String public var id: String? public var failureCount: UInt = 0 @@ -23,18 +24,22 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject public static let maxFailureCount: UInt = 20 // MARK: Initialization - public init(attachmentID: String) { + public init(attachmentID: String, tsIncomingMessageID: String) { self.attachmentID = attachmentID + self.tsIncomingMessageID = tsIncomingMessageID } // MARK: Coding public init?(coder: NSCoder) { - guard let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String? else { return nil } + guard let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String?, + let tsIncomingMessageID = coder.decodeObject(forKey: "tsIncomingMessageID") as! String? else { return nil } self.attachmentID = attachmentID + self.tsIncomingMessageID = tsIncomingMessageID } public func encode(with coder: NSCoder) { coder.encode(attachmentID, forKey: "attachmentID") + coder.encode(tsIncomingMessageID, forKey: "tsIncomingMessageID") } // MARK: Running @@ -42,19 +47,30 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject guard let pointer = TSAttachmentPointer.fetch(uniqueId: attachmentID) else { return handleFailure(error: Error.noAttachment) } + let storage = Configuration.shared.storage + storage.withAsync({ transaction in + storage.setAttachmentState(to: .downloading, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) + }, completion: { }) let temporaryFilePath = URL(fileURLWithPath: OWSTemporaryDirectoryAccessibleAfterFirstAuth() + UUID().uuidString) - FileServerAPI.downloadAttachment(from: pointer.downloadURL).done(on: DispatchQueue.global(qos: .userInitiated)) { data in // Intentionally capture self + let handleFailure: (Swift.Error) -> Void = { error in // Intentionally capture self + OWSFileSystem.deleteFile(temporaryFilePath.absoluteString) + storage.withAsync({ transaction in + storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) + }, completion: { }) + self.handleFailure(error: error) + } + FileServerAPI.downloadAttachment(from: pointer.downloadURL).done(on: DispatchQueue.global(qos: .userInitiated)) { data in do { try data.write(to: temporaryFilePath, options: .atomic) } catch { - return self.handleFailure(error: error) + return handleFailure(error) } let plaintext: Data if let key = pointer.encryptionKey, let digest = pointer.digest { do { plaintext = try Cryptography.decryptAttachment(data, withKey: key, digest: digest, unpaddedSize: pointer.byteCount) } catch { - return self.handleFailure(error: error) + return handleFailure(error) } } else { plaintext = data // Open group attachments are unencrypted @@ -63,15 +79,14 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject do { try stream.write(plaintext) } catch { - return self.handleFailure(error: error) + return handleFailure(error) } OWSFileSystem.deleteFile(temporaryFilePath.absoluteString) - Configuration.shared.storage.withAsync({ transaction in - stream.save(with: transaction as! YapDatabaseReadWriteTransaction) - // TODO: Update the message + storage.withAsync({ transaction in + storage.persist(stream, associatedWith: self.tsIncomingMessageID, using: transaction) }, completion: { }) }.catch(on: DispatchQueue.global()) { error in - self.handleFailure(error: error) + handleFailure(error) } } diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h index 3e67f5f08..121a19be9 100644 --- a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h @@ -41,11 +41,6 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { @property (nonatomic, readonly, nullable) NSString *caption; @property (nonatomic, nullable) NSString *albumMessageId; -// `migrateAlbumMessageId` is only used in the migration to the new multi-attachment message scheme, -// and shouldn't be used as a general purpose setter. Instead, `albumMessageId` should be passed as -// an initializer param. -- (void)migrateAlbumMessageId:(NSString *)albumMesssageId; - #pragma mark - // This constructor is used for new instances of TSAttachmentPointer, diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m index 43c7139b5..2a36909ee 100644 --- a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m @@ -244,13 +244,6 @@ NSUInteger const TSAttachmentSchemaVersion = 4; return _contentType.filterFilename; } -#pragma mark - Relationships - -- (void)migrateAlbumMessageId:(NSString *)albumMesssageId -{ - _albumMessageId = albumMesssageId; -} - @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h index f8f8e6276..66ae2d8d8 100644 --- a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h @@ -35,6 +35,9 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { @property (nonatomic, readonly) CGSize mediaSize; +// Optional property. Only set for attachments which need "lazy backup restore." +@property (nonatomic, nullable) NSString *lazyRestoreFragmentId; + - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - (instancetype)initWithServerId:(UInt64)serverId diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m index c7bad6658..666904683 100644 --- a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m +++ b/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m @@ -15,16 +15,6 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - - -@interface TSAttachmentPointer () - -// Optional property. Only set for attachments which need "lazy backup restore." -@property (nonatomic, nullable) NSString *lazyRestoreFragmentId; - -@end - -#pragma mark - - @implementation TSAttachmentPointer - (nullable instancetype)initWithCoder:(NSCoder *)coder diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 8f6caf6f2..885298ba2 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -139,16 +139,24 @@ internal enum MessageReceiver { private static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { let delegate = Configuration.shared.messageReceiverDelegate let storage = Configuration.shared.storage - // Handle attachments + // Parse & persist attachments let attachments: [VisibleMessage.Attachment] = proto.dataMessage!.attachments.compactMap { proto in guard let attachment = VisibleMessage.Attachment.fromProto(proto) else { return nil } return attachment.isValid ? attachment : nil } - let attachmentIDs = storage.save(attachments, using: transaction) + let attachmentIDs = storage.persist(attachments, using: transaction) message.attachmentIDs = attachmentIDs + // Update profile if needed + if let profile = message.profile { + delegate.updateProfile(for: message.sender!, from: profile, using: transaction) + } + // Persist the message + guard let (threadID, tsIncomingMessageID) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + message.threadID = threadID + // Start attachment downloads if needed storage.withAsync({ transaction in attachmentIDs.forEach { attachmentID in - let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID) + let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) if CurrentAppContext().isMainAppAndActive { JobQueue.shared.add(downloadJob, using: transaction) } else { @@ -156,16 +164,9 @@ internal enum MessageReceiver { } } }, completion: { }) - // Update profile if needed - if let profile = message.profile { - delegate.updateProfile(for: message.sender!, from: profile, using: transaction) - } - // Persist the message - guard let (threadID, tsIncomingMessage) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } - message.threadID = threadID // Cancel any typing indicators delegate.cancelTypingIndicatorsIfNeeded(for: message.sender!) // Notify the user if needed - delegate.notifyUserIfNeeded(for: tsIncomingMessage, threadID: threadID) + delegate.notifyUserIfNeeded(forMessageWithID: tsIncomingMessageID, threadID: threadID) } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift index cba87224d..4ac94717d 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift @@ -6,7 +6,7 @@ public protocol MessageReceiverDelegate { func showTypingIndicatorIfNeeded(for senderPublicKey: String) func hideTypingIndicatorIfNeeded(for senderPublicKey: String) func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) - func notifyUserIfNeeded(for message: Any, threadID: String) + func notifyUserIfNeeded(forMessageWithID messageID: String, threadID: String) func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 71b0d3fab..62978ad4b 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -61,8 +61,12 @@ public protocol SessionMessagingKitStorageProtocol { // MARK: - Message Handling - /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. - func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, Any)? + /// Returns the ID of the thread the message was stored under along with the ID of the `TSIncomingMessage` that was constructed. + func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, String)? /// Returns the IDs of the saved attachments. - func save(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] + func persist(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] + /// Also touches the associated message. + func setAttachmentState(to state: TSAttachmentPointerState, for pointer: TSAttachmentPointer, associatedWith tsIncomingMessageID: String, using transaction: Any) + /// Also touches the associated message. + func persist(_ stream: TSAttachmentStream, associatedWith tsIncomingMessageID: String, using transaction: Any) } diff --git a/SessionUtilitiesKit/Configuration.swift b/SessionUtilitiesKit/Configuration.swift index 2e3699ab3..22c85f3a3 100644 --- a/SessionUtilitiesKit/Configuration.swift +++ b/SessionUtilitiesKit/Configuration.swift @@ -1,5 +1,5 @@ -@objc(SNConfiguration) +@objc(SNUtilitiesKitConfiguration) public final class Configuration : NSObject { @objc public let owsPrimaryStorage: OWSPrimaryStorageProtocol public let maxFileSize: UInt diff --git a/SessionUtilitiesKit/TSYapDatabaseObject.m b/SessionUtilitiesKit/TSYapDatabaseObject.m index ce9aa7f73..1c3c84b0a 100644 --- a/SessionUtilitiesKit/TSYapDatabaseObject.m +++ b/SessionUtilitiesKit/TSYapDatabaseObject.m @@ -113,7 +113,7 @@ NS_ASSUME_NONNULL_BEGIN + (YapDatabaseConnection *)dbReadWriteConnection { - return SNConfiguration.shared.owsPrimaryStorage.dbReadWriteConnection; + return SNUtilitiesKitConfiguration.shared.owsPrimaryStorage.dbReadWriteConnection; } + (NSString *)collection diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 05c2cdedf..66780ac69 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -263,6 +263,10 @@ B8CCF63723961D6D0091D419 /* NewPrivateChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */; }; B8CCF63F23975CFB0091D419 /* JoinPublicChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */; }; B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF6422397711F0091D419 /* SettingsVC.swift */; }; + B8D797B2256B25A1007C59DF /* TSAttachmentPointer+Backups.m in Sources */ = {isa = PBXBuildFile; fileRef = B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */; }; + B8D797C3256B25A8007C59DF /* TSAttachmentPointer+Backups.h in Headers */ = {isa = PBXBuildFile; fileRef = B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8D797D5256B2715007C59DF /* TSAttachment+Albums.m in Sources */ = {isa = PBXBuildFile; fileRef = B8D797D4256B2715007C59DF /* TSAttachment+Albums.m */; }; + B8D797DF256B2737007C59DF /* TSAttachment+Albums.h in Headers */ = {isa = PBXBuildFile; fileRef = B8D797DE256B2732007C59DF /* TSAttachment+Albums.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8D8F0F32565F98E0092EF10 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; B8D8F0F42565F98E0092EF10 /* PushNotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */; }; B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */; }; @@ -1385,6 +1389,10 @@ B8CCF638239721E20091D419 /* TabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = ""; }; B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinPublicChatVC.swift; sourceTree = ""; }; B8CCF6422397711F0091D419 /* SettingsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsVC.swift; sourceTree = ""; }; + B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TSAttachmentPointer+Backups.h"; sourceTree = ""; }; + B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "TSAttachmentPointer+Backups.m"; sourceTree = ""; }; + B8D797D4256B2715007C59DF /* TSAttachment+Albums.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "TSAttachment+Albums.m"; sourceTree = ""; }; + B8D797DE256B2732007C59DF /* TSAttachment+Albums.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TSAttachment+Albums.h"; sourceTree = ""; }; B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = ""; }; B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Jobs.swift"; sourceTree = ""; }; B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = ""; }; @@ -3289,6 +3297,10 @@ children = ( C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */, C38EF224255B6D5D007E1867 /* SignalAttachment.swift */, + B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */, + B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */, + B8D797DE256B2732007C59DF /* TSAttachment+Albums.h */, + B8D797D4256B2715007C59DF /* TSAttachment+Albums.m */, ); path = Attachments; sourceTree = ""; @@ -3970,6 +3982,7 @@ C33FDC97255A582000E217F9 /* TSInfoMessage.h in Headers */, C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */, C33FDC3A255A581F00E217F9 /* OWSDisappearingMessagesJob.h in Headers */, + B8D797C3256B25A8007C59DF /* TSAttachmentPointer+Backups.h in Headers */, C33FDD6A255A582000E217F9 /* TSErrorMessage.h in Headers */, C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */, C33FDC7A255A582000E217F9 /* OWSIncomingMessageFinder.h in Headers */, @@ -4029,6 +4042,7 @@ C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */, C38EF403255B6DF7007E1867 /* ContactCellView.h in Headers */, C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */, + B8D797DF256B2737007C59DF /* TSAttachment+Albums.h in Headers */, C33FDD68255A582000E217F9 /* SignalAccount.h in Headers */, C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */, C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */, @@ -5155,6 +5169,7 @@ C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */, + B8D797D5256B2715007C59DF /* TSAttachment+Albums.m in Sources */, C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */, C38EF293255B6D86007E1867 /* AppSetup.m in Sources */, C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */, @@ -5202,6 +5217,7 @@ C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */, C33FDC2D255A581F00E217F9 /* ECKeyPair+Hexadecimal.swift in Sources */, C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */, + B8D797B2256B25A1007C59DF /* TSAttachmentPointer+Backups.m in Sources */, C38EF319255B6DBF007E1867 /* Weak.swift in Sources */, C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */, C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */, diff --git a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h index ec59a44cd..3f1bd715e 100644 --- a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h +++ b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift b/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift index ca05b565c..fca7c17b5 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift +++ b/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift @@ -16,8 +16,8 @@ extension Storage { return try! promise.wait() } - /// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed. - public func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, Any)? { + /// Returns the ID of the thread the message was stored under along with the ID of the `TSIncomingMessage` that was constructed. + public func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, String)? { let transaction = transaction as! YapDatabaseReadWriteTransaction var threadOrNil: TSThread? if let groupPublicKey = groupPublicKey { @@ -30,14 +30,32 @@ extension Storage { guard let thread = threadOrNil else { return nil } let message = TSIncomingMessage.from(message, associatedWith: thread) message.save(with: transaction) - return (thread.uniqueId!, message) + return (thread.uniqueId!, message.uniqueId!) } - public func save(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] { + /// Returns the IDs of the saved attachments. + public func persist(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] { return attachments.map { attachment in let tsAttachment = TSAttachmentPointer.from(attachment) tsAttachment.save(with: transaction as! YapDatabaseReadWriteTransaction) return tsAttachment.uniqueId! } } + + /// Also touches the associated message. + public func setAttachmentState(to state: TSAttachmentPointerState, for pointer: TSAttachmentPointer, associatedWith tsIncomingMessageID: String, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + pointer.state = state + pointer.save(with: transaction) + guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { return } + tsIncomingMessage.touch(with: transaction) + } + + /// Also touches the associated message. + public func persist(_ stream: TSAttachmentStream, associatedWith tsIncomingMessageID: String, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction + stream.save(with: transaction) + guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { return } + tsIncomingMessage.touch(with: transaction) + } } diff --git a/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m b/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m index 86b1658ec..fdb13e221 100644 --- a/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m +++ b/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m @@ -3,7 +3,7 @@ // #import "TSDatabaseView.h" - +#import "TSAttachmentPointer+Backups.h" #import "OWSReadTracking.h" #import "TSAttachment.h" #import "TSAttachmentPointer.h" diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h new file mode 100644 index 000000000..946791856 --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h @@ -0,0 +1,18 @@ +#import +#import "TSMessage.h" + +#ifndef TSAttachment_Albums_h +#define TSAttachment_Albums_h + +@interface TSAttachment (Albums) + +- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction; + +// `migrateAlbumMessageId` is only used in the migration to the new multi-attachment message scheme, +// and shouldn't be used as a general purpose setter. Instead, `albumMessageId` should be passed as +// an initializer param. +- (void)migrateAlbumMessageId:(NSString *)albumMesssageId; + +@end + +#endif diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m new file mode 100644 index 000000000..83999453c --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m @@ -0,0 +1,18 @@ +#import "TSAttachment+Albums.h" + +@implementation TSAttachment (Albums) + +- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + if (self.albumMessageId == nil) { + return nil; + } + return [TSMessage fetchObjectWithUniqueID:self.albumMessageId transaction:transaction]; +} + +- (void)migrateAlbumMessageId:(NSString *)albumMesssageId +{ + self.albumMessageId = albumMesssageId; +} + +@end diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.h b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.h new file mode 100644 index 000000000..7fab5a7d9 --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.h @@ -0,0 +1,19 @@ +#import +#import +#import "OWSBackupFragment.h" + +#ifndef TSAttachmentPointer_Backups_h +#define TSAttachmentPointer_Backups_h + +@interface TSAttachmentPointer (Backups) + +// Non-nil for attachments which need "lazy backup restore." +- (nullable OWSBackupFragment *)lazyRestoreFragment; + +// Marks attachment as needing "lazy backup restore." +- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment + transaction:(YapDatabaseReadWriteTransaction *)transaction; + +@end + +#endif diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.m b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.m new file mode 100644 index 000000000..2e21f84df --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.m @@ -0,0 +1,34 @@ +#import "TSAttachmentPointer+Backups.h" + +@implementation TSAttachmentPointer (Backups) + +- (nullable OWSBackupFragment *)lazyRestoreFragment +{ + if (!self.lazyRestoreFragmentId) { + return nil; + } + OWSBackupFragment *_Nullable backupFragment = + [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId]; + OWSAssertDebug(backupFragment); + return backupFragment; +} + +- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssertDebug(lazyRestoreFragment); + OWSAssertDebug(transaction); + + if (!lazyRestoreFragment.uniqueId) { + // If metadata hasn't been saved yet, save now. + [lazyRestoreFragment saveWithTransaction:transaction]; + + OWSAssertDebug(lazyRestoreFragment.uniqueId); + } + [self applyChangeToSelfAndLatestCopy:transaction + changeBlock:^(TSAttachmentPointer *attachment) { + [attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId]; + }]; +} + +@end diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h index 477a59a7f..906bbf1fe 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h index c84747523..3b1c12e19 100644 --- a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h +++ b/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m b/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m index 29d9f5e32..3ea9a8420 100644 --- a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m +++ b/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m @@ -6,10 +6,9 @@ #import "ConversationViewItem.h" #import #import - #import -#import -#import +#import +#import #import #import #import diff --git a/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h b/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h index ecfb822ce..bf18aaddb 100644 --- a/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h +++ b/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h @@ -3,7 +3,7 @@ // #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift index 84eb02a3f..bea7e37c4 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift @@ -89,10 +89,10 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver // MARK: - Notifications - public func notifyUserIfNeeded(for message: Any, threadID: String) { - guard let thread = TSThread.fetch(uniqueId: threadID) else { return } + public func notifyUserIfNeeded(forMessageWithID messageID: String, threadID: String) { + guard let message = TSIncomingMessage.fetch(uniqueId: messageID), let thread = TSThread.fetch(uniqueId: threadID) else { return } Storage.read { transaction in - SSKEnvironment.shared.notificationsManager!.notifyUser(for: (message as! TSIncomingMessage), in: thread, transaction: transaction) + SSKEnvironment.shared.notificationsManager!.notifyUser(for: message, in: thread, transaction: transaction) } } diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index ec10aed87..2a123cb5f 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -12,14 +12,12 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import #import #import #import -#import #import #import #import @@ -72,8 +70,8 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import -#import +#import +#import #import #import #import @@ -88,7 +86,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import diff --git a/SignalUtilitiesKit/OWSBackupFragment.h b/SignalUtilitiesKit/OWSBackupFragment.h index 571d1af3e..392a7e73a 100644 --- a/SignalUtilitiesKit/OWSBackupFragment.h +++ b/SignalUtilitiesKit/OWSBackupFragment.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/OWSMediaGalleryFinder.m b/SignalUtilitiesKit/OWSMediaGalleryFinder.m index 04b39fb94..55bd348cb 100644 --- a/SignalUtilitiesKit/OWSMediaGalleryFinder.m +++ b/SignalUtilitiesKit/OWSMediaGalleryFinder.m @@ -12,6 +12,7 @@ #import #import #import +#import "TSAttachment+Albums.h" NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/OWSRecipientIdentity.h b/SignalUtilitiesKit/OWSRecipientIdentity.h index f1486c656..fec840379 100644 --- a/SignalUtilitiesKit/OWSRecipientIdentity.h +++ b/SignalUtilitiesKit/OWSRecipientIdentity.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/SSKJobRecord.h b/SignalUtilitiesKit/SSKJobRecord.h index 4ee258d5c..30c4adf2b 100644 --- a/SignalUtilitiesKit/SSKJobRecord.h +++ b/SignalUtilitiesKit/SSKJobRecord.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/SignalAccount.h b/SignalUtilitiesKit/SignalAccount.h index e8b54290e..bbf29282d 100644 --- a/SignalUtilitiesKit/SignalAccount.h +++ b/SignalUtilitiesKit/SignalAccount.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/SignalRecipient.h b/SignalUtilitiesKit/SignalRecipient.h index b1638cd4a..430698ae3 100644 --- a/SignalUtilitiesKit/SignalRecipient.h +++ b/SignalUtilitiesKit/SignalRecipient.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Threads/TSGroupModel.h b/SignalUtilitiesKit/Threads/TSGroupModel.h index 9a3de614f..0855a2880 100644 --- a/SignalUtilitiesKit/Threads/TSGroupModel.h +++ b/SignalUtilitiesKit/Threads/TSGroupModel.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import #import diff --git a/SignalUtilitiesKit/Threads/TSThread.h b/SignalUtilitiesKit/Threads/TSThread.h index 08e8f8ecb..1c1858e58 100644 --- a/SignalUtilitiesKit/Threads/TSThread.h +++ b/SignalUtilitiesKit/Threads/TSThread.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m index 8e99e6925..07bf55f90 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -11,7 +11,7 @@ #import #import #import -#import +#import #import #import #import @@ -21,8 +21,8 @@ #import #import #import -#import -#import +#import +#import #import diff --git a/SignalUtilitiesKit/To Do/OWSUserProfile.h b/SignalUtilitiesKit/To Do/OWSUserProfile.h index 1c79e4531..5e8d2a283 100644 --- a/SignalUtilitiesKit/To Do/OWSUserProfile.h +++ b/SignalUtilitiesKit/To Do/OWSUserProfile.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/UI/UIUtil.h b/SignalUtilitiesKit/UI/UIUtil.h index 96983e675..c10563a72 100644 --- a/SignalUtilitiesKit/UI/UIUtil.h +++ b/SignalUtilitiesKit/UI/UIUtil.h @@ -5,7 +5,7 @@ #import #import #import -#import +#import #define ACCESSIBILITY_IDENTIFIER_WITH_NAME(_root_view, _variable_name) \ ([NSString stringWithFormat:@"%@.%@", _root_view.class, _variable_name]) diff --git a/SignalUtilitiesKit/Utilities/AttachmentSharing.m b/SignalUtilitiesKit/Utilities/AttachmentSharing.m index aada8799c..cb4f18bd1 100644 --- a/SignalUtilitiesKit/Utilities/AttachmentSharing.m +++ b/SignalUtilitiesKit/Utilities/AttachmentSharing.m @@ -5,7 +5,7 @@ #import "AttachmentSharing.h" #import "UIUtil.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN From d2e8f2142e19881dde353bc052f0455d7481eaab Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 23 Nov 2020 15:08:01 +1100 Subject: [PATCH 020/177] WIP --- .../Jobs/AttachmentUploadJob.swift | 3 +++ SessionMessagingKit/Jobs/JobDelegate.swift | 1 + SessionMessagingKit/Jobs/JobQueue.swift | 4 ++++ SessionMessagingKit/Jobs/MessageSendJob.swift | 20 +++++++++++++++++-- .../Sending & Receiving/MessageReceiver.swift | 6 ------ SessionMessagingKit/Storage.swift | 1 + 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 2efedb6f4..838e4a63e 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -11,6 +11,9 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N public class var collection: String { return "AttachmentUploadJobCollection" } public static let maxFailureCount: UInt = 20 + // MARK: Initialization + public override init() { } + // MARK: Coding public init?(coder: NSCoder) { } diff --git a/SessionMessagingKit/Jobs/JobDelegate.swift b/SessionMessagingKit/Jobs/JobDelegate.swift index b45a5bf28..d4b27f5b8 100644 --- a/SessionMessagingKit/Jobs/JobDelegate.swift +++ b/SessionMessagingKit/Jobs/JobDelegate.swift @@ -5,4 +5,5 @@ public protocol JobDelegate { func handleJobSucceeded(_ job: Job) func handleJobFailed(_ job: Job, with error: Error) func handleJobFailedPermanently(_ job: Job, with error: Error) + func postpone(_ job: Job) } diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index f02dc971e..f2328bc8d 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -64,6 +64,10 @@ public final class JobQueue : NSObject, JobDelegate { }) }) } + + public func postpone(_ job: Job) { + Timer.weakScheduledTimer(withTimeInterval: 3, target: self, selector: #selector(self.retry(_:)), userInfo: job, repeats: false) + } private func getRetryInterval(for job: Job) -> TimeInterval { // Arbitrary backoff factor... diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 7f6bb4282..4574a1e33 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -10,7 +10,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // MARK: Settings public class var collection: String { return "MessageSendJobCollection" } - public static let maxFailureCount: UInt = 20 + public static let maxFailureCount: UInt = 10 // MARK: Initialization @objc public convenience init(message: Message, publicKey: String) { self.init(message: message, destination: .contact(publicKey: publicKey)) } @@ -61,7 +61,23 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // MARK: Running public func execute() { - Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self + let storage = Configuration.shared.storage + if let message = message as? VisibleMessage { + let attachments = message.attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0) } + let attachmentsToUpload = attachments.filter { !$0.isUploaded } + attachmentsToUpload.forEach { attachment in + if storage.getAttachmentUploadJob(for: attachment.uniqueId!) != nil { + // Wait for it to finish + } else { + let job = AttachmentUploadJob() + storage.withAsync({ transaction in + JobQueue.shared.add(job, using: transaction) + }, completion: { }) + } + } + if !attachmentsToUpload.isEmpty { delegate?.postpone(self); return } // Wait for all attachments to upload before continuing + } + storage.withAsync({ transaction in // Intentionally capture self Threading.workQueue.async { MessageSender.send(self.message, to: self.destination, using: transaction).done(on: Threading.workQueue) { self.handleSuccess() diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 885298ba2..ee1a48c3a 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -1,11 +1,5 @@ import SessionUtilitiesKit -// TODO: -// • Threads don't show up on the first message; only on the second. -// • Profile pictures aren't showing up. -// • Check that message expiration works. -// • Open group messages (sync messages). - internal enum MessageReceiver { internal enum Error : LocalizedError { diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 62978ad4b..92476e886 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -29,6 +29,7 @@ public protocol SessionMessagingKitStorageProtocol { func markJobAsSucceeded(_ job: Job, using transaction: Any) func markJobAsFailed(_ job: Job, using transaction: Any) func getAllPendingJobs(of type: Job.Type) -> [Job] + func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? // MARK: - Authorization From 3b252056de7b57765085a0e6f2d0b7a55e1e831d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 23 Nov 2020 15:37:25 +1100 Subject: [PATCH 021/177] Implement attachment uploading --- .../Jobs/AttachmentUploadJob.swift | 45 ++++++++++++++++--- SessionMessagingKit/Storage.swift | 4 ++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 838e4a63e..4e9fe1be5 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -1,26 +1,59 @@ import SessionUtilitiesKit -// TODO: Implementation - public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? + private let attachmentID: String + private let threadID: String public var id: String? public var failureCount: UInt = 0 + public enum Error : LocalizedError { + case noAttachment + + public var errorDescription: String? { + switch self { + case .noAttachment: return "No such attachment." + } + } + } + // MARK: Settings public class var collection: String { return "AttachmentUploadJobCollection" } public static let maxFailureCount: UInt = 20 // MARK: Initialization - public override init() { } + public init(attachmentID: String, threadID: String) { + self.attachmentID = attachmentID + self.threadID = threadID + } // MARK: Coding - public init?(coder: NSCoder) { } + public init?(coder: NSCoder) { + guard let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String?, + let threadID = coder.decodeObject(forKey: "threadID") as! String? else { return nil } + self.attachmentID = attachmentID + self.threadID = threadID + } - public func encode(with coder: NSCoder) { } + public func encode(with coder: NSCoder) { + coder.encode(attachmentID, forKey: "attachmentID") + coder.encode(threadID, forKey: "threadID") + } // MARK: Running - public func execute() { } + public func execute() { + guard let stream = TSAttachmentStream.fetch(uniqueId: attachmentID) else { + return handleFailure(error: Error.noAttachment) + } + guard !stream.isUploaded else { return handleSuccess() } // Should never occur + let openGroup = Configuration.shared.storage.getOpenGroup(for: threadID) + let server = openGroup?.server ?? FileServerAPI.server + FileServerAPI.uploadAttachment(stream, with: attachmentID, to: server).done(on: DispatchQueue.global(qos: .userInitiated)) { // Intentionally capture self + self.handleSuccess() + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in + self.handleFailure(error: error) + } + } private func handleSuccess() { delegate?.handleJobSucceeded(self) diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 92476e886..0d55606e5 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -37,6 +37,10 @@ public protocol SessionMessagingKitStorageProtocol { func setAuthToken(for server: String, to newValue: String, using transaction: Any) func removeAuthToken(for server: String, using transaction: Any) + // MARK: - Open Groups + + func getOpenGroup(for threadID: String) -> OpenGroup? + // MARK: - Open Group Public Keys func getOpenGroupPublicKey(for server: String) -> String? From 64cf19f461b2a8f26b8030177bd0b7f98cf54ff5 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 23 Nov 2020 15:46:53 +1100 Subject: [PATCH 022/177] Improve job error handling --- .../Jobs/AttachmentDownloadJob.swift | 16 ++++++++++++---- .../Jobs/AttachmentUploadJob.swift | 15 +++++++++++++-- SessionMessagingKit/Jobs/MessageSendJob.swift | 12 ++++++++++-- .../Sending & Receiving/MessageSender.swift | 7 +++++++ SessionMessagingKit/Utilities/DotNetAPI.swift | 4 ++++ 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 1ebb22422..e82ea6917 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -54,10 +54,14 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject let temporaryFilePath = URL(fileURLWithPath: OWSTemporaryDirectoryAccessibleAfterFirstAuth() + UUID().uuidString) let handleFailure: (Swift.Error) -> Void = { error in // Intentionally capture self OWSFileSystem.deleteFile(temporaryFilePath.absoluteString) - storage.withAsync({ transaction in - storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) - }, completion: { }) - self.handleFailure(error: error) + if let error = error as? Error, case .noAttachment = error { + storage.withAsync({ transaction in + storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) + }, completion: { }) + self.handlePermanentFailure(error: error) + } else { + self.handleFailure(error: error) + } } FileServerAPI.downloadAttachment(from: pointer.downloadURL).done(on: DispatchQueue.global(qos: .userInitiated)) { data in do { @@ -93,6 +97,10 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject private func handleSuccess() { delegate?.handleJobSucceeded(self) } + + private func handlePermanentFailure(error: Swift.Error) { + delegate?.handleJobFailedPermanently(self, with: error) + } private func handleFailure(error: Swift.Error) { delegate?.handleJobFailed(self, with: error) diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 4e9fe1be5..b504272e8 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -48,18 +48,29 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N guard !stream.isUploaded else { return handleSuccess() } // Should never occur let openGroup = Configuration.shared.storage.getOpenGroup(for: threadID) let server = openGroup?.server ?? FileServerAPI.server + // FIXME: A lot of what's currently happening in FileServerAPI should really be happening here FileServerAPI.uploadAttachment(stream, with: attachmentID, to: server).done(on: DispatchQueue.global(qos: .userInitiated)) { // Intentionally capture self self.handleSuccess() }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in - self.handleFailure(error: error) + if let error = error as? Error, case .noAttachment = error { + self.handlePermanentFailure(error: error) + } else if let error = error as? DotNetAPI.Error, !error.isRetryable { + self.handlePermanentFailure(error: error) + } else { + self.handleFailure(error: error) + } } } private func handleSuccess() { delegate?.handleJobSucceeded(self) } + + private func handlePermanentFailure(error: Swift.Error) { + delegate?.handleJobFailedPermanently(self, with: error) + } - private func handleFailure(error: Error) { + private func handleFailure(error: Swift.Error) { delegate?.handleJobFailed(self, with: error) } } diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 4574a1e33..467c9e00c 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -69,7 +69,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi if storage.getAttachmentUploadJob(for: attachment.uniqueId!) != nil { // Wait for it to finish } else { - let job = AttachmentUploadJob() + let job = AttachmentUploadJob(attachmentID: attachment.uniqueId!, threadID: message.threadID!) storage.withAsync({ transaction in JobQueue.shared.add(job, using: transaction) }, completion: { }) @@ -83,7 +83,11 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi self.handleSuccess() }.catch(on: Threading.workQueue) { error in SNLog("Couldn't send message due to error: \(error).") - self.handleFailure(error: error) + if let error = error as? MessageSender.Error, !error.isRetryable { + self.handlePermanentFailure(error: error) + } else { + self.handleFailure(error: error) + } } } }, completion: { }) @@ -92,6 +96,10 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi private func handleSuccess() { delegate?.handleJobSucceeded(self) } + + private func handlePermanentFailure(error: Error) { + delegate?.handleJobFailedPermanently(self, with: error) + } private func handleFailure(error: Error) { delegate?.handleJobFailed(self, with: error) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index c7cf38752..0c7b3e57b 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -11,6 +11,13 @@ public final class MessageSender : NSObject { case proofOfWorkCalculationFailed case noUserPublicKey + internal var isRetryable: Bool { + switch self { + case .invalidMessage, .protoConversionFailed, .proofOfWorkCalculationFailed: return false + default: return true + } + } + public var errorDescription: String? { switch self { case .invalidMessage: return "Invalid message." diff --git a/SessionMessagingKit/Utilities/DotNetAPI.swift b/SessionMessagingKit/Utilities/DotNetAPI.swift index 36fcdba1e..4631439bd 100644 --- a/SessionMessagingKit/Utilities/DotNetAPI.swift +++ b/SessionMessagingKit/Utilities/DotNetAPI.swift @@ -22,6 +22,10 @@ public class DotNetAPI : NSObject { case decryptionFailed case maxFileSizeExceeded + internal var isRetryable: Bool { + return false + } + public var errorDescription: String? { switch self { case .generic: return "An error occurred." From ac1bbb3de1feaf2413d40789b7e99555eeb3c1c2 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 23 Nov 2020 15:58:48 +1100 Subject: [PATCH 023/177] Handle open group message ID --- .../Sending & Receiving/MessageReceiver.swift | 7 +++++-- .../Sending & Receiving/MessageSender.swift | 18 ++++++++++++------ .../MessageSenderDelegate.swift | 3 +++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index ee1a48c3a..bbd0dcb88 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -10,11 +10,11 @@ internal enum MessageReceiver { case noData case senderBlocked case noThread + case selfSend // Shared sender keys case invalidGroupPublicKey case noGroupPrivateKey case sharedSecretGenerationFailed - case selfSend internal var isRetryable: Bool { switch self { @@ -42,6 +42,7 @@ internal enum MessageReceiver { } internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { + let userPublicKey = Configuration.shared.storage.getUserPublicKey() // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) // Decrypt the contents @@ -57,6 +58,8 @@ internal enum MessageReceiver { } // Don't process the envelope any further if the sender is blocked guard !Configuration.shared.messageReceiverDelegate.isBlocked(sender) else { throw Error.senderBlocked } + // Ignore self sends + guard sender != userPublicKey else { throw Error.selfSend } // Parse the proto let proto: SNProtoContent do { @@ -76,7 +79,7 @@ internal enum MessageReceiver { }() if let message = message { message.sender = sender - message.recipient = Configuration.shared.storage.getUserPublicKey() + message.recipient = userPublicKey message.sentTimestamp = envelope.timestamp message.receivedTimestamp = NSDate.millisecondTimestamp() message.groupPublicKey = groupPublicKey diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 0c7b3e57b..04c3c36f1 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -38,10 +38,11 @@ public final class MessageSender : NSObject { } internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { + let storage = Configuration.shared.storage if message.sentTimestamp == nil { // Visible messages will already have the sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() } - message.sender = Configuration.shared.storage.getUserPublicKey() + message.sender = storage.getUserPublicKey() switch destination { case .contact(let publicKey): message.recipient = publicKey case .closedGroup(let groupPublicKey): message.recipient = groupPublicKey @@ -137,7 +138,6 @@ public final class MessageSender : NSObject { seal.reject(error) } let _ = promise.done(on: DispatchQueue.main) { - let storage = Configuration.shared.storage storage.withAsync({ transaction in Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) @@ -150,7 +150,7 @@ public final class MessageSender : NSObject { }, completion: { }) } let _ = promise.catch(on: DispatchQueue.main) { _ in - Configuration.shared.storage.withAsync({ transaction in + storage.withAsync({ transaction in Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, using: transaction) }, completion: { }) if case .contact(_) = destination { @@ -161,6 +161,7 @@ public final class MessageSender : NSObject { } internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { + let storage = Configuration.shared.storage message.sentTimestamp = NSDate.millisecondTimestamp() switch destination { case .contact(_): preconditionFailure() @@ -177,11 +178,16 @@ public final class MessageSender : NSObject { guard let message = message as? VisibleMessage, let openGroupMessage = OpenGroupMessage.from(message, for: server) else { return Promise(error: Error.invalidMessage) } let promise = OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server) - let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { _ in - // TODO: Save server message ID + let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in + message.openGroupServerMessageID = openGroupMessage.serverID + storage.withAsync({ transaction in + Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) + }, completion: { }) } promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { _ in - // TODO: Handle failure + storage.withAsync({ transaction in + Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, using: transaction) + }, completion: { }) } return promise.map { _ in } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index aa26c37a6..c08bcbfe1 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -5,6 +5,9 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele public func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + if let openGroupServerMessageID = message.openGroupServerMessageID { + tsMessage.openGroupServerMessageID = openGroupServerMessageID + } tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) } From bbd3ecd54a8de9a4a1940af435bfe615bdcc611f Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 23 Nov 2020 16:05:39 +1100 Subject: [PATCH 024/177] Delete ClosedGroupsProtocol --- Signal.xcodeproj/project.pbxproj | 4 - .../Database/Storage/Storage+Jobs.swift | 4 + .../MessageSenderDelegate.swift | 207 +++++++++++++ .../To Do/ClosedGroupsProtocol.swift | 271 ------------------ 4 files changed, 211 insertions(+), 275 deletions(-) delete mode 100644 SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 66780ac69..480ed9c80 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -342,7 +342,6 @@ C33FDC2B255A581F00E217F9 /* OWSReadReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */; }; C33FDC2C255A581F00E217F9 /* OWSFailedAttachmentDownloadsJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA72255A57FA00E217F9 /* OWSFailedAttachmentDownloadsJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC2D255A581F00E217F9 /* ECKeyPair+Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */; }; - C33FDC2E255A581F00E217F9 /* ClosedGroupsProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */; }; C33FDC2F255A581F00E217F9 /* OWSSyncManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC33255A581F00E217F9 /* TSGroupThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA79255A57FB00E217F9 /* TSGroupThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC34255A581F00E217F9 /* NSRegularExpression+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */; }; @@ -1443,7 +1442,6 @@ C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSReadReceiptManager.m; sourceTree = ""; }; C33FDA72255A57FA00E217F9 /* OWSFailedAttachmentDownloadsJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSFailedAttachmentDownloadsJob.h; sourceTree = ""; }; C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ECKeyPair+Hexadecimal.swift"; sourceTree = ""; }; - C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupsProtocol.swift; sourceTree = ""; }; C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSyncManagerProtocol.h; sourceTree = ""; }; C33FDA79255A57FB00E217F9 /* TSGroupThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSGroupThread.h; sourceTree = ""; }; C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+SSK.swift"; sourceTree = ""; }; @@ -3271,7 +3269,6 @@ isa = PBXGroup; children = ( C33FDB19255A580900E217F9 /* GroupUtilities.swift */, - C33FDA74255A57FB00E217F9 /* ClosedGroupsProtocol.swift */, C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, @@ -4978,7 +4975,6 @@ B8D8F16B256615DE0092EF10 /* Storage+VolumeSamples.swift in Sources */, C33FDC41255A581F00E217F9 /* TypingIndicators.swift in Sources */, C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */, - C33FDC2E255A581F00E217F9 /* ClosedGroupsProtocol.swift in Sources */, B84072962565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift in Sources */, C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */, C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */, diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift b/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift index 98649f318..12a223fc6 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift +++ b/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift @@ -23,4 +23,8 @@ extension Storage { } return result } + + public func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? { + return nil // TODO: Implement + } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index c08bcbfe1..3452f3d68 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -1,6 +1,21 @@ +import PromiseKit public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDelegate, SharedSenderKeysDelegate { + public enum Error : LocalizedError { + case noThread + case noPrivateKey + case invalidUpdate + + public var errorDescription: String? { + switch self { + case .noThread: return "Couldn't find a thread associated with the given group public key." + case .noPrivateKey: return "Couldn't find a private key associated with the given group public key." + case .invalidUpdate: return "Invalid group update." + } + } + } + public static let shared = MessageSenderDelegate() public func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { @@ -15,6 +30,198 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele // TODO: Implement } + public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { + // Prepare + var members = members + let userPublicKey = getUserHexEncodedPublicKey() + // Generate a key pair for the group + let groupKeyPair = Curve25519.generateKeyPair() + let groupPublicKey = groupKeyPair.hexEncodedPublicKey // Includes the "05" prefix + // Ensure the current user is included in the member list + members.insert(userPublicKey) + let membersAsData = members.map { Data(hex: $0) } + // Create ratchets for all members + let senderKeys: [ClosedGroupSenderKey] = members.map { publicKey in + let ratchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) + } + // Create the group + let admins = [ userPublicKey ] + let adminsAsData = admins.map { Data(hex: $0) } + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + let group = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) + let thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction) + thread.usesSharedSenderKeys = true + thread.save(with: transaction) + // Send a closed group update message to all members using established channels + var promises: [Promise] = [] + for member in members { + guard member != userPublicKey else { continue } + let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, + groupPrivateKey: groupKeyPair.privateKey, senderKeys: senderKeys, members: membersAsData, admins: adminsAsData) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + let promise = MessageSender.sendNonDurably(closedGroupUpdate, in: thread, using: transaction) + promises.append(promise) + } + // Add the group to the user's set of public keys to poll for + Storage.shared.setClosedGroupPrivateKey(groupKeyPair.privateKey.toHexString(), for: groupPublicKey, using: transaction) + // Notify the PN server + promises.append(PushNotificationAPI.performOperation(.subscribe, for: groupPublicKey, publicKey: userPublicKey)) + // Notify the user + let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) + infoMessage.save(with: transaction) + // Return + return when(fulfilled: promises).map2 { thread } + } + + /// - Note: The returned promise is only relevant for group leaving. + public static func update(_ groupPublicKey: String, with members: Set, name: String, transaction: YapDatabaseReadWriteTransaction) -> Promise { + let (promise, seal) = Promise.pending() + let userPublicKey = getUserHexEncodedPublicKey() + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { + SNLog("Can't update nonexistent closed group.") + return Promise(error: Error.noThread) + } + let group = thread.groupModel + let oldMembers = Set(group.groupMemberIds) + let newMembers = members.subtracting(oldMembers) + let membersAsData = members.map { Data(hex: $0) } + let admins = group.groupAdminIds + let adminsAsData = admins.map { Data(hex: $0) } + guard let groupPrivateKey = Storage.shared.getClosedGroupPrivateKey(for: groupPublicKey) else { + SNLog("Couldn't get private key for closed group.") + return Promise(error: Error.noPrivateKey) + } + let wasAnyUserRemoved = Set(members).intersection(oldMembers) != oldMembers + let removedMembers = oldMembers.subtracting(members) + let isUserLeaving = removedMembers.contains(userPublicKey) + var newSenderKeys: [ClosedGroupSenderKey] = [] + if wasAnyUserRemoved { + if isUserLeaving && removedMembers.count != 1 { + SNLog("Can't remove self and others simultaneously.") + return Promise(error: Error.invalidUpdate) + } + // Send the update to the existing members using established channels (don't include new ratchets as everyone should regenerate new ratchets individually) + let promises: [Promise] = oldMembers.map { member in + let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], + members: membersAsData, admins: adminsAsData) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + return MessageSender.sendNonDurably(closedGroupUpdate, in: thread, using: transaction) + } + when(resolved: promises).done2 { _ in seal.fulfill(()) }.catch2 { seal.reject($0) } + let _ = promise.done { + Storage.writeSync { transaction in + let allOldRatchets = Storage.shared.getAllClosedGroupRatchets(for: groupPublicKey) + for (senderPublicKey, oldRatchet) in allOldRatchets { + let collection = ClosedGroupRatchetCollectionType.old + Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) + } + // Delete all ratchets (it's important that this happens * after * sending out the update) + Storage.shared.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) + // Remove the group from the user's set of public keys to poll for if the user is leaving. Otherwise generate a new ratchet and + // send it out to all members (minus the removed ones) using established channels. + if isUserLeaving { + Storage.shared.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) + // Notify the PN server + let _ = PushNotificationAPI.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) + } else { + // Send closed group update messages to any new members using established channels + for member in newMembers { + let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, + groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [], members: membersAsData, admins: adminsAsData) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } + // Send out the user's new ratchet to all members (minus the removed ones) using established channels + let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) + for member in members { + guard member != userPublicKey else { continue } + let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } + } + } + } + } else if !newMembers.isEmpty { + seal.fulfill(()) + // Generate ratchets for any new members + newSenderKeys = newMembers.map { publicKey in + let ratchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) + } + // Send a closed group update message to the existing members with the new members' ratchets (this message is aimed at the group) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: newSenderKeys, + members: membersAsData, admins: adminsAsData) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + // Send closed group update messages to the new members using established channels + var allSenderKeys = Storage.shared.getAllClosedGroupSenderKeys(for: groupPublicKey) + allSenderKeys.formUnion(newSenderKeys) + for member in newMembers { + let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, + groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } + } else { + seal.fulfill(()) + let allSenderKeys = Storage.shared.getAllClosedGroupSenderKeys(for: groupPublicKey) + let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, + senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) + let closedGroupUpdate = ClosedGroupUpdate() + closedGroupUpdate.kind = closedGroupUpdateKind + MessageSender.send(closedGroupUpdate, in: thread, using: transaction) + } + // Update the group + let newGroupModel = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) + thread.setGroupModel(newGroupModel, with: transaction) + // Notify the user + let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel) + let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate, customMessage: updateInfo) + infoMessage.save(with: transaction) + // Return + return promise + } + + /// The returned promise is fulfilled when the group update message has been sent. It doesn't wait for the user's new ratchet to be distributed. + @objc(leaveGroupWithPublicKey:transaction:) + public static func objc_leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(leave(groupPublicKey, using: transaction)) + } + + /// The returned promise is fulfilled when the group update message has been sent. It doesn't wait for the user's new ratchet to be distributed. + public static func leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + let userPublicKey = getUserHexEncodedPublicKey() + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { + SNLog("Can't leave nonexistent closed group.") + return Promise(error: Error.noThread) + } + let group = thread.groupModel + var newMembers = Set(group.groupMemberIds) + newMembers.remove(userPublicKey) + return update(groupPublicKey, with: newMembers, name: group.groupName!, transaction: transaction) + } + public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { SNLog("Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") let transaction = transaction as! YapDatabaseReadWriteTransaction diff --git a/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift b/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift deleted file mode 100644 index 04acd3ead..000000000 --- a/SignalUtilitiesKit/To Do/ClosedGroupsProtocol.swift +++ /dev/null @@ -1,271 +0,0 @@ -import PromiseKit - -// A few notes about making changes in this file: -// -// • Don't use a database transaction if you can avoid it. -// • If you do need to use a database transaction, use a read transaction if possible. -// • For write transactions, consider making it the caller's responsibility to manage the database transaction (this helps avoid unnecessary transactions). -// • Think carefully about adding a function; there might already be one for what you need. -// • Document the expected cases in which a function will be used. -// • Express those cases in tests. - -/// See [the documentation](https://github.com/loki-project/session-protocol-docs/wiki/Medium-Size-Groups) for more information. -@objc(LKClosedGroupsProtocol) -public final class ClosedGroupsProtocol : NSObject { - public static let isSharedSenderKeysEnabled = true - public static let groupSizeLimit = 20 - public static let maxNameSize = 64 - - public enum Error : LocalizedError { - case noThread - case noPrivateKey - case invalidUpdate - - public var errorDescription: String? { - switch self { - case .noThread: return "Couldn't find a thread associated with the given group public key." - case .noPrivateKey: return "Couldn't find a private key associated with the given group public key." - case .invalidUpdate: return "Invalid group update." - } - } - } - - // MARK: - Sending - - /// - Note: It's recommended to batch fetch the device links for the given set of members before invoking this, to avoid the message sending pipeline - /// making a request for each member. - public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { - // Prepare - var members = members - let userPublicKey = getUserHexEncodedPublicKey() - // Generate a key pair for the group - let groupKeyPair = Curve25519.generateKeyPair() - let groupPublicKey = groupKeyPair.hexEncodedPublicKey // Includes the "05" prefix - // Ensure the current user is included in the member list - members.insert(userPublicKey) - let membersAsData = members.map { Data(hex: $0) } - // Create ratchets for all members - let senderKeys: [ClosedGroupSenderKey] = members.map { publicKey in - let ratchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) - return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) - } - // Create the group - let admins = [ userPublicKey ] - let adminsAsData = admins.map { Data(hex: $0) } - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - let group = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) - let thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction) - thread.usesSharedSenderKeys = true - thread.save(with: transaction) - // Establish sessions if needed - establishSessionsIfNeeded(with: [String](members), using: transaction) - // Send a closed group update message to all members using established channels - var promises: [Promise] = [] - for member in members { - guard member != userPublicKey else { continue } - let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, - groupPrivateKey: groupKeyPair.privateKey, senderKeys: senderKeys, members: membersAsData, admins: adminsAsData) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - let promise = MessageSender.sendNonDurably(closedGroupUpdate, in: thread, using: transaction) - promises.append(promise) - } - // Add the group to the user's set of public keys to poll for - Storage.shared.setClosedGroupPrivateKey(groupKeyPair.privateKey.toHexString(), for: groupPublicKey, using: transaction) - // Notify the PN server - promises.append(PushNotificationAPI.performOperation(.subscribe, for: groupPublicKey, publicKey: userPublicKey)) - // Notify the user - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate) - infoMessage.save(with: transaction) - // Return - return when(fulfilled: promises).map2 { thread } - } - - /// - Note: The returned promise is only relevant for group leaving. - public static func update(_ groupPublicKey: String, with members: Set, name: String, transaction: YapDatabaseReadWriteTransaction) -> Promise { - let (promise, seal) = Promise.pending() - let userPublicKey = getUserHexEncodedPublicKey() - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - SNLog("Can't update nonexistent closed group.") - return Promise(error: Error.noThread) - } - let group = thread.groupModel - let oldMembers = Set(group.groupMemberIds) - let newMembers = members.subtracting(oldMembers) - let membersAsData = members.map { Data(hex: $0) } - let admins = group.groupAdminIds - let adminsAsData = admins.map { Data(hex: $0) } - guard let groupPrivateKey = Storage.shared.getClosedGroupPrivateKey(for: groupPublicKey) else { - SNLog("Couldn't get private key for closed group.") - return Promise(error: Error.noPrivateKey) - } - let wasAnyUserRemoved = Set(members).intersection(oldMembers) != oldMembers - let removedMembers = oldMembers.subtracting(members) - let isUserLeaving = removedMembers.contains(userPublicKey) - var newSenderKeys: [ClosedGroupSenderKey] = [] - if wasAnyUserRemoved { - if isUserLeaving && removedMembers.count != 1 { - SNLog("Can't remove self and others simultaneously.") - return Promise(error: Error.invalidUpdate) - } - // Establish sessions if needed - establishSessionsIfNeeded(with: [String](members), using: transaction) - // Send the update to the existing members using established channels (don't include new ratchets as everyone should regenerate new ratchets individually) - let promises: [Promise] = oldMembers.map { member in - let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], - members: membersAsData, admins: adminsAsData) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - return MessageSender.sendNonDurably(closedGroupUpdate, in: thread, using: transaction) - } - when(resolved: promises).done2 { _ in seal.fulfill(()) }.catch2 { seal.reject($0) } - let _ = promise.done { - Storage.writeSync { transaction in - let allOldRatchets = Storage.shared.getAllClosedGroupRatchets(for: groupPublicKey) - for (senderPublicKey, oldRatchet) in allOldRatchets { - let collection = ClosedGroupRatchetCollectionType.old - Storage.shared.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: oldRatchet, in: collection, using: transaction) - } - // Delete all ratchets (it's important that this happens * after * sending out the update) - Storage.shared.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) - // Remove the group from the user's set of public keys to poll for if the user is leaving. Otherwise generate a new ratchet and - // send it out to all members (minus the removed ones) using established channels. - if isUserLeaving { - Storage.shared.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction) - // Notify the PN server - let _ = PushNotificationAPI.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) - } else { - // Send closed group update messages to any new members using established channels - for member in newMembers { - let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, - groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [], members: membersAsData, admins: adminsAsData) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - // Send out the user's new ratchet to all members (minus the removed ones) using established channels - let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) - let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) - for member in members { - guard member != userPublicKey else { continue } - let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - } - } - } - } else if !newMembers.isEmpty { - seal.fulfill(()) - // Generate ratchets for any new members - newSenderKeys = newMembers.map { publicKey in - let ratchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) - return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) - } - // Send a closed group update message to the existing members with the new members' ratchets (this message is aimed at the group) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: newSenderKeys, - members: membersAsData, admins: adminsAsData) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - // Establish sessions if needed - establishSessionsIfNeeded(with: [String](newMembers), using: transaction) - // Send closed group update messages to the new members using established channels - var allSenderKeys = Storage.shared.getAllClosedGroupSenderKeys(for: groupPublicKey) - allSenderKeys.formUnion(newSenderKeys) - for member in newMembers { - let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, - groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - } else { - seal.fulfill(()) - let allSenderKeys = Storage.shared.getAllClosedGroupSenderKeys(for: groupPublicKey) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, - senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - // Update the group - let newGroupModel = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) - thread.setGroupModel(newGroupModel, with: transaction) - // Notify the user - let updateInfo = group.getInfoStringAboutUpdate(to: newGroupModel) - let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate, customMessage: updateInfo) - infoMessage.save(with: transaction) - // Return - return promise - } - - /// The returned promise is fulfilled when the group update message has been sent. It doesn't wait for the user's new ratchet to be distributed. - @objc(leaveGroupWithPublicKey:transaction:) - public static func objc_leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { - return AnyPromise.from(leave(groupPublicKey, using: transaction)) - } - - /// The returned promise is fulfilled when the group update message has been sent. It doesn't wait for the user's new ratchet to be distributed. - public static func leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise { - let userPublicKey = getUserHexEncodedPublicKey() - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { - SNLog("Can't leave nonexistent closed group.") - return Promise(error: Error.noThread) - } - let group = thread.groupModel - var newMembers = Set(group.groupMemberIds) - newMembers.remove(userPublicKey) - return update(groupPublicKey, with: newMembers, name: group.groupName!, transaction: transaction) - } - - public static func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - SNLog("Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") - // Establish session if needed - SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) - // Send the request - let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) - thread.save(with: transaction) - let closedGroupUpdateKind = ClosedGroupUpdate.Kind.senderKeyRequest(groupPublicKey: Data(hex: groupPublicKey)) - let closedGroupUpdate = ClosedGroupUpdate() - closedGroupUpdate.kind = closedGroupUpdateKind - MessageSender.send(closedGroupUpdate, in: thread, using: transaction) - } - - // MARK: - General - - @objc(establishSessionsIfNeededWithClosedGroupMembers:transaction:) - public static func establishSessionsIfNeeded(with closedGroupMembers: [String], using transaction: YapDatabaseReadWriteTransaction) { - closedGroupMembers.forEach { publicKey in - SessionManagementProtocol.sendSessionRequestIfNeeded(to: publicKey, using: transaction) - } - } - - @objc(shouldIgnoreClosedGroupMessage:inThread:wrappedIn:) - public static func shouldIgnoreClosedGroupMessage(_ dataMessage: SNProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SNProtoEnvelope) -> Bool { - guard thread.groupModel.groupType == .closedGroup else { return true } - let publicKey = envelope.source! // Set during UD decryption - return !thread.isUserMember(inGroup: publicKey) - } - - /// - Note: Deprecated. - @objc(shouldIgnoreClosedGroupUpdateMessage:inThread:wrappedIn:) - public static func shouldIgnoreClosedGroupUpdateMessage(_ dataMessage: SNProtoDataMessage, in thread: TSGroupThread, wrappedIn envelope: SNProtoEnvelope) -> Bool { - guard thread.groupModel.groupType == .closedGroup else { return true } - let publicKey = envelope.source! // Set during UD decryption - return !thread.isUserAdmin(inGroup: publicKey) - } -} From aec182f36c04dee2ce43b446b318ee2571713cac Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 23 Nov 2020 16:35:49 +1100 Subject: [PATCH 025/177] WIP --- .../ConversationViewController.m | 6 - .../OWSConversationSettingsViewController.m | 18 +- .../View Controllers/EditClosedGroupVC.swift | 4 +- Session/View Controllers/HomeVC.swift | 2 +- .../View Controllers/NewClosedGroupVC.swift | 6 +- Signal.xcodeproj/project.pbxproj | 8 - .../Read Tracking/OWSOutgoingReceiptManager.m | 4 +- .../MessageReceiverDelegate.swift | 1 - .../MessageSenderDelegate.swift | 9 +- .../Typing Indicators/TypingIndicators.swift | 2 +- .../To Do/SessionManagementProtocol.swift | 225 ------------------ .../To Do/SessionMetaProtocol.swift | 119 --------- 12 files changed, 20 insertions(+), 384 deletions(-) delete mode 100644 SignalUtilitiesKit/To Do/SessionManagementProtocol.swift delete mode 100644 SignalUtilitiesKit/To Do/SessionMetaProtocol.swift diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 3917855a8..ff1bc290e 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3248,12 +3248,6 @@ typedef enum : NSUInteger { // }]; [self messageWasSent:message]; - - if ([self.thread isKindOfClass:TSContactThread.class]) { - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [LKSessionManagementProtocol sendSessionRequestIfNeededToPublicKey:self.thread.contactIdentifier transaction:transaction]; - }]; - } }); } diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index d4ae93edd..449485ae1 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -950,7 +950,7 @@ static CGRect oldframe; if (gThread.usesSharedSenderKeys) { NSString *groupPublicKey = [LKGroupUtilities getDecodedGroupID:gThread.groupModel.groupId]; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [[LKClosedGroupsProtocol leaveGroupWithPublicKey:groupPublicKey transaction:transaction] retainUntilComplete]; + [[SNMessageSenderDelegate leaveGroupWithPublicKey:groupPublicKey transaction:transaction] retainUntilComplete]; }]; } @@ -1197,21 +1197,7 @@ static CGRect oldframe; - (void)resetSecureSession { - if (![self.thread isKindOfClass:TSContactThread.class]) { return; } - TSContactThread *thread = (TSContactThread *)self.thread; - __weak OWSConversationSettingsViewController *weakSelf = self; - NSString *message = @"This may help if you're having encryption problems in this conversation. Your messages will be kept."; - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Reset Secure Session?" message:message preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"") style:UIAlertActionStyleDefault handler:nil]]; - [alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - dispatch_async(dispatch_get_main_queue(), ^{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [LKSessionManagementProtocol startSessionResetInThread:thread transaction:transaction]; - }]; - [weakSelf.navigationController popViewControllerAnimated:YES]; - }); - }]]; - [self presentViewController:alert animated:YES completion:nil]; + } #pragma mark - Notifications diff --git a/Session/View Controllers/EditClosedGroupVC.swift b/Session/View Controllers/EditClosedGroupVC.swift index 472cfe9e9..fc05185a8 100644 --- a/Session/View Controllers/EditClosedGroupVC.swift +++ b/Session/View Controllers/EditClosedGroupVC.swift @@ -209,7 +209,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega guard !name.isEmpty else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_missing_error", comment: "")) } - guard name.count < ClosedGroupsProtocol.maxNameSize else { + guard name.count < 64 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } isEditingGroupName = false @@ -253,7 +253,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega } ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in Storage.writeSync { [weak self] transaction in - ClosedGroupsProtocol.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) { + MessageSenderDelegate.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) { guard let self = self else { return } self.dismiss(animated: true, completion: nil) // Dismiss the loader popToConversationVC(self) diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index 4e6df7b5c..20f9f3d30 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -384,7 +384,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys == true { let groupID = thread.groupModel.groupId let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) - let _ = ClosedGroupsProtocol.leave(groupPublicKey, using: transaction).ensure { + let _ = MessageSenderDelegate.leave(groupPublicKey, using: transaction).ensure { Storage.writeSync { transaction in thread.removeAllThreadInteractions(with: transaction) thread.remove(with: transaction) diff --git a/Session/View Controllers/NewClosedGroupVC.swift b/Session/View Controllers/NewClosedGroupVC.swift index 027b85f06..d81ba17f7 100644 --- a/Session/View Controllers/NewClosedGroupVC.swift +++ b/Session/View Controllers/NewClosedGroupVC.swift @@ -157,20 +157,20 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat guard let name = nameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), name.count > 0 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_missing_error", comment: "")) } - guard name.count < ClosedGroupsProtocol.maxNameSize else { + guard name.count < 64 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } guard selectedContacts.count >= 1 else { return showError(title: "Please pick at least 1 group member") } - guard selectedContacts.count < ClosedGroupsProtocol.groupSizeLimit else { // Minus one because we're going to include self later + guard selectedContacts.count < 20 else { // Minus one because we're going to include self later return showError(title: NSLocalizedString("vc_create_closed_group_too_many_group_members_error", comment: "")) } let selectedContacts = self.selectedContacts ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in var promise: Promise! Storage.writeSync { transaction in - promise = ClosedGroupsProtocol.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) + promise = MessageSenderDelegate.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) } let _ = promise.done(on: DispatchQueue.main) { thread in self?.presentingViewController?.dismiss(animated: true, completion: nil) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 480ed9c80..cfbf33f06 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -403,7 +403,6 @@ C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF4255A580600E217F9 /* SSKEnvironment.m */; }; C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */; }; C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF9255A580600E217F9 /* TSContactThread.m */; }; - C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */; }; C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; }; C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */; }; @@ -485,7 +484,6 @@ C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */; }; C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */; }; C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */; }; @@ -1511,7 +1509,6 @@ C33FDAF4255A580600E217F9 /* SSKEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKEnvironment.m; sourceTree = ""; }; C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+SignedPreKeyStore.m"; sourceTree = ""; }; C33FDAF9255A580600E217F9 /* TSContactThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSContactThread.m; sourceTree = ""; }; - C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionMetaProtocol.swift; sourceTree = ""; }; C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIMETypeUtil.h; sourceTree = ""; }; C33FDAFD255A580600E217F9 /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = ""; }; C33FDAFE255A580600E217F9 /* OWSStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSStorage.h; sourceTree = ""; }; @@ -1605,7 +1602,6 @@ C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentPointer.m; sourceTree = ""; }; C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageHeaders.h; sourceTree = ""; }; C33FDBA1255A581400E217F9 /* OWSOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOperation.h; sourceTree = ""; }; - C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionManagementProtocol.swift; sourceTree = ""; }; C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesConfiguration.m; sourceTree = ""; }; C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeySendingErrorMessage.h; sourceTree = ""; }; C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSLinkPreview.swift; sourceTree = ""; }; @@ -3272,8 +3268,6 @@ C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, - C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */, - C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */, C33FDADF255A580400E217F9 /* PublicChatManager.swift */, C38EF3E5255B6DF4007E1867 /* ContactCellView.h */, C38EF3D6255B6DEF007E1867 /* ContactCellView.m */, @@ -5075,7 +5069,6 @@ C38EF218255B6D3B007E1867 /* Theme.m in Sources */, C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */, B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */, - C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */, C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */, C33FDD76255A582000E217F9 /* SSKKeychainStorage.swift in Sources */, C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */, @@ -5097,7 +5090,6 @@ C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */, C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */, C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */, - C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */, C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */, C38EF24B255B6D67007E1867 /* UIView+OWS.m in Sources */, C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */, diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m b/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m index 07e8e7708..8163fa538 100644 --- a/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m +++ b/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m @@ -165,10 +165,12 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa TSThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - if (![LKSessionMetaProtocol shouldSendReceiptInThread:thread]) { + if (thread.isGroupThread) { // Don't send receipts in group threads continue; } + // TODO TODO TODO + /* OWSReceiptsForSenderMessage *message; NSString *receiptName; diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift index bea7e37c4..bb72e8bac 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift @@ -289,7 +289,6 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver } // Respond to the request SNLog("Responding to sender key request from: \(message.sender!).") - SessionManagementProtocol.sendSessionRequestIfNeeded(to: message.sender!, using: transaction) let userRatchet = Storage.shared.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey) ?? SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index 3452f3d68..92fc37e3c 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -1,7 +1,9 @@ import PromiseKit -public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDelegate, SharedSenderKeysDelegate { +@objc(SNMessageSenderDelegate) +public final class MessageSenderDelegate : NSObject, SessionMessagingKit.MessageSenderDelegate, SharedSenderKeysDelegate { + // MARK: Error public enum Error : LocalizedError { case noThread case noPrivateKey @@ -16,8 +18,12 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele } } + // MARK: Initialization public static let shared = MessageSenderDelegate() + private override init() { } + + // MARK: Sending public func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } if let openGroupServerMessageID = message.openGroupServerMessageID { @@ -30,6 +36,7 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele // TODO: Implement } + // MARK: Closed Groups public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { // Prepare var members = members diff --git a/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift b/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift index 18b5325fb..7e8e64bdb 100644 --- a/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift +++ b/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift @@ -309,7 +309,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { return } - if !SessionMetaProtocol.shouldSendTypingIndicator(in: thread) { return } + if thread.isGroupThread() { return } // Don't send typing indicators in group threads let typingIndicator = TypingIndicator() typingIndicator.kind = action diff --git a/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift b/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift deleted file mode 100644 index bb0df42fd..000000000 --- a/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift +++ /dev/null @@ -1,225 +0,0 @@ -import PromiseKit - -// A few notes about making changes in this file: -// -// • Don't use a database transaction if you can avoid it. -// • If you do need to use a database transaction, use a read transaction if possible. -// • For write transactions, consider making it the caller's responsibility to manage the database transaction (this helps avoid unnecessary transactions). -// • Think carefully about adding a function; there might already be one for what you need. -// • Document the expected cases in which a function will be used -// • Express those cases in tests. - -@objc(LKSessionManagementProtocol) -public final class SessionManagementProtocol : NSObject { - - internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } - - // MARK: - General - - @objc(createPreKeys) - public static func createPreKeys() { - // We don't generate new pre keys here like Signal does. - // This is because we need the records to be linked to a contact since we don't have a central server. - // It's done automatically when we generate a pre key bundle to send to a contact (generatePreKeyBundleForContact:). - // You can use getOrCreatePreKeyForContact: to generate one if needed. - let signedPreKeyRecord = storage.generateRandomSignedRecord() - signedPreKeyRecord.markAsAcceptedByService() - storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - SNLog("Pre keys created successfully.") - } - - @objc(refreshSignedPreKey) - public static func refreshSignedPreKey() { - // We don't generate new pre keys here like Signal does. - // This is because we need the records to be linked to a contact since we don't have a central server. - // It's done automatically when we generate a pre key bundle to send to a contact (generatePreKeyBundleForContact:). - // You can use getOrCreatePreKeyForContact: to generate one if needed. - guard storage.currentSignedPrekeyId() == nil else { return } - let signedPreKeyRecord = storage.generateRandomSignedRecord() - signedPreKeyRecord.markAsAcceptedByService() - storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - TSPreKeyManager.clearPreKeyUpdateFailureCount() - TSPreKeyManager.clearSignedPreKeyRecords() - SNLog("Signed pre key refreshed successfully.") - } - - @objc(rotateSignedPreKey) - public static func rotateSignedPreKey() { - // This is identical to what Signal does, except that it doesn't upload the signed pre key - // to a server. - let signedPreKeyRecord = storage.generateRandomSignedRecord() - signedPreKeyRecord.markAsAcceptedByService() - storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - TSPreKeyManager.clearPreKeyUpdateFailureCount() - TSPreKeyManager.clearSignedPreKeyRecords() - SNLog("Signed pre key rotated successfully.") - } - - // MARK: - Sending - - @objc(isSessionRequiredForMessage:recipientID:transaction:) - public static func isSessionRequired(for message: TSOutgoingMessage, recipientID: String, transaction: YapDatabaseReadWriteTransaction) -> Bool { - return false -// if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { -// return false -// } else { -// return !shouldUseFallbackEncryption(for: message, recipientID: recipientID, transaction: transaction) -// } - } - - @objc(shouldUseFallbackEncryptionForMessage:recipientID:transaction:) - public static func shouldUseFallbackEncryption(for message: TSOutgoingMessage, recipientID: String, transaction: YapDatabaseReadWriteTransaction) -> Bool { - return true -// if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { return false } -// else if message is SessionRequestMessage { return true } -// else if message is EndSessionMessage { return true } -// else if let message = message as? DeviceLinkMessage, message.kind == .request { return true } -// else if message is OWSOutgoingNullMessage { return false } -// return !storage.containsSession(recipientID, deviceId: Int32(OWSDevicePrimaryDeviceId), protocolContext: transaction) - } - - private static func hasSentSessionRequestExpired(for publicKey: String) -> Bool { - return false -// let timestamp = Storage.getSessionRequestSentTimestamp(for: publicKey) -// let expiration = timestamp + TTLUtilities.getTTL(for: .sessionRequest) -// return NSDate.ows_millisecondTimeStamp() > expiration - } - - @objc(sendSessionRequestIfNeededToPublicKey:transaction:) - public static func sendSessionRequestIfNeeded(to publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - // It's never necessary to establish a session with self - guard publicKey != getUserHexEncodedPublicKey() else { return } - // Check that we don't already have a session - let hasSession = storage.containsSession(publicKey, deviceId: Int32(1), protocolContext: transaction) - guard !hasSession else { return } - // Check that we didn't already send a session request - let hasSentSessionRequest = (Storage.shared.getSessionRequestSentTimestamp(for: publicKey) > 0) - let hasSentSessionRequestExpired = SessionManagementProtocol.hasSentSessionRequestExpired(for: publicKey) - if hasSentSessionRequestExpired { - Storage.shared.setSessionRequestSentTimestamp(for: publicKey, to: 0, using: transaction) - } - guard !hasSentSessionRequest || hasSentSessionRequestExpired else { return } - // Create the thread if needed - let thread = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) - thread.save(with: transaction) - // Send the session request - SNLog("Sending session request to: \(publicKey).") - Storage.shared.setSessionRequestSentTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) - let sessionRequest = SessionRequest() - sessionRequest.preKeyBundle = storage.generatePreKeyBundle(forContact: publicKey) - MessageSender.send(sessionRequest, in: thread, using: transaction) - } - - @objc(sendNullMessageToPublicKey:transaction:) - public static func sendNullMessage(to publicKey: String, in transaction: YapDatabaseReadWriteTransaction) { - let thread = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) - thread.save(with: transaction) - let nullMessage = NullMessage() - MessageSender.send(nullMessage, in: thread, using: transaction) - } - - /// - Note: Deprecated. - /// - /// Only relevant for closed groups that don't use shared sender keys. - @objc(shouldIgnoreMissingPreKeyBundleExceptionForMessage:to:) - public static func shouldIgnoreMissingPreKeyBundleException(for message: TSOutgoingMessage, to hexEncodedPublicKey: String) -> Bool { - // When a closed group is created, members try to establish sessions with eachother in the background through - // session requests. Until ALL users those session requests were sent to have come online, stored the pre key - // bundles contained in the session requests and replied with background messages to finalize the session - // creation, a given user won't be able to successfully send a message to all members of a group. This check - // is so that until we can do better on this front the user at least won't see this as an error in the UI. - guard let groupThread = message.thread as? TSGroupThread else { return false } - return groupThread.groupModel.groupType == .closedGroup && !groupThread.usesSharedSenderKeys - } - - @objc(startSessionResetInThread:transaction:) - public static func startSessionReset(in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { -// // Check preconditions -// guard let thread = thread as? TSContactThread else { -// return SNLog("Can't restore session for non contact thread.") -// } -// // Send end session messages to the devices requiring session restoration -// let devices = thread.sessionRestoreDevices // TODO: Rename this to something that reads better -// for device in devices { -// guard ECKeyPair.isValidHexEncodedPublicKey(candidate: device) else { continue } -// let thread = TSContactThread.getOrCreateThread(withContactId: device, transaction: transaction) -// thread.save(with: transaction) -// /* -// let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread) -// let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue -// messageSenderJobQueue.add(message: endSessionMessage, transaction: transaction) -// */ -// } -// thread.removeAllSessionRestoreDevices(with: transaction) -// // Notify the user -// let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) -// infoMessage.save(with: transaction) -// // Update the session reset status -// thread.sessionResetStatus = .initiated -// thread.save(with: transaction) - } - - // MARK: - Receiving - - @objc(handleDecryptionError:forPublicKey:transaction:) - public static func handleDecryptionError(_ errorMessage: TSErrorMessage, for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { -// let type = errorMessage.errorType -// let masterPublicKey = storage.getMasterHexEncodedPublicKey(for: publicKey, in: transaction) ?? publicKey -// let thread = TSContactThread.getOrCreateThread(withContactId: masterPublicKey, transaction: transaction) -// let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) -// // Show the session reset prompt upon certain errors -// switch type { -// case .noSession, .invalidMessage, .invalidKeyException: -// if restorationTimeInMs > errorMessage.timestamp { -// // Automatically rebuild session after restoration -// sendSessionRequestIfNeeded(to: publicKey, using: transaction) -// } else { -// // Store the source device's public key in case it was a secondary device -// thread.addSessionRestoreDevice(publicKey, transaction: transaction) -// } -// default: break -// } - } - - private static func shouldProcessSessionRequest(from publicKey: String, at timestamp: UInt64) -> Bool { - let sentTimestamp = Storage.shared.getSessionRequestSentTimestamp(for: publicKey) - let processedTimestamp = Storage.shared.getSessionRequestProcessedTimestamp(for: publicKey) - let restorationTimestamp = UInt64(storage.getRestorationTime() * 1000) - return timestamp > sentTimestamp && timestamp > processedTimestamp && timestamp > restorationTimestamp - } - - @objc(handlePreKeyBundleMessageIfNeeded:wrappedIn:transaction:) - public static func handlePreKeyBundleMessageIfNeeded(_ protoContent: SNProtoContent, wrappedIn envelope: SNProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { -// let publicKey = envelope.source! // Set during UD decryption -// guard let preKeyBundleMessage = protoContent.prekeyBundleMessage else { return } -// SNLog("Received a pre key bundle message from: \(publicKey).") -// guard let preKeyBundle = preKeyBundleMessage.getPreKeyBundle(with: transaction) else { -// return SNLog("Couldn't parse pre key bundle received from: \(publicKey).") -// } -// if !shouldProcessSessionRequest(from: publicKey, at: envelope.timestamp) { -// return SNLog("Ignoring session request from: \(publicKey).") -// } -// storage.setPreKeyBundle(preKeyBundle, forContact: publicKey, transaction: transaction) -// Storage.setSessionRequestProcessedTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) -// sendNullMessage(to: publicKey, in: transaction) - } - - @objc(handleEndSessionMessageReceivedInThread:using:) - public static func handleEndSessionMessageReceived(in thread: TSContactThread, using transaction: YapDatabaseReadWriteTransaction) { -// let publicKey = thread.contactIdentifier() -// SNLog("End session message received from: \(publicKey).") -// // Notify the user -// let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) -// infoMessage.save(with: transaction) -// // Archive all sessions -// storage.archiveAllSessions(forContact: publicKey, protocolContext: transaction) -// // Update the session reset status -// thread.sessionResetStatus = .requestReceived -// thread.save(with: transaction) -// // Send a null message -// sendNullMessage(to: publicKey, in: transaction) - } -} diff --git a/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift b/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift deleted file mode 100644 index a47c8e5ee..000000000 --- a/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift +++ /dev/null @@ -1,119 +0,0 @@ -import PromiseKit - -// A few notes about making changes in this file: -// -// • Don't use a database transaction if you can avoid it. -// • If you do need to use a database transaction, use a read transaction if possible. -// • For write transactions, consider making it the caller's responsibility to manage the database transaction (this helps avoid unnecessary transactions). -// • Think carefully about adding a function; there might already be one for what you need. -// • Document the expected cases in which a function will be used -// • Express those cases in tests. - -/// See [Receipts, Transcripts & Typing Indicators](https://github.com/loki-project/session-protocol-docs/wiki/Receipts,-Transcripts-&-Typing-Indicators) for more information. -@objc(LKSessionMetaProtocol) -public final class SessionMetaProtocol : NSObject { - - internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } - - // MARK: - Sending - - // MARK: Message Destination(s) - @objc public static func getDestinationsForOutgoingSyncMessage() -> NSMutableSet { - return NSMutableSet(set: [ getUserHexEncodedPublicKey() ]) // return NSMutableSet(set: MultiDeviceProtocol.getUserLinkedDevices()) - } - - @objc(getDestinationsForOutgoingGroupMessage:inThread:) - public static func getDestinations(for outgoingGroupMessage: TSOutgoingMessage, in thread: TSThread) -> NSMutableSet { - guard let thread = thread as? TSGroupThread else { preconditionFailure("Can't get destinations for group message in non-group thread.") } - var result: Set = [] - if thread.isOpenGroup { - if let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!) { - result = [ openGroup.server ] // Aim the message at the open group server - } else { - // Should never occur - } - } else { - if let groupThread = thread as? TSGroupThread, groupThread.usesSharedSenderKeys { - let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupThread.groupModel.groupId) - result = [ groupPublicKey ] - } else { - result = Set(outgoingGroupMessage.sendingRecipientIds()) - .intersection(thread.groupModel.groupMemberIds) - .subtracting([ getUserHexEncodedPublicKey() ]) // .subtracting(MultiDeviceProtocol.getUserLinkedDevices()) - } - } - return NSMutableSet(set: result) - } - - // MARK: Note to Self - @objc(isThreadNoteToSelf:) - public static func isThreadNoteToSelf(_ thread: TSThread) -> Bool { - guard let thread = thread as? TSContactThread else { return false } - return thread.contactIdentifier() == getUserHexEncodedPublicKey() - /* - var isNoteToSelf = false - storage.dbReadConnection.read { transaction in - isNoteToSelf = LokiDatabaseUtilities.isUserLinkedDevice(thread.contactIdentifier(), transaction: transaction) - } - return isNoteToSelf - */ - } - - // MARK: Transcripts - @objc(shouldSendTranscriptForMessage:inThread:) - public static func shouldSendTranscript(for message: TSOutgoingMessage, in thread: TSThread) -> Bool { - guard message.shouldSyncTranscript() else { return false } - let isOpenGroupMessage = (thread as? TSGroupThread)?.isOpenGroup == true - let wouldSignalRequireTranscript = (AreRecipientUpdatesEnabled() || !message.hasSyncedTranscript) - guard wouldSignalRequireTranscript && !isOpenGroupMessage else { return false } - return false - /* - var usesMultiDevice = false - storage.dbReadConnection.read { transaction in - usesMultiDevice = !storage.getDeviceLinks(for: getUserHexEncodedPublicKey(), in: transaction).isEmpty - || UserDefaults.standard[.masterHexEncodedPublicKey] != nil - } - return usesMultiDevice - */ - } - - // MARK: Typing Indicators - /// Invoked only if typing indicators are enabled in the settings. Provides an opportunity - /// to avoid sending them if certain conditions are met. - @objc(shouldSendTypingIndicatorInThread:) - public static func shouldSendTypingIndicator(in thread: TSThread) -> Bool { - return !thread.isGroupThread() && thread.numberOfInteractions() > 0 - } - - // MARK: Receipts - @objc(shouldSendReceiptInThread:) - public static func shouldSendReceipt(in thread: TSThread) -> Bool { - return !thread.isGroupThread() - } - - // MARK: - Receiving - - @objc(isErrorMessageFromBeforeRestoration:) - public static func isErrorMessageFromBeforeRestoration(_ errorMessage: TSErrorMessage) -> Bool { - let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) - return errorMessage.timestamp < restorationTimeInMs - } - - @objc(updateDisplayNameIfNeededForPublicKey:using:transaction:) - public static func updateDisplayNameIfNeeded(for publicKey: String, using dataMessage: SNProtoDataMessage, in transaction: YapDatabaseReadWriteTransaction) { - guard let profile = dataMessage.profile, let displayName = profile.displayName, !displayName.isEmpty else { return } - let profileManager = SSKEnvironment.shared.profileManager - profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) - } - - @objc(updateProfileKeyIfNeededForPublicKey:using:) - public static func updateProfileKeyIfNeeded(for publicKey: String, using dataMessage: SNProtoDataMessage) { - guard dataMessage.hasProfileKey, let profileKey = dataMessage.profileKey else { return } - guard profileKey.count == kAES256_KeyByteLength else { - return SNLog("Unexpected profile key size: \(profileKey.count).") - } - let profilePictureURL = dataMessage.profile?.profilePicture - let profileManager = SSKEnvironment.shared.profileManager - profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) - } -} From 4317b17e7e85e6baa3f18e970213e05cd14e7542 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 09:49:31 +1100 Subject: [PATCH 026/177] Fill in some gaps --- Session/Signal/AppDelegate.m | 4 ++++ SessionMessagingKit/Jobs/AttachmentUploadJob.swift | 2 +- SessionMessagingKit/Jobs/MessageSendJob.swift | 1 + .../Messages/Visible Messages/VisibleMessage.swift | 9 ++++++++- .../Database/Storage/Storage+Jobs.swift | 12 +++++++++++- 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 338fac2b4..238397962 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -217,6 +217,10 @@ static NSTimeInterval launchStartedAt; [SNConfiguration performMainSetup]; + if (CurrentAppContext().isMainApp) { + [SNJobQueue resumePendingJobs]; + } + [LKAppearanceUtilities switchToSessionAppearance]; if (CurrentAppContext().isRunningTests) { diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index b504272e8..6caf85c4b 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -2,7 +2,7 @@ import SessionUtilitiesKit public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? - private let attachmentID: String + public let attachmentID: String private let threadID: String public var id: String? public var failureCount: UInt = 0 diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 467c9e00c..1c9a9b2ea 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -77,6 +77,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi } if !attachmentsToUpload.isEmpty { delegate?.postpone(self); return } // Wait for all attachments to upload before continuing } + // FIXME: This doesn't yet handle the attachment side of link previews, quotes, etc. storage.withAsync({ transaction in // Intentionally capture self Threading.workQueue.async { MessageSender.send(self.message, to: self.destination, using: transaction).done(on: Threading.workQueue) { diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index e0339d25f..3cd5fab53 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -55,7 +55,14 @@ public final class VisibleMessage : Message { dataMessage = SNProtoDataMessage.builder() } if let text = text { dataMessage.setBody(text) } - // TODO: Attachments + let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0) } + if !attachments.allSatisfy({ $0.isUploaded }) { + #if DEBUG + preconditionFailure("Sending a message before all associated attachments have been uploaded.") + #endif + } + let attachmentProtos = attachments.compactMap { TSAttachmentStream.buildProto(forAttachmentId: $0.uniqueId!) } + dataMessage.setAttachments(attachmentProtos) if let quote = quote, let quoteProto = quote.toProto() { dataMessage.setQuote(quoteProto) } if let linkPreview = linkPreview, let linkPreviewProto = linkPreview.toProto() { dataMessage.setPreview([ linkPreviewProto ]) } // TODO: Contact diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift b/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift index 12a223fc6..60c18412f 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift +++ b/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift @@ -25,6 +25,16 @@ extension Storage { } public func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? { - return nil // TODO: Implement + var result: [AttachmentUploadJob] = [] + Storage.read { transaction in + transaction.enumerateRows(inCollection: AttachmentUploadJob.collection) { _, object, _, _ in + guard let job = object as? AttachmentUploadJob, job.attachmentID == attachmentID else { return } + result.append(job) + } + } + #if DEBUG + assert(result.isEmpty || result.count == 1) + #endif + return result.first } } From 58b312f341d8fa7bc6c2c60b425b706feddedc3c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 11:45:03 +1100 Subject: [PATCH 027/177] Fix job resuming --- Session/Signal/AppDelegate.m | 44 ++++-------------------------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 238397962..a8fa1c079 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -195,8 +195,6 @@ static NSTimeInterval launchStartedAt; [AppVersion sharedInstance]; - [self startupLogging]; - // Prevent the device from sleeping during database view async registration // (e.g. long database upgrades). // @@ -217,10 +215,6 @@ static NSTimeInterval launchStartedAt; [SNConfiguration performMainSetup]; - if (CurrentAppContext().isMainApp) { - [SNJobQueue resumePendingJobs]; - } - [LKAppearanceUtilities switchToSessionAppearance]; if (CurrentAppContext().isRunningTests) { @@ -367,40 +361,6 @@ static NSTimeInterval launchStartedAt; } } -- (void)startupLogging -{ - OWSLogInfo(@"iOS Version: %@", [UIDevice currentDevice].systemVersion); - - NSString *localeIdentifier = [NSLocale.currentLocale objectForKey:NSLocaleIdentifier]; - if (localeIdentifier.length > 0) { - OWSLogInfo(@"Locale Identifier: %@", localeIdentifier); - } - NSString *countryCode = [NSLocale.currentLocale objectForKey:NSLocaleCountryCode]; - if (countryCode.length > 0) { - OWSLogInfo(@"Country Code: %@", countryCode); - } - NSString *languageCode = [NSLocale.currentLocale objectForKey:NSLocaleLanguageCode]; - if (languageCode.length > 0) { - OWSLogInfo(@"Language Code: %@", languageCode); - } - - struct utsname systemInfo; - uname(&systemInfo); - - OWSLogInfo(@"Device Model: %@ (%@)", - UIDevice.currentDevice.model, - [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]); - - NSDictionary *buildDetails = - [[NSBundle mainBundle] objectForInfoDictionaryKey:@"BuildDetails"]; - OWSLogInfo(@"WebRTC Commit: %@", buildDetails[@"WebRTCCommit"]); - OWSLogInfo(@"Build XCode Version: %@", buildDetails[@"XCodeVersion"]); - OWSLogInfo(@"Build OS X Version: %@", buildDetails[@"OSXVersion"]); - OWSLogInfo(@"Build Cocoapods Version: %@", buildDetails[@"CocoapodsVersion"]); - OWSLogInfo(@"Build Carthage Version: %@", buildDetails[@"CarthageVersion"]); - OWSLogInfo(@"Build Date/Time: %@", buildDetails[@"DateTime"]); -} - - (void)enableBackgroundRefreshIfNecessary { [AppReadiness runNowOrWhenAppDidBecomeReady:^{ @@ -435,6 +395,10 @@ static NSTimeInterval launchStartedAt; // sent before the app exited should be marked as failures. [[[OWSFailedMessagesJob alloc] initWithPrimaryStorage:self.primaryStorage] run]; [[[OWSFailedAttachmentDownloadsJob alloc] initWithPrimaryStorage:self.primaryStorage] run]; + + if (CurrentAppContext().isMainApp) { + [SNJobQueue.shared resumePendingJobs]; + } }); } }); // end dispatchOnce for first time we become active From 921e2bced60031ca37f3501ebbf9425348bd40db Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 14:10:32 +1100 Subject: [PATCH 028/177] Debug --- Session/Components/ConversationCell.swift | 3 +- .../ConversationViewController.m | 43 ++++++++----------- .../ConversationView/ConversationViewModel.m | 11 ----- .../Jobs/AttachmentUploadJob.swift | 2 +- SessionMessagingKit/Jobs/MessageSendJob.swift | 2 +- .../Sending & Receiving/MessageSender.swift | 8 ++-- .../MessageSenderDelegate.swift | 2 +- .../Database/Storage/Storage+Jobs.swift | 19 ++++++++ .../Messaging/Core Messages/TSInteraction.h | 3 +- .../Messaging/Core Messages/TSInteraction.m | 19 ++++---- .../MessageSenderDelegate.swift | 5 ++- SignalUtilitiesKit/OWSAttachmentDownloads.m | 2 - SignalUtilitiesKit/TSPreKeyManager.m | 1 - 13 files changed, 57 insertions(+), 63 deletions(-) diff --git a/Session/Components/ConversationCell.swift b/Session/Components/ConversationCell.swift index e4230a88d..2fcc524bd 100644 --- a/Session/Components/ConversationCell.swift +++ b/Session/Components/ConversationCell.swift @@ -132,8 +132,7 @@ final class ConversationCell : UITableViewCell { // MARK: Updating private func update() { AssertIsOnMainThread() - let thread = threadViewModel.threadRecord - guard let threadID = thread.uniqueId else { return } + guard let thread = threadViewModel?.threadRecord, let threadID = thread.uniqueId else { return } MentionsManager.populateUserPublicKeyCacheIfNeeded(for: threadID) // FIXME: This is a terrible place to do this let isBlocked: Bool if let thread = thread as? TSContactThread { diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index ff1bc290e..d4259f70c 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3797,7 +3797,6 @@ typedef enum : NSUInteger { - (void)tryToSendTextMessage:(NSString *)text updateKeyboardState:(BOOL)updateKeyboardState { OWSAssertIsOnMainThread(); - __weak ConversationViewController *weakSelf = self; if ([self isBlockedConversation]) { [self showUnblockConversationUI:^(BOOL isBlocked) { @@ -3807,38 +3806,26 @@ typedef enum : NSUInteger { }]; return; } - text = [text ows_stripped]; - if (text.length < 1) { return; } - SNVisibleMessage *message = [SNVisibleMessage new]; - [message setSentTimestamp:[NSDate millisecondTimestamp]]; + message.sentTimestamp = [NSDate millisecondTimestamp]; message.text = text; message.quote = [SNQuote from:self.inputToolbar.quotedReply]; - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [SNMessageSender send:message inThread:self.thread usingTransaction:transaction]; - }]; - - TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread]; - - [tsMessage save]; - + TSThread *thread = self.thread; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; - - [self messageWasSent:tsMessage]; - - [self.inputToolbar clearTextMessageAnimated:YES]; - - [self resetMentions]; - - dispatch_async(dispatch_get_main_queue(), ^{ - [self.inputToolbar toggleDefaultKeyboard]; - }); - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self.thread setDraft:@"" transaction:transaction]; + [tsMessage saveWithTransaction:transaction]; + [SNMessageSender send:message inThread:thread usingTransaction:transaction]; + [thread setDraft:@"" transaction:transaction]; }]; + [self messageWasSent:tsMessage]; + [self.inputToolbar clearTextMessageAnimated:YES]; + [self resetMentions]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[weakSelf inputToolbar] toggleDefaultKeyboard]; + }); } - (void)voiceMemoGestureDidStart @@ -4562,7 +4549,10 @@ typedef enum : NSUInteger { - (void)handleMessageSendingFailedNotification:(NSNotification *)notification { NSNumber *timestamp = (NSNumber *)notification.object; - [self hideProgressIndicatorViewForMessageWithTimestamp:timestamp]; + self.progressIndicatorView.progressTintColor = LKColors.destructive; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { + [self hideProgressIndicatorViewForMessageWithTimestamp:timestamp]; + }); } - (void)setProgressIfNeededTo:(float)progress forMessageWithTimestamp:(NSNumber *)timestamp @@ -4600,6 +4590,7 @@ typedef enum : NSUInteger { self.progressIndicatorView.alpha = 0; } completion:^(BOOL finished) { [self.progressIndicatorView setProgress:0.0f]; + self.progressIndicatorView.progressTintColor = LKColors.accent; }]; }); } diff --git a/Session/Signal/ConversationView/ConversationViewModel.m b/Session/Signal/ConversationView/ConversationViewModel.m index c791e5474..c7884aa4b 100644 --- a/Session/Signal/ConversationView/ConversationViewModel.m +++ b/Session/Signal/ConversationView/ConversationViewModel.m @@ -1068,17 +1068,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; OWSAssertDebug(!viewItemCache[interaction.uniqueId]); viewItemCache[interaction.uniqueId] = viewItem; [viewItems addObject:viewItem]; - TSMessage *message = (TSMessage *)viewItem.interaction; - if (message.hasUnfetchedAttachmentsFromPN) { - [SSKEnvironment.shared.attachmentDownloads downloadAttachmentsForMessage:message - transaction:transaction - success:^(NSArray *attachmentStreams) { - OWSLogInfo(@"Successfully redownloaded attachment in thread: %@", message.thread); - } - failure:^(NSError *error) { - OWSLogWarn(@"Failed to redownload message with error: %@", error); - }]; - } return viewItem; }; diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 6caf85c4b..7b49adc7a 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -3,7 +3,7 @@ import SessionUtilitiesKit public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? public let attachmentID: String - private let threadID: String + public let threadID: String public var id: String? public var failureCount: UInt = 0 diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 1c9a9b2ea..d91e1c46d 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -3,7 +3,7 @@ import SessionUtilitiesKit @objc(SNMessageSendJob) public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var delegate: JobDelegate? - private let message: Message + public let message: Message private let destination: Message.Destination public var id: String? public var failureCount: UInt = 0 diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 04c3c36f1..cc8bac427 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -149,9 +149,9 @@ public final class MessageSender : NSObject { JobQueue.shared.add(notifyPNServerJob, using: transaction) }, completion: { }) } - let _ = promise.catch(on: DispatchQueue.main) { _ in + let _ = promise.catch(on: DispatchQueue.main) { error in storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, using: transaction) + Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) }, completion: { }) if case .contact(_) = destination { NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) @@ -184,9 +184,9 @@ public final class MessageSender : NSObject { Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) } - promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { _ in + promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, using: transaction) + Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) }, completion: { }) } return promise.map { _ in } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift index dac0ecc66..1f1cc0969 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift @@ -2,5 +2,5 @@ public protocol MessageSenderDelegate { func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) - func handleFailedMessageSend(_ message: Message, using transaction: Any) + func handleFailedMessageSend(_ message: Message, with error: Error, using transaction: Any) } diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift b/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift index 60c18412f..ac91708a7 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift +++ b/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift @@ -23,6 +23,25 @@ extension Storage { } return result } + + public func cancelAllPendingJobs(of type: Job.Type, using transaction: YapDatabaseReadWriteTransaction) { + transaction.removeAllObjects(inCollection: type.collection) + } + + public func cancelPendingMessageSendJobs(for threadID: String, using transaction: YapDatabaseReadWriteTransaction) { + var attachmentUploadJobKeys: [String] = [] + transaction.enumerateRows(inCollection: AttachmentUploadJob.collection) { key, object, _, _ in + guard let job = object as? AttachmentUploadJob, job.threadID == threadID else { return } + attachmentUploadJobKeys.append(key) + } + var messageSendJobKeys: [String] = [] + transaction.enumerateRows(inCollection: MessageSendJob.collection) { key, object, _, _ in + guard let job = object as? MessageSendJob, job.message.threadID == threadID else { return } + messageSendJobKeys.append(key) + } + transaction.removeObjects(forKeys: attachmentUploadJobKeys, inCollection: AttachmentUploadJob.collection) + transaction.removeObjects(forKeys: messageSendJobKeys, inCollection: MessageSendJob.collection) + } public func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? { var result: [AttachmentUploadJob] = [] diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h index 906bbf1fe..e8010e70e 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h @@ -40,8 +40,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value); @property (nonatomic, readonly) uint64_t sortId; @property (nonatomic, readonly) uint64_t receivedAtTimestamp; @property (nonatomic, readonly) BOOL shouldUseServerTime; -// Push notifications -@property (nonatomic) BOOL hasUnfetchedAttachmentsFromPN; +@property (nonatomic, readonly) BOOL isOpenGroupMessage; - (void)setServerTimestampToReceivedTimestamp:(uint64_t)receivedAtTimestamp; diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m index 6bc729a9e..004d923f5 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m @@ -205,19 +205,18 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) { OWSAssertDebug(other); - // Sort the messages by the sender's timestamp (Signal uses sortId) - uint64_t sortId1 = self.timestamp; - uint64_t sortId2 = other.timestamp; + uint64_t sortId1; + uint64_t sortId2; - // In open groups messages should be sorted by their server timestamp. `sortId` represents the order in which messages + // In open groups messages should be sorted by server timestamp. `sortId` represents the order in which messages // were processed. Since in the open group poller we sort messages by their server timestamp, sorting by `sortId` is // effectively the same as sorting by server timestamp. - if (self.thread.isGroupThread) { - TSGroupThread *thread = (TSGroupThread *)self.thread; - if (thread.isOpenGroup) { - sortId1 = self.sortId; - sortId2 = other.sortId; - } + if (self.isOpenGroupMessage) { + sortId1 = self.sortId; + sortId2 = other.sortId; + } else { + sortId1 = self.timestamp; + sortId2 = other.timestamp; } if (sortId1 > sortId2) { diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index 92fc37e3c..e720bcfa1 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -32,8 +32,9 @@ public final class MessageSenderDelegate : NSObject, SessionMessagingKit.Message tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) } - public func handleFailedMessageSend(_ message: Message, using transaction: Any) { - // TODO: Implement + public func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction) } // MARK: Closed Groups diff --git a/SignalUtilitiesKit/OWSAttachmentDownloads.m b/SignalUtilitiesKit/OWSAttachmentDownloads.m index a1d02969a..5501818f8 100644 --- a/SignalUtilitiesKit/OWSAttachmentDownloads.m +++ b/SignalUtilitiesKit/OWSAttachmentDownloads.m @@ -282,8 +282,6 @@ typedef void (^AttachmentDownloadFailure)(NSError *error); [job.attachmentPointer saveWithTransaction:transaction]; if (job.message) { - job.message.hasUnfetchedAttachmentsFromPN = !CurrentAppContext().isMainApp; - [job.message saveWithTransaction:transaction]; [job.message touchWithTransaction:transaction]; } diff --git a/SignalUtilitiesKit/TSPreKeyManager.m b/SignalUtilitiesKit/TSPreKeyManager.m index 612265b73..91ea8857d 100644 --- a/SignalUtilitiesKit/TSPreKeyManager.m +++ b/SignalUtilitiesKit/TSPreKeyManager.m @@ -216,7 +216,6 @@ static const NSUInteger kMaxPrekeyUpdateFailureCount = 5; if (!keyId) { // currentSignedPreKeyId should only be nil before we've completed registration. // We have this guard here for robustness, but we should never get here. - OWSFailDebug(@"Ignoring request to clear signed preKeys since no keyId was specified"); return; } From ce7a23c40120378993da5d59198f157e141f0457 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 14:43:53 +1100 Subject: [PATCH 029/177] Make sure sending errors bubble up to the user --- .../Sending & Receiving/MessageSender.swift | 60 +++++++++++-------- .../TSIncomingMessage+Conversion.swift | 1 + .../Messaging/Core Messages/TSInteraction.h | 2 +- .../Messaging/Core Messages/TSMessage.h | 2 - .../Messaging/Core Messages/TSMessage.m | 6 -- .../Core Messages/TSOutgoingMessage.m | 3 +- .../MessageSenderDelegate.swift | 5 +- 7 files changed, 40 insertions(+), 39 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index cc8bac427..1f518bf75 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -38,6 +38,7 @@ public final class MessageSender : NSObject { } internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { + let (promise, seal) = Promise.pending() let storage = Configuration.shared.storage if message.sentTimestamp == nil { // Visible messages will already have the sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() @@ -48,17 +49,27 @@ public final class MessageSender : NSObject { case .closedGroup(let groupPublicKey): message.recipient = groupPublicKey case .openGroup(_, _): preconditionFailure() } + // Set the failure handler + let _ = promise.catch(on: DispatchQueue.main) { error in + storage.withAsync({ transaction in + Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) + }, completion: { }) + if case .contact(_) = destination { + NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) + } + } // Validate the message - guard message.isValid else { return Promise(error: Error.invalidMessage) } + guard message.isValid else { seal.reject(Error.invalidMessage); return promise } // Convert it to protobuf - guard let proto = message.toProto() else { return Promise(error: Error.protoConversionFailed) } + guard let proto = message.toProto() else { seal.reject(Error.protoConversionFailed); return promise } // Serialize the protobuf let plaintext: Data do { plaintext = try proto.serializedData() } catch { SNLog("Couldn't serialize proto due to error: \(error).") - return Promise(error: error) + seal.reject(error) + return promise } // Encrypt the serialized protobuf if case .contact(_) = destination { @@ -75,7 +86,8 @@ public final class MessageSender : NSObject { } } catch { SNLog("Couldn't encrypt message for destination: \(destination) due to error: \(error).") - return Promise(error: error) + seal.reject(error) + return promise } // Wrap the result let kind: SNProtoEnvelope.SNProtoEnvelopeType @@ -95,7 +107,8 @@ public final class MessageSender : NSObject { senderPublicKey: senderPublicKey, base64EncodedContent: ciphertext.base64EncodedString()) } catch { SNLog("Couldn't wrap message due to error: \(error).") - return Promise(error: error) + seal.reject(error) + return promise } // Calculate proof of work if case .contact(_) = destination { @@ -107,7 +120,8 @@ public final class MessageSender : NSObject { let base64EncodedData = wrappedMessage.base64EncodedString() guard let (timestamp, nonce) = ProofOfWork.calculate(ttl: type(of: message).ttl, publicKey: recipient, data: base64EncodedData) else { SNLog("Proof of work calculation failed.") - return Promise(error: Error.proofOfWorkCalculationFailed) + seal.reject(Error.proofOfWorkCalculationFailed) + return promise } // Send the result if case .contact(_) = destination { @@ -116,7 +130,6 @@ public final class MessageSender : NSObject { } } let snodeMessage = SnodeMessage(recipient: recipient, data: base64EncodedData, ttl: type(of: message).ttl, timestamp: timestamp, nonce: nonce) - let (promise, seal) = Promise.pending() SnodeAPI.sendMessage(snodeMessage).done(on: Threading.workQueue) { promises in var isSuccess = false let promiseCount = promises.count @@ -149,18 +162,11 @@ public final class MessageSender : NSObject { JobQueue.shared.add(notifyPNServerJob, using: transaction) }, completion: { }) } - let _ = promise.catch(on: DispatchQueue.main) { error in - storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) - }, completion: { }) - if case .contact(_) = destination { - NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) - } - } return promise } internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { + let (promise, seal) = Promise.pending() let storage = Configuration.shared.storage message.sentTimestamp = NSDate.millisecondTimestamp() switch destination { @@ -168,7 +174,12 @@ public final class MessageSender : NSObject { case .closedGroup(_): preconditionFailure() case .openGroup(let channel, let server): message.recipient = "\(server).\(channel)" } - guard message.isValid else { return Promise(error: Error.invalidMessage) } + let _ = promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in + storage.withAsync({ transaction in + Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) + }, completion: { }) + } + guard message.isValid else { seal.reject(Error.invalidMessage); return promise } let (channel, server) = { () -> (UInt64, String) in switch destination { case .openGroup(let channel, let server): return (channel, server) @@ -176,19 +187,18 @@ public final class MessageSender : NSObject { } }() guard let message = message as? VisibleMessage, - let openGroupMessage = OpenGroupMessage.from(message, for: server) else { return Promise(error: Error.invalidMessage) } - let promise = OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server) - let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in + let openGroupMessage = OpenGroupMessage.from(message, for: server) else { seal.reject(Error.invalidMessage); return promise } + OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = openGroupMessage.serverID + seal.fulfill(()) + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in + seal.reject(error) + } + let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { storage.withAsync({ transaction in Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) } - promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in - storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) - }, completion: { }) - } - return promise.map { _ in } + return promise } } diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift b/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift index 6917b7235..05762914d 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift @@ -17,6 +17,7 @@ public extension TSIncomingMessage { wasReceivedByUD: true ) result.openGroupServerMessageID = visibleMessage.openGroupServerMessageID ?? 0 + result.isOpenGroupMessage = result.openGroupServerMessageID != 0 return result } } diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h index e8010e70e..983103a49 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h @@ -40,7 +40,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value); @property (nonatomic, readonly) uint64_t sortId; @property (nonatomic, readonly) uint64_t receivedAtTimestamp; @property (nonatomic, readonly) BOOL shouldUseServerTime; -@property (nonatomic, readonly) BOOL isOpenGroupMessage; +@property (nonatomic) BOOL isOpenGroupMessage; - (void)setServerTimestampToReceivedTimestamp:(uint64_t)receivedAtTimestamp; diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h b/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h index 6b5a1d660..436780bfe 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h @@ -27,9 +27,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) BOOL isExpiringMessage; @property (nonatomic, readonly, nullable) TSQuotedMessage *quotedMessage; @property (nonatomic, nullable) OWSLinkPreview *linkPreview; -// Open groups @property (nonatomic) uint64_t openGroupServerMessageID; -@property (nonatomic, readonly) BOOL isOpenGroupMessage; - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m index 6d7c2575c..53ab3c0b5 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m @@ -432,12 +432,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4; }]; } -#pragma mark - Open Groups - -- (BOOL)isOpenGroupMessage { - return self.openGroupServerMessageID > 0; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m index 5b2449b23..35fe9dd7c 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m +++ b/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m @@ -602,8 +602,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { // Mark any "sending" recipients as "failed." - for (TSOutgoingMessageRecipientState *recipientState in message.recipientStateMap - .allValues) { + for (TSOutgoingMessageRecipientState *recipientState in message.recipientStateMap.allValues) { if (recipientState.state == OWSOutgoingMessageRecipientStateSending) { recipientState.state = OWSOutgoingMessageRecipientStateFailed; } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index e720bcfa1..bf9d2b33a 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -26,9 +26,8 @@ public final class MessageSenderDelegate : NSObject, SessionMessagingKit.Message // MARK: Sending public func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } - if let openGroupServerMessageID = message.openGroupServerMessageID { - tsMessage.openGroupServerMessageID = openGroupServerMessageID - } + tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 + tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) } From 70fb7eb185aae0f3441727812289e9db2027d645 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 15:04:46 +1100 Subject: [PATCH 030/177] Fix thread updating issue --- SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift b/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift index fca7c17b5..0d6df572d 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift +++ b/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift @@ -15,7 +15,7 @@ extension Storage { } return try! promise.wait() } - + /// Returns the ID of the thread the message was stored under along with the ID of the `TSIncomingMessage` that was constructed. public func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, String)? { let transaction = transaction as! YapDatabaseReadWriteTransaction @@ -30,6 +30,7 @@ extension Storage { guard let thread = threadOrNil else { return nil } let message = TSIncomingMessage.from(message, associatedWith: thread) message.save(with: transaction) + DispatchQueue.main.async { message.touch() } // FIXME: Hack for a thread updating issue return (thread.uniqueId!, message.uniqueId!) } @@ -59,3 +60,4 @@ extension Storage { tsIncomingMessage.touch(with: transaction) } } + From 19c29b2bf9686d4b17ab368eb67f51cb9f2e290c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 15:36:03 +1100 Subject: [PATCH 031/177] WIP --- .../ConversationViewController.m | 27 +++++++------------ SessionMessagingKit/Jobs/JobQueue.swift | 5 +++- .../MessageSender+Utilities.swift | 13 +++++++-- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index d4259f70c..a2715010f 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3225,7 +3225,6 @@ typedef enum : NSUInteger { }]; return; } - for (SignalAttachment *attachment in attachments) { if ([attachment hasError]) { OWSLogWarn(@"Invalid attachment: %@.", attachment ? [attachment errorName] : @"Missing data"); @@ -3233,21 +3232,15 @@ typedef enum : NSUInteger { return; } } - - __block TSOutgoingMessage *message; - - // TODO TODO TODO - -// [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { -// message = [ThreadUtil enqueueMessageWithText:messageText -// mediaAttachments:attachments -// inThread:self.thread -// quotedReplyModel:self.inputToolbar.quotedReply -// linkPreviewDraft:nil -// transaction:transaction]; -// }]; - - [self messageWasSent:message]; + SNVisibleMessage *message = [SNVisibleMessage new]; + message.sentTimestamp = [NSDate millisecondTimestamp]; + TSThread *thread = self.thread; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [tsMessage saveWithTransaction:transaction]; + [SNMessageSender send:message withAttachments:attachments inThread:thread usingTransaction:transaction]; + }]; + [self messageWasSent:tsMessage]; }); } @@ -3817,7 +3810,7 @@ typedef enum : NSUInteger { [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [tsMessage saveWithTransaction:transaction]; - [SNMessageSender send:message inThread:thread usingTransaction:transaction]; + [SNMessageSender send:message withAttachments:[NSArray new] inThread:thread usingTransaction:transaction]; [thread setDraft:@"" transaction:transaction]; }]; [self messageWasSent:tsMessage]; diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index f2328bc8d..401dab361 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -6,8 +6,11 @@ public final class JobQueue : NSObject, JobDelegate { @objc public static let shared = JobQueue() @objc public func add(_ job: Job, using transaction: Any) { + let transaction = transaction as! YapDatabaseReadWriteTransaction addWithoutExecuting(job, using: transaction) - job.execute() + transaction.addCompletionQueue(Threading.workQueue) { + job.execute() + } } @objc public func addWithoutExecuting(_ job: Job, using transaction: Any) { diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift index 5343e447a..4bc81442b 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift @@ -2,8 +2,17 @@ import PromiseKit public extension MessageSender { - @objc(send:inThread:usingTransaction:) - static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + @objc(send:withAttachments:inThread:usingTransaction:) + static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + if let message = message as? VisibleMessage { + let streams = attachments.map { + return TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, + caption: $0.captionText, albumMessageId: nil + ) + } + streams.forEach { $0.save(with: transaction) } + message.attachmentIDs = streams.map { $0.uniqueId! } + } message.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) let job = MessageSendJob(message: message, destination: destination) From 5e476e83301033e75ac45257714aae95b4e6d475 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 16:18:58 +1100 Subject: [PATCH 032/177] Fix coding issues --- SessionMessagingKit/Jobs/AttachmentDownloadJob.swift | 7 ++++++- SessionMessagingKit/Jobs/AttachmentUploadJob.swift | 7 ++++++- .../MessageSender+Utilities.swift | 12 +++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index e82ea6917..eaf2a9b8f 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -32,14 +32,19 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject // MARK: Coding public init?(coder: NSCoder) { guard let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String?, - let tsIncomingMessageID = coder.decodeObject(forKey: "tsIncomingMessageID") as! String? else { return nil } + let tsIncomingMessageID = coder.decodeObject(forKey: "tsIncomingMessageID") as! String?, + let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.attachmentID = attachmentID self.tsIncomingMessageID = tsIncomingMessageID + self.id = id + self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(attachmentID, forKey: "attachmentID") coder.encode(tsIncomingMessageID, forKey: "tsIncomingMessageID") + coder.encode(id, forKey: "id") + coder.encode(failureCount, forKey: "failureCount") } // MARK: Running diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 7b49adc7a..ff8fc8cb9 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -30,14 +30,19 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N // MARK: Coding public init?(coder: NSCoder) { guard let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String?, - let threadID = coder.decodeObject(forKey: "threadID") as! String? else { return nil } + let threadID = coder.decodeObject(forKey: "threadID") as! String?, + let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.attachmentID = attachmentID self.threadID = threadID + self.id = id + self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(attachmentID, forKey: "attachmentID") coder.encode(threadID, forKey: "threadID") + coder.encode(id, forKey: "id") + coder.encode(failureCount, forKey: "failureCount") } // MARK: Running diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift index 4bc81442b..bde7d7541 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift @@ -5,12 +5,14 @@ public extension MessageSender { @objc(send:withAttachments:inThread:usingTransaction:) static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { if let message = message as? VisibleMessage { - let streams = attachments.map { - return TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, - caption: $0.captionText, albumMessageId: nil - ) + var streams: [TSAttachmentStream] = [] + attachments.forEach { + let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, + caption: $0.captionText, albumMessageId: nil) + streams.append(stream) + stream.write($0.dataSource) + stream.save(with: transaction) } - streams.forEach { $0.save(with: transaction) } message.attachmentIDs = streams.map { $0.uniqueId! } } message.threadID = thread.uniqueId! From 178ab7e3e2d2acfd889d901a5eedf4d2ed81dcba Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 24 Nov 2020 20:09:23 +1100 Subject: [PATCH 033/177] WIP --- .../ConversationViewController.m | 5 ++- .../Jobs/AttachmentDownloadJob.swift | 4 +- .../Jobs/AttachmentUploadJob.swift | 2 +- SessionMessagingKit/Jobs/JobQueue.swift | 9 ++++- .../Jobs/MessageReceiveJob.swift | 30 +++++++-------- SessionMessagingKit/Jobs/MessageSendJob.swift | 24 ++++++------ .../Jobs/NotifyPNServerJob.swift | 2 +- .../Open Groups/OpenGroupAPI.swift | 1 - .../Sending & Receiving/MessageReceiver.swift | 3 ++ .../Sending & Receiving/MessageSender.swift | 37 +++++++++++++------ SessionMessagingKit/Utilities/Threading.swift | 6 --- Signal.xcodeproj/project.pbxproj | 4 -- .../Database/Storage/Storage+Shared.swift | 5 +++ .../MessageSender+Utilities.swift | 8 +++- .../OpenGroupAPIDelegate.swift | 4 +- 15 files changed, 84 insertions(+), 60 deletions(-) delete mode 100644 SessionMessagingKit/Utilities/Threading.swift diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index a2715010f..7f376a217 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3238,7 +3238,10 @@ typedef enum : NSUInteger { TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [tsMessage saveWithTransaction:transaction]; - [SNMessageSender send:message withAttachments:attachments inThread:thread usingTransaction:transaction]; + } completion:^{ + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [SNMessageSender send:message withAttachments:attachments inThread:thread usingTransaction:transaction]; + }]; }]; [self messageWasSent:tsMessage]; }); diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index eaf2a9b8f..bfc4939c1 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -3,9 +3,9 @@ import SessionUtilitiesKit import SignalCoreKit public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility + public let attachmentID: String + public let tsIncomingMessageID: String public var delegate: JobDelegate? - private let attachmentID: String - private let tsIncomingMessageID: String public var id: String? public var failureCount: UInt = 0 diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index ff8fc8cb9..c50c78b37 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -1,9 +1,9 @@ import SessionUtilitiesKit public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility - public var delegate: JobDelegate? public let attachmentID: String public let threadID: String + public var delegate: JobDelegate? public var id: String? public var failureCount: UInt = 0 diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 401dab361..839242d0b 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -2,13 +2,14 @@ import SessionUtilitiesKit @objc(SNJobQueue) public final class JobQueue : NSObject, JobDelegate { + private var hasResumedPendingJobs = false // Just for debugging @objc public static let shared = JobQueue() @objc public func add(_ job: Job, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction addWithoutExecuting(job, using: transaction) - transaction.addCompletionQueue(Threading.workQueue) { + transaction.addCompletionQueue(DispatchQueue.global(qos: .userInitiated)) { job.execute() } } @@ -20,6 +21,12 @@ public final class JobQueue : NSObject, JobDelegate { } @objc public func resumePendingJobs() { + if hasResumedPendingJobs { + #if DEBUG + preconditionFailure("resumePendingJobs() should only be called once.") + #endif + } + hasResumedPendingJobs = true let allJobTypes: [Job.Type] = [ AttachmentDownloadJob.self, AttachmentUploadJob.self, MessageReceiveJob.self, MessageSendJob.self, NotifyPNServerJob.self ] allJobTypes.forEach { type in let allPendingJobs = Configuration.shared.storage.getAllPendingJobs(of: type) diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 1049b8a11..b66a039f8 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -1,10 +1,10 @@ import SessionUtilitiesKit public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility + public let data: Data + public let messageServerID: UInt64? public var delegate: JobDelegate? - private let data: Data public var id: String? - private let messageServerID: UInt64? public var failureCount: UInt = 0 // MARK: Settings @@ -22,33 +22,31 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC guard let data = coder.decodeObject(forKey: "data") as! Data?, let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.data = data - self.id = id self.messageServerID = coder.decodeObject(forKey: "messageServerUD") as! UInt64? + self.id = id self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(data, forKey: "data") - coder.encode(id, forKey: "id") coder.encode(messageServerID, forKey: "messageServerID") + coder.encode(id, forKey: "id") coder.encode(failureCount, forKey: "failureCount") } // MARK: Running public func execute() { Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self - Threading.workQueue.async { - do { - let (message, proto) = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) - try MessageReceiver.handle(message, associatedWithProto: proto, using: transaction) - self.handleSuccess() - } catch { - SNLog("Couldn't parse message due to error: \(error).") - if let error = error as? MessageReceiver.Error, !error.isRetryable { - self.handlePermanentFailure(error: error) - } else { - self.handleFailure(error: error) - } + do { + let (message, proto) = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) + try MessageReceiver.handle(message, associatedWithProto: proto, using: transaction) + self.handleSuccess() + } catch { + SNLog("Couldn't parse message due to error: \(error).") + if let error = error as? MessageReceiver.Error, !error.isRetryable { + self.handlePermanentFailure(error: error) + } else { + self.handleFailure(error: error) } } }, completion: { }) diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index d91e1c46d..5bb1b1f5d 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -2,9 +2,9 @@ import SessionUtilitiesKit @objc(SNMessageSendJob) public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility - public var delegate: JobDelegate? public let message: Message - private let destination: Message.Destination + public let destination: Message.Destination + public var delegate: JobDelegate? public var id: String? public var failureCount: UInt = 0 @@ -50,12 +50,12 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi public func encode(with coder: NSCoder) { coder.encode(message, forKey: "message") - coder.encode(id, forKey: "id") switch destination { case .contact(let publicKey): coder.encode("contact(\(publicKey))", forKey: "destination") case .closedGroup(let groupPublicKey): coder.encode("closedGroup(\(groupPublicKey))", forKey: "destination") case .openGroup(let channel, let server): coder.encode("openGroup(\(channel), \(server))") } + coder.encode(id, forKey: "id") coder.encode(failureCount, forKey: "failureCount") } @@ -79,16 +79,14 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi } // FIXME: This doesn't yet handle the attachment side of link previews, quotes, etc. storage.withAsync({ transaction in // Intentionally capture self - Threading.workQueue.async { - MessageSender.send(self.message, to: self.destination, using: transaction).done(on: Threading.workQueue) { - self.handleSuccess() - }.catch(on: Threading.workQueue) { error in - SNLog("Couldn't send message due to error: \(error).") - if let error = error as? MessageSender.Error, !error.isRetryable { - self.handlePermanentFailure(error: error) - } else { - self.handleFailure(error: error) - } + MessageSender.send(self.message, to: self.destination, using: transaction).done(on: DispatchQueue.global(qos: .userInitiated)) { + self.handleSuccess() + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in + SNLog("Couldn't send message due to error: \(error).") + if let error = error as? MessageSender.Error, !error.isRetryable { + self.handlePermanentFailure(error: error) + } else { + self.handleFailure(error: error) } } }, completion: { }) diff --git a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift index 8cc35c6e3..2c94a5c79 100644 --- a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift +++ b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift @@ -3,8 +3,8 @@ import SessionSnodeKit import SessionUtilitiesKit public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility + public let message: SnodeMessage public var delegate: JobDelegate? - private let message: SnodeMessage public var id: String? public var failureCount: UInt = 0 diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index f88017434..423a36652 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -16,7 +16,6 @@ public final class OpenGroupAPI : DotNetAPI { private static let maxRetryCount: UInt = 4 public static let profilePictureType = "network.loki.messenger.avatar" - @objc public static let openGroupMessageType = "network.loki.messenger.publicChat" // MARK: Open Group Public Key Validation diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index bbd0dcb88..7da27586b 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -2,6 +2,7 @@ import SessionUtilitiesKit internal enum MessageReceiver { + // MARK: Error internal enum Error : LocalizedError { case invalidMessage case unknownMessage @@ -41,6 +42,7 @@ internal enum MessageReceiver { } } + // MARK: Parsing internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { let userPublicKey = Configuration.shared.storage.getUserPublicKey() // Parse the envelope @@ -91,6 +93,7 @@ internal enum MessageReceiver { } } + // MARK: Handling internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 1f518bf75..f31f00162 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -5,6 +5,7 @@ import SessionUtilitiesKit @objc(SNMessageSender) public final class MessageSender : NSObject { + // MARK: Error public enum Error : LocalizedError { case invalidMessage case protoConversionFailed @@ -27,9 +28,11 @@ public final class MessageSender : NSObject { } } } - + + // MARK: Initialization private override init() { } + // MARK: Convenience public static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise { switch destination { case .contact(_), .closedGroup(_): return sendToSnodeDestination(destination, message: message, using: transaction) @@ -37,10 +40,11 @@ public final class MessageSender : NSObject { } } + // MARK: One-on-One Chats & Closed Groups internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { let (promise, seal) = Promise.pending() let storage = Configuration.shared.storage - if message.sentTimestamp == nil { // Visible messages will already have the sent timestamp set + if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() } message.sender = storage.getUserPublicKey() @@ -49,7 +53,7 @@ public final class MessageSender : NSObject { case .closedGroup(let groupPublicKey): message.recipient = groupPublicKey case .openGroup(_, _): preconditionFailure() } - // Set the failure handler + // Set the failure handler (for precondition failure handling) let _ = promise.catch(on: DispatchQueue.main) { error in storage.withAsync({ transaction in Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) @@ -130,26 +134,27 @@ public final class MessageSender : NSObject { } } let snodeMessage = SnodeMessage(recipient: recipient, data: base64EncodedData, ttl: type(of: message).ttl, timestamp: timestamp, nonce: nonce) - SnodeAPI.sendMessage(snodeMessage).done(on: Threading.workQueue) { promises in + SnodeAPI.sendMessage(snodeMessage).done(on: DispatchQueue.global(qos: .userInitiated)) { promises in var isSuccess = false let promiseCount = promises.count var errorCount = 0 promises.forEach { - let _ = $0.done(on: Threading.workQueue) { _ in + let _ = $0.done(on: DispatchQueue.global(qos: .userInitiated)) { _ in guard !isSuccess else { return } // Succeed as soon as the first promise succeeds isSuccess = true seal.fulfill(()) } - $0.catch(on: Threading.workQueue) { error in + $0.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in errorCount += 1 guard errorCount == promiseCount else { return } // Only error out if all promises failed seal.reject(error) } } - }.catch(on: Threading.workQueue) { error in + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in SNLog("Couldn't send message due to error: \(error).") seal.reject(error) } + // Handle completion let _ = promise.done(on: DispatchQueue.main) { storage.withAsync({ transaction in Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) @@ -157,14 +162,18 @@ public final class MessageSender : NSObject { if case .contact(_) = destination { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) } - let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) - storage.withAsync({ transaction in - JobQueue.shared.add(notifyPNServerJob, using: transaction) - }, completion: { }) + if message is VisibleMessage { + let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) + storage.withAsync({ transaction in + JobQueue.shared.add(notifyPNServerJob, using: transaction) + }, completion: { }) + } } + // Return return promise } + // MARK: Open Groups internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { let (promise, seal) = Promise.pending() let storage = Configuration.shared.storage @@ -174,12 +183,15 @@ public final class MessageSender : NSObject { case .closedGroup(_): preconditionFailure() case .openGroup(let channel, let server): message.recipient = "\(server).\(channel)" } + // Set the failure handler (for precondition failure handling) let _ = promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in storage.withAsync({ transaction in Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) }, completion: { }) } + // Validate the message guard message.isValid else { seal.reject(Error.invalidMessage); return promise } + // Convert the message to an open group message let (channel, server) = { () -> (UInt64, String) in switch destination { case .openGroup(let channel, let server): return (channel, server) @@ -188,17 +200,20 @@ public final class MessageSender : NSObject { }() guard let message = message as? VisibleMessage, let openGroupMessage = OpenGroupMessage.from(message, for: server) else { seal.reject(Error.invalidMessage); return promise } + // Send the result OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = openGroupMessage.serverID seal.fulfill(()) }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in seal.reject(error) } + // Handle completion let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { storage.withAsync({ transaction in Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) } + // Return return promise } } diff --git a/SessionMessagingKit/Utilities/Threading.swift b/SessionMessagingKit/Utilities/Threading.swift deleted file mode 100644 index 493fad165..000000000 --- a/SessionMessagingKit/Utilities/Threading.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -internal enum Threading { - - internal static let workQueue = DispatchQueue(label: "SessionMessagingKit.workQueue", qos: .userInitiated) // It's important that this is a serial queue -} diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index cfbf33f06..4df8c5640 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -538,7 +538,6 @@ C3402FE52559036600EA6424 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; }; C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */; }; C3471ED42555386B00297E91 /* AESGCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D72553860B00C340D1 /* AESGCM.swift */; }; - C3471F4225553A4D00297E91 /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471F4125553A4D00297E91 /* Threading.swift */; }; C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */; }; C3471FA42555439E00297E91 /* Notification+MessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471FA32555439E00297E91 /* Notification+MessageSender.swift */; }; C34C8F7423A7830B00D82669 /* SpaceMono-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */; }; @@ -1658,7 +1657,6 @@ C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUploadOperation.m; sourceTree = ""; }; C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LokiSessionRestorationImplementation.swift; sourceTree = ""; }; C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Encryption.swift"; sourceTree = ""; }; - C3471F4125553A4D00297E91 /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = ""; }; C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Decryption.swift"; sourceTree = ""; }; C3471FA32555439E00297E91 /* Notification+MessageSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+MessageSender.swift"; sourceTree = ""; }; C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SpaceMono-Bold.ttf"; sourceTree = ""; }; @@ -3410,7 +3408,6 @@ C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */, C3A71D0A2558989C0043A11F /* MessageWrapper.swift */, C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */, - C3471F4125553A4D00297E91 /* Threading.swift */, ); path = Utilities; sourceTree = ""; @@ -5309,7 +5306,6 @@ C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */, C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */, C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */, - C3471F4225553A4D00297E91 /* Threading.swift in Sources */, C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */, C3471FA42555439E00297E91 /* Notification+MessageSender.swift in Sources */, C3A7222A2558C1E40043A11F /* DotNetAPI.swift in Sources */, diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Shared.swift b/SignalUtilitiesKit/Database/Storage/Storage+Shared.swift index d2dffbac2..0f22ad986 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+Shared.swift +++ b/SignalUtilitiesKit/Database/Storage/Storage+Shared.swift @@ -1,10 +1,15 @@ +// TODO: Since we now have YapDatabase as a dependency in all modules we can work with YapDatabaseTransactions directly +// rather than passing transactions around as Any everywhere. + extension Storage { + // TODO: This is essentially a duplicate of Storage.writeSync public func with(_ work: @escaping (Any) -> Void) { Storage.writeSync { work($0) } } + // TODO: This is essentially a duplicate of Storage.write public func withAsync(_ work: @escaping (Any) -> Void, completion: @escaping () -> Void) { Storage.write(with: { work($0) }, completion: completion) } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift index bde7d7541..b473294fe 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift @@ -5,10 +5,16 @@ public extension MessageSender { @objc(send:withAttachments:inThread:usingTransaction:) static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { if let message = message as? VisibleMessage { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { + #if DEBUG + preconditionFailure() + #endif + return + } var streams: [TSAttachmentStream] = [] attachments.forEach { let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, - caption: $0.captionText, albumMessageId: nil) + caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) streams.append(stream) stream.write($0.dataSource) stream.save(with: transaction) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift index 24f6ce249..e13fae704 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift @@ -22,9 +22,9 @@ public final class OpenGroupAPIDelegate : SessionMessagingKit.OpenGroupAPIDelega Storage.shared.setProfilePictureURL(to: info.profilePictureURL, forOpenGroupWithID: openGroupID, using: transaction) if let profilePictureURL = info.profilePictureURL { var sanitizedServerURL = server + while sanitizedServerURL.hasSuffix("/") { sanitizedServerURL.removeLast() } var sanitizedProfilePictureURL = profilePictureURL - while sanitizedServerURL.hasSuffix("/") { sanitizedServerURL.removeLast(1) } - while sanitizedProfilePictureURL.hasPrefix("/") { sanitizedProfilePictureURL.removeFirst(1) } + while sanitizedProfilePictureURL.hasPrefix("/") { sanitizedProfilePictureURL.removeFirst() } let url = "\(sanitizedServerURL)/\(sanitizedProfilePictureURL)" FileServerAPI.downloadAttachment(from: url).map2 { data in let attachmentStream = TSAttachmentStream(contentType: OWSMimeTypeImageJpeg, byteCount: UInt32(data.count), sourceFilename: nil, caption: nil, albumMessageId: nil) From 5dfd4b1965ed0d36bb62d0049d743ef955c52e8a Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 25 Nov 2020 16:15:16 +1100 Subject: [PATCH 034/177] Restructure --- Podfile | 6 + Podfile.lock | 2 +- .../Database}/Storage+VolumeSamples.swift | 0 Session/Meta/Signal-Bridging-Header.h | 18 +- Session/Signal/AboutTableViewController.m | 4 +- Session/Signal/AddToBlockListViewController.m | 4 +- Session/Signal/AppDelegate.m | 14 +- Session/Signal/AvatarViewHelper.m | 4 +- .../ConversationViewController.m | 14 +- .../ConversationView/ConversationViewItem.m | 2 +- .../ConversationView/ConversationViewModel.m | 16 +- Session/Signal/MainAppContext.m | 2 +- Session/Signal/OWSBackup.m | 4 +- Session/Signal/OWSBackupExportJob.m | 4 +- Session/Signal/OWSBackupImportJob.m | 4 +- .../OWSConversationSettingsViewController.m | 10 +- Session/Signal/OWSOrphanDataCleaner.m | 8 +- Session/Signal/OWSSessionResetJobRecord.h | 2 +- Session/Signal/OWSSessionResetJobRecord.m | 2 +- .../PrivacySettingsTableViewController.m | 2 +- Session/Signal/SignalApp.m | 6 +- SessionMessagingKit/Configuration.swift | 19 +- .../Database}/OWSPrimaryStorage.h | 2 +- .../Database}/OWSPrimaryStorage.m | 7 +- .../Database}/OWSStorage.h | 0 .../Database}/OWSStorage.m | 147 +-- .../Database}/SSKPreferences.swift | 0 .../Database}/Storage+ClosedGroups.swift | 1 + .../Database}/Storage+Jobs.swift | 0 .../Database}/Storage+Messaging.swift | 0 .../Database}/Storage+OpenGroups.swift | 0 .../Database}/Storage+Shared.swift | 0 .../Database}/TSDatabaseSecondaryIndexes.h | 0 .../Database}/TSDatabaseSecondaryIndexes.m | 0 .../Database}/TSDatabaseView.h | 2 +- .../Database}/TSDatabaseView.m | 37 - .../Jobs/NotifyPNServerJob.swift | 4 +- .../Messages/Message+Destination.swift | 15 + .../Messages/Signal}/TSErrorMessage.h | 4 +- .../Messages/Signal}/TSErrorMessage.m | 5 +- .../TSErrorMessage_privateConstructor.h | 2 +- .../TSIncomingMessage+Conversion.swift | 0 .../Messages/Signal}/TSIncomingMessage.h | 4 +- .../Messages/Signal}/TSIncomingMessage.m | 17 +- .../Messages/Signal}/TSInfoMessage.h | 4 +- .../Messages/Signal}/TSInfoMessage.m | 9 +- .../Messages/Signal}/TSInteraction.h | 0 .../Messages/Signal}/TSInteraction.m | 17 +- .../TSInvalidIdentityKeyErrorMessage.h | 4 +- .../TSInvalidIdentityKeyErrorMessage.m | 4 +- ...SInvalidIdentityKeyReceivingErrorMessage.h | 2 +- ...SInvalidIdentityKeyReceivingErrorMessage.m | 12 +- .../Messages/Signal}/TSMessage.h | 4 +- .../TSOutgoingMessage+Conversion.swift | 0 .../Messages/Signal}/TSOutgoingMessage.h | 2 +- .../Messages/Signal}/TSOutgoingMessage.m | 82 +- .../VisibleMessage+Attachment.swift | 0 .../Meta/SessionMessagingKit.h | 41 + .../Open Groups/OpenGroupAPI.swift | 35 +- .../Open Groups/OpenGroupAPIDelegate.swift | 5 - .../Attachments/OWSThumbnailService.swift | 0 .../Attachments/SignalAttachment.swift | 51 +- .../Attachments/TSAttachment.h | 11 + .../Attachments/TSAttachment.m | 15 + .../TSAttachmentPointer+Conversion.swift | 0 .../Attachments/TSAttachmentPointer.h | 0 .../Attachments/TSAttachmentPointer.m | 0 .../Attachments/TSAttachmentStream.h | 0 .../Attachments/TSAttachmentStream.m | 0 .../Blocking/OWSBlockingManager.h | 0 .../Blocking/OWSBlockingManager.m | 2 +- ...sappearingConfigurationUpdateInfoMessage.h | 2 +- ...sappearingConfigurationUpdateInfoMessage.m | 5 +- .../OWSDisappearingMessagesConfiguration.h | 1 + .../OWSDisappearingMessagesConfiguration.m | 6 +- .../Expiration}/OWSDisappearingMessagesJob.h | 0 .../Expiration}/OWSDisappearingMessagesJob.m | 2 +- .../Link Previews/OWSLinkPreview.swift | 71 +- .../Mentions/Mention.swift | 0 .../Mentions/MentionsManager.swift | 0 .../MessageReceiver+Handling.swift | 141 ++- .../Sending & Receiving/MessageReceiver.swift | 81 +- .../MessageReceiverDelegate.swift | 17 - .../Sending & Receiving/MessageSender.swift | 33 +- .../MessageSenderDelegate.swift | 6 - .../Notifications}/NotificationsProtocol.h | 0 .../Notifications/PushNotificationAPI.swift | 1 + .../Pollers}/ClosedGroupPoller.swift | 5 +- .../Pollers}/OpenGroupPoller.swift | 4 +- .../Sending & Receiving/Pollers}/Poller.swift | 1 + .../OWSQuotedReplyModel+Conversion.swift | 13 + .../Quotes/OWSQuotedReplyModel.h | 3 +- .../Quotes/OWSQuotedReplyModel.m | 24 +- .../Quotes/TSQuotedMessage+Conversion.swift | 13 - .../Quotes/TSQuotedMessage.h | 0 .../Quotes/TSQuotedMessage.m | 40 +- .../Read Tracking/OWSOutgoingReceiptManager.h | 0 .../Read Tracking/OWSOutgoingReceiptManager.m | 27 +- .../Read Tracking/OWSReadReceiptManager.h | 9 - .../Read Tracking/OWSReadReceiptManager.m | 172 +-- .../Read Tracking/OWSReadTracking.h | 0 .../TSUnreadIndicatorInteraction.h | 2 +- .../TSUnreadIndicatorInteraction.m | 0 .../Typing Indicators/TypingIndicators.swift | 65 +- .../Threads/Notification+Thread.swift | 10 + .../Threads/TSContactThread.h | 5 +- .../Threads/TSContactThread.m | 19 +- .../Threads/TSGroupModel.h | 3 +- .../Threads/TSGroupModel.m | 8 +- .../Threads/TSGroupThread.h | 5 +- .../Threads/TSGroupThread.m | 46 +- .../Threads/TSThread.h | 0 .../Threads/TSThread.m | 49 +- .../To Do/DisplayNameUtilities.swift | 0 .../To Do}/OWSRecipientIdentity.h | 4 - .../To Do}/OWSRecipientIdentity.m | 31 +- SessionMessagingKit/To Do/OWSUDManager.swift | 71 ++ .../To Do/ProfileManagerProtocol.h | 0 .../To Do}/TSAccountManager.h | 2 +- .../To Do}/TSAccountManager.m | 4 +- .../Utilities}/AppReadiness.h | 0 .../Utilities}/AppReadiness.m | 2 + .../Utilities}/FullTextSearchFinder.swift | 8 - .../Utilities/GeneralUtilities.swift | 0 .../Utilities}/OWSBackgroundTask.h | 0 .../Utilities}/OWSBackgroundTask.m | 35 +- .../OWSDisappearingMessagesFinder.h | 0 .../OWSDisappearingMessagesFinder.m | 28 - .../Utilities}/OWSIdentityManager.h | 8 +- .../Utilities}/OWSIdentityManager.m | 297 +---- .../Utilities/OWSIncomingMessageFinder.h | 0 .../Utilities/OWSIncomingMessageFinder.m | 6 - .../Utilities}/OWSMediaGalleryFinder.h | 0 .../Utilities}/OWSMediaGalleryFinder.m | 14 +- .../Utilities/ProtoUtils.h | 5 - .../Utilities/ProtoUtils.m | 12 +- .../SNProtoEnvelope+Conversion.swift | 0 .../Utilities}/SSKEnvironment.h | 4 +- .../Utilities}/SSKEnvironment.m | 26 - .../Utilities/SSKIncrementingIdFinder.swift | 0 .../Utilities}/SSKJobRecord.h | 0 .../Utilities}/SSKJobRecord.m | 2 +- .../Utilities/SSKJobRecordFinder.swift | 108 ++ .../Utilities/SSKReachabilityManager.swift | 15 + .../Utilities}/YapDatabaseConnection+OWS.h | 0 .../Utilities}/YapDatabaseConnection+OWS.m | 22 - .../Utilities}/YapDatabaseTransaction+OWS.h | 0 .../Utilities}/YapDatabaseTransaction+OWS.m | 46 - SessionProtocolKit/Meta/SessionProtocolKit.h | 1 + .../SignalShareExtension-Bridging-Header.h | 4 +- .../ShareAppExtensionContext.m | 2 +- .../Storage+OnionRequests.swift | 1 + .../Storage+SnodeAPI.swift | 1 + .../BuildConfiguration.swift | 0 .../ContentProxy.swift | 5 +- .../ECKeyPair+Hexadecimal.swift | 1 + .../LKGroupUtilities.h | 0 .../LKGroupUtilities.m | 2 - .../LKUserDefaults.swift | 0 .../LRUCache.swift | 5 - .../Meta/SessionUtilitiesKit.h | 4 + .../NSArray+Functional.h | 0 .../NSArray+Functional.m | 0 .../NSNotificationCenter+OWS.h | 0 .../NSNotificationCenter+OWS.m | 0 .../NSRegularExpression+SSK.swift | 3 - .../NSUserDefaults+OWS.h | 0 .../NSUserDefaults+OWS.m | 6 - .../ProxiedContentDownloader.swift | 83 +- .../SSKKeychainStorage.swift | 3 - Signal.xcodeproj/project.pbxproj | 1124 ++++++++--------- SignalUtilitiesKit/AppSetup.m | 21 +- .../Database/Migration/OWSDatabaseMigration.m | 4 +- .../OWSPrimaryStorage+PreKeyStore.h | 2 +- .../OWSPrimaryStorage+PreKeyStore.m | 0 .../OWSPrimaryStorage+SessionStore.h | 2 +- .../OWSPrimaryStorage+SessionStore.m | 0 .../OWSPrimaryStorage+SignedPreKeyStore.h | 2 +- .../OWSPrimaryStorage+SignedPreKeyStore.m | 0 .../OWSPrimaryStorage+keyFromIntLong.h | 2 +- .../OWSPrimaryStorage+keyFromIntLong.m | 0 .../{Utilities => }/OWSStorage+Subclass.h | 2 +- .../{Utilities => }/SignalKeyingStorage.h | 0 .../{Utilities => }/SignalKeyingStorage.m | 4 +- .../{Storage => }/Storage+Conformances.swift | 0 .../Storage+SessionManagement.swift | 0 .../{Utilities => }/TSStorageHeaders.h | 4 +- .../Database/{Utilities => }/TSStorageKeys.h | 0 .../{Utilities => }/ThreadViewHelper.h | 0 .../{Utilities => }/ThreadViewHelper.m | 8 +- .../YapDatabase+Promise.swift | 0 SignalUtilitiesKit/JobQueue.swift | 108 -- ...LokiSessionRestorationImplementation.swift | 3 +- .../Attachments/TSAttachment+Albums.h | 18 - .../Attachments/TSAttachment+Albums.m | 18 - .../Messaging/Core Messages/TSMessage.m | 437 ------- .../{Utilities => }/OWSMessageUtils.h | 0 .../{Utilities => }/OWSMessageUtils.m | 0 .../Destination+Conversion.swift | 18 - ...ate.swift => MessageSender+Handling.swift} | 68 +- .../MessageSender+Utilities.swift | 40 - .../OpenGroupAPIDelegate.swift | 38 - .../TSAttachmentPointer+Backups.h | 0 .../TSAttachmentPointer+Backups.m | 0 .../TSInvalidIdentityKeySendingErrorMessage.h | 2 +- .../TSInvalidIdentityKeySendingErrorMessage.m | 0 SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 33 +- .../OWSFailedAttachmentDownloadsJob.m | 5 - SignalUtilitiesKit/OWSPreferences.m | 10 +- SignalUtilitiesKit/OWSRecordTranscriptJob.m | 5 - SignalUtilitiesKit/OWSSounds.m | 6 +- SignalUtilitiesKit/OWSUDManager.swift | 71 -- SignalUtilitiesKit/ReachabilityManager.swift | 14 - .../SSKMessageSenderJobRecord.h | 2 +- SignalUtilitiesKit/TSPreKeyManager.h | 2 +- SignalUtilitiesKit/{Threads => }/ThreadUtil.h | 0 SignalUtilitiesKit/{Threads => }/ThreadUtil.m | 20 +- SignalUtilitiesKit/To Do/ContactCellView.m | 8 +- .../To Do/OWSPrimaryStorage+Loki.h | 2 +- SignalUtilitiesKit/To Do/OWSProfileManager.h | 2 +- SignalUtilitiesKit/To Do/OWSProfileManager.m | 16 +- SignalUtilitiesKit/To Do/OWSUserProfile.m | 8 +- SignalUtilitiesKit/UI/BlockListUIUtils.m | 6 +- .../UI/SelectRecipientViewController.m | 2 +- .../UI/SelectThreadViewController.m | 6 +- .../UI/SharingThreadPickerViewController.m | 2 +- SignalUtilitiesKit/UI/Theme.m | 6 +- .../Utilities/Notification+Loki.swift | 2 - SignalUtilitiesKit/VersionMigrations.m | 8 +- 229 files changed, 1311 insertions(+), 3304 deletions(-) rename {SignalUtilitiesKit/Database/Storage => Session/Database}/Storage+VolumeSamples.swift (100%) rename {SignalUtilitiesKit/Database/OWSStorage => SessionMessagingKit/Database}/OWSPrimaryStorage.h (97%) rename {SignalUtilitiesKit/Database/OWSStorage => SessionMessagingKit/Database}/OWSPrimaryStorage.m (98%) rename {SignalUtilitiesKit/Database/OWSStorage => SessionMessagingKit/Database}/OWSStorage.h (100%) rename {SignalUtilitiesKit/Database/OWSStorage => SessionMessagingKit/Database}/OWSStorage.m (83%) rename {SignalUtilitiesKit/Database/Utilities => SessionMessagingKit/Database}/SSKPreferences.swift (100%) rename {SignalUtilitiesKit/Database/Storage => SessionMessagingKit/Database}/Storage+ClosedGroups.swift (99%) rename {SignalUtilitiesKit/Database/Storage => SessionMessagingKit/Database}/Storage+Jobs.swift (100%) rename {SignalUtilitiesKit/Database/Storage => SessionMessagingKit/Database}/Storage+Messaging.swift (100%) rename {SignalUtilitiesKit/Database/Storage => SessionMessagingKit/Database}/Storage+OpenGroups.swift (100%) rename {SignalUtilitiesKit/Database/Storage => SessionMessagingKit/Database}/Storage+Shared.swift (100%) rename {SignalUtilitiesKit/Database/Utilities => SessionMessagingKit/Database}/TSDatabaseSecondaryIndexes.h (100%) rename {SignalUtilitiesKit/Database/Utilities => SessionMessagingKit/Database}/TSDatabaseSecondaryIndexes.m (100%) rename {SignalUtilitiesKit/Database/Utilities => SessionMessagingKit/Database}/TSDatabaseView.h (98%) rename {SignalUtilitiesKit/Database/Utilities => SessionMessagingKit/Database}/TSDatabaseView.m (89%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSErrorMessage.h (97%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSErrorMessage.m (97%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSErrorMessage_privateConstructor.h (90%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSIncomingMessage+Conversion.swift (100%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSIncomingMessage.h (97%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSIncomingMessage.m (90%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInfoMessage.h (96%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInfoMessage.m (95%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInteraction.h (100%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInteraction.m (95%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInvalidIdentityKeyErrorMessage.h (84%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInvalidIdentityKeyErrorMessage.m (85%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInvalidIdentityKeyReceivingErrorMessage.h (90%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSInvalidIdentityKeyReceivingErrorMessage.m (87%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSMessage.h (96%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSOutgoingMessage+Conversion.swift (100%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSOutgoingMessage.h (99%) rename {SignalUtilitiesKit/Messaging/Core Messages => SessionMessagingKit/Messages/Signal}/TSOutgoingMessage.m (92%) rename SessionMessagingKit/Messages/Visible Messages/{Attachments => }/VisibleMessage+Attachment.swift (100%) delete mode 100644 SessionMessagingKit/Open Groups/OpenGroupAPIDelegate.swift rename SessionMessagingKit/{Messages/Visible Messages => Sending & Receiving}/Attachments/OWSThumbnailService.swift (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Attachments/SignalAttachment.swift (93%) rename SessionMessagingKit/{Messages/Visible Messages => Sending & Receiving}/Attachments/TSAttachment.h (88%) rename SessionMessagingKit/{Messages/Visible Messages => Sending & Receiving}/Attachments/TSAttachment.m (94%) rename SignalUtilitiesKit/Messaging/Attachments/Attachment+Conversion.swift => SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer+Conversion.swift (100%) rename SessionMessagingKit/{Messages/Visible Messages => Sending & Receiving}/Attachments/TSAttachmentPointer.h (100%) rename SessionMessagingKit/{Messages/Visible Messages => Sending & Receiving}/Attachments/TSAttachmentPointer.m (100%) rename SessionMessagingKit/{Messages/Visible Messages => Sending & Receiving}/Attachments/TSAttachmentStream.h (100%) rename SessionMessagingKit/{Messages/Visible Messages => Sending & Receiving}/Attachments/TSAttachmentStream.m (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Blocking/OWSBlockingManager.h (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Blocking/OWSBlockingManager.m (99%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Sending & Receiving/Expiration}/OWSDisappearingConfigurationUpdateInfoMessage.h (94%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Sending & Receiving/Expiration}/OWSDisappearingConfigurationUpdateInfoMessage.m (95%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Sending & Receiving/Expiration}/OWSDisappearingMessagesConfiguration.h (96%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Sending & Receiving/Expiration}/OWSDisappearingMessagesConfiguration.m (95%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Sending & Receiving/Expiration}/OWSDisappearingMessagesJob.h (100%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Sending & Receiving/Expiration}/OWSDisappearingMessagesJob.m (99%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Link Previews/OWSLinkPreview.swift (88%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Mentions/Mention.swift (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Mentions/MentionsManager.swift (100%) rename SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift => SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift (73%) delete mode 100644 SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift delete mode 100644 SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift rename {SignalUtilitiesKit => SessionMessagingKit/Sending & Receiving/Notifications}/NotificationsProtocol.h (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Notifications/PushNotificationAPI.swift (99%) rename {SignalUtilitiesKit/Messaging/Sending & Receiving => SessionMessagingKit/Sending & Receiving/Pollers}/ClosedGroupPoller.swift (95%) rename {SignalUtilitiesKit/Messaging/Sending & Receiving => SessionMessagingKit/Sending & Receiving/Pollers}/OpenGroupPoller.swift (97%) rename {SignalUtilitiesKit/Messaging/Sending & Receiving => SessionMessagingKit/Sending & Receiving/Pollers}/Poller.swift (99%) create mode 100644 SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Quotes/OWSQuotedReplyModel.h (96%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Quotes/OWSQuotedReplyModel.m (92%) rename SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift => SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift (51%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Quotes/TSQuotedMessage.h (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Quotes/TSQuotedMessage.m (88%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Read Tracking/OWSOutgoingReceiptManager.h (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Read Tracking/OWSOutgoingReceiptManager.m (94%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Read Tracking/OWSReadReceiptManager.h (85%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Read Tracking/OWSReadReceiptManager.m (66%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Read Tracking/OWSReadTracking.h (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Read Tracking/TSUnreadIndicatorInteraction.h (87%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Read Tracking/TSUnreadIndicatorInteraction.m (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit/Sending & Receiving}/Typing Indicators/TypingIndicators.swift (87%) create mode 100644 SessionMessagingKit/Threads/Notification+Thread.swift rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSContactThread.h (85%) rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSContactThread.m (83%) rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSGroupModel.h (96%) rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSGroupModel.m (97%) rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSGroupThread.h (94%) rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSGroupThread.m (88%) rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSThread.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit}/Threads/TSThread.m (90%) rename {SignalUtilitiesKit => SessionMessagingKit}/To Do/DisplayNameUtilities.swift (100%) rename {SignalUtilitiesKit => SessionMessagingKit/To Do}/OWSRecipientIdentity.h (97%) rename {SignalUtilitiesKit => SessionMessagingKit/To Do}/OWSRecipientIdentity.m (81%) create mode 100644 SessionMessagingKit/To Do/OWSUDManager.swift rename {SignalUtilitiesKit => SessionMessagingKit}/To Do/ProfileManagerProtocol.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/To Do}/TSAccountManager.h (99%) rename {SignalUtilitiesKit => SessionMessagingKit/To Do}/TSAccountManager.m (99%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/AppReadiness.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/AppReadiness.m (97%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/FullTextSearchFinder.swift (97%) rename {SignalUtilitiesKit => SessionMessagingKit}/Utilities/GeneralUtilities.swift (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSBackgroundTask.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSBackgroundTask.m (93%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Utilities}/OWSDisappearingMessagesFinder.h (100%) rename {SignalUtilitiesKit/Messaging/Disappearing Messages => SessionMessagingKit/Utilities}/OWSDisappearingMessagesFinder.m (91%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSIdentityManager.h (89%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSIdentityManager.m (56%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit}/Utilities/OWSIncomingMessageFinder.h (100%) rename {SignalUtilitiesKit/Messaging => SessionMessagingKit}/Utilities/OWSIncomingMessageFinder.m (94%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSMediaGalleryFinder.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSMediaGalleryFinder.m (92%) rename {SignalUtilitiesKit => SessionMessagingKit}/Utilities/ProtoUtils.h (71%) rename {SignalUtilitiesKit => SessionMessagingKit}/Utilities/ProtoUtils.m (83%) rename {SignalUtilitiesKit/Messaging/Sending & Receiving => SessionMessagingKit/Utilities}/SNProtoEnvelope+Conversion.swift (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/SSKEnvironment.h (94%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/SSKEnvironment.m (82%) rename {SignalUtilitiesKit => SessionMessagingKit}/Utilities/SSKIncrementingIdFinder.swift (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/SSKJobRecord.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/SSKJobRecord.m (98%) create mode 100644 SessionMessagingKit/Utilities/SSKJobRecordFinder.swift create mode 100644 SessionMessagingKit/Utilities/SSKReachabilityManager.swift rename {SignalUtilitiesKit/Database/YapDatabase => SessionMessagingKit/Utilities}/YapDatabaseConnection+OWS.h (100%) rename {SignalUtilitiesKit/Database/YapDatabase => SessionMessagingKit/Utilities}/YapDatabaseConnection+OWS.m (90%) rename {SignalUtilitiesKit/Database/YapDatabase => SessionMessagingKit/Utilities}/YapDatabaseTransaction+OWS.h (100%) rename {SignalUtilitiesKit/Database/YapDatabase => SessionMessagingKit/Utilities}/YapDatabaseTransaction+OWS.m (77%) rename {SignalUtilitiesKit/Database/Storage => SessionSnodeKit}/Storage+OnionRequests.swift (98%) rename {SignalUtilitiesKit/Database/Storage => SessionSnodeKit}/Storage+SnodeAPI.swift (99%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/BuildConfiguration.swift (100%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/ContentProxy.swift (95%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/ECKeyPair+Hexadecimal.swift (97%) rename {SignalUtilitiesKit/Threads => SessionUtilitiesKit}/LKGroupUtilities.h (100%) rename {SignalUtilitiesKit/Threads => SessionUtilitiesKit}/LKGroupUtilities.m (95%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/LKUserDefaults.swift (100%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/LRUCache.swift (95%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSArray+Functional.h (100%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSArray+Functional.m (100%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/NSNotificationCenter+OWS.h (100%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/NSNotificationCenter+OWS.m (100%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSRegularExpression+SSK.swift (93%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSUserDefaults+OWS.h (100%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSUserDefaults+OWS.m (88%) rename {SignalUtilitiesKit => SessionUtilitiesKit}/ProxiedContentDownloader.swift (90%) rename {SignalUtilitiesKit/Database/Keychain => SessionUtilitiesKit}/SSKKeychainStorage.swift (97%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+PreKeyStore.h (90%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+PreKeyStore.m (100%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+SessionStore.h (92%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+SessionStore.m (100%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+SignedPreKeyStore.h (95%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+SignedPreKeyStore.m (100%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+keyFromIntLong.h (81%) rename SignalUtilitiesKit/Database/{OWSStorage => }/OWSPrimaryStorage+keyFromIntLong.m (100%) rename SignalUtilitiesKit/Database/{Utilities => }/OWSStorage+Subclass.h (93%) rename SignalUtilitiesKit/Database/{Utilities => }/SignalKeyingStorage.h (100%) rename SignalUtilitiesKit/Database/{Utilities => }/SignalKeyingStorage.m (95%) rename SignalUtilitiesKit/Database/{Storage => }/Storage+Conformances.swift (100%) rename SignalUtilitiesKit/Database/{Storage => }/Storage+SessionManagement.swift (100%) rename SignalUtilitiesKit/Database/{Utilities => }/TSStorageHeaders.h (79%) rename SignalUtilitiesKit/Database/{Utilities => }/TSStorageKeys.h (100%) rename SignalUtilitiesKit/Database/{Utilities => }/ThreadViewHelper.h (100%) rename SignalUtilitiesKit/Database/{Utilities => }/ThreadViewHelper.m (97%) rename SignalUtilitiesKit/Database/{YapDatabase => }/YapDatabase+Promise.swift (100%) delete mode 100644 SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h delete mode 100644 SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m delete mode 100644 SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m rename SignalUtilitiesKit/Messaging/{Utilities => }/OWSMessageUtils.h (100%) rename SignalUtilitiesKit/Messaging/{Utilities => }/OWSMessageUtils.m (100%) delete mode 100644 SignalUtilitiesKit/Messaging/Sending & Receiving/Destination+Conversion.swift rename SignalUtilitiesKit/Messaging/Sending & Receiving/{MessageSenderDelegate.swift => MessageSender+Handling.swift} (87%) delete mode 100644 SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift delete mode 100644 SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift rename SignalUtilitiesKit/Messaging/{Attachments => }/TSAttachmentPointer+Backups.h (100%) rename SignalUtilitiesKit/Messaging/{Attachments => }/TSAttachmentPointer+Backups.m (100%) rename SignalUtilitiesKit/Messaging/{Core Messages => }/TSInvalidIdentityKeySendingErrorMessage.h (90%) rename SignalUtilitiesKit/Messaging/{Core Messages => }/TSInvalidIdentityKeySendingErrorMessage.m (100%) rename SignalUtilitiesKit/{Threads => }/ThreadUtil.h (100%) rename SignalUtilitiesKit/{Threads => }/ThreadUtil.m (97%) diff --git a/Podfile b/Podfile index ea1aa18d9..05252c6c5 100644 --- a/Podfile +++ b/Podfile @@ -69,8 +69,11 @@ target 'SessionMessagingKit' do pod 'AFNetworking', inhibit_warnings: true pod 'CryptoSwift', :inhibit_warnings => true pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true + pod 'HKDFKit', :inhibit_warnings => true pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true + pod 'Reachability', :inhibit_warnings => true + pod 'SAMKeychain', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'SwiftProtobuf', '~> 1.5.0', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true @@ -92,13 +95,16 @@ target 'SessionSnodeKit' do pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true end target 'SessionUtilitiesKit' do + pod 'AFNetworking', inhibit_warnings: true pod 'CryptoSwift', :inhibit_warnings => true pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true + pod 'SAMKeychain', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true end diff --git a/Podfile.lock b/Podfile.lock index 4f46bd158..2b4ff5437 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 62df79698293257648cb6e60724f720f8477bd0f +PODFILE CHECKSUM: b12682bc3bf974c758ec8e4b9838639f7ec51d5e COCOAPODS: 1.10.0.rc.1 diff --git a/SignalUtilitiesKit/Database/Storage/Storage+VolumeSamples.swift b/Session/Database/Storage+VolumeSamples.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage/Storage+VolumeSamples.swift rename to Session/Database/Storage+VolumeSamples.swift diff --git a/Session/Meta/Signal-Bridging-Header.h b/Session/Meta/Signal-Bridging-Header.h index 578c0f2e7..93706eb46 100644 --- a/Session/Meta/Signal-Bridging-Header.h +++ b/Session/Meta/Signal-Bridging-Header.h @@ -66,31 +66,31 @@ #import #import #import -#import +#import #import -#import +#import #import #import #import #import -#import +#import #import #import #import #import #import -#import +#import #import #import #import -#import +#import #import -#import -#import +#import +#import #import -#import +#import #import -#import +#import #import #import #import diff --git a/Session/Signal/AboutTableViewController.m b/Session/Signal/AboutTableViewController.m index 21d436adc..0c32a1dba 100644 --- a/Session/Signal/AboutTableViewController.m +++ b/Session/Signal/AboutTableViewController.m @@ -8,8 +8,8 @@ #import #import #import -#import -#import +#import +#import @implementation AboutTableViewController diff --git a/Session/Signal/AddToBlockListViewController.m b/Session/Signal/AddToBlockListViewController.m index 58b64c436..8d3315238 100644 --- a/Session/Signal/AddToBlockListViewController.m +++ b/Session/Signal/AddToBlockListViewController.m @@ -4,8 +4,8 @@ #import "AddToBlockListViewController.h" #import "BlockListUIUtils.h" -#import -#import +#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index a8fa1c079..569f8783f 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -18,17 +18,17 @@ #import #import #import -#import -#import -#import +#import +#import +#import #import #import #import -#import -#import +#import +#import #import -#import -#import +#import +#import #import #import #import diff --git a/Session/Signal/AvatarViewHelper.m b/Session/Signal/AvatarViewHelper.m index bf4664007..1b2c41163 100644 --- a/Session/Signal/AvatarViewHelper.m +++ b/Session/Signal/AvatarViewHelper.m @@ -10,8 +10,8 @@ #import #import -#import -#import +#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 7f376a217..180490268 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -32,7 +32,7 @@ #import "TSGroupThread.h" #import "TSIncomingMessage.h" #import "TSInfoMessage.h" -#import +#import #import "UIFont+OWS.h" #import "UIViewController+Permissions.h" #import @@ -53,15 +53,15 @@ #import #import #import -#import -#import -#import +#import +#import +#import #import -#import +#import #import -#import +#import #import -#import +#import #import #import #import diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index 0d9b25ee6..371c55eb8 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -15,7 +15,7 @@ #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/ConversationViewModel.m b/Session/Signal/ConversationView/ConversationViewModel.m index c7884aa4b..eaef14c18 100644 --- a/Session/Signal/ConversationView/ConversationViewModel.m +++ b/Session/Signal/ConversationView/ConversationViewModel.m @@ -11,14 +11,14 @@ #import #import #import -#import -#import -#import -#import -#import -#import -#import -#import +#import +#import +#import +#import +#import +#import +#import +#import #import #import #import diff --git a/Session/Signal/MainAppContext.m b/Session/Signal/MainAppContext.m index a6c020904..48b2cd22b 100644 --- a/Session/Signal/MainAppContext.m +++ b/Session/Signal/MainAppContext.m @@ -8,7 +8,7 @@ #import #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSBackup.m b/Session/Signal/OWSBackup.m index 2ab57d41b..4f0ec36b0 100644 --- a/Session/Signal/OWSBackup.m +++ b/Session/Signal/OWSBackup.m @@ -9,8 +9,8 @@ #import "Session-Swift.h" #import #import -#import -#import +#import +#import @import CloudKit; diff --git a/Session/Signal/OWSBackupExportJob.m b/Session/Signal/OWSBackupExportJob.m index 0d0593483..a2156a81f 100644 --- a/Session/Signal/OWSBackupExportJob.m +++ b/Session/Signal/OWSBackupExportJob.m @@ -10,13 +10,13 @@ #import #import #import -#import +#import #import #import #import #import #import -#import +#import @import CloudKit; diff --git a/Session/Signal/OWSBackupImportJob.m b/Session/Signal/OWSBackupImportJob.m index 024f47e56..e746d4a51 100644 --- a/Session/Signal/OWSBackupImportJob.m +++ b/Session/Signal/OWSBackupImportJob.m @@ -9,11 +9,11 @@ #import "Session-Swift.h" #import #import -#import +#import #import #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index 449485ae1..7e178370a 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -23,12 +23,12 @@ #import #import #import -#import +#import -#import -#import -#import -#import +#import +#import +#import +#import @import ContactsUI; @import PromiseKit; diff --git a/Session/Signal/OWSOrphanDataCleaner.m b/Session/Signal/OWSOrphanDataCleaner.m index 5da139091..2d7ca614f 100644 --- a/Session/Signal/OWSOrphanDataCleaner.m +++ b/Session/Signal/OWSOrphanDataCleaner.m @@ -7,17 +7,17 @@ #import #import #import -#import +#import #import #import #import -#import +#import #import #import #import #import -#import -#import +#import +#import #import #import diff --git a/Session/Signal/OWSSessionResetJobRecord.h b/Session/Signal/OWSSessionResetJobRecord.h index cadc73300..3d7020832 100644 --- a/Session/Signal/OWSSessionResetJobRecord.h +++ b/Session/Signal/OWSSessionResetJobRecord.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import @class TSContactThread; diff --git a/Session/Signal/OWSSessionResetJobRecord.m b/Session/Signal/OWSSessionResetJobRecord.m index 02b90f513..95953daac 100644 --- a/Session/Signal/OWSSessionResetJobRecord.m +++ b/Session/Signal/OWSSessionResetJobRecord.m @@ -3,7 +3,7 @@ // #import "OWSSessionResetJobRecord.h" -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/PrivacySettingsTableViewController.m b/Session/Signal/PrivacySettingsTableViewController.m index f3ad86240..b18449d1e 100644 --- a/Session/Signal/PrivacySettingsTableViewController.m +++ b/Session/Signal/PrivacySettingsTableViewController.m @@ -13,7 +13,7 @@ #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/SignalApp.m b/Session/Signal/SignalApp.m index bf5e6ef07..0061f9a77 100644 --- a/Session/Signal/SignalApp.m +++ b/Session/Signal/SignalApp.m @@ -9,9 +9,9 @@ #import #import #import -#import -#import -#import +#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index f514bc6aa..c4bf93445 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -2,15 +2,10 @@ import SessionProtocolKit public struct Configuration { public let storage: SessionMessagingKitStorageProtocol - public let messageSenderDelegate: MessageSenderDelegate - public let messageReceiverDelegate: MessageReceiverDelegate public let signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore public let identityKeyStore: IdentityKeyStore public let sessionRestorationImplementation: SessionRestorationProtocol public let certificateValidator: SMKCertificateValidator - public let openGroupAPIDelegate: OpenGroupAPIDelegate - public let pnServerURL: String - public let pnServerPublicKey: String internal static var shared: Configuration! } @@ -19,27 +14,17 @@ public enum SNMessagingKit { // Just to make the external API nice public static func configure( storage: SessionMessagingKitStorageProtocol, - messageSenderDelegate: MessageSenderDelegate, - messageReceiverDelegate: MessageReceiverDelegate, signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore, identityKeyStore: IdentityKeyStore, sessionRestorationImplementation: SessionRestorationProtocol, - certificateValidator: SMKCertificateValidator, - openGroupAPIDelegate: OpenGroupAPIDelegate, - pnServerURL: String, - pnServerPublicKey: String + certificateValidator: SMKCertificateValidator ) { Configuration.shared = Configuration( storage: storage, - messageSenderDelegate: messageSenderDelegate, - messageReceiverDelegate: messageReceiverDelegate, signalStorage: signalStorage, identityKeyStore: identityKeyStore, sessionRestorationImplementation: sessionRestorationImplementation, - certificateValidator: certificateValidator, - openGroupAPIDelegate: openGroupAPIDelegate, - pnServerURL: pnServerURL, - pnServerPublicKey: pnServerPublicKey + certificateValidator: certificateValidator ) } } diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.h b/SessionMessagingKit/Database/OWSPrimaryStorage.h similarity index 97% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.h rename to SessionMessagingKit/Database/OWSPrimaryStorage.h index 2599b378d..269ad1fc9 100644 --- a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.h +++ b/SessionMessagingKit/Database/OWSPrimaryStorage.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.m b/SessionMessagingKit/Database/OWSPrimaryStorage.m similarity index 98% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.m rename to SessionMessagingKit/Database/OWSPrimaryStorage.m index edd029b88..69b39cdc0 100644 --- a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage.m +++ b/SessionMessagingKit/Database/OWSPrimaryStorage.m @@ -5,8 +5,6 @@ #import "OWSPrimaryStorage.h" #import "AppContext.h" #import "OWSDisappearingMessagesFinder.h" -#import "OWSFailedAttachmentDownloadsJob.h" -#import "OWSFailedMessagesJob.h" #import "OWSFileSystem.h" #import "OWSIncomingMessageFinder.h" #import "OWSMediaGalleryFinder.h" @@ -14,7 +12,8 @@ #import "SSKEnvironment.h" #import "TSDatabaseSecondaryIndexes.h" #import "TSDatabaseView.h" -#import +#import +#import #import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN @@ -201,8 +200,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) [FullTextSearchFinder asyncRegisterDatabaseExtensionWithStorage:self]; [OWSIncomingMessageFinder asyncRegisterExtensionWithPrimaryStorage:self]; [OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self]; - [OWSFailedMessagesJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; - [OWSFailedAttachmentDownloadsJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; [OWSMediaGalleryFinder asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self]; [SSKJobRecordFinder asyncRegisterDatabaseExtensionObjCWithStorage:self]; diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSStorage.h b/SessionMessagingKit/Database/OWSStorage.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage/OWSStorage.h rename to SessionMessagingKit/Database/OWSStorage.h diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSStorage.m b/SessionMessagingKit/Database/OWSStorage.m similarity index 83% rename from SignalUtilitiesKit/Database/OWSStorage/OWSStorage.m rename to SessionMessagingKit/Database/OWSStorage.m index f1df7a394..30c081e1c 100644 --- a/SignalUtilitiesKit/Database/OWSStorage/OWSStorage.m +++ b/SessionMessagingKit/Database/OWSStorage.m @@ -4,24 +4,24 @@ #import "OWSStorage.h" #import "AppContext.h" -#import "NSNotificationCenter+OWS.h" -#import "NSUserDefaults+OWS.h" #import "OWSBackgroundTask.h" #import "OWSFileSystem.h" #import "OWSPrimaryStorage.h" -#import "OWSStorage+Subclass.h" +#import "TSYapDatabaseObject.h" #import "TSAttachmentStream.h" -#import +#import #import -#import #import #import -#import #import +#import #import #import #import #import +#import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -59,8 +59,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ return self; } - OWSAssertDebug(delegate); - self.delegate = delegate; return self; @@ -76,8 +74,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (void)readWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block { id delegate = self.delegate; - OWSAssertDebug(delegate); - OWSAssertDebug(delegate.areAllRegistrationsComplete); OWSBackgroundTask *_Nullable backgroundTask = nil; if (CurrentAppContext().isMainApp && !CurrentAppContext().isRunningTests) { @@ -103,8 +99,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ completionBlock:(nullable dispatch_block_t)completionBlock { id delegate = self.delegate; - OWSAssertDebug(delegate); - OWSAssertDebug(delegate.areAllRegistrationsComplete); __block OWSBackgroundTask *_Nullable backgroundTask = nil; if (CurrentAppContext().isMainApp) { @@ -155,8 +149,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ return self; } - OWSAssertDebug(delegate); - self.delegate = delegate; return self; @@ -169,7 +161,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (YapDatabaseConnection *)newConnection { id delegate = self.delegate; - OWSAssertDebug(delegate); OWSDatabaseConnection *connection = [[OWSDatabaseConnection alloc] initWithDatabase:self delegate:delegate]; [self addConnection:connection]; @@ -201,8 +192,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (void)encodeWithCoder:(NSCoder *)aCoder { - OWSFailDebug(@"Tried to save object from unknown collection"); - return [super encodeWithCoder:aCoder]; } @@ -218,22 +207,16 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSFailDebug(@"Tried to save unknown object"); - // No-op. } - (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSFailDebug(@"Tried to touch unknown object"); - // No-op. } - (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSFailDebug(@"Tried to remove unknown object"); - // No-op. } @@ -253,11 +236,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ cannotDecodeObjectOfClassName:(NSString *)name originalClasses:(NSArray *)classNames { - if ([name isEqualToString:@"TSRecipient"]) { - OWSLogError(@"Could not decode object: %@", name); - } else { - NSLog(@"Could not decode object: %@", name); - } return [OWSUnknownDBObject class]; } @@ -295,9 +273,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (void)dealloc { - // Surface memory leaks by logging the deallocation of this class. - OWSLogVerbose(@"Dealloc: %@", self.class); - [[NSNotificationCenter defaultCenter] removeObserver:self]; } @@ -308,7 +283,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ // // The best we can try to do is to discard the current database // and behave like a clean install. - OWSFailDebug(@"Could not load database"); // Try to reset app by deleting all databases. // @@ -316,34 +290,27 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ // [OWSStorage deleteDatabaseFiles]; if (![self tryToLoadDatabase]) { - OWSFailDebug(@"Could not load database (second try)"); // Sleep to give analytics events time to be delivered. [NSThread sleepForTimeInterval:15.0f]; - OWSFail(@"Failed to initialize database."); + NSAssert(NO, @"Couldn't load database"); } } } - (nullable id)dbNotificationObject { - OWSAssertDebug(self.database); - return self.database; } - (BOOL)areAsyncRegistrationsComplete { - OWSAbstractMethod(); - return NO; } - (BOOL)areSyncRegistrationsComplete { - OWSAbstractMethod(); - return NO; } @@ -354,26 +321,22 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (void)runSyncRegistrations { - OWSAbstractMethod(); + } - (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion { - OWSAbstractMethod(); + } + (void)registerExtensionsWithMigrationBlock:(OWSStorageMigrationBlock)migrationBlock { - OWSAssertDebug(migrationBlock); - __block OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; [OWSPrimaryStorage.sharedManager runSyncRegistrations]; [OWSPrimaryStorage.sharedManager runAsyncRegistrationsWithCompletion:^{ - OWSAssertDebug(self.isStorageReady); - [self postRegistrationCompleteNotification]; migrationBlock(); @@ -390,10 +353,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ // Returns YES IFF all registrations are complete. + (void)postRegistrationCompleteNotification { - OWSAssertDebug(self.isStorageReady); - - OWSLogInfo(@""); - static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [[NSNotificationCenter defaultCenter] postNotificationNameAsync:StorageIsReadyNotification @@ -424,15 +383,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ // https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_migrate options.legacyCipherCompatibilityVersion = 3; - // If any of these asserts fails, we need to verify and update - // OWSDatabaseConverter which assumes the values of these options. - OWSAssertDebug(options.cipherDefaultkdfIterNumber == 0); - OWSAssertDebug(options.kdfIterNumber == 0); - OWSAssertDebug(options.cipherPageSize == 0); - OWSAssertDebug(options.pragmaPageSize == 0); - OWSAssertDebug(options.pragmaJournalSizeLimit == 0); - OWSAssertDebug(options.pragmaMMapSize == 0); - return options; } @@ -445,13 +395,11 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ // (e.g. by using OWSAssertDebug()) or this database will contain a // circular reference and will leak. OWSStorage *strongSelf = weakSelf; - OWSCAssertDebug(strongSelf); // Rather than compute this once and capture the value of the key // in the closure, we prefer to fetch the key from the keychain multiple times // in order to keep the key out of application memory. NSData *databaseKeySpec = [strongSelf databaseKeySpec]; - OWSCAssertDebug(databaseKeySpec.length == kSQLCipherKeySpecLength); return databaseKeySpec; }; @@ -484,7 +432,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ return ^id(NSString __unused *collection, NSString __unused *key, NSData *data) { if (!data || data.length <= 0) { - OWSFailDebug(@"can't deserialize null object: %@", collection); return [OWSUnknownDBObject new]; } @@ -502,9 +449,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (YapDatabaseConnection *)newDatabaseConnection { YapDatabaseConnection *dbConnection = self.database.newConnection; - if (!dbConnection) { - OWSFail(@"Storage could not open new database connection."); - } return dbConnection; } @@ -512,8 +456,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ + (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName { - OWSLogError(@"%@", extensionName); - // Don't increment version of a given extension more than once // per launch. static NSMutableSet *incrementedViewSet = nil; @@ -523,14 +465,12 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ }); @synchronized(incrementedViewSet) { if ([incrementedViewSet containsObject:extensionName]) { - OWSLogInfo(@"Ignoring redundant increment: %@", extensionName); return; } [incrementedViewSet addObject:extensionName]; } NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults]; - OWSAssertDebug(appUserDefaults); NSMutableDictionary *_Nullable versionMap = [[appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionMap] mutableCopy]; if (!versionMap) { @@ -545,10 +485,7 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (nullable NSString *)appendSuffixToDatabaseExtensionVersionIfNecessary:(nullable NSString *)versionTag extensionName:(NSString *)extensionName { - OWSAssertIsOnMainThread(); - NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults]; - OWSAssertDebug(appUserDefaults); NSDictionary *_Nullable versionMap = [appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionMap]; NSNumber *_Nullable versionSuffix = versionMap[extensionName]; @@ -556,7 +493,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ if (versionSuffix) { NSString *result = [NSString stringWithFormat:@"%@.%@", (versionTag.length < 1 ? @"0" : versionTag), versionSuffix]; - OWSLogWarn(@"database extension version: %@ + %@ -> %@", versionTag, versionSuffix, result); return result; } return versionTag; @@ -564,9 +500,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (YapDatabaseExtension *)updateExtensionVersion:(YapDatabaseExtension *)extension withName:(NSString *)extensionName { - OWSAssertDebug(extension); - OWSAssertDebug(extensionName.length > 0); - if ([extension isKindOfClass:[YapDatabaseAutoView class]]) { YapDatabaseAutoView *databaseView = (YapDatabaseAutoView *)extension; YapDatabaseAutoView *databaseViewCopy = [[YapDatabaseAutoView alloc] @@ -578,8 +511,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ return databaseViewCopy; } else if ([extension isKindOfClass:[YapDatabaseSecondaryIndex class]]) { YapDatabaseSecondaryIndex *secondaryIndex = (YapDatabaseSecondaryIndex *)extension; - OWSAssertDebug(secondaryIndex->setup); - OWSAssertDebug(secondaryIndex->handler); YapDatabaseSecondaryIndex *secondaryIndexCopy = [[YapDatabaseSecondaryIndex alloc] initWithSetup:secondaryIndex->setup handler:secondaryIndex->handler @@ -606,7 +537,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ // This method needs to be able to update the versionTag of all extensions. // If we start using other extension types, we need to modify this method to // handle them as well. - OWSFailDebug(@"Unknown extension type: %@", [extension class]); return extension; } @@ -616,7 +546,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ { extension = [self updateExtensionVersion:extension withName:extensionName]; - OWSAssertDebug(![self.extensionNames containsObject:extensionName]); [self.extensionNames addObject:extensionName]; return [self.database registerExtension:extension withName:extensionName]; @@ -634,18 +563,11 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ { extension = [self updateExtensionVersion:extension withName:extensionName]; - OWSAssertDebug(![self.extensionNames containsObject:extensionName]); [self.extensionNames addObject:extensionName]; [self.database asyncRegisterExtension:extension withName:extensionName completionBlock:^(BOOL ready) { - if (!ready) { - OWSFailDebug(@"asyncRegisterExtension failed: %@", extensionName); - } else { - OWSLogVerbose(@"asyncRegisterExtension succeeded: %@", extensionName); - } - dispatch_async(dispatch_get_main_queue(), ^{ if (completion) { completion(); @@ -710,22 +632,16 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (NSString *)databaseFilePath { - OWSAbstractMethod(); - return @""; } - (NSString *)databaseFilePath_SHM { - OWSAbstractMethod(); - return @""; } - (NSString *)databaseFilePath_WAL { - OWSAbstractMethod(); - return @""; } @@ -740,10 +656,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ return YES; } - if (error) { - OWSLogWarn(@"Database key couldn't be accessed: %@", error.localizedDescription); - } - return NO; } @@ -755,29 +667,21 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ + (nullable NSData *)tryToLoadDatabaseCipherKeySpec:(NSError **)errorHandle { NSData *_Nullable data = [self tryToLoadKeyChainValue:keychainDBCipherKeySpec errorHandle:errorHandle]; - OWSAssertDebug(!data || data.length == kSQLCipherKeySpecLength); return data; } + (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData { - OWSAssertDebug(cipherKeySpecData.length == kSQLCipherKeySpecLength); - [self storeKeyChainValue:cipherKeySpecData keychainKey:keychainDBCipherKeySpec]; } + (void)removeLegacyPassphrase { - OWSLogInfo(@"removing legacy passphrase"); - NSError *_Nullable error; BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService key:keychainDBLegacyPassphrase error:&error]; - if (error || !result) { - OWSFailDebug(@"could not remove legacy passphrase."); - } } - (void)ensureDatabaseKeySpecExists @@ -800,8 +704,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ errorDescription = [errorDescription stringByAppendingFormat:@", ApplicationState: %@", NSStringForUIApplicationState(applicationState)]; } - OWSLogError(@"%@", errorDescription); - [DDLog flushLog]; if (CurrentAppContext().isMainApp) { if (CurrentAppContext().isInBackground) { @@ -818,9 +720,6 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ // or the keychain has become corrupt. Either way, we want to get back to a // "known good state" and behave like a new install. BOOL doesDBExist = [NSFileManager.defaultManager fileExistsAtPath:[self databaseFilePath]]; - if (doesDBExist) { - OWSFailDebug(@"Could not load database metadata"); - } if (!CurrentAppContext().isRunningTests) { // Try to reset app by deleting database. @@ -838,12 +737,10 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error]; if (error) { - OWSLogError(@"failed to fetch databaseKeySpec with error: %@", error); [self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible"]; } if (keySpec.length != kSQLCipherKeySpecLength) { - OWSLogError(@"keyspec had length: %lu", (unsigned long)keySpec.length); [self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec invalid"]; } @@ -852,15 +749,12 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ - (void)raiseKeySpecInaccessibleExceptionWithErrorDescription:(NSString *)errorDescription { - OWSAssertDebug(CurrentAppContext().isMainApp && CurrentAppContext().isInBackground); - // Sleep to give analytics events time to be delivered. [NSThread sleepForTimeInterval:5.0f]; // Presumably this happened in response to a push notification. It's possible that the keychain is corrupted // but it could also just be that the user hasn't yet unlocked their device since our password is // kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly - OWSFail(@"%@", errorDescription); } + (void)deleteDBKeys @@ -869,15 +763,9 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService key:keychainDBLegacyPassphrase error:&error]; - if (error || !result) { - OWSFailDebug(@"could not remove legacy passphrase."); - } result = [CurrentAppContext().keychainStorage removeWithService:keychainService key:keychainDBCipherKeySpec error:&error]; - if (error || !result) { - OWSFailDebug(@"could not remove cipher key spec."); - } } - (unsigned long long)databaseFileSize @@ -897,42 +785,27 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ + (nullable NSData *)tryToLoadKeyChainValue:(NSString *)keychainKey errorHandle:(NSError **)errorHandle { - OWSAssertDebug(keychainKey.length > 0); - OWSAssertDebug(errorHandle); - NSData *_Nullable data = [CurrentAppContext().keychainStorage dataForService:keychainService key:keychainKey error:errorHandle]; - if (*errorHandle || !data) { - OWSLogWarn(@"could not load keychain value."); - } return data; } + (void)storeKeyChainValue:(NSData *)data keychainKey:(NSString *)keychainKey { - OWSAssertDebug(keychainKey.length > 0); - OWSAssertDebug(data.length > 0); - NSError *error; BOOL success = [CurrentAppContext().keychainStorage setWithData:data service:keychainService key:keychainKey error:&error]; if (!success || error) { - OWSFailDebug(@"Could not store database metadata"); // Sleep to give analytics events time to be delivered. [NSThread sleepForTimeInterval:15.0f]; - OWSFail(@"Setting keychain value failed with error: %@", error); - } else { - OWSLogWarn(@"Successfully set new keychain value."); } } - (void)logFileSizes { - OWSLogInfo(@"Database file size: %@", [OWSFileSystem fileSizeOfPath:self.databaseFilePath]); - OWSLogInfo(@"\t SHM file size: %@", [OWSFileSystem fileSizeOfPath:self.databaseFilePath_SHM]); - OWSLogInfo(@"\t WAL file size: %@", [OWSFileSystem fileSizeOfPath:self.databaseFilePath_WAL]); + } @end diff --git a/SignalUtilitiesKit/Database/Utilities/SSKPreferences.swift b/SessionMessagingKit/Database/SSKPreferences.swift similarity index 100% rename from SignalUtilitiesKit/Database/Utilities/SSKPreferences.swift rename to SessionMessagingKit/Database/SSKPreferences.swift diff --git a/SignalUtilitiesKit/Database/Storage/Storage+ClosedGroups.swift b/SessionMessagingKit/Database/Storage+ClosedGroups.swift similarity index 99% rename from SignalUtilitiesKit/Database/Storage/Storage+ClosedGroups.swift rename to SessionMessagingKit/Database/Storage+ClosedGroups.swift index 5aed45fc9..ea75d9c54 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+ClosedGroups.swift +++ b/SessionMessagingKit/Database/Storage+ClosedGroups.swift @@ -1,3 +1,4 @@ +import SessionProtocolKit extension Storage { diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage/Storage+Jobs.swift rename to SessionMessagingKit/Database/Storage+Jobs.swift diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage/Storage+Messaging.swift rename to SessionMessagingKit/Database/Storage+Messaging.swift diff --git a/SignalUtilitiesKit/Database/Storage/Storage+OpenGroups.swift b/SessionMessagingKit/Database/Storage+OpenGroups.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage/Storage+OpenGroups.swift rename to SessionMessagingKit/Database/Storage+OpenGroups.swift diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Shared.swift b/SessionMessagingKit/Database/Storage+Shared.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage/Storage+Shared.swift rename to SessionMessagingKit/Database/Storage+Shared.swift diff --git a/SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.h b/SessionMessagingKit/Database/TSDatabaseSecondaryIndexes.h similarity index 100% rename from SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.h rename to SessionMessagingKit/Database/TSDatabaseSecondaryIndexes.h diff --git a/SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.m b/SessionMessagingKit/Database/TSDatabaseSecondaryIndexes.m similarity index 100% rename from SignalUtilitiesKit/Database/Utilities/TSDatabaseSecondaryIndexes.m rename to SessionMessagingKit/Database/TSDatabaseSecondaryIndexes.m diff --git a/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.h b/SessionMessagingKit/Database/TSDatabaseView.h similarity index 98% rename from SignalUtilitiesKit/Database/Utilities/TSDatabaseView.h rename to SessionMessagingKit/Database/TSDatabaseView.h index bdd52ee8b..1598f55fd 100644 --- a/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.h +++ b/SessionMessagingKit/Database/TSDatabaseView.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m b/SessionMessagingKit/Database/TSDatabaseView.m similarity index 89% rename from SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m rename to SessionMessagingKit/Database/TSDatabaseView.m index fdb13e221..876063959 100644 --- a/SignalUtilitiesKit/Database/Utilities/TSDatabaseView.m +++ b/SessionMessagingKit/Database/TSDatabaseView.m @@ -60,8 +60,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" + (void)registerCrossProcessNotifier:(OWSStorage *)storage { - OWSAssertDebug(storage); - // I don't think the identifier and name of this extension matter for our purposes, // so long as they don't conflict with any other extension names. YapDatabaseExtension *extension = @@ -74,14 +72,8 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" version:(NSString *)version storage:(OWSStorage *)storage { - OWSAssertIsOnMainThread(); - OWSAssertDebug(viewName.length > 0); - OWSAssertDebug((viewGrouping)); - OWSAssertDebug(storage); - YapDatabaseView *existingView = [storage registeredExtension:viewName]; if (existingView) { - OWSFailDebug(@"Registered database view twice: %@", viewName); return; } @@ -142,7 +134,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); return nil; } TSInteraction *interaction = (TSInteraction *)object; @@ -167,19 +158,14 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" + (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage { - OWSAssertIsOnMainThread(); - OWSAssert(storage); - YapDatabaseView *existingView = [storage registeredExtension:TSMessageDatabaseViewExtensionName_Legacy]; if (existingView) { - OWSFailDebug(@"Registered database view twice: %@", TSMessageDatabaseViewExtensionName_Legacy); return; } YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object class], collection); return nil; } TSInteraction *interaction = (TSInteraction *)object; @@ -197,11 +183,9 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" NSString *key2, id object2) { if (![object1 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object1 class], collection1); return NSOrderedSame; } if (![object2 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object2 class], collection2); return NSOrderedSame; } TSInteraction *interaction1 = (TSInteraction *)object1; @@ -237,7 +221,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); return nil; } TSInteraction *interaction = (TSInteraction *)object; @@ -271,14 +254,12 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" { YapDatabaseView *threadView = [storage registeredExtension:TSThreadDatabaseViewExtensionName]; if (threadView) { - OWSFailDebug(@"Registered database view twice: %@", TSThreadDatabaseViewExtensionName); return; } YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { if (![object isKindOfClass:[TSThread class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); return nil; } TSThread *thread = (TSThread *)object; @@ -287,7 +268,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" // Do nothing; we never hide threads that have ever had a message. } else { YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName]; - OWSAssertDebug(viewTransaction); NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId]; if (threadMessageCount < 1) { return nil; @@ -320,11 +300,9 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" NSString *key2, id object2) { if (![object1 isKindOfClass:[TSThread class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); return NSOrderedSame; } if (![object2 isKindOfClass:[TSThread class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); return NSOrderedSame; } TSThread *thread1 = (TSThread *)object1; @@ -356,11 +334,9 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" NSString *key2, id object2) { if (![object1 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); return NSOrderedSame; } if (![object2 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); return NSOrderedSame; } TSInteraction *message1 = (TSInteraction *)object1; @@ -375,7 +351,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable( YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { if (![object isKindOfClass:[TSAttachment class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); return nil; } if (![object isKindOfClass:[TSAttachmentPointer class]]) { @@ -399,11 +374,9 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" NSString *key2, id object2) { if (![object1 isKindOfClass:[TSAttachmentPointer class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); return NSOrderedSame; } if (![object2 isKindOfClass:[TSAttachmentPointer class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); return NSOrderedSame; } @@ -424,15 +397,11 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" + (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - id _Nullable result = [transaction ext:TSUnseenDatabaseViewExtensionName]; - OWSAssertDebug(result); // TODO: I believe we can now safely remove this? if (!result) { result = [transaction ext:TSUnreadDatabaseViewExtensionName]; - OWSAssertDebug(result); } return result; @@ -441,20 +410,14 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" // MJK TODO - dynamic interactions + (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - id result = [transaction ext:TSThreadOutgoingMessageDatabaseViewExtensionName]; - OWSAssertDebug(result); return result; } + (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - id result = [transaction ext:TSThreadSpecialMessagesDatabaseViewExtensionName]; - OWSAssertDebug(result); return result; } diff --git a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift index 2c94a5c79..c26ed550c 100644 --- a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift +++ b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift @@ -34,13 +34,13 @@ public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSC // MARK: Running public func execute() { - let server = Configuration.shared.pnServerURL + let server = PushNotificationAPI.server let parameters = [ "data" : message.data.description, "send_to" : message.recipient ] let url = URL(string: "\(server)/notify")! let request = TSRequest(url: url, method: "POST", parameters: parameters) request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.global()) { - OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: Configuration.shared.pnServerPublicKey).map { _ in } + OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: PushNotificationAPI.serverPublicKey).map { _ in } }.done(on: DispatchQueue.global()) { // Intentionally capture self self.handleSuccess() }.catch(on: DispatchQueue.global()) { error in diff --git a/SessionMessagingKit/Messages/Message+Destination.swift b/SessionMessagingKit/Messages/Message+Destination.swift index f35a2181c..55f1d2dc4 100644 --- a/SessionMessagingKit/Messages/Message+Destination.swift +++ b/SessionMessagingKit/Messages/Message+Destination.swift @@ -5,5 +5,20 @@ public extension Message { case contact(publicKey: String) case closedGroup(groupPublicKey: String) case openGroup(channel: UInt64, server: String) + + static func from(_ thread: TSThread) -> Message.Destination { + if let thread = thread as? TSContactThread { + return .contact(publicKey: thread.contactIdentifier()) + } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys { + let groupID = thread.groupModel.groupId + let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) + return .closedGroup(groupPublicKey: groupPublicKey) + } else if let thread = thread as? TSGroupThread, thread.isOpenGroup { + let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!)! + return .openGroup(channel: openGroup.channel, server: openGroup.server) + } else { + preconditionFailure("TODO: Handle legacy closed groups.") + } + } } } diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.h b/SessionMessagingKit/Messages/Signal/TSErrorMessage.h similarity index 97% rename from SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.h rename to SessionMessagingKit/Messages/Signal/TSErrorMessage.h index bb04ed25f..a0a65d6d5 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSErrorMessage.h @@ -2,8 +2,8 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import -#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.m b/SessionMessagingKit/Messages/Signal/TSErrorMessage.m similarity index 97% rename from SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.m rename to SessionMessagingKit/Messages/Signal/TSErrorMessage.m index 09944f332..572da4454 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSErrorMessage.m @@ -7,8 +7,8 @@ #import "TSContactThread.h" #import "TSErrorMessage_privateConstructor.h" #import -#import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -205,13 +205,10 @@ NSUInteger TSErrorMessageSchemaVersion = 1; sendReadReceipt:(BOOL)sendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - if (_read) { return; } - OWSLogDebug(@"marking as read uniqueId: %@ which has timestamp: %llu", self.uniqueId, self.timestamp); _read = YES; [self saveWithTransaction:transaction]; diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage_privateConstructor.h b/SessionMessagingKit/Messages/Signal/TSErrorMessage_privateConstructor.h similarity index 90% rename from SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage_privateConstructor.h rename to SessionMessagingKit/Messages/Signal/TSErrorMessage_privateConstructor.h index 08de35a44..e402d95fb 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSErrorMessage_privateConstructor.h +++ b/SessionMessagingKit/Messages/Signal/TSErrorMessage_privateConstructor.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage+Conversion.swift rename to SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.h b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h similarity index 97% rename from SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.h rename to SessionMessagingKit/Messages/Signal/TSIncomingMessage.h index 84c3f1cf2..58b770a40 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h @@ -2,8 +2,8 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import -#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.m b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m similarity index 90% rename from SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.m rename to SessionMessagingKit/Messages/Signal/TSIncomingMessage.m index 40092305c..69e3a0f3a 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSIncomingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m @@ -13,6 +13,7 @@ #import "TSGroupThread.h" #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -36,7 +37,6 @@ NS_ASSUME_NONNULL_BEGIN } if (_authorId == nil) { - OWSAssertDebug([self.uniqueThreadId hasPrefix:TSContactThreadPrefix]); _authorId = [TSContactThread contactIdFromThreadId:self.uniqueThreadId]; } @@ -81,8 +81,6 @@ NS_ASSUME_NONNULL_BEGIN timestamp:(uint64_t)timestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - __block TSIncomingMessage *foundMessage; // In theory we could build a new secondaryIndex for (authorId,timestamp), but in practice there should // be *very* few (millisecond) timestamps with multiple authors. @@ -93,9 +91,6 @@ NS_ASSUME_NONNULL_BEGIN [TSInteraction fetchObjectWithUniqueID:key transaction:transaction]; if ([interaction isKindOfClass:[TSIncomingMessage class]]) { TSIncomingMessage *message = (TSIncomingMessage *)interaction; - - OWSAssertDebug(message.authorId > 0); - if ([message.authorId isEqualToString:authorId]) { foundMessage = message; } @@ -133,7 +128,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)markAsReadNowWithSendReadReceipt:(BOOL)sendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction; { - [self markAsReadAtTimestamp:[NSDate ows_millisecondTimeStamp] + [self markAsReadAtTimestamp:[NSDate millisecondTimestamp] sendReadReceipt:sendReadReceipt transaction:transaction]; } @@ -142,17 +137,11 @@ NS_ASSUME_NONNULL_BEGIN sendReadReceipt:(BOOL)sendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction; { - OWSAssertDebug(transaction); - if (_read && readTimestamp >= self.expireStartedAt) { return; } - NSTimeInterval secondsAgoRead = ((NSTimeInterval)[NSDate ows_millisecondTimeStamp] - (NSTimeInterval)readTimestamp) / 1000; - OWSLogDebug(@"marking uniqueId: %@ which has timestamp: %llu as read: %f seconds ago", - self.uniqueId, - self.timestamp, - secondsAgoRead); + NSTimeInterval secondsAgoRead = ((NSTimeInterval)[NSDate millisecondTimestamp] - (NSTimeInterval)readTimestamp) / 1000; _read = YES; [self saveWithTransaction:transaction]; diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.h b/SessionMessagingKit/Messages/Signal/TSInfoMessage.h similarity index 96% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.h rename to SessionMessagingKit/Messages/Signal/TSInfoMessage.h index 53e462619..e7ae3d82e 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSInfoMessage.h @@ -2,8 +2,8 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import -#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.m b/SessionMessagingKit/Messages/Signal/TSInfoMessage.m similarity index 95% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.m rename to SessionMessagingKit/Messages/Signal/TSInfoMessage.m index 1db237167..39d168d7e 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInfoMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSInfoMessage.m @@ -6,6 +6,7 @@ #import "SSKEnvironment.h" #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -97,11 +98,8 @@ NSUInteger TSInfoMessageSchemaVersion = 1; + (instancetype)userNotRegisteredMessageInThread:(TSThread *)thread recipientId:(NSString *)recipientId { - OWSAssertDebug(thread); - OWSAssertDebug(recipientId); - // MJK TODO - remove senderTimestamp - return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] + return [[self alloc] initWithTimestamp:[NSDate millisecondTimestamp] inThread:thread messageType:TSInfoMessageUserNotRegistered unregisteredRecipientId:recipientId]; @@ -169,13 +167,10 @@ NSUInteger TSInfoMessageSchemaVersion = 1; sendReadReceipt:(BOOL)sendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - if (_read) { return; } - OWSLogDebug(@"marking as read uniqueId: %@ which has timestamp: %llu", self.uniqueId, self.timestamp); _read = YES; [self saveWithTransaction:transaction]; diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h b/SessionMessagingKit/Messages/Signal/TSInteraction.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.h rename to SessionMessagingKit/Messages/Signal/TSInteraction.h diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m b/SessionMessagingKit/Messages/Signal/TSInteraction.m similarity index 95% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m rename to SessionMessagingKit/Messages/Signal/TSInteraction.m index 004d923f5..813145b3f 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInteraction.m +++ b/SessionMessagingKit/Messages/Signal/TSInteraction.m @@ -7,7 +7,7 @@ #import "TSThread.h" #import "TSGroupThread.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -47,8 +47,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) ofClass:(Class)clazz withTransaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(timestamp > 0); - // Accept any interaction. return [self interactionsWithTimestamp:timestamp filter:^(TSInteraction *interaction) { @@ -61,8 +59,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) filter:(BOOL (^_Nonnull)(TSInteraction *))filter withTransaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(timestamp > 0); - NSMutableArray *interactions = [NSMutableArray new]; [TSDatabaseSecondaryIndexes @@ -88,8 +84,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) timestamp:(uint64_t)timestamp inThread:(TSThread *)thread { - OWSAssertDebug(timestamp > 0); - self = [super initWithUniqueId:uniqueId]; if (!self) { @@ -104,8 +98,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread { - OWSAssertDebug(timestamp > 0); - self = [super initWithUniqueId:[[NSUUID UUID] UUIDString]]; if (!self) { @@ -169,8 +161,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) - (void)applyChangeToSelfAndLatestCopy:(YapDatabaseReadWriteTransaction *)transaction changeBlock:(void (^)(id))changeBlock { - OWSAssertDebug(transaction); - [super applyChangeToSelfAndLatestCopy:transaction changeBlock:changeBlock]; [self touchThreadWithTransaction:transaction]; } @@ -203,8 +193,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) - (NSComparisonResult)compareForSorting:(TSInteraction *)other { - OWSAssertDebug(other); - uint64_t sortId1; uint64_t sortId2; @@ -230,8 +218,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) - (OWSInteractionType)interactionType { - OWSFailDebug(@"unknown interaction type."); - return OWSInteractionType_Unknown; } @@ -246,7 +232,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) - (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { if (!self.uniqueId) { - OWSFailDebug(@"Missing uniqueId."); self.uniqueId = [NSUUID new].UUIDString; } if (self.sortId == 0) { diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.h b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyErrorMessage.h similarity index 84% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.h rename to SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyErrorMessage.h index effae70d4..a12d51534 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyErrorMessage.h @@ -2,12 +2,10 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN -@class OWSFingerprint; - @interface TSInvalidIdentityKeyErrorMessage : TSErrorMessage - (void)throws_acceptNewIdentityKey NS_SWIFT_UNAVAILABLE("throws objc exceptions"); diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.m b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyErrorMessage.m similarity index 85% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.m rename to SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyErrorMessage.m index 028466323..ce9e3a62d 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyErrorMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyErrorMessage.m @@ -11,18 +11,16 @@ NS_ASSUME_NONNULL_BEGIN - (void)throws_acceptNewIdentityKey { - OWSAbstractMethod(); + } - (nullable NSData *)throws_newIdentityKey { - OWSAbstractMethod(); return nil; } - (NSString *)theirSignalId { - OWSAbstractMethod(); return nil; } diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.h b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.h similarity index 90% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.h rename to SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.h index a59fe3bbb..8b2de8c6f 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.m b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.m similarity index 87% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.m rename to SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.m index 168db6d70..c85c57276 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -12,8 +12,8 @@ #import "TSErrorMessage_privateConstructor.h" #import #import -#import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -59,7 +59,6 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage NSError *error; _envelopeData = [envelope serializedDataAndReturnError:&error]; if (!_envelopeData || error != nil) { - OWSFailDebug(@"failure: envelope data failed with error: %@", error); return nil; } @@ -75,7 +74,7 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage NSError *error; SNProtoEnvelope *_Nullable envelope = [SNProtoEnvelope parseData:self.envelopeData error:&error]; if (error || envelope == nil) { - OWSFailDebug(@"Could not parse proto: %@", error); + } else { _envelope = envelope; } @@ -85,16 +84,12 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage - (void)throws_acceptNewIdentityKey { - OWSAssertIsOnMainThread(); - if (self.errorType != TSErrorMessageWrongTrustedIdentityKey) { - OWSLogError(@"Refusing to accept identity key for anything but a Key error."); return; } NSData *_Nullable newKey = [self throws_newIdentityKey]; if (!newKey) { - OWSFailDebug(@"Couldn't extract identity key to accept"); return; } @@ -116,18 +111,15 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage - (nullable NSData *)throws_newIdentityKey { if (!self.envelope) { - OWSLogError(@"Error message had no envelope data to extract key from"); return nil; } if (self.envelope.type != SNProtoEnvelopeTypePrekeyBundle) { - OWSLogError(@"Refusing to attempt key extraction from an envelope which isn't a prekey bundle"); return nil; } NSData *pkwmData = self.envelope.content; if (!pkwmData) { - OWSLogError(@"Ignoring acceptNewIdentityKey for empty message"); return nil; } diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h b/SessionMessagingKit/Messages/Signal/TSMessage.h similarity index 96% rename from SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h rename to SessionMessagingKit/Messages/Signal/TSMessage.h index 436780bfe..d5f9058cf 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSMessage.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN @class TSQuotedMessage; @class YapDatabaseReadWriteTransaction; +extern const NSUInteger kOversizeTextMessageSizeThreshold; + @interface TSMessage : TSInteraction @property (nonatomic, readonly) NSMutableArray *attachmentIds; diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage+Conversion.swift rename to SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.h b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h similarity index 99% rename from SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.h rename to SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h index dfd9d73e2..61958afc8 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m similarity index 92% rename from SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m rename to SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m index 35fe9dd7c..7ba4eaa91 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSOutgoingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m @@ -5,7 +5,6 @@ @import Foundation; #import "TSOutgoingMessage.h" -#import "NSString+SSK.h" #import "TSDatabaseSecondaryIndexes.h" #import "OWSPrimaryStorage.h" #import "ProfileManagerProtocol.h" @@ -18,9 +17,9 @@ #import "TSGroupThread.h" #import "TSQuotedMessage.h" #import -#import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -109,7 +108,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt if (!self.recipientStateMap) { [self migrateRecipientStateMapWithCoder:coder]; - OWSAssertDebug(self.recipientStateMap); } } @@ -118,9 +116,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)migrateRecipientStateMapWithCoder:(NSCoder *)coder { - OWSAssertDebug(!self.recipientStateMap); - OWSAssertDebug(coder); - // Determine the "overall message state." TSOutgoingMessageState oldMessageState = TSOutgoingMessageStateFailed; NSNumber *_Nullable messageStateValue = [coder decodeObjectForKey:@"messageState"]; @@ -184,7 +179,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt NSString *_Nullable singleGroupRecipient = [coder decodeObjectForKey:@"singleGroupRecipient"]; if (singleGroupRecipient) { - OWSFailDebug(@"unexpected single group recipient message."); // If this is a "single group recipient message", treat it as such. recipientIds = @[ singleGroupRecipient, @@ -207,7 +201,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt recipientState.state = OWSOutgoingMessageRecipientStateSent; recipientState.deliveryTimestamp = deliveryTimestamp; } else if (wasDeliveredToContact) { - OWSAssertDebug(!isGroupThread); recipientState.state = OWSOutgoingMessageRecipientStateSent; // Use message time as an estimate of delivery time. recipientState.deliveryTimestamp = @(self.timestamp); @@ -329,7 +322,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt _groupMetaMessage = groupMetaMessage; } } else { - OWSAssertDebug(groupMetaMessage == TSGroupMetaMessageUnspecified); // Specifying a group meta message only makes sense for Group threads _groupMetaMessage = TSGroupMetaMessageUnspecified; } @@ -377,7 +369,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; if (!attachment) { - OWSLogError(@"Couldn't load interaction's attachment for deletion."); continue; } [attachment removeWithTransaction:transaction]; @@ -417,8 +408,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt + (TSOutgoingMessageState)messageStateForRecipientStates:(NSArray *)recipientStates { - OWSAssertDebug(recipientStates); - // If there are any "sending" recipients, consider this message "sending". BOOL hasFailed = NO; for (TSOutgoingMessageRecipientState *recipientState in recipientStates) { @@ -455,8 +444,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt // There's no need to save this message, since it's not displayed to the user. // // Should we find a need to save this in the future, we need to exclude any non-serializable properties. - OWSLogDebug(@"Skipping save for transient outgoing message."); - return; } @@ -483,8 +470,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt // no longer be considered sent. // So here we take extra care not to stop any expiration that had previously started. // This can also happen under normal cirumstances with an outgoing group message. - OWSLogWarn(@"expiration previously started"); - return YES; } @@ -587,10 +572,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (nullable TSOutgoingMessageRecipientState *)recipientStateForRecipientId:(NSString *)recipientId { - OWSAssertDebug(recipientId.length > 0); - TSOutgoingMessageRecipientState *_Nullable result = self.recipientStateMap[recipientId]; - OWSAssertDebug(result); return [result copy]; } @@ -598,7 +580,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithSendingError:(NSError *)error transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(error); [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { // Mark any "sending" recipients as "failed." @@ -613,8 +594,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithAllSendingRecipientsMarkedAsFailedWithTansaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { // Mark any "sending" recipients as "failed." @@ -629,8 +608,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithMarkingAllUnsentRecipientsAsSendingWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { // Mark any "sending" recipients as "failed." @@ -654,9 +631,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithCustomMessage:(NSString *)customMessage transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(customMessage); - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { [message setCustomMessage:customMessage]; @@ -673,9 +647,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithSentRecipient:(NSString *)recipientId wasSentByUD:(BOOL)wasSentByUD transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { TSOutgoingMessageRecipientState *_Nullable recipientState @@ -688,9 +659,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithSkippedRecipient:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { TSOutgoingMessageRecipientState *_Nullable recipientState @@ -704,9 +672,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt deliveryTimestamp:(NSNumber *_Nullable)deliveryTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - // If delivery notification doesn't include timestamp, use "now" as an estimate. if (!deliveryTimestamp) { deliveryTimestamp = @([NSDate ows_millisecondTimeStamp]); @@ -716,13 +681,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt changeBlock:^(TSOutgoingMessage *message) { TSOutgoingMessageRecipientState *_Nullable recipientState = message.recipientStateMap[recipientId]; - if (!recipientState) { - // OWSFailDebug(@"Missing recipient state for delivered recipient: %@", recipientId); - return; - } - if (recipientState.state != OWSOutgoingMessageRecipientStateSent) { - OWSLogWarn(@"marking unsent message as delivered."); - } + if (!recipientState) { return; } recipientState.state = OWSOutgoingMessageRecipientStateSent; recipientState.deliveryTimestamp = deliveryTimestamp; }]; @@ -732,16 +691,10 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt readTimestamp:(uint64_t)readTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { TSOutgoingMessageRecipientState *_Nullable recipientState = message.recipientStateMap[recipientId]; if (!recipientState) { return; } - if (recipientState.state != OWSOutgoingMessageRecipientStateSent) { - OWSLogWarn(@"Marking unsent message as delivered."); - } recipientState.state = OWSOutgoingMessageRecipientStateSent; recipientState.readTimestamp = @(readTimestamp); }]; @@ -752,8 +705,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt isSentUpdate:(BOOL)isSentUpdate transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { @@ -764,8 +715,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt = [NSMutableDictionary new]; for (NSString *recipientId in udRecipientIds) { if (recipientStateMap[recipientId]) { - OWSFailDebug( - @"recipient appears more than once in recipient lists: %@", recipientId); continue; } TSOutgoingMessageRecipientState *recipientState = @@ -776,8 +725,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } for (NSString *recipientId in nonUdRecipientIds) { if (recipientStateMap[recipientId]) { - OWSFailDebug( - @"recipient appears more than once in recipient lists: %@", recipientId); continue; } TSOutgoingMessageRecipientState *recipientState = @@ -822,9 +769,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithSendingToSingleGroupRecipient:(NSString *)singleGroupRecipient transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(singleGroupRecipient.length > 0); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { TSOutgoingMessageRecipientState *recipientState = @@ -853,8 +797,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (void)updateWithFakeMessageState:(TSOutgoingMessageState)messageState transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - [self applyChangeToSelfAndLatestCopy:transaction changeBlock:^(TSOutgoingMessage *message) { for (TSOutgoingMessageRecipientState *recipientState in message.recipientStateMap @@ -870,7 +812,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt recipientState.state = OWSOutgoingMessageRecipientStateSent; break; default: - OWSFailDebug(@"unexpected message state."); break; } } @@ -882,7 +823,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (nullable id)dataMessageBuilder { TSThread *thread = self.thread; - OWSAssertDebug(thread); SNProtoDataMessageBuilder *builder = [SNProtoDataMessage builder]; [builder setTimestamp:self.timestamp]; @@ -890,11 +830,8 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt if ([self.body lengthOfBytesUsingEncoding:NSUTF8StringEncoding] <= kOversizeTextMessageSizeThreshold) { [builder setBody:self.body]; } else { - OWSFailDebug(@"message body length too long."); NSString *truncatedBody = [self.body copy]; while ([truncatedBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > kOversizeTextMessageSizeThreshold) { - OWSLogError(@"truncating body which is too long: %lu", - (unsigned long)[truncatedBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); truncatedBody = [truncatedBody substringToIndex:truncatedBody.length / 2]; } [builder setBody:truncatedBody]; @@ -926,7 +863,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt SNProtoAttachmentPointer *_Nullable attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; if (!attachmentProto) { - OWSFailDebug(@"could not build protobuf."); return nil; } [groupBuilder setAvatar:attachmentProto]; @@ -939,7 +875,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt NSError *error; SNProtoGroupContext *_Nullable groupContextProto = [groupBuilder buildAndReturnError:&error]; if (error || !groupContextProto) { - OWSFailDebug(@"could not build protobuf: %@.", error); return nil; } [builder setGroup:groupContextProto]; @@ -952,7 +887,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt SNProtoAttachmentPointer *_Nullable attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:attachmentId]; if (!attachmentProto) { - OWSFailDebug(@"could not build protobuf."); return nil; } [attachments addObject:attachmentProto]; @@ -966,7 +900,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt NSError *error; SNProtoDataMessageQuote *_Nullable quoteProto = [quotedMessageBuilder buildAndReturnError:&error]; if (error || !quoteProto) { - OWSFailDebug(@"could not build protobuf: %@.", error); return nil; } [builder setQuote:quoteProto]; @@ -983,7 +916,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt SNProtoAttachmentPointer *_Nullable attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:self.linkPreview.imageAttachmentId]; if (!attachmentProto) { - OWSFailDebug(@"Could not build link preview image protobuf."); + } else { [previewBuilder setImage:attachmentProto]; } @@ -992,7 +925,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt NSError *error; SNProtoDataMessagePreview *_Nullable previewProto = [previewBuilder buildAndReturnError:&error]; if (error || !previewProto) { - OWSFailDebug(@"Could not build link preview protobuf: %@.", error); + } else { [builder addPreview:previewProto]; } @@ -1036,7 +969,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt SNProtoDataMessageQuoteQuotedAttachment *_Nullable quotedAttachmentMessage = [quotedAttachmentBuilder buildAndReturnError:&error]; if (error || !quotedAttachmentMessage) { - OWSFailDebug(@"could not build protobuf: %@", error); return nil; } @@ -1047,7 +979,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt if (hasQuotedText || hasQuotedAttachment) { return quoteBuilder; } else { - OWSFailDebug(@"Invalid quoted message data."); return nil; } } @@ -1055,10 +986,8 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt // recipientId is nil when building "sent" sync messages for messages sent to groups. - (nullable SNProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId { - OWSAssertDebug(self.thread); SNProtoDataMessageBuilder *_Nullable builder = [self dataMessageBuilder]; if (builder == nil) { - OWSFailDebug(@"Couldn't build protobuf."); return nil; } @@ -1082,7 +1011,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt NSError *error; SNProtoDataMessage *_Nullable dataProto = [builder buildAndReturnError:&error]; if (error != nil || dataProto == nil) { - OWSFailDebug(@"Couldn't build protobuf due to error: %@.", error); return nil; } return dataProto; @@ -1092,7 +1020,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt SNProtoDataMessage *_Nullable dataMessage = [self buildDataMessage:recipient.recipientId]; if (dataMessage == nil) { - OWSFailDebug(@"Couldn't build protobuf."); return nil; } @@ -1109,7 +1036,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt NSError *error; NSData *_Nullable contentData = [contentBuilder buildSerializedDataAndReturnError:&error]; if (error != nil || contentData == nil) { - OWSFailDebug(@"Couldn't serialize protobuf due to error: %@.", error); return nil; } diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/VisibleMessage+Attachment.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Attachment.swift similarity index 100% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/VisibleMessage+Attachment.swift rename to SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Attachment.swift diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index 0665b4812..07bef159a 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -3,6 +3,47 @@ FOUNDATION_EXPORT double SessionMessagingKitVersionNumber; FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import #import #import #import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 423a36652..7c75c7672 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -350,7 +350,7 @@ public final class OpenGroupAPI : DotNetAPI { storage.setUserCount(to: memberCount, forOpenGroupWithID: "\(server).\(channel)", using: transaction) } let openGroupInfo = OpenGroupInfo(displayName: displayName, profilePictureURL: profilePictureURL, memberCount: memberCount) - Configuration.shared.openGroupAPIDelegate.updateProfileIfNeeded(for: channel, on: server, from: openGroupInfo) + OpenGroupAPI.updateProfileIfNeeded(for: channel, on: server, from: openGroupInfo) return openGroupInfo } } @@ -358,6 +358,39 @@ public final class OpenGroupAPI : DotNetAPI { } } + public static func updateProfileIfNeeded(for channel: UInt64, on server: String, from info: OpenGroupInfo) { + let openGroupID = "\(server).\(channel)" + Storage.write { transaction in + // Update user count + Storage.shared.setUserCount(to: info.memberCount, forOpenGroupWithID: openGroupID, using: transaction) + let thread = TSGroupThread.getOrCreateThread(withGroupId: openGroupID.data(using: .utf8)!, groupType: .openGroup, transaction: transaction) + // Update display name if needed + let model = thread.groupModel + if model.groupName != info.displayName { + let newGroupModel = TSGroupModel(title: info.displayName, memberIds: model.groupMemberIds, image: model.groupImage, groupId: model.groupId, groupType: model.groupType, adminIds: model.groupAdminIds) + thread.groupModel = newGroupModel + thread.save(with: transaction) + } + // Download and update profile picture if needed + let oldProfilePictureURL = Storage.shared.getProfilePictureURL(forOpenGroupWithID: openGroupID) + if oldProfilePictureURL != info.profilePictureURL || model.groupImage == nil { + Storage.shared.setProfilePictureURL(to: info.profilePictureURL, forOpenGroupWithID: openGroupID, using: transaction) + if let profilePictureURL = info.profilePictureURL { + var sanitizedServerURL = server + while sanitizedServerURL.hasSuffix("/") { sanitizedServerURL.removeLast() } + var sanitizedProfilePictureURL = profilePictureURL + while sanitizedProfilePictureURL.hasPrefix("/") { sanitizedProfilePictureURL.removeFirst() } + let url = "\(sanitizedServerURL)/\(sanitizedProfilePictureURL)" + FileServerAPI.downloadAttachment(from: url).map2 { data in + let attachmentStream = TSAttachmentStream(contentType: OWSMimeTypeImageJpeg, byteCount: UInt32(data.count), sourceFilename: nil, caption: nil, albumMessageId: nil) + try attachmentStream.write(data) + thread.updateAvatar(with: attachmentStream) + } + } + } + } + } + public static func join(_ channel: UInt64, on server: String) -> Promise { return attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global(qos: .default)) { getOpenGroupServerPublicKey(for: server).then(on: DispatchQueue.global(qos: .default)) { serverPublicKey in diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPIDelegate.swift b/SessionMessagingKit/Open Groups/OpenGroupAPIDelegate.swift deleted file mode 100644 index a8418c4f8..000000000 --- a/SessionMessagingKit/Open Groups/OpenGroupAPIDelegate.swift +++ /dev/null @@ -1,5 +0,0 @@ - -public protocol OpenGroupAPIDelegate { - - func updateProfileIfNeeded(for channel: UInt64, on server: String, from info: OpenGroupInfo) -} diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/OWSThumbnailService.swift b/SessionMessagingKit/Sending & Receiving/Attachments/OWSThumbnailService.swift similarity index 100% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/OWSThumbnailService.swift rename to SessionMessagingKit/Sending & Receiving/Attachments/OWSThumbnailService.swift diff --git a/SignalUtilitiesKit/Messaging/Attachments/SignalAttachment.swift b/SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift similarity index 93% rename from SignalUtilitiesKit/Messaging/Attachments/SignalAttachment.swift rename to SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift index 3547fa2f5..b60dabb61 100644 --- a/SignalUtilitiesKit/Messaging/Attachments/SignalAttachment.swift +++ b/SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift @@ -8,7 +8,7 @@ import MobileCoreServices import PromiseKit import AVFoundation -enum SignalAttachmentError: Error { +public enum SignalAttachmentError: Error { case missingData case fileSizeTooLarge case invalidData @@ -21,17 +21,16 @@ enum SignalAttachmentError: Error { } extension String { - var filenameWithoutExtension: String { + public var filenameWithoutExtension: String { return (self as NSString).deletingPathExtension } - var fileExtension: String? { + public var fileExtension: String? { return (self as NSString).pathExtension } - func appendingFileExtension(_ fileExtension: String) -> String { + public func appendingFileExtension(_ fileExtension: String) -> String { guard let result = (self as NSString).appendingPathExtension(fileExtension) else { - owsFailDebug("Failed to append file extension: \(fileExtension) to string: \(self)") return self } return result @@ -160,12 +159,9 @@ public class SignalAttachment: NSObject { @objc public let dataUTI: String - var error: SignalAttachmentError? { + public var error: SignalAttachmentError? { didSet { - AssertIsOnMainThread() - assert(oldValue == nil) - Logger.verbose("Attachment has error: \(String(describing: error))") } } @@ -213,7 +209,6 @@ public class SignalAttachment: NSObject { public var errorName: String? { guard let error = error else { // This method should only be called if there is an error. - owsFailDebug("Missing error") return nil } @@ -224,11 +219,9 @@ public class SignalAttachment: NSObject { public var localizedErrorDescription: String? { guard let error = self.error else { // This method should only be called if there is an error. - owsFailDebug("Missing error") return nil } guard let errorDescription = error.errorDescription else { - owsFailDebug("Missing error description") return nil } @@ -238,7 +231,6 @@ public class SignalAttachment: NSObject { @objc public class var missingDataErrorMessage: String { guard let errorDescription = SignalAttachmentError.missingData.errorDescription else { - owsFailDebug("Missing error description") return "" } return errorDescription @@ -284,7 +276,6 @@ public class SignalAttachment: NSObject { do { let filePath = mediaUrl.path guard FileManager.default.fileExists(atPath: filePath) else { - owsFailDebug("asset at \(filePath) doesn't exist") return nil } @@ -298,7 +289,6 @@ public class SignalAttachment: NSObject { return image } catch let error { - Logger.verbose("Could not generate video thumbnail: \(error.localizedDescription)") return nil } } @@ -536,7 +526,6 @@ public class SignalAttachment: NSObject { for dataUTI in inputImageUTISet { if pasteboardUTISet.contains(dataUTI) { guard let data = dataForFirstPasteboardItem(dataUTI: dataUTI) else { - owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") return nil } let dataSource = DataSourceValue.dataSource(with: data, utiType: dataUTI) @@ -547,7 +536,6 @@ public class SignalAttachment: NSObject { for dataUTI in videoUTISet { if pasteboardUTISet.contains(dataUTI) { guard let data = dataForFirstPasteboardItem(dataUTI: dataUTI) else { - owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") return nil } let dataSource = DataSourceValue.dataSource(with: data, utiType: dataUTI) @@ -557,7 +545,6 @@ public class SignalAttachment: NSObject { for dataUTI in audioUTISet { if pasteboardUTISet.contains(dataUTI) { guard let data = dataForFirstPasteboardItem(dataUTI: dataUTI) else { - owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") return nil } let dataSource = DataSourceValue.dataSource(with: data, utiType: dataUTI) @@ -567,7 +554,6 @@ public class SignalAttachment: NSObject { let dataUTI = pasteboardUTISet[pasteboardUTISet.startIndex] guard let data = dataForFirstPasteboardItem(dataUTI: dataUTI) else { - owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") return nil } let dataSource = DataSourceValue.dataSource(with: data, utiType: dataUTI) @@ -579,11 +565,9 @@ public class SignalAttachment: NSObject { private class func dataForFirstPasteboardItem(dataUTI: String) -> Data? { let itemSet = IndexSet(integer: 0) guard let datas = UIPasteboard.general.data(forPasteboardType: dataUTI, inItemSet: itemSet) else { - owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") return nil } guard datas.count > 0 else { - owsFailDebug("Missing expected pasteboard data for UTI: \(dataUTI)") return nil } return datas[0] @@ -613,7 +597,6 @@ public class SignalAttachment: NSObject { } guard dataSource.dataLength() > 0 else { - owsFailDebug("imageData was empty") attachment.error = .invalidData return attachment } @@ -625,7 +608,6 @@ public class SignalAttachment: NSObject { } // Never re-encode animated images (i.e. GIFs) as JPEGs. - Logger.verbose("Sending raw \(attachment.mimeType) to retain any animation") return attachment } else { guard let image = UIImage(data: dataSource.data()) else { @@ -649,17 +631,14 @@ public class SignalAttachment: NSObject { // However the problem comes in when you edit an HEIC image in Photos.app - the image is saved // in the Photos.app as a JPEG, but retains the (now incongruous) HEIC extension in the filename. assert(dataUTI == kUTTypeJPEG as String || !isValidOutput) - Logger.verbose("changing extension: \(sourceFileExtension) to match jpg uti type") let baseFilename = sourceFilename.filenameWithoutExtension dataSource.sourceFilename = baseFilename.appendingFileExtension("jpg") } if isValidOutput { - Logger.verbose("Rewriting attachment with metadata removed \(attachment.mimeType)") return removeImageMetadata(attachment: attachment) } else { - Logger.verbose("Compressing attachment as image/jpeg, \(dataSource.dataLength()) bytes") return compressImageAsJPEG(image: image, attachment: attachment, filename: dataSource.sourceFilename, imageQuality: imageQuality) } } @@ -706,7 +685,6 @@ public class SignalAttachment: NSObject { let attachment = SignalAttachment(dataSource: dataSource, dataUTI: dataUTI) attachment.cachedImage = image - Logger.verbose("Writing \(attachment.mimeType) as image/jpeg") return compressImageAsJPEG(image: image, attachment: attachment, filename: filename, imageQuality: imageQuality) } @@ -751,7 +729,6 @@ public class SignalAttachment: NSObject { dataSource.dataLength() <= kMaxFileSizeImage { let recompressedAttachment = SignalAttachment(dataSource: dataSource, dataUTI: kUTTypeJPEG as String) recompressedAttachment.cachedImage = dstImage - Logger.verbose("Converted \(attachment.mimeType) to image/jpeg, \(jpgImageData.count) bytes") return recompressedAttachment } @@ -781,7 +758,6 @@ public class SignalAttachment: NSObject { // Resizing using a CGContext seems to work fine. private class func imageScaled(_ uiImage: UIImage, toMaxSize maxSize: CGFloat) -> UIImage? { guard let cgImage = uiImage.cgImage else { - owsFailDebug("UIImage missing cgImage.") return nil } @@ -804,7 +780,6 @@ public class SignalAttachment: NSObject { bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else { - owsFailDebug("could not create CGContext.") return nil } context.interpolationQuality = .high @@ -814,7 +789,6 @@ public class SignalAttachment: NSObject { context.draw(cgImage, in: drawRect) guard let newCGImage = context.makeImage() else { - owsFailDebug("could not create new CGImage.") return nil } return UIImage(cgImage: newCGImage, @@ -914,7 +888,6 @@ public class SignalAttachment: NSObject { return strippedAttachment } else { - Logger.verbose("CGImageDestinationFinalize failed") attachment.error = .couldNotRemoveMetadata return attachment } @@ -934,10 +907,6 @@ public class SignalAttachment: NSObject { return attachment } - if !isValidOutputVideo(dataSource: dataSource, dataUTI: dataUTI) { - owsFailDebug("building video with invalid output, migrate to async API using compressVideoAsMp4") - } - return newAttachment(dataSource: dataSource, dataUTI: dataUTI, validUTISet: videoUTISet, @@ -949,7 +918,6 @@ public class SignalAttachment: NSObject { OWSFileSystem.ensureDirectoryExists(baseDir.path) let toUrl = baseDir.appendingPathComponent(fromUrl.lastPathComponent) - Logger.debug("moving \(fromUrl) -> \(toUrl)") try FileManager.default.copyItem(at: fromUrl, to: toUrl) return toUrl @@ -962,8 +930,6 @@ public class SignalAttachment: NSObject { } public class func compressVideoAsMp4(dataSource: DataSource, dataUTI: String) -> (Promise, AVAssetExportSession?) { - Logger.debug("") - guard let url = dataSource.dataUrl() else { let attachment = SignalAttachment(dataSource: DataSourceValue.emptyDataSource(), dataUTI: dataUTI) attachment.error = .missingData @@ -987,15 +953,12 @@ public class SignalAttachment: NSObject { let (promise, resolver) = Promise.pending() - Logger.debug("starting video export") exportSession.exportAsynchronously { - Logger.debug("Completed video export") let baseFilename = dataSource.sourceFilename let mp4Filename = baseFilename?.filenameWithoutExtension.appendingFileExtension("mp4") guard let dataSource = DataSourcePath.dataSource(with: exportURL, shouldDeleteOnDeallocation: true) else { - owsFailDebug("Failed to build data source for exported video URL") let attachment = SignalAttachment(dataSource: DataSourceValue.emptyDataSource(), dataUTI: dataUTI) attachment.error = .couldNotConvertToMpeg4 resolver.fulfill(attachment) @@ -1120,9 +1083,6 @@ public class SignalAttachment: NSObject { // Check the attachment's error property. @objc public class func attachment(dataSource: DataSource?, dataUTI: String) -> SignalAttachment { - if inputImageUTISet.contains(dataUTI) { - owsFailDebug("must specify image quality type") - } return attachment(dataSource: dataSource, dataUTI: dataUTI, imageQuality: .original) } @@ -1175,7 +1135,6 @@ public class SignalAttachment: NSObject { } guard dataSource.dataLength() > 0 else { - owsFailDebug("Empty attachment") assert(dataSource.dataLength() > 0) attachment.error = .invalidData return attachment diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachment.h similarity index 88% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h rename to SessionMessagingKit/Sending & Receiving/Attachments/TSAttachment.h index 121a19be9..89f3b4aae 100644 --- a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.h +++ b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachment.h @@ -1,4 +1,5 @@ #import +#import NS_ASSUME_NONNULL_BEGIN @@ -87,6 +88,16 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { + (NSString *)emojiForMimeType:(NSString *)contentType; +#pragma mark - Media Album + +- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction; + +// `migrateAlbumMessageId` is only used in the migration to the new multi-attachment message scheme, +// and shouldn't be used as a general purpose setter. Instead, `albumMessageId` should be passed as +// an initializer param. +- (void)migrateAlbumMessageId:(NSString *)albumMesssageId; + + @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachment.m similarity index 94% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m rename to SessionMessagingKit/Sending & Receiving/Attachments/TSAttachment.m index 2a36909ee..e32418bdf 100644 --- a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachment.m +++ b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachment.m @@ -244,6 +244,21 @@ NSUInteger const TSAttachmentSchemaVersion = 4; return _contentType.filterFilename; } +#pragma mark - Media Album + +- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + if (self.albumMessageId == nil) { + return nil; + } + return [TSMessage fetchObjectWithUniqueID:self.albumMessageId transaction:transaction]; +} + +- (void)migrateAlbumMessageId:(NSString *)albumMesssageId +{ + self.albumMessageId = albumMesssageId; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Messaging/Attachments/Attachment+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Attachments/Attachment+Conversion.swift rename to SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer+Conversion.swift diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.h similarity index 100% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.h rename to SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.h diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.m similarity index 100% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentPointer.m rename to SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.m diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.h b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentStream.h similarity index 100% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.h rename to SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentStream.h diff --git a/SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.m b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentStream.m similarity index 100% rename from SessionMessagingKit/Messages/Visible Messages/Attachments/TSAttachmentStream.m rename to SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentStream.m diff --git a/SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.h b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.h rename to SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h diff --git a/SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.m b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m similarity index 99% rename from SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.m rename to SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m index 34a1767f4..cdb20550c 100644 --- a/SignalUtilitiesKit/Messaging/Blocking/OWSBlockingManager.m +++ b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m @@ -11,7 +11,7 @@ #import "TSContactThread.h" #import "TSGroupThread.h" #import "YapDatabaseConnection+OWS.h" -#import +#import #import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.h b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.h similarity index 94% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.h rename to SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.h index 18d61e452..347c2f80e 100644 --- a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.h +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.m b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.m similarity index 95% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.m rename to SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.m index 27c7add0b..3b1c7250b 100644 --- a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingConfigurationUpdateInfoMessage.m +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.m @@ -5,7 +5,7 @@ #import "OWSDisappearingConfigurationUpdateInfoMessage.h" #import "NSString+SSK.h" #import "OWSDisappearingMessagesConfiguration.h" -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -34,8 +34,6 @@ NS_ASSUME_NONNULL_BEGIN _configurationDurationSeconds = configuration.durationSeconds; // At most one should be set - OWSAssertDebug(!remoteName || !createdInExistingGroup); - _createdByRemoteName = remoteName; _createdInExistingGroup = createdInExistingGroup; @@ -52,7 +50,6 @@ NS_ASSUME_NONNULL_BEGIN -(NSString *)previewTextWithTransaction:(YapDatabaseReadTransaction *)transaction { if (self.createdInExistingGroup) { - OWSAssertDebug(self.configurationIsEnabled && self.configurationDurationSeconds > 0); NSString *infoFormat = NSLocalizedString(@"DISAPPEARING_MESSAGES_CONFIGURATION_GROUP_EXISTING_FORMAT", @"Info Message when added to a group which has enabled disappearing messages. Embeds {{time amount}} " @"before messages disappear, see the *_TIME_AMOUNT strings for context."); diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.h similarity index 96% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h rename to SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.h index 3b1c12e19..dfbee9b3a 100644 --- a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.h +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.h @@ -3,6 +3,7 @@ // #import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.m b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.m similarity index 95% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.m rename to SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.m index 4422da013..88e0ee576 100644 --- a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesConfiguration.m +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.m @@ -4,7 +4,8 @@ #import "OWSDisappearingMessagesConfiguration.h" #import "NSString+SSK.h" -#import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -85,9 +86,6 @@ NS_ASSUME_NONNULL_BEGIN static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ max = [[self.validDurationsSeconds valueForKeyPath:@"@max.intValue"] unsignedIntValue]; - - // It's safe to update this assert if we add a larger duration - OWSAssertDebug(max == 1 * kWeekInterval); }); return max; diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.h b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.h rename to SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.h diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.m b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.m similarity index 99% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.m rename to SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.m index ee95b421c..8ebcadb59 100644 --- a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesJob.m +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.m @@ -15,7 +15,7 @@ #import "TSMessage.h" #import "TSThread.h" #import -#import +#import #import #import "SSKAsserts.h" diff --git a/SignalUtilitiesKit/Messaging/Link Previews/OWSLinkPreview.swift b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview.swift similarity index 88% rename from SignalUtilitiesKit/Messaging/Link Previews/OWSLinkPreview.swift rename to SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview.swift index a5e6260b8..f134d9971 100644 --- a/SignalUtilitiesKit/Messaging/Link Previews/OWSLinkPreview.swift +++ b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview.swift @@ -2,6 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // +import AFNetworking import Foundation import PromiseKit @@ -138,29 +139,23 @@ public class OWSLinkPreview: MTLModel { throw LinkPreviewError.noPreview } guard dataMessage.attachments.count < 1 else { - Logger.error("Discarding link preview; message has attachments.") throw LinkPreviewError.invalidInput } let urlString = previewProto.url guard URL(string: urlString) != nil else { - Logger.error("Could not parse preview URL.") throw LinkPreviewError.invalidInput } guard let body = body else { - Logger.error("Preview for message without body.") throw LinkPreviewError.invalidInput } let previewUrls = allPreviewUrls(forMessageBodyText: body) guard previewUrls.contains(urlString) else { - Logger.error("URL not present in body.") throw LinkPreviewError.invalidInput } guard isValidLinkUrl(urlString) else { - Logger.verbose("Invalid link URL \(urlString).") - Logger.error("Invalid link URL.") throw LinkPreviewError.invalidInput } @@ -178,7 +173,6 @@ public class OWSLinkPreview: MTLModel { imageAttachmentPointer.save(with: transaction) imageAttachmentId = imageAttachmentPointer.uniqueId } else { - Logger.error("Could not parse image proto.") throw LinkPreviewError.invalidInput } } @@ -186,7 +180,6 @@ public class OWSLinkPreview: MTLModel { let linkPreview = OWSLinkPreview(urlString: urlString, title: title, imageAttachmentId: imageAttachmentId) guard linkPreview.isValid() else { - Logger.error("Preview has neither title nor image.") throw LinkPreviewError.invalidInput } @@ -208,7 +201,6 @@ public class OWSLinkPreview: MTLModel { let linkPreview = OWSLinkPreview(urlString: info.urlString, title: info.title, imageAttachmentId: imageAttachmentId) guard linkPreview.isValid() else { - owsFailDebug("Preview has neither title nor image.") throw LinkPreviewError.invalidInput } @@ -225,7 +217,6 @@ public class OWSLinkPreview: MTLModel { let fileSize = imageData.count guard fileSize > 0 else { - owsFailDebug("Invalid file size for image data.") return nil } @@ -234,17 +225,14 @@ public class OWSLinkPreview: MTLModel { do { try imageData.write(to: NSURL.fileURL(withPath: filePath), options: .atomicWrite) } catch let error as NSError { - owsFailDebug("file write failed: \(filePath), \(error)") return nil } guard let dataSource = DataSourcePath.dataSource(withFilePath: filePath, shouldDeleteOnDeallocation: true) else { - owsFailDebug("Could not create data source for path: \(filePath)") return nil } let attachment = TSAttachmentStream(contentType: mimeType, byteCount: UInt32(fileSize), sourceFilename: nil, caption: nil, albumMessageId: nil) guard attachment.write(dataSource) else { - owsFailDebug("Could not write data source for path: \(filePath)") return nil } attachment.save(with: transaction) @@ -264,11 +252,9 @@ public class OWSLinkPreview: MTLModel { @objc public func removeAttachment(transaction: YapDatabaseReadWriteTransaction) { guard let imageAttachmentId = imageAttachmentId else { - owsFailDebug("No attachment id.") return } guard let attachment = TSAttachment.fetch(uniqueId: imageAttachmentId, transaction: transaction) else { - owsFailDebug("Could not load attachment.") return } attachment.remove(with: transaction) @@ -376,18 +362,15 @@ public class OWSLinkPreview: MTLModel { @objc public class func displayDomain(forUrl urlString: String?) -> String? { guard let urlString = urlString else { - owsFailDebug("Missing url.") return nil } guard let url = URL(string: urlString) else { - owsFailDebug("Invalid url.") return nil } guard let result = whitelistedDomain(forUrl: url, domainWhitelist: OWSLinkPreview.linkDomainWhitelist, allowSubdomains: false) else { - Logger.error("Missing domain.") - return nil + return nil } return result } @@ -443,12 +426,6 @@ public class OWSLinkPreview: MTLModel { private static let serialQueue = DispatchQueue(label: "org.signal.linkPreview") - private class func assertIsOnSerialQueue() { - if _isDebugAssertConfiguration(), #available(iOS 10.0, *) { - assertOnQueue(serialQueue) - } - } - // MARK: - Text Parsing // This cache should only be accessed on main thread. @@ -465,7 +442,6 @@ public class OWSLinkPreview: MTLModel { } public class func previewUrl(forMessageBodyText body: String?, selectedRange: NSRange?) -> String? { - AssertIsOnMainThread() // Exit early if link previews are not enabled in order to avoid // tainting the cache. @@ -482,7 +458,6 @@ public class OWSLinkPreview: MTLModel { } if let cachedUrl = previewUrlCache.object(forKey: body as NSString) as String? { - Logger.verbose("URL parsing cache hit.") guard cachedUrl.count > 0 else { return nil } @@ -496,16 +471,13 @@ public class OWSLinkPreview: MTLModel { } if let selectedRange = selectedRange { - Logger.verbose("match: urlString: \(urlMatch.urlString) range: \(urlMatch.matchRange) selectedRange: \(selectedRange)") let cursorAtEndOfMatch = urlMatch.matchRange.location + urlMatch.matchRange.length == selectedRange.location if selectedRange.location != body.count, (urlMatch.matchRange.intersection(selectedRange) != nil || cursorAtEndOfMatch) { - Logger.debug("ignoring URL, since the user is currently editing it.") // we don't want to cache the result here, as we want to fetch the link preview // if the user moves the cursor. return nil } - Logger.debug("considering URL, since the user is not currently editing it.") } previewUrlCache.setObject(urlMatch.urlString as NSString, forKey: body as NSString) @@ -533,7 +505,6 @@ public class OWSLinkPreview: MTLModel { do { detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) } catch { - owsFailDebug("Could not create NSDataDetector: \(error).") return [] } @@ -541,7 +512,6 @@ public class OWSLinkPreview: MTLModel { let matches = detector.matches(in: body, options: [], range: NSRange(location: 0, length: body.count)) for match in matches { guard let matchURL = match.url else { - owsFailDebug("Match missing url") continue } let urlString = matchURL.absoluteString @@ -564,10 +534,8 @@ public class OWSLinkPreview: MTLModel { return serialQueue.sync { guard let linkPreviewDraft = linkPreviewDraftCache, linkPreviewDraft.urlString == previewUrl else { - Logger.verbose("----- Cache miss.") return nil } - Logger.verbose("----- Cache hit.") return linkPreviewDraft } } @@ -606,7 +574,6 @@ public class OWSLinkPreview: MTLModel { return Promise(error: LinkPreviewError.invalidInput) } if let cachedInfo = cachedLinkPreview(forPreviewUrl: previewUrl) { - Logger.verbose("Link preview info cache hit.") return Promise.value(cachedInfo) } return downloadLink(url: previewUrl) @@ -624,9 +591,6 @@ public class OWSLinkPreview: MTLModel { class func downloadLink(url urlString: String, remainingRetries: UInt = 3) -> Promise { - - Logger.verbose("url: \(urlString)") - // let sessionConfiguration = ContentProxy.sessionConfiguration() // Loki: Signal's proxy appears to have been banned by YouTube let sessionConfiguration = URLSessionConfiguration.ephemeral @@ -640,7 +604,6 @@ public class OWSLinkPreview: MTLModel { sessionManager.responseSerializer = AFHTTPResponseSerializer() guard ContentProxy.configureSessionManager(sessionManager: sessionManager, forUrl: urlString) else { - owsFailDebug("Could not configure url: \(urlString).") return Promise(error: LinkPreviewError.assertionFailure) } @@ -652,40 +615,32 @@ public class OWSLinkPreview: MTLModel { success: { task, value in guard let response = task.response as? HTTPURLResponse else { - Logger.warn("Invalid response: \(type(of: task.response)).") resolver.reject(LinkPreviewError.assertionFailure) return } if let contentType = response.allHeaderFields["Content-Type"] as? String { guard contentType.lowercased().hasPrefix("text/") else { - Logger.warn("Invalid content type: \(contentType).") resolver.reject(LinkPreviewError.invalidContent) return } } guard let data = value as? Data else { - Logger.warn("Result is not data: \(type(of: value)).") resolver.reject(LinkPreviewError.assertionFailure) return } guard data.count > 0 else { - Logger.warn("Empty data: \(type(of: value)).") resolver.reject(LinkPreviewError.invalidContent) return } resolver.fulfill(data) }, failure: { _, error in - Logger.verbose("Error: \(error)") - guard isRetryable(error: error) else { - Logger.warn("Error is not retryable.") resolver.reject(LinkPreviewError.couldNotDownload) return } guard remainingRetries > 0 else { - Logger.warn("No more retries.") resolver.reject(LinkPreviewError.couldNotDownload) return } @@ -700,16 +655,11 @@ public class OWSLinkPreview: MTLModel { } private class func downloadImage(url urlString: String, imageMimeType: String) -> Promise { - - Logger.verbose("url: \(urlString)") - guard let url = URL(string: urlString) else { - Logger.error("Could not parse URL.") return Promise(error: LinkPreviewError.invalidInput) } guard let assetDescription = ProxiedContentAssetDescription(url: url as NSURL) else { - Logger.error("Could not create asset description.") return Promise(error: LinkPreviewError.invalidInput) } let (promise, resolver) = Promise.pending() @@ -719,7 +669,6 @@ public class OWSLinkPreview: MTLModel { success: { (_, asset) in resolver.fulfill(asset) }, failure: { (_) in - Logger.warn("Error downloading asset") resolver.reject(LinkPreviewError.couldNotDownload) }) } @@ -727,13 +676,11 @@ public class OWSLinkPreview: MTLModel { do { let imageSize = NSData.imageSize(forFilePath: asset.filePath, mimeType: imageMimeType) guard imageSize.width > 0, imageSize.height > 0 else { - Logger.error("Link preview is invalid or has invalid size.") return Promise(error: LinkPreviewError.invalidContent) } let data = try Data(contentsOf: URL(fileURLWithPath: asset.filePath)) guard let srcImage = UIImage(data: data) else { - Logger.error("Could not parse image.") return Promise(error: LinkPreviewError.invalidContent) } @@ -744,23 +691,19 @@ public class OWSLinkPreview: MTLModel { let shouldResize = imageSize.width > maxImageSize || imageSize.height > maxImageSize guard shouldResize else { guard let dstData = srcImage.jpegData(compressionQuality: 0.8) else { - Logger.error("Could not write resized image.") return Promise(error: LinkPreviewError.invalidContent) } return Promise.value(dstData) } guard let dstImage = srcImage.resized(withMaxDimensionPoints: maxImageSize) else { - Logger.error("Could not resize image.") return Promise(error: LinkPreviewError.invalidContent) } guard let dstData = dstImage.jpegData(compressionQuality: 0.8) else { - Logger.error("Could not write resized image.") return Promise(error: LinkPreviewError.invalidContent) } return Promise.value(dstData) } catch { - owsFailDebug("Could not load asset data: \(type(of: asset.filePath)).") return Promise(error: LinkPreviewError.assertionFailure) } } @@ -786,15 +729,12 @@ public class OWSLinkPreview: MTLModel { } guard isValidMediaUrl(imageUrl) else { - Logger.error("Invalid image URL.") return Promise.value(OWSLinkPreviewDraft(urlString: linkUrlString, title: title)) } guard let imageFileExtension = fileExtension(forImageUrl: imageUrl) else { - Logger.error("Image URL has unknown or invalid file extension: \(imageUrl).") return Promise.value(OWSLinkPreviewDraft(urlString: linkUrlString, title: title)) } guard let imageMimeType = mimetype(forImageFileExtension: imageFileExtension) else { - Logger.error("Image URL has unknown or invalid content type: \(imageUrl).") return Promise.value(OWSLinkPreviewDraft(urlString: linkUrlString, title: title)) } @@ -808,7 +748,6 @@ public class OWSLinkPreview: MTLModel { return Promise.value(OWSLinkPreviewDraft(urlString: linkUrlString, title: title)) } } catch { - owsFailDebug("Could not parse link data: \(error).") return Promise(error: error) } } @@ -819,7 +758,6 @@ public class OWSLinkPreview: MTLModel { // class func parse(linkData: Data) throws -> OWSLinkPreviewContents { guard let linkText = String(bytes: linkData, encoding: .utf8) else { - owsFailDebug("Could not parse link text.") throw LinkPreviewError.invalidInput } @@ -835,8 +773,6 @@ public class OWSLinkPreview: MTLModel { } } - Logger.verbose("title: \(String(describing: title))") - guard let rawImageUrlString = NSRegularExpression.parseFirstMatch(pattern: "]*content\\s*=\\s*\"(.*?)\"[^>]*/?>", text: linkText) else { return OWSLinkPreviewContents(title: title) } @@ -849,7 +785,6 @@ public class OWSLinkPreview: MTLModel { class func fileExtension(forImageUrl urlString: String) -> String? { guard let imageUrl = URL(string: urlString) else { - Logger.error("Could not parse image URL.") return nil } let imageFilename = imageUrl.lastPathComponent @@ -874,7 +809,6 @@ public class OWSLinkPreview: MTLModel { return nil } guard let imageMimeType = MIMETypeUtil.mimeType(forFileExtension: imageFileExtension) else { - Logger.error("Image URL has unknown content type: \(imageFileExtension).") return nil } let kValidMimeTypes = [ @@ -883,7 +817,6 @@ public class OWSLinkPreview: MTLModel { OWSMimeTypeImageGif, ] guard kValidMimeTypes.contains(imageMimeType) else { - Logger.error("Image URL has invalid content type: \(imageMimeType).") return nil } return imageMimeType diff --git a/SignalUtilitiesKit/Messaging/Mentions/Mention.swift b/SessionMessagingKit/Sending & Receiving/Mentions/Mention.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Mentions/Mention.swift rename to SessionMessagingKit/Sending & Receiving/Mentions/Mention.swift diff --git a/SignalUtilitiesKit/Messaging/Mentions/MentionsManager.swift b/SessionMessagingKit/Sending & Receiving/Mentions/MentionsManager.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Mentions/MentionsManager.swift rename to SessionMessagingKit/Sending & Receiving/Mentions/MentionsManager.swift diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift similarity index 73% rename from SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift rename to SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index bb72e8bac..8bd51b568 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -1,37 +1,35 @@ -import SessionMessagingKit +import SessionProtocolKit +import SignalCoreKit -public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiverDelegate { +extension MessageReceiver { - public static let shared = MessageReceiverDelegate() - - - - // MARK: - Blocking - - public func isBlocked(_ publicKey: String) -> Bool { + internal static func isBlocked(_ publicKey: String) -> Bool { return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey) } - - - // MARK: - Profiles - - public func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) { - let transaction = transaction as! YapDatabaseReadWriteTransaction - let profileManager = SSKEnvironment.shared.profileManager - if let displayName = profile.displayName { - profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) - } - if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { - profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) + internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { + switch message { + case let message as ReadReceipt: handleReadReceipt(message, using: transaction) + case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) + case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) + case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) + case let message as VisibleMessage: try handleVisibleMessage(message, associatedWithProto: proto, using: transaction) + default: fatalError() } } + private static func handleReadReceipt(_ message: ReadReceipt, using transaction: Any) { + SSKEnvironment.shared.readReceiptManager.processReadReceipts(fromRecipientId: message.sender!, sentTimestamps: message.timestamps!.map { NSNumber(value: $0) }, readTimestamp: message.receivedTimestamp!) + } + private static func handleTypingIndicator(_ message: TypingIndicator, using transaction: Any) { + switch message.kind! { + case .started: showTypingIndicatorIfNeeded(for: message.sender!) + case .stopped: hideTypingIndicatorIfNeeded(for: message.sender!) + } + } - // MARK: - Typing Indicators - - public func showTypingIndicatorIfNeeded(for senderPublicKey: String) { + public static func showTypingIndicatorIfNeeded(for senderPublicKey: String) { var threadOrNil: TSContactThread? Storage.read { transaction in threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) @@ -49,7 +47,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver } } - public func hideTypingIndicatorIfNeeded(for senderPublicKey: String) { + public static func hideTypingIndicatorIfNeeded(for senderPublicKey: String) { var threadOrNil: TSContactThread? Storage.read { transaction in threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) @@ -67,7 +65,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver } } - public func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) { + public static func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) { var threadOrNil: TSContactThread? Storage.read { transaction in threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) @@ -85,30 +83,15 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver } } - - - // MARK: - Notifications - - public func notifyUserIfNeeded(forMessageWithID messageID: String, threadID: String) { - guard let message = TSIncomingMessage.fetch(uniqueId: messageID), let thread = TSThread.fetch(uniqueId: threadID) else { return } - Storage.read { transaction in - SSKEnvironment.shared.notificationsManager!.notifyUser(for: message, in: thread, transaction: transaction) + private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) { + if message.duration! > 0 { + setExpirationTimer(to: message.duration!, for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) + } else { + disableExpirationTimer(for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) } } - - - // MARK: - Read Receipts - - public func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) { - SSKEnvironment.shared.readReceiptManager.processReadReceipts(fromRecipientId: senderPublicKey, sentTimestamps: timestamps.map { NSNumber(value: $0) }, readTimestamp: timestamp) - } - - - - // MARK: - Expiration - - public func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { + public static func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction var threadOrNil: TSThread? Storage.read { transaction in @@ -130,7 +113,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() } - public func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { + public static func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction var threadOrNil: TSThread? Storage.read { transaction in @@ -152,11 +135,59 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() } + private static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { + let storage = Configuration.shared.storage + let transaction = transaction as! YapDatabaseReadWriteTransaction + // Parse & persist attachments + let attachments: [VisibleMessage.Attachment] = proto.dataMessage!.attachments.compactMap { proto in + guard let attachment = VisibleMessage.Attachment.fromProto(proto) else { return nil } + return attachment.isValid ? attachment : nil + } + let attachmentIDs = storage.persist(attachments, using: transaction) + message.attachmentIDs = attachmentIDs + // Update profile if needed + if let profile = message.profile { + let profileManager = SSKEnvironment.shared.profileManager + if let displayName = profile.displayName { + profileManager.updateProfileForContact(withID: message.sender!, displayName: displayName, with: transaction) + } + if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { + profileManager.setProfileKeyData(profileKey, forRecipientId: message.sender!, avatarURL: profilePictureURL) + } + } + // Persist the message + guard let (threadID, tsIncomingMessageID) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + message.threadID = threadID + // Start attachment downloads if needed + storage.withAsync({ transaction in + attachmentIDs.forEach { attachmentID in + let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) + if CurrentAppContext().isMainAppAndActive { + JobQueue.shared.add(downloadJob, using: transaction) + } else { + JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) + } + } + }, completion: { }) + // Cancel any typing indicators + cancelTypingIndicatorsIfNeeded(for: message.sender!) + // Notify the user if needed + guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID), let thread = TSThread.fetch(uniqueId: threadID) else { return } + Storage.read { transaction in + SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction) + } + } + private static func handleClosedGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { + switch message.kind! { + case .new: handleNewGroup(message, using: transaction) + case .info: handleGroupUpdate(message, using: transaction) + case .senderKeyRequest: handleSenderKeyRequest(message, using: transaction) + case .senderKey: handleSenderKey(message, using: transaction) + } + } - // MARK: - Closed Groups - - public func handleNewGroup(_ message: ClosedGroupUpdate, using transaction: Any) { + private static func handleNewGroup(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .new(groupPublicKeyAsData, name, groupPrivateKey, senderKeys, membersAsData, adminsAsData) = message.kind else { return } let transaction = transaction as! YapDatabaseReadWriteTransaction let groupPublicKey = groupPublicKeyAsData.toHexString() @@ -185,7 +216,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver } } missingSenderKeys.subtracting([ userPublicKey ]).forEach { publicKey in - MessageSenderDelegate.shared.requestSenderKey(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + MessageSender.shared.requestSenderKey(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) } // Create the group let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) @@ -208,7 +239,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver infoMessage.save(with: transaction) } - public func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { + private static func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .info(groupPublicKeyAsData, name, senderKeys, membersAsData, adminsAsData) = message.kind else { return } let transaction = transaction as! YapDatabaseReadWriteTransaction let groupPublicKey = groupPublicKeyAsData.toHexString() @@ -272,7 +303,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver } } - public func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) { + private static func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .senderKeyRequest(groupPublicKeyAsData) = message.kind else { return } let transaction = transaction as! YapDatabaseReadWriteTransaction let userPublicKey = getUserHexEncodedPublicKey() @@ -300,7 +331,7 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver MessageSender.send(closedGroupUpdate, in: thread, using: transaction) } - public func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) { + private static func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) { guard case let .senderKey(groupPublicKeyAsData, senderKey) = message.kind else { return } let groupPublicKey = groupPublicKeyAsData.toHexString() guard senderKey.publicKey.toHexString() == message.sender! else { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 7da27586b..ced2e30ae 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -2,7 +2,6 @@ import SessionUtilitiesKit internal enum MessageReceiver { - // MARK: Error internal enum Error : LocalizedError { case invalidMessage case unknownMessage @@ -42,7 +41,6 @@ internal enum MessageReceiver { } } - // MARK: Parsing internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { let userPublicKey = Configuration.shared.storage.getUserPublicKey() // Parse the envelope @@ -59,7 +57,7 @@ internal enum MessageReceiver { default: throw Error.unknownEnvelopeType } // Don't process the envelope any further if the sender is blocked - guard !Configuration.shared.messageReceiverDelegate.isBlocked(sender) else { throw Error.senderBlocked } + guard !isBlocked(sender) else { throw Error.senderBlocked } // Ignore self sends guard sender != userPublicKey else { throw Error.selfSend } // Parse the proto @@ -92,81 +90,4 @@ internal enum MessageReceiver { throw Error.unknownMessage } } - - // MARK: Handling - internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { - switch message { - case let message as ReadReceipt: handleReadReceipt(message, using: transaction) - case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) - case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) - case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) - case let message as VisibleMessage: try handleVisibleMessage(message, associatedWithProto: proto, using: transaction) - default: fatalError() - } - } - - private static func handleReadReceipt(_ message: ReadReceipt, using transaction: Any) { - Configuration.shared.messageReceiverDelegate.markMessagesAsRead(message.timestamps!, from: message.sender!, at: message.receivedTimestamp!) - } - - private static func handleTypingIndicator(_ message: TypingIndicator, using transaction: Any) { - let delegate = Configuration.shared.messageReceiverDelegate - switch message.kind! { - case .started: delegate.showTypingIndicatorIfNeeded(for: message.sender!) - case .stopped: delegate.hideTypingIndicatorIfNeeded(for: message.sender!) - } - } - - private static func handleClosedGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { - let delegate = Configuration.shared.messageReceiverDelegate - switch message.kind! { - case .new: delegate.handleNewGroup(message, using: transaction) - case .info: delegate.handleGroupUpdate(message, using: transaction) - case .senderKeyRequest: delegate.handleSenderKeyRequest(message, using: transaction) - case .senderKey: delegate.handleSenderKey(message, using: transaction) - } - } - - private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) { - let delegate = Configuration.shared.messageReceiverDelegate - if message.duration! > 0 { - delegate.setExpirationTimer(to: message.duration!, for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) - } else { - delegate.disableExpirationTimer(for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) - } - } - - private static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { - let delegate = Configuration.shared.messageReceiverDelegate - let storage = Configuration.shared.storage - // Parse & persist attachments - let attachments: [VisibleMessage.Attachment] = proto.dataMessage!.attachments.compactMap { proto in - guard let attachment = VisibleMessage.Attachment.fromProto(proto) else { return nil } - return attachment.isValid ? attachment : nil - } - let attachmentIDs = storage.persist(attachments, using: transaction) - message.attachmentIDs = attachmentIDs - // Update profile if needed - if let profile = message.profile { - delegate.updateProfile(for: message.sender!, from: profile, using: transaction) - } - // Persist the message - guard let (threadID, tsIncomingMessageID) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } - message.threadID = threadID - // Start attachment downloads if needed - storage.withAsync({ transaction in - attachmentIDs.forEach { attachmentID in - let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) - if CurrentAppContext().isMainAppAndActive { - JobQueue.shared.add(downloadJob, using: transaction) - } else { - JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) - } - } - }, completion: { }) - // Cancel any typing indicators - delegate.cancelTypingIndicatorsIfNeeded(for: message.sender!) - // Notify the user if needed - delegate.notifyUserIfNeeded(forMessageWithID: tsIncomingMessageID, threadID: threadID) - } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift deleted file mode 100644 index 4ac94717d..000000000 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiverDelegate.swift +++ /dev/null @@ -1,17 +0,0 @@ - -public protocol MessageReceiverDelegate { - - func isBlocked(_ publicKey: String) -> Bool - func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) - func showTypingIndicatorIfNeeded(for senderPublicKey: String) - func hideTypingIndicatorIfNeeded(for senderPublicKey: String) - func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String) - func notifyUserIfNeeded(forMessageWithID messageID: String, threadID: String) - func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) - func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) - func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) - func handleNewGroup(_ message: ClosedGroupUpdate, using transaction: Any) - func handleGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) - func handleSenderKeyRequest(_ message: ClosedGroupUpdate, using transaction: Any) - func handleSenderKey(_ message: ClosedGroupUpdate, using transaction: Any) -} diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index f31f00162..dabf06e6e 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -11,10 +11,14 @@ public final class MessageSender : NSObject { case protoConversionFailed case proofOfWorkCalculationFailed case noUserPublicKey + // Closed groups + case noThread + case noPrivateKey + case invalidClosedGroupUpdate internal var isRetryable: Bool { switch self { - case .invalidMessage, .protoConversionFailed, .proofOfWorkCalculationFailed: return false + case .invalidMessage, .protoConversionFailed, .proofOfWorkCalculationFailed, .invalidClosedGroupUpdate: return false default: return true } } @@ -25,6 +29,10 @@ public final class MessageSender : NSObject { case .protoConversionFailed: return "Couldn't convert message to proto." case .proofOfWorkCalculationFailed: return "Proof of work calculation failed." case .noUserPublicKey: return "Couldn't find user key pair." + // Closed groups + case .noThread: return "Couldn't find a thread associated with the given group public key." + case .noPrivateKey: return "Couldn't find a private key associated with the given group public key." + case .invalidClosedGroupUpdate: return "Invalid group update." } } } @@ -32,6 +40,8 @@ public final class MessageSender : NSObject { // MARK: Initialization private override init() { } + public static let shared = MessageSender() // FIXME: Remove once requestSenderKey is static + // MARK: Convenience public static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise { switch destination { @@ -56,7 +66,7 @@ public final class MessageSender : NSObject { // Set the failure handler (for precondition failure handling) let _ = promise.catch(on: DispatchQueue.main) { error in storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) + MessageSender.handleFailedMessageSend(message, with: error, using: transaction) }, completion: { }) if case .contact(_) = destination { NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) @@ -157,7 +167,7 @@ public final class MessageSender : NSObject { // Handle completion let _ = promise.done(on: DispatchQueue.main) { storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) + MessageSender.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) if case .contact(_) = destination { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) @@ -186,7 +196,7 @@ public final class MessageSender : NSObject { // Set the failure handler (for precondition failure handling) let _ = promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleFailedMessageSend(message, with: error, using: transaction) + MessageSender.handleFailedMessageSend(message, with: error, using: transaction) }, completion: { }) } // Validate the message @@ -210,10 +220,23 @@ public final class MessageSender : NSObject { // Handle completion let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { storage.withAsync({ transaction in - Configuration.shared.messageSenderDelegate.handleSuccessfulMessageSend(message, using: transaction) + MessageSender.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) } // Return return promise } + + // MARK: Result Handling + public static func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 + tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 + tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) + } + + public static func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction) + } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift b/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift deleted file mode 100644 index 1f1cc0969..000000000 --- a/SessionMessagingKit/Sending & Receiving/MessageSenderDelegate.swift +++ /dev/null @@ -1,6 +0,0 @@ - -public protocol MessageSenderDelegate { - - func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) - func handleFailedMessageSend(_ message: Message, with error: Error, using transaction: Any) -} diff --git a/SignalUtilitiesKit/NotificationsProtocol.h b/SessionMessagingKit/Sending & Receiving/Notifications/NotificationsProtocol.h similarity index 100% rename from SignalUtilitiesKit/NotificationsProtocol.h rename to SessionMessagingKit/Sending & Receiving/Notifications/NotificationsProtocol.h diff --git a/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift similarity index 99% rename from SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift rename to SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift index 560440b66..a7076ad8c 100644 --- a/SignalUtilitiesKit/Messaging/Notifications/PushNotificationAPI.swift +++ b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift @@ -1,3 +1,4 @@ +import SessionSnodeKit import PromiseKit @objc(LKPushNotificationAPI) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift similarity index 95% rename from SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift rename to SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift index d8effed4e..ca2ae693e 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/ClosedGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift @@ -1,3 +1,4 @@ +import SessionSnodeKit import PromiseKit @objc(LKClosedGroupPoller) @@ -23,7 +24,9 @@ public final class ClosedGroupPoller : NSObject { // MARK: Public API @objc public func startIfNeeded() { - AssertIsOnMainThread() // Timers don't do well on background queues + #if DEBUG + assert(Thread.current.isMainThread) // Timers don't do well on background queues + #endif guard !isPolling else { return } isPolling = true timer = Timer.scheduledTimer(withTimeInterval: ClosedGroupPoller.pollInterval, repeats: true) { [weak self] _ in diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift similarity index 97% rename from SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupPoller.swift rename to SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index bae1a244a..5dccd17da 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -162,10 +162,10 @@ public final class OpenGroupPoller : NSObject { private func pollForDeletedMessages() { let openGroup = self.openGroup let _ = OpenGroupAPI.getDeletedMessageServerIDs(for: openGroup.channel, on: openGroup.server).done(on: DispatchQueue.global(qos: .default)) { deletedMessageServerIDs in + let deletedMessageIDs = deletedMessageServerIDs.compactMap { Storage.shared.getIDForMessage(withServerID: UInt64($0)) } Storage.writeSync { transaction in - let deletedMessageIDs = deletedMessageServerIDs.compactMap { OWSPrimaryStorage.shared().getIDForMessage(withServerID: UInt($0), in: transaction) } deletedMessageIDs.forEach { messageID in - TSMessage.fetch(uniqueId: messageID)?.remove(with: transaction) + TSMessage.fetch(uniqueId: String(messageID))?.remove(with: transaction) } } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift similarity index 99% rename from SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift rename to SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift index c02223ceb..082e3a7fc 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/Poller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift @@ -1,3 +1,4 @@ +import SessionSnodeKit import PromiseKit @objc(LKPoller) diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift new file mode 100644 index 000000000..3c932b16b --- /dev/null +++ b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift @@ -0,0 +1,13 @@ + +extension VisibleMessage.Quote { + + @objc(from:) + public static func from(_ quote: OWSQuotedReplyModel?) -> VisibleMessage.Quote? { + guard let quote = quote else { return nil } + let result = VisibleMessage.Quote() + result.timestamp = quote.timestamp + result.publicKey = quote.authorId + result.text = quote.body + return result + } +} diff --git a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.h similarity index 96% rename from SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h rename to SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.h index d478b1bd2..44dc4be9c 100644 --- a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h +++ b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.h @@ -2,7 +2,8 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m similarity index 92% rename from SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m rename to SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m index 3ea9a8420..2505ae6ee 100644 --- a/SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m +++ b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m @@ -4,16 +4,15 @@ #import "OWSQuotedReplyModel.h" #import "ConversationViewItem.h" -#import #import -#import +#import #import #import -#import -#import -#import -#import -#import +#import +#import +#import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -78,7 +77,6 @@ NS_ASSUME_NONNULL_BEGIN threadId:(NSString *)threadId transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(quotedMessage.quotedAttachments.count <= 1); OWSAttachmentInfo *attachmentInfo = quotedMessage.quotedAttachments.firstObject; BOOL thumbnailDownloadFailed = NO; @@ -123,17 +121,12 @@ NS_ASSUME_NONNULL_BEGIN threadId:(NSString *)threadId transaction:(YapDatabaseReadTransaction *)transaction; { - OWSAssertDebug(conversationItem); - OWSAssertDebug(transaction); - TSMessage *message = (TSMessage *)conversationItem.interaction; if (![message isKindOfClass:[TSMessage class]]) { - OWSFailDebug(@"unexpected reply message: %@", message); return nil; } TSThread *thread = [message threadWithTransaction:transaction]; - OWSAssertDebug(thread); uint64_t timestamp = message.timestamp; @@ -143,11 +136,9 @@ NS_ASSUME_NONNULL_BEGIN } else if ([message isKindOfClass:[TSIncomingMessage class]]) { return [(TSIncomingMessage *)message authorId]; } else { - OWSFailDebug(@"Unexpected message type: %@", message.class); return (NSString * _Nullable) nil; } }(); - OWSAssertDebug(authorId.length > 0); NSString *_Nullable quotedText = message.body; BOOL hasText = quotedText.length > 0; @@ -192,8 +183,6 @@ NS_ASSUME_NONNULL_BEGIN } if ([truncatedText dataUsingEncoding:NSUTF8StringEncoding].length < kOversizeTextMessageSizeThreshold) { quotedText = truncatedText; - } else { - OWSFailDebug(@"Missing valid text snippet."); } } } else { @@ -209,7 +198,6 @@ NS_ASSUME_NONNULL_BEGIN BOOL hasAttachment = quotedAttachment != nil; if (!hasText && !hasAttachment) { - OWSFailDebug(@"quoted message has neither text nor attachment"); quotedText = @""; hasText = YES; } diff --git a/SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift similarity index 51% rename from SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift rename to SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift index e7bee2c4c..1d018b5a4 100644 --- a/SignalUtilitiesKit/Messaging/Quotes/Quote+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift @@ -1,17 +1,4 @@ -extension VisibleMessage.Quote { - - @objc(from:) - public static func from(_ quote: OWSQuotedReplyModel?) -> VisibleMessage.Quote? { - guard let quote = quote else { return nil } - let result = VisibleMessage.Quote() - result.timestamp = quote.timestamp - result.publicKey = quote.authorId - result.text = quote.body - return result - } -} - extension TSQuotedMessage { @objc(from:) diff --git a/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.h rename to SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage.h diff --git a/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.m b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage.m similarity index 88% rename from SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.m rename to SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage.m index 8af86dafb..d69b971e0 100644 --- a/SignalUtilitiesKit/Messaging/Quotes/TSQuotedMessage.m +++ b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage.m @@ -11,8 +11,8 @@ #import "TSInteraction.h" #import "TSOutgoingMessage.h" #import "TSThread.h" -#import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -20,10 +20,6 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithAttachmentStream:(TSAttachmentStream *)attachmentStream; { - OWSAssertDebug([attachmentStream isKindOfClass:[TSAttachmentStream class]]); - OWSAssertDebug(attachmentStream.uniqueId); - OWSAssertDebug(attachmentStream.contentType); - return [self initWithAttachmentId:attachmentStream.uniqueId contentType:attachmentStream.contentType sourceFilename:attachmentStream.sourceFilename]; @@ -62,9 +58,6 @@ NS_ASSUME_NONNULL_BEGIN bodySource:(TSQuotedMessageContentSource)bodySource receivedQuotedAttachmentInfos:(NSArray *)attachmentInfos { - OWSAssertDebug(timestamp > 0); - OWSAssertDebug(authorId.length > 0); - self = [super init]; if (!self) { return nil; @@ -84,9 +77,6 @@ NS_ASSUME_NONNULL_BEGIN body:(NSString *_Nullable)body quotedAttachmentsForSending:(NSArray *)attachments { - OWSAssertDebug(timestamp > 0); - OWSAssertDebug(authorId.length > 0); - self = [super init]; if (!self) { return nil; @@ -110,8 +100,6 @@ NS_ASSUME_NONNULL_BEGIN thread:(TSThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(dataMessage); - if (!dataMessage.quote) { return nil; } @@ -119,13 +107,11 @@ NS_ASSUME_NONNULL_BEGIN SNProtoDataMessageQuote *quoteProto = [dataMessage quote]; if (quoteProto.id == 0) { - OWSFailDebug(@"quoted message missing id"); return nil; } uint64_t timestamp = [quoteProto id]; if (quoteProto.author.length == 0) { - OWSFailDebug(@"quoted message missing author"); return nil; } // TODO: We could verify that this is a valid e164 value. @@ -173,18 +159,10 @@ NS_ASSUME_NONNULL_BEGIN transaction:transaction]; if (localThumbnail) { - OWSLogDebug(@"Generated local thumbnail for quoted quoted message: %@:%lu", - thread.uniqueId, - (unsigned long)timestamp); - [localThumbnail saveWithTransaction:transaction]; attachmentInfo.thumbnailAttachmentStreamId = localThumbnail.uniqueId; } else if (quotedAttachment.thumbnail) { - OWSLogDebug(@"Saving reference for fetching remote thumbnail for quoted message: %@:%lu", - thread.uniqueId, - (unsigned long)timestamp); - SNProtoAttachmentPointer *thumbnailAttachmentProto = quotedAttachment.thumbnail; TSAttachmentPointer *_Nullable thumbnailPointer = [TSAttachmentPointer attachmentPointerFromProto:thumbnailAttachmentProto albumMessage:nil]; @@ -192,11 +170,7 @@ NS_ASSUME_NONNULL_BEGIN [thumbnailPointer saveWithTransaction:transaction]; attachmentInfo.thumbnailAttachmentPointerId = thumbnailPointer.uniqueId; - } else { - OWSFailDebug(@"Invalid thumbnail attachment."); } - } else { - OWSLogDebug(@"No thumbnail for quoted message: %@:%lu", thread.uniqueId, (unsigned long)timestamp); } [attachmentInfos addObject:attachmentInfo]; @@ -251,18 +225,13 @@ NS_ASSUME_NONNULL_BEGIN authorId:(NSString *)authorId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - if (timestamp <= 0) { - OWSFailDebug(@"Invalid timestamp: %llu", timestamp); return nil; } if (threadId.length <= 0) { - OWSFailDebug(@"Invalid thread."); return nil; } if (authorId.length <= 0) { - OWSFailDebug(@"Invalid authorId: %@", authorId); return nil; } @@ -284,7 +253,6 @@ NS_ASSUME_NONNULL_BEGIN return message; } - OWSLogWarn(@"Could not find quoted message: %llu", timestamp); return nil; } @@ -292,7 +260,6 @@ NS_ASSUME_NONNULL_BEGIN - (nullable OWSAttachmentInfo *)firstAttachmentInfo { - OWSAssertDebug(self.quotedAttachments.count <= 1); return self.quotedAttachments.firstObject; } @@ -326,9 +293,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)setThumbnailAttachmentStream:(TSAttachmentStream *)attachmentStream { - OWSAssertDebug([attachmentStream isKindOfClass:[TSAttachmentStream class]]); - OWSAssertDebug(self.quotedAttachments.count == 1); - OWSAttachmentInfo *firstAttachment = self.firstAttachmentInfo; firstAttachment.thumbnailAttachmentStreamId = attachmentStream.uniqueId; } @@ -352,8 +316,6 @@ NS_ASSUME_NONNULL_BEGIN NSMutableArray *thumbnailAttachments = [NSMutableArray new]; for (OWSAttachmentInfo *info in self.quotedAttachments) { - - OWSAssertDebug(info.attachmentId); TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:info.attachmentId transaction:transaction]; if (![attachment isKindOfClass:[TSAttachmentStream class]]) { continue; diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.h b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.h rename to SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.h diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m similarity index 94% rename from SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m rename to SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m index 8163fa538..0bb42314a 100644 --- a/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m @@ -3,16 +3,16 @@ // #import "OWSOutgoingReceiptManager.h" -#import "AppReadiness.h" -#import "OWSError.h" -#import -#import "OWSPrimaryStorage.h" +#import #import "SSKEnvironment.h" +#import "AppReadiness.h" +#import "OWSPrimaryStorage.h" #import "TSContactThread.h" #import "TSYapDatabaseObject.h" +#import +#import #import -#import -#import "SSKAsserts.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -41,8 +41,6 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa + (instancetype)sharedManager { - OWSAssert(SSKEnvironment.shared.outgoingReceiptManager); - return SSKEnvironment.shared.outgoingReceiptManager; } @@ -58,8 +56,6 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa _dbConnection = primaryStorage.newDatabaseConnection; - OWSSingletonAssert(); - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged) name:kReachabilityChangedNotification @@ -93,15 +89,11 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa // Schedules a processing pass, unless one is already scheduled. - (void)process { - OWSAssertDebug(AppReadiness.isAppReady); - dispatch_async(self.serialQueue, ^{ if (self.isProcessing) { return; } - OWSLogVerbose(@"Processing outbound receipts."); - self.isProcessing = YES; if (!self.reachability.isReachable) { @@ -159,7 +151,6 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa for (NSString *recipientId in queuedReceiptMap) { NSSet *timestamps = queuedReceiptMap[recipientId]; if (timestamps.count < 1) { - OWSFailDebug(@"Missing timestamps."); continue; } @@ -236,11 +227,9 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa NSString *collection = [self collectionForReceiptType:receiptType]; if (recipientId.length < 1) { - OWSFailDebug(@"Invalid recipient id."); return; } if (timestamp < 1) { - OWSFailDebug(@"Invalid timestamp."); return; } dispatch_async(self.serialQueue, ^{ @@ -263,11 +252,9 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa NSString *collection = [self collectionForReceiptType:receiptType]; if (recipientId.length < 1) { - OWSFailDebug(@"Invalid recipient id."); return; } if (timestamps.count < 1) { - OWSFailDebug(@"Invalid timestamps."); return; } dispatch_async(self.serialQueue, ^{ @@ -288,8 +275,6 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa - (void)reachabilityChanged { - OWSAssertIsOnMainThread(); - [self process]; } diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.h b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.h similarity index 85% rename from SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.h rename to SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.h index aeacacee3..d369acf74 100644 --- a/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.h +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.h @@ -51,15 +51,6 @@ extern NSString *const kIncomingMessageMarkedAsReadNotification; - (void)applyEarlyReadReceiptsForOutgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message transaction:(YapDatabaseReadWriteTransaction *)transaction; -#pragma mark - Linked Device Read Receipts - -- (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos - readTimestamp:(uint64_t)readTimestamp - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -- (void)applyEarlyReadReceiptsForIncomingMessage:(TSIncomingMessage *)message - transaction:(YapDatabaseReadWriteTransaction *)transaction; - #pragma mark - Locally Read // This method cues this manager: diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m similarity index 66% rename from SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.m rename to SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m index 4ec0df35f..67006c39d 100644 --- a/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m @@ -10,13 +10,13 @@ #import "SSKEnvironment.h" #import "TSAccountManager.h" #import "TSContactThread.h" +#import "TSOutgoingMessage.h" #import "TSDatabaseView.h" #import "TSIncomingMessage.h" #import "YapDatabaseConnection+OWS.h" #import -#import +#import #import -#import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN @@ -41,8 +41,6 @@ NSString *const kIncomingMessageMarkedAsReadNotification = @"kIncomingMessageMar - (instancetype)initWithSentTimestamp:(uint64_t)sentTimestamp { - OWSAssertDebug(sentTimestamp > 0); - self = [super initWithUniqueId:[TSRecipientReadReceipt uniqueIdForSentTimestamp:sentTimestamp]]; if (self) { @@ -60,9 +58,6 @@ NSString *const kIncomingMessageMarkedAsReadNotification = @"kIncomingMessageMar - (void)addRecipientId:(NSString *)recipientId timestamp:(uint64_t)timestamp { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(timestamp > 0); - NSMutableDictionary *recipientMapCopy = [self.recipientMap mutableCopy]; recipientMapCopy[recipientId] = @(timestamp); _recipientMap = [recipientMapCopy copy]; @@ -73,8 +68,6 @@ NSString *const kIncomingMessageMarkedAsReadNotification = @"kIncomingMessageMar readTimestamp:(uint64_t)readTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - TSRecipientReadReceipt *_Nullable recipientReadReceipt = [transaction objectForKey:[self uniqueIdForSentTimestamp:sentTimestamp] inCollection:[self collection]]; if (!recipientReadReceipt) { @@ -88,8 +81,6 @@ NSString *const kIncomingMessageMarkedAsReadNotification = @"kIncomingMessageMar transaction: (YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - TSRecipientReadReceipt *_Nullable recipientReadReceipt = [transaction objectForKey:[self uniqueIdForSentTimestamp:sentTimestamp] inCollection:[self collection]]; return recipientReadReceipt.recipientMap; @@ -98,8 +89,6 @@ NSString *const kIncomingMessageMarkedAsReadNotification = @"kIncomingMessageMar + (void)removeRecipientIdsForTimestamp:(uint64_t)sentTimestamp transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - [transaction removeObjectForKey:[self uniqueIdForSentTimestamp:sentTimestamp] inCollection:[self collection]]; } @@ -133,8 +122,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE + (instancetype)sharedManager { - OWSAssert(SSKEnvironment.shared.readReceiptManager); - return SSKEnvironment.shared.readReceiptManager; } @@ -148,8 +135,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE _dbConnection = primaryStorage.newDatabaseConnection; - OWSSingletonAssert(); - // Start processing. [AppReadiness runNowOrWhenAppDidBecomeReady:^{ [self scheduleProcessing]; @@ -167,8 +152,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (OWSOutgoingReceiptManager *)outgoingReceiptManager { - OWSAssertDebug(SSKEnvironment.shared.outgoingReceiptManager); - return SSKEnvironment.shared.outgoingReceiptManager; } @@ -177,8 +160,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE // Schedules a processing pass, unless one is already scheduled. - (void)scheduleProcessing { - OWSAssertDebug(AppReadiness.isAppReady); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(self) { @@ -240,13 +221,11 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread { - OWSAssertDebug(thread); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self markAsReadBeforeSortId:sortId thread:thread - readTimestamp:[NSDate ows_millisecondTimeStamp] + readTimestamp:[NSDate millisecondTimestamp] wasLocal:YES transaction:transaction]; }]; @@ -303,11 +282,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE sentTimestamps:(NSArray *)sentTimestamps readTimestamp:(uint64_t)readTimestamp { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(sentTimestamps); - if (![self areReadReceiptsEnabled]) { - OWSLogInfo(@"Ignoring incoming receipt message as read receipts are disabled."); return; } @@ -320,9 +295,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE = (NSArray *)[TSInteraction interactionsWithTimestamp:sentTimestamp ofClass:[TSOutgoingMessage class] withTransaction:transaction]; - if (messages.count > 1) { - OWSLogError(@"More than one matching message with timestamp: %llu.", sentTimestamp); - } if (messages.count > 0) { // TODO: We might also need to "mark as read by recipient" any older messages // from us in that thread. Or maybe this state should hang on the thread? @@ -344,124 +316,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE }); } -- (void)applyEarlyReadReceiptsForOutgoingMessageFromLinkedDevice:(TSOutgoingMessage *)message - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(message); - OWSAssertDebug(transaction); - - uint64_t sentTimestamp = message.timestamp; - NSDictionary *recipientMap = - [TSRecipientReadReceipt recipientMapForSentTimestamp:sentTimestamp transaction:transaction]; - if (!recipientMap) { - return; - } - OWSAssertDebug(recipientMap.count > 0); - for (NSString *recipientId in recipientMap) { - NSNumber *nsReadTimestamp = recipientMap[recipientId]; - OWSAssertDebug(nsReadTimestamp); - uint64_t readTimestamp = [nsReadTimestamp unsignedLongLongValue]; - - [message updateWithReadRecipientId:recipientId readTimestamp:readTimestamp transaction:transaction]; - } - [TSRecipientReadReceipt removeRecipientIdsForTimestamp:message.timestamp transaction:transaction]; -} - -#pragma mark - Linked Device Read Receipts - -- (void)applyEarlyReadReceiptsForIncomingMessage:(TSIncomingMessage *)message - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - /* - OWSAssertDebug(message); - OWSAssertDebug(transaction); - - NSString *senderId = message.authorId; - uint64_t timestamp = message.timestamp; - if (senderId.length < 1 || timestamp < 1) { - OWSFailDebug(@"Invalid incoming message: %@ %llu", senderId, timestamp); - return; - } - - OWSLinkedDeviceReadReceipt *_Nullable readReceipt = - [OWSLinkedDeviceReadReceipt findLinkedDeviceReadReceiptWithSenderId:senderId - messageIdTimestamp:timestamp - transaction:transaction]; - if (!readReceipt) { - return; - } - - [message markAsReadAtTimestamp:readReceipt.readTimestamp sendReadReceipt:NO transaction:transaction]; - [readReceipt removeWithTransaction:transaction]; - */ -} - -- (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos - readTimestamp:(uint64_t)readTimestamp - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - // TODO TODO TODO - - /* - OWSAssertDebug(readReceiptProtos); - OWSAssertDebug(transaction); - - for (SNProtoSyncMessageRead *readReceiptProto in readReceiptProtos) { - NSString *_Nullable senderId = readReceiptProto.sender; - uint64_t messageIdTimestamp = readReceiptProto.timestamp; - - if (senderId.length == 0) { - OWSFailDebug(@"senderId was unexpectedly nil"); - continue; - } - - if (messageIdTimestamp == 0) { - OWSFailDebug(@"messageIdTimestamp was unexpectedly 0"); - continue; - } - - NSArray *messages - = (NSArray *)[TSInteraction interactionsWithTimestamp:messageIdTimestamp - ofClass:[TSIncomingMessage class] - withTransaction:transaction]; - if (messages.count > 0) { - for (TSIncomingMessage *message in messages) { - NSTimeInterval secondsSinceRead = [NSDate new].timeIntervalSince1970 - readTimestamp / 1000; - OWSAssertDebug([message isKindOfClass:[TSIncomingMessage class]]); - OWSLogDebug(@"read on linked device %f seconds ago", secondsSinceRead); - [self markAsReadOnLinkedDevice:message readTimestamp:readTimestamp transaction:transaction]; - } - } else { - // Received read receipt for unknown incoming message. - // Persist in case we receive the incoming message later. - OWSLinkedDeviceReadReceipt *readReceipt = - [[OWSLinkedDeviceReadReceipt alloc] initWithSenderId:senderId - messageIdTimestamp:messageIdTimestamp - readTimestamp:readTimestamp]; - [readReceipt saveWithTransaction:transaction]; - } - } - */ -} - -- (void)markAsReadOnLinkedDevice:(TSIncomingMessage *)message - readTimestamp:(uint64_t)readTimestamp - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(message); - OWSAssertDebug(transaction); - - // Always re-mark the message as read to ensure any earlier read time is applied to disappearing messages. - [message markAsReadAtTimestamp:readTimestamp sendReadReceipt:NO transaction:transaction]; - - // Also mark any unread messages appearing earlier in the thread as read as well. - [self markAsReadBeforeSortId:message.sortId - thread:[message threadWithTransaction:transaction] - readTimestamp:readTimestamp - wasLocal:NO - transaction:transaction]; -} - #pragma mark - Mark As Read - (void)markAsReadBeforeSortId:(uint64_t)sortId @@ -470,22 +324,12 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE wasLocal:(BOOL)wasLocal transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(sortId > 0); - OWSAssertDebug(thread); - OWSAssertDebug(transaction); - NSMutableArray> *newlyReadList = [NSMutableArray new]; [[TSDatabaseView unseenDatabaseViewExtension:transaction] enumerateKeysAndObjectsInGroup:thread.uniqueId usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { if (![object conformsToProtocol:@protocol(OWSReadTracking)]) { - OWSFailDebug( - @"Expected to conform to OWSReadTracking: object with class: %@ collection: %@ " - @"key: %@", - [object class], - collection, - key); return; } id possiblyRead = (id)object; @@ -498,7 +342,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE // there is a bug that can somehow cause it to be false leading to conversations permanently being // stuck with "unread" messages. - OWSAssertDebug(possiblyRead.expireStartedAt == 0); if (!possiblyRead.read) { [newlyReadList addObject:possiblyRead]; } @@ -507,12 +350,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE if (newlyReadList.count < 1) { return; } - - if (wasLocal) { - OWSLogError(@"Marking %lu messages as read locally.", (unsigned long)newlyReadList.count); - } else { - OWSLogError(@"Marking %lu messages as read by linked device.", (unsigned long)newlyReadList.count); - } + for (id readItem in newlyReadList) { [readItem markAsReadAtTimestamp:readTimestamp sendReadReceipt:wasLocal transaction:transaction]; } @@ -539,8 +377,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)setAreReadReceiptsEnabled:(BOOL)value { - OWSLogInfo(@"setAreReadReceiptsEnabled: %d.", value); - [self.dbConnection setBool:value forKey:OWSReadReceiptManagerAreReadReceiptsEnabled inCollection:OWSReadReceiptManagerCollection]; diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/OWSReadTracking.h b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadTracking.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Read Tracking/OWSReadTracking.h rename to SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadTracking.h diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.h b/SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.h similarity index 87% rename from SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.h rename to SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.h index 06b75058e..4545e6d99 100644 --- a/SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.h +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.m similarity index 100% rename from SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.m rename to SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.m diff --git a/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift similarity index 87% rename from SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift rename to SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift index 7e8e64bdb..2ac63c633 100644 --- a/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift +++ b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift @@ -62,34 +62,22 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { } private func setup() { - AssertIsOnMainThread() - - _areTypingIndicatorsEnabled = primaryStorage.dbReadConnection.bool(forKey: kDatabaseKey_TypingIndicatorsEnabled, inCollection: kDatabaseCollection, defaultValue: true) - } - - // MARK: - Dependencies - - private var primaryStorage: OWSPrimaryStorage { - return SSKEnvironment.shared.primaryStorage + _areTypingIndicatorsEnabled = OWSPrimaryStorage.shared().dbReadConnection.bool(forKey: kDatabaseKey_TypingIndicatorsEnabled, inCollection: kDatabaseCollection, defaultValue: true) } // MARK: - @objc public func setTypingIndicatorsEnabled(value: Bool) { - AssertIsOnMainThread() - Logger.info("\(_areTypingIndicatorsEnabled) -> \(value)") _areTypingIndicatorsEnabled = value - primaryStorage.dbReadWriteConnection.setBool(value, forKey: kDatabaseKey_TypingIndicatorsEnabled, inCollection: kDatabaseCollection) + OWSPrimaryStorage.shared().dbReadWriteConnection.setBool(value, forKey: kDatabaseKey_TypingIndicatorsEnabled, inCollection: kDatabaseCollection) NotificationCenter.default.postNotificationNameAsync(TypingIndicatorsImpl.typingIndicatorStateDidChange, object: nil) } @objc public func areTypingIndicatorsEnabled() -> Bool { - AssertIsOnMainThread() - return _areTypingIndicatorsEnabled } @@ -97,9 +85,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { @objc public func didStartTypingOutgoingInput(inThread thread: TSThread) { - AssertIsOnMainThread() guard let outgoingIndicators = ensureOutgoingIndicators(forThread: thread) else { - owsFailDebug("Could not locate outgoing indicators state") return } outgoingIndicators.didStartTypingOutgoingInput() @@ -107,9 +93,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { @objc public func didStopTypingOutgoingInput(inThread thread: TSThread) { - AssertIsOnMainThread() guard let outgoingIndicators = ensureOutgoingIndicators(forThread: thread) else { - owsFailDebug("Could not locate outgoing indicators state") return } outgoingIndicators.didStopTypingOutgoingInput() @@ -117,9 +101,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { @objc public func didSendOutgoingMessage(inThread thread: TSThread) { - AssertIsOnMainThread() guard let outgoingIndicators = ensureOutgoingIndicators(forThread: thread) else { - owsFailDebug("Could not locate outgoing indicators state") return } outgoingIndicators.didSendOutgoingMessage() @@ -127,32 +109,24 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { @objc public func didReceiveTypingStartedMessage(inThread thread: TSThread, recipientId: String, deviceId: UInt) { - AssertIsOnMainThread() - Logger.info("") let incomingIndicators = ensureIncomingIndicators(forThread: thread, recipientId: recipientId, deviceId: deviceId) incomingIndicators.didReceiveTypingStartedMessage() } @objc public func didReceiveTypingStoppedMessage(inThread thread: TSThread, recipientId: String, deviceId: UInt) { - AssertIsOnMainThread() - Logger.info("") let incomingIndicators = ensureIncomingIndicators(forThread: thread, recipientId: recipientId, deviceId: deviceId) incomingIndicators.didReceiveTypingStoppedMessage() } @objc public func didReceiveIncomingMessage(inThread thread: TSThread, recipientId: String, deviceId: UInt) { - AssertIsOnMainThread() - Logger.info("") let incomingIndicators = ensureIncomingIndicators(forThread: thread, recipientId: recipientId, deviceId: deviceId) incomingIndicators.didReceiveIncomingMessage() } @objc public func typingRecipientId(forThread thread: TSThread) -> String? { - AssertIsOnMainThread() - guard areTypingIndicatorsEnabled() else { return nil } @@ -170,7 +144,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { continue } guard let startedTypingTimestamp = incomingIndicators.startedTypingTimestamp else { - owsFailDebug("Typing device is missing start timestamp.") continue } if let firstTimestamp = firstTimestamp, @@ -191,10 +164,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { private var outgoingIndicatorsMap = [String: OutgoingIndicators]() private func ensureOutgoingIndicators(forThread thread: TSThread) -> OutgoingIndicators? { - AssertIsOnMainThread() - guard let threadId = thread.uniqueId else { - owsFailDebug("Thread missing id") return nil } if let outgoingIndicators = outgoingIndicatorsMap[threadId] { @@ -223,8 +193,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { // MARK: - func didStartTypingOutgoingInput() { - AssertIsOnMainThread() - if sendRefreshTimer == nil { // If the user types a character into the compose box, and the sendRefresh timer isn’t running: @@ -249,8 +217,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { } func didStopTypingOutgoingInput() { - AssertIsOnMainThread() - sendTypingMessageIfNecessary(forThread: thread, action: .stopped) sendRefreshTimer?.invalidate() @@ -262,8 +228,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { @objc func sendPauseTimerDidFire() { - AssertIsOnMainThread() - sendTypingMessageIfNecessary(forThread: thread, action: .stopped) sendRefreshTimer?.invalidate() @@ -275,8 +239,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { @objc func sendRefreshTimerDidFire() { - AssertIsOnMainThread() - sendTypingMessageIfNecessary(forThread: thread, action: .started) sendRefreshTimer?.invalidate() @@ -288,8 +250,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { } func didSendOutgoingMessage() { - AssertIsOnMainThread() - sendRefreshTimer?.invalidate() sendRefreshTimer = nil @@ -299,7 +259,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { private func sendTypingMessageIfNecessary(forThread thread: TSThread, action: TypingIndicator.Kind) { guard let delegate = delegate else { - owsFailDebug("Missing delegate.") return } // `areTypingIndicatorsEnabled` reflects the user-facing setting in the app preferences. @@ -336,8 +295,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { } private func ensureIncomingIndicators(forThread thread: TSThread, recipientId: String, deviceId: UInt) -> IncomingIndicators { - AssertIsOnMainThread() - let threadKey = incomingIndicatorsKey(forThread: thread) let deviceKey = incomingIndicatorsKey(recipientId: recipientId, deviceId: deviceId) guard let deviceMap = incomingIndicatorsMap[threadKey] else { @@ -366,12 +323,8 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { var isTyping = false { didSet { - AssertIsOnMainThread() - let didChange = oldValue != isTyping if didChange { - Logger.debug("isTyping changed: \(oldValue) -> \(self.isTyping)") - notifyIfNecessary() } } @@ -386,8 +339,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { } func didReceiveTypingStartedMessage() { - AssertIsOnMainThread() - displayTypingTimer?.invalidate() displayTypingTimer = Timer.weakScheduledTimer(withTimeInterval: 5, target: self, @@ -401,27 +352,19 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { } func didReceiveTypingStoppedMessage() { - AssertIsOnMainThread() - clearTyping() } @objc func displayTypingTimerDidFire() { - AssertIsOnMainThread() - clearTyping() } func didReceiveIncomingMessage() { - AssertIsOnMainThread() - clearTyping() } private func clearTyping() { - AssertIsOnMainThread() - displayTypingTimer?.invalidate() displayTypingTimer = nil startedTypingTimestamp = nil @@ -429,10 +372,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { } private func notifyIfNecessary() { - Logger.verbose("") - guard let delegate = delegate else { - owsFailDebug("Missing delegate.") return } // `areTypingIndicatorsEnabled` reflects the user-facing setting in the app preferences. @@ -442,7 +382,6 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { return } guard let threadId = thread.uniqueId else { - owsFailDebug("Thread is missing id.") return } NotificationCenter.default.postNotificationNameAsync(TypingIndicatorsImpl.typingIndicatorStateDidChange, object: threadId) diff --git a/SessionMessagingKit/Threads/Notification+Thread.swift b/SessionMessagingKit/Threads/Notification+Thread.swift new file mode 100644 index 000000000..4254aff63 --- /dev/null +++ b/SessionMessagingKit/Threads/Notification+Thread.swift @@ -0,0 +1,10 @@ + +public extension Notification.Name { + + static let groupThreadUpdated = Notification.Name("groupThreadUpdated") +} + +@objc public extension NSNotification { + + @objc static let groupThreadUpdated = Notification.Name.groupThreadUpdated.rawValue as NSString +} diff --git a/SignalUtilitiesKit/Threads/TSContactThread.h b/SessionMessagingKit/Threads/TSContactThread.h similarity index 85% rename from SignalUtilitiesKit/Threads/TSContactThread.h rename to SessionMessagingKit/Threads/TSContactThread.h index 15c63d31f..c24278fbe 100644 --- a/SignalUtilitiesKit/Threads/TSContactThread.h +++ b/SessionMessagingKit/Threads/TSContactThread.h @@ -2,17 +2,14 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN extern NSString *const TSContactThreadPrefix; -typedef NS_ENUM(NSInteger, SNSessionRestorationStatus); - @interface TSContactThread : TSThread -@property (atomic) SNSessionRestorationStatus sessionRestorationStatus; @property (nonatomic) BOOL hasDismissedOffers; - (instancetype)initWithContactId:(NSString *)contactId; diff --git a/SignalUtilitiesKit/Threads/TSContactThread.m b/SessionMessagingKit/Threads/TSContactThread.m similarity index 83% rename from SignalUtilitiesKit/Threads/TSContactThread.m rename to SessionMessagingKit/Threads/TSContactThread.m index 93efedf57..f97ab07be 100644 --- a/SignalUtilitiesKit/Threads/TSContactThread.m +++ b/SessionMessagingKit/Threads/TSContactThread.m @@ -3,12 +3,9 @@ // #import "TSContactThread.h" -#import "NotificationsProtocol.h" -#import "OWSIdentityManager.h" -#import "SSKEnvironment.h" -#import -#import -#import +#import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -19,19 +16,13 @@ NSString *const TSContactThreadPrefix = @"c"; - (instancetype)initWithContactId:(NSString *)contactId { NSString *uniqueIdentifier = [[self class] threadIdFromContactId:contactId]; - OWSAssertDebug(contactId.length > 0); - self = [super initWithUniqueId:uniqueIdentifier]; - _sessionRestorationStatus = SNSessionRestorationStatusNone; - return self; } + (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(contactId.length > 0); - TSContactThread *thread = [self fetchObjectWithUniqueID:[self threadIdFromContactId:contactId] transaction:transaction]; @@ -45,8 +36,6 @@ NSString *const TSContactThreadPrefix = @"c"; + (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId { - OWSAssertDebug(contactId.length > 0); - __block TSContactThread *thread; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { thread = [self getOrCreateThreadWithContactId:contactId transaction:transaction]; @@ -80,7 +69,7 @@ NSString *const TSContactThreadPrefix = @"c"; - (NSString *)name { - return [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.contactIdentifier avoidingWriteTransaction:YES]; + return [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.contactIdentifier avoidingWriteTransaction:YES] ?: self.contactIdentifier; } + (NSString *)threadIdFromContactId:(NSString *)contactId { diff --git a/SignalUtilitiesKit/Threads/TSGroupModel.h b/SessionMessagingKit/Threads/TSGroupModel.h similarity index 96% rename from SignalUtilitiesKit/Threads/TSGroupModel.h rename to SessionMessagingKit/Threads/TSGroupModel.h index 0855a2880..6467d216d 100644 --- a/SignalUtilitiesKit/Threads/TSGroupModel.h +++ b/SessionMessagingKit/Threads/TSGroupModel.h @@ -2,9 +2,8 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +#import #import -#import - NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Threads/TSGroupModel.m b/SessionMessagingKit/Threads/TSGroupModel.m similarity index 97% rename from SignalUtilitiesKit/Threads/TSGroupModel.m rename to SessionMessagingKit/Threads/TSGroupModel.m index fac56262a..fbf20a269 100644 --- a/SignalUtilitiesKit/Threads/TSGroupModel.m +++ b/SessionMessagingKit/Threads/TSGroupModel.m @@ -3,10 +3,8 @@ // #import "TSGroupModel.h" -#import "FunctionalUtil.h" -#import "NSString+SSK.h" -#import -#import "OWSIdentityManager.h" +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -30,8 +28,6 @@ const int32_t kGroupIdLength = 16; groupType:(GroupType)groupType adminIds:(NSArray *)adminIds { - OWSAssertDebug(memberIds); - _groupName = title; _groupMemberIds = [memberIds copy]; _groupImage = image; // image is stored in DB diff --git a/SignalUtilitiesKit/Threads/TSGroupThread.h b/SessionMessagingKit/Threads/TSGroupThread.h similarity index 94% rename from SignalUtilitiesKit/Threads/TSGroupThread.h rename to SessionMessagingKit/Threads/TSGroupThread.h index 7abf873f3..452ef5550 100644 --- a/SignalUtilitiesKit/Threads/TSGroupThread.h +++ b/SessionMessagingKit/Threads/TSGroupThread.h @@ -2,9 +2,8 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import -#import -#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Threads/TSGroupThread.m b/SessionMessagingKit/Threads/TSGroupThread.m similarity index 88% rename from SignalUtilitiesKit/Threads/TSGroupThread.m rename to SessionMessagingKit/Threads/TSGroupThread.m index ba2d23403..bf80e185f 100644 --- a/SignalUtilitiesKit/Threads/TSGroupThread.m +++ b/SessionMessagingKit/Threads/TSGroupThread.m @@ -5,11 +5,10 @@ #import "TSGroupThread.h" #import "TSAttachmentStream.h" #import -#import -#import -#import -#import -#import "OWSPrimaryStorage.h" +#import +#import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -22,14 +21,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (instancetype)initWithGroupModel:(TSGroupModel *)groupModel { - OWSAssertDebug(groupModel); - OWSAssertDebug(groupModel.groupId.length > 0); - OWSAssertDebug(groupModel.groupMemberIds.count > 0); - - for (NSString *recipientId in groupModel.groupMemberIds) { - OWSAssertDebug(recipientId.length > 0); - } - NSString *uniqueIdentifier = [[self class] threadIdFromGroupId:groupModel.groupId]; self = [super initWithUniqueId:uniqueIdentifier]; @@ -44,10 +35,7 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (instancetype)initWithGroupId:(NSData *)groupId groupType:(GroupType)groupType { - OWSAssertDebug(groupId.length > 0); - NSString *localNumber = [TSAccountManager localNumber]; - OWSAssertDebug(localNumber.length > 0); TSGroupModel *groupModel = [[TSGroupModel alloc] initWithTitle:nil memberIds:@[ localNumber ] @@ -67,8 +55,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific + (nullable instancetype)threadWithGroupId:(NSData *)groupId transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(groupId.length > 0); - return [self fetchObjectWithUniqueID:[self threadIdFromGroupId:groupId] transaction:transaction]; } @@ -76,9 +62,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific groupType:(GroupType)groupType transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(groupId.length > 0); - OWSAssertDebug(transaction); - TSGroupThread *thread = [self fetchObjectWithUniqueID:[self threadIdFromGroupId:groupId] transaction:transaction]; if (!thread) { @@ -91,8 +74,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific + (instancetype)getOrCreateThreadWithGroupId:(NSData *)groupId groupType:(GroupType)groupType { - OWSAssertDebug(groupId.length > 0); - __block TSGroupThread *thread; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { @@ -104,10 +85,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific + (instancetype)getOrCreateThreadWithGroupModel:(TSGroupModel *)groupModel transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(groupModel); - OWSAssertDebug(groupModel.groupId.length > 0); - OWSAssertDebug(transaction); - TSGroupThread *thread = [self fetchObjectWithUniqueID:[self threadIdFromGroupId:groupModel.groupId] transaction:transaction]; @@ -121,9 +98,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific + (instancetype)getOrCreateThreadWithGroupModel:(TSGroupModel *)groupModel { - OWSAssertDebug(groupModel); - OWSAssertDebug(groupModel.groupId.length > 0); - __block TSGroupThread *thread; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { @@ -135,15 +109,11 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific + (NSString *)threadIdFromGroupId:(NSData *)groupId { - OWSAssertDebug(groupId.length > 0); - return [TSGroupThreadPrefix stringByAppendingString:[[LKGroupUtilities getDecodedGroupIDAsData:groupId] base64EncodedString]]; } + (NSData *)groupIdFromThreadId:(NSString *)threadId { - OWSAssertDebug(threadId.length > 0); - return [NSData dataFromBase64String:[threadId substringWithRange:NSMakeRange(1, threadId.length - 1)]]; } @@ -167,9 +137,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific + (NSArray *)groupThreadsWithRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - NSMutableArray *groupThreads = [NSMutableArray new]; [self enumerateCollectionObjectsWithTransaction:transaction usingBlock:^(id obj, BOOL *stop) { @@ -276,9 +243,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (void)updateAvatarWithAttachmentStream:(TSAttachmentStream *)attachmentStream transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(attachmentStream); - OWSAssertDebug(transaction); - self.groupModel.groupImage = [attachmentStream thumbnailImageSmallSync]; [self saveWithTransaction:transaction]; @@ -294,8 +258,6 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (void)fireAvatarChangedNotification { - OWSAssertIsOnMainThread(); - NSDictionary *userInfo = @{ TSGroupThread_NotificationKey_UniqueId : self.uniqueId }; [[NSNotificationCenter defaultCenter] postNotificationName:TSGroupThreadAvatarChangedNotification diff --git a/SignalUtilitiesKit/Threads/TSThread.h b/SessionMessagingKit/Threads/TSThread.h similarity index 100% rename from SignalUtilitiesKit/Threads/TSThread.h rename to SessionMessagingKit/Threads/TSThread.h diff --git a/SignalUtilitiesKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m similarity index 90% rename from SignalUtilitiesKit/Threads/TSThread.m rename to SessionMessagingKit/Threads/TSThread.m index a142b4805..11fca049e 100644 --- a/SignalUtilitiesKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -3,22 +3,13 @@ // #import "TSThread.h" -#import "NSString+SSK.h" #import "OWSDisappearingMessagesConfiguration.h" -#import "OWSPrimaryStorage.h" -#import "OWSReadTracking.h" -#import "SSKEnvironment.h" -#import "TSAccountManager.h" -#import "TSDatabaseView.h" -#import "TSIncomingMessage.h" -#import "TSInfoMessage.h" -#import "TSInteraction.h" -#import "TSInvalidIdentityKeyReceivingErrorMessage.h" -#import "TSOutgoingMessage.h" #import #import -#import +#import #import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -50,8 +41,6 @@ BOOL IsNoteToSelfEnabled(void) - (TSAccountManager *)tsAccountManager { - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - return SSKEnvironment.shared.tsAccountManager; } @@ -120,13 +109,10 @@ BOOL IsNoteToSelfEnabled(void) // or when deleting them. NSMutableArray *interactionIds = [NSMutableArray new]; YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName]; - OWSAssertDebug(interactionsByThread); __block BOOL didDetectCorruption = NO; [interactionsByThread enumerateKeysInGroup:self.uniqueId usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) { if (![key isKindOfClass:[NSString class]] || key.length < 1) { - OWSFailDebug( - @"invalid key in thread interactions: %@, %@.", key, [key class]); didDetectCorruption = YES; return; } @@ -134,7 +120,6 @@ BOOL IsNoteToSelfEnabled(void) }]; if (didDetectCorruption) { - OWSLogWarn(@"incrementing version of: %@", TSMessageDatabaseViewExtensionName); [OWSPrimaryStorage incrementVersionOfDatabaseExtension:TSMessageDatabaseViewExtensionName]; } @@ -143,7 +128,6 @@ BOOL IsNoteToSelfEnabled(void) TSInteraction *_Nullable interaction = [TSInteraction fetchObjectWithUniqueID:interactionId transaction:transaction]; if (!interaction) { - OWSFailDebug(@"couldn't load thread's interaction for deletion."); continue; } [interaction removeWithTransaction:transaction]; @@ -160,8 +144,6 @@ BOOL IsNoteToSelfEnabled(void) #pragma mark - To be subclassed. - (BOOL)isGroupThread { - OWSAbstractMethod(); - return NO; } @@ -172,15 +154,11 @@ BOOL IsNoteToSelfEnabled(void) } - (NSString *)name { - OWSAbstractMethod(); - return nil; } - (NSArray *)recipientIdentifiers { - OWSAbstractMethod(); - return @[]; } @@ -259,7 +237,7 @@ BOOL IsNoteToSelfEnabled(void) [errorMessages addObject:(TSInvalidIdentityKeyReceivingErrorMessage *)interaction]; } } @catch (NSException *exception) { - OWSFailDebug(@"exception: %@", exception); + } } }]; @@ -285,7 +263,6 @@ BOOL IsNoteToSelfEnabled(void) enumerateKeysAndObjectsInGroup:self.uniqueId usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { if (![object conformsToProtocol:@protocol(OWSReadTracking)]) { - OWSFailDebug(@"Unexpected object in unseen messages: %@", [object class]); return; } id unread = (id)object; @@ -307,7 +284,6 @@ BOOL IsNoteToSelfEnabled(void) [unreadMessages enumerateKeysAndObjectsInGroup:self.uniqueId usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { if (![object conformsToProtocol:@protocol(OWSReadTracking)]) { - OWSFailDebug(@"Unexpected object in unread messages: %@", [object class]); return; } id unread = (id)object; @@ -326,23 +302,16 @@ BOOL IsNoteToSelfEnabled(void) for (id message in [self unseenMessagesWithTransaction:transaction]) { [message markAsReadAtTimestamp:[NSDate ows_millisecondTimeStamp] sendReadReceipt:YES transaction:transaction]; } - - // Just to be defensive, we'll also check for unread messages. - OWSAssertDebug([self unseenMessagesWithTransaction:transaction].count < 1); } - (nullable TSInteraction *)lastInteractionForInboxWithTransaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - __block NSUInteger missedCount = 0; __block TSInteraction *last = nil; [[transaction ext:TSMessageDatabaseViewExtensionName] enumerateKeysAndObjectsInGroup:self.uniqueId withOptions:NSEnumerationReverse usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { - OWSAssertDebug([object isKindOfClass:[TSInteraction class]]); - missedCount++; TSInteraction *interaction = (TSInteraction *)object; @@ -354,10 +323,7 @@ BOOL IsNoteToSelfEnabled(void) // members who's test devices are constantly reinstalled. We could add a // purpose-built DB view, but I think in the real world this is rare to be a // hotspot. - if (missedCount > 50) { - OWSLogWarn(@"found last interaction for inbox after skipping %lu items", - (unsigned long)missedCount); - } + *stop = YES; } }]; @@ -378,8 +344,6 @@ BOOL IsNoteToSelfEnabled(void) // Returns YES IFF the interaction should show up in the inbox as the last message. + (BOOL)shouldInteractionAppearInInbox:(TSInteraction *)interaction { - OWSAssertDebug(interaction); - if (interaction.isDynamicInteraction) { return NO; } @@ -397,9 +361,6 @@ BOOL IsNoteToSelfEnabled(void) } - (void)updateWithLastMessage:(TSInteraction *)lastMessage transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(lastMessage); - OWSAssertDebug(transaction); - if (![self.class shouldInteractionAppearInInbox:lastMessage]) { return; } diff --git a/SignalUtilitiesKit/To Do/DisplayNameUtilities.swift b/SessionMessagingKit/To Do/DisplayNameUtilities.swift similarity index 100% rename from SignalUtilitiesKit/To Do/DisplayNameUtilities.swift rename to SessionMessagingKit/To Do/DisplayNameUtilities.swift diff --git a/SignalUtilitiesKit/OWSRecipientIdentity.h b/SessionMessagingKit/To Do/OWSRecipientIdentity.h similarity index 97% rename from SignalUtilitiesKit/OWSRecipientIdentity.h rename to SessionMessagingKit/To Do/OWSRecipientIdentity.h index fec840379..18f225156 100644 --- a/SignalUtilitiesKit/OWSRecipientIdentity.h +++ b/SessionMessagingKit/To Do/OWSRecipientIdentity.h @@ -46,10 +46,6 @@ SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinati createdAt:(NSDate *)createdAt verificationState:(OWSVerificationState)verificationState NS_DESIGNATED_INITIALIZER; -#pragma mark - debug - -+ (void)printAllIdentities; - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/OWSRecipientIdentity.m b/SessionMessagingKit/To Do/OWSRecipientIdentity.m similarity index 81% rename from SignalUtilitiesKit/OWSRecipientIdentity.m rename to SessionMessagingKit/To Do/OWSRecipientIdentity.m index 55bd13414..31ed11171 100644 --- a/SignalUtilitiesKit/OWSRecipientIdentity.m +++ b/SessionMessagingKit/To Do/OWSRecipientIdentity.m @@ -4,10 +4,9 @@ #import "OWSRecipientIdentity.h" #import "OWSIdentityManager.h" -#import "OWSPrimaryStorage+SessionStore.h" #import "OWSPrimaryStorage.h" #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -41,11 +40,6 @@ SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinati OWSVerificationState verificationState, NSUInteger paddingBytesLength) { - OWSCAssertDebug(identityKey.length == kIdentityKeyLength); - OWSCAssertDebug(destinationRecipientId.length > 0); - // we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device - // will figure that out on it's own. - OWSCAssertDebug(verificationState != OWSVerificationStateNoLongerVerified); SNProtoVerifiedBuilder *verifiedBuilder = [SNProtoVerified builderWithDestination:destinationRecipientId]; verifiedBuilder.identityKey = identityKey; @@ -63,7 +57,6 @@ SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinati NSError *error; SNProtoVerified *_Nullable verifiedProto = [verifiedBuilder buildAndReturnError:&error]; if (error || !verifiedProto) { - OWSCFailDebug(@"%@ could not build protobuf: %@", @"[BuildVerifiedProtoWithRecipientId]", error); return nil; } return verifiedProto; @@ -119,8 +112,6 @@ SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinati - (void)updateWithVerificationState:(OWSVerificationState)verificationState transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - // Ensure changes are persisted without clobbering any work done on another thread or instance. [self updateWithChangeBlock:^(OWSRecipientIdentity *_Nonnull obj) { obj.verificationState = verificationState; @@ -131,8 +122,6 @@ SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinati - (void)updateWithChangeBlock:(void (^)(OWSRecipientIdentity *obj))changeBlock transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - changeBlock(self); OWSRecipientIdentity *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction]; @@ -161,24 +150,6 @@ SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinati }]; } -#pragma mark - debug - -+ (void)printAllIdentities -{ - OWSLogInfo(@"### All Recipient Identities ###"); - __block int count = 0; - [self enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) { - count++; - if (![obj isKindOfClass:[self class]]) { - OWSFailDebug(@"unexpected object in collection: %@", obj); - return; - } - OWSRecipientIdentity *recipientIdentity = (OWSRecipientIdentity *)obj; - - OWSLogInfo(@"Identity %d: %@", count, recipientIdentity.debugDescription); - }]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/To Do/OWSUDManager.swift b/SessionMessagingKit/To Do/OWSUDManager.swift new file mode 100644 index 000000000..6a8f4226a --- /dev/null +++ b/SessionMessagingKit/To Do/OWSUDManager.swift @@ -0,0 +1,71 @@ + +@objc +public enum UnidentifiedAccessMode: Int { + case unknown + case enabled + case disabled + case unrestricted +} + +@objc +public class OWSUDAccess: NSObject { + @objc + public let udAccessKey: SMKUDAccessKey + + @objc + public let udAccessMode: UnidentifiedAccessMode + + @objc + public let isRandomKey: Bool + + @objc + public required init(udAccessKey: SMKUDAccessKey, + udAccessMode: UnidentifiedAccessMode, + isRandomKey: Bool) { + self.udAccessKey = udAccessKey + self.udAccessMode = udAccessMode + self.isRandomKey = isRandomKey + } +} + +@objc public protocol OWSUDManager: class { + + @objc func setup() + + @objc func trustRoot() -> ECPublicKey + + @objc func isUDVerboseLoggingEnabled() -> Bool + + // MARK: - Recipient State + + @objc + func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String) + + @objc + func unidentifiedAccessMode(forRecipientId recipientId: String) -> UnidentifiedAccessMode + + @objc + func udAccessKey(forRecipientId recipientId: String) -> SMKUDAccessKey? + + @objc + func udAccess(forRecipientId recipientId: String, + requireSyncAccess: Bool) -> OWSUDAccess? + + // MARK: Sender Certificate + + // We use completion handlers instead of a promise so that message sending + // logic can access the strongly typed certificate data. + @objc + func ensureSenderCertificate(success:@escaping (SMKSenderCertificate) -> Void, + failure:@escaping (Error) -> Void) + + // MARK: Unrestricted Access + + @objc + func shouldAllowUnrestrictedAccessLocal() -> Bool + @objc + func setShouldAllowUnrestrictedAccessLocal(_ value: Bool) + + @objc + func getSenderCertificate() -> SMKSenderCertificate? +} diff --git a/SignalUtilitiesKit/To Do/ProfileManagerProtocol.h b/SessionMessagingKit/To Do/ProfileManagerProtocol.h similarity index 100% rename from SignalUtilitiesKit/To Do/ProfileManagerProtocol.h rename to SessionMessagingKit/To Do/ProfileManagerProtocol.h diff --git a/SignalUtilitiesKit/TSAccountManager.h b/SessionMessagingKit/To Do/TSAccountManager.h similarity index 99% rename from SignalUtilitiesKit/TSAccountManager.h rename to SessionMessagingKit/To Do/TSAccountManager.h index 979c9526f..d660f5801 100644 --- a/SignalUtilitiesKit/TSAccountManager.h +++ b/SessionMessagingKit/To Do/TSAccountManager.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/TSAccountManager.m b/SessionMessagingKit/To Do/TSAccountManager.m similarity index 99% rename from SignalUtilitiesKit/TSAccountManager.m rename to SessionMessagingKit/To Do/TSAccountManager.m index 4114a65fb..e30b00917 100644 --- a/SignalUtilitiesKit/TSAccountManager.m +++ b/SessionMessagingKit/To Do/TSAccountManager.m @@ -9,10 +9,8 @@ #import "NSURLSessionDataTask+StatusCode.h" #import "OWSError.h" #import "OWSPrimaryStorage+SessionStore.h" - #import "ProfileManagerProtocol.h" #import "SSKEnvironment.h" - #import "TSPreKeyManager.h" #import "YapDatabaseConnection+OWS.h" #import "YapDatabaseTransaction+OWS.h" @@ -20,7 +18,7 @@ #import #import #import -#import +#import #import #import "SSKAsserts.h" diff --git a/SignalUtilitiesKit/AppReadiness.h b/SessionMessagingKit/Utilities/AppReadiness.h similarity index 100% rename from SignalUtilitiesKit/AppReadiness.h rename to SessionMessagingKit/Utilities/AppReadiness.h diff --git a/SignalUtilitiesKit/AppReadiness.m b/SessionMessagingKit/Utilities/AppReadiness.m similarity index 97% rename from SignalUtilitiesKit/AppReadiness.m rename to SessionMessagingKit/Utilities/AppReadiness.m index 4424e177e..7370141b1 100755 --- a/SignalUtilitiesKit/AppReadiness.m +++ b/SessionMessagingKit/Utilities/AppReadiness.m @@ -5,6 +5,8 @@ #import "AppReadiness.h" #import "AppContext.h" #import "SSKAsserts.h" +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/FullTextSearchFinder.swift b/SessionMessagingKit/Utilities/FullTextSearchFinder.swift similarity index 97% rename from SignalUtilitiesKit/FullTextSearchFinder.swift rename to SessionMessagingKit/Utilities/FullTextSearchFinder.swift index c12258a1a..83ff10ea8 100644 --- a/SignalUtilitiesKit/FullTextSearchFinder.swift +++ b/SessionMessagingKit/Utilities/FullTextSearchFinder.swift @@ -3,7 +3,6 @@ // import Foundation -import libPhoneNumber_iOS // Create a searchable index for objects of type T public class SearchIndexer { @@ -88,14 +87,11 @@ public class FullTextSearchFinder: NSObject { public func enumerateObjects(searchText: String, transaction: YapDatabaseReadTransaction, block: @escaping (Any, String) -> Void) { guard let ext: YapDatabaseFullTextSearchTransaction = ext(transaction: transaction) else { - owsFailDebug("ext was unexpectedly nil") return } let query = FullTextSearchFinder.query(searchText: searchText) - Logger.verbose("query: \(query)") - let maxSearchResults = 500 var searchResultCount = 0 let snippetOptions = YapDatabaseFullTextSearchSnippetOptions() @@ -206,8 +202,6 @@ public class FullTextSearchFinder: NSObject { return self.contactThreadIndexer.index(contactThread, transaction: transaction) } else if let message = object as? TSMessage { return self.messageIndexer.index(message, transaction: transaction) - } else if let signalAccount = object as? SignalAccount { - return self.recipientIndexer.index(signalAccount.recipientId, transaction: transaction) } else { return nil } @@ -236,8 +230,6 @@ public class FullTextSearchFinder: NSObject { } private class var dbExtensionConfig: YapDatabaseFullTextSearch { - AssertIsOnMainThread() - let contentColumnName = "content" let handler = YapDatabaseFullTextSearchHandler.withObjectBlock { (transaction: YapDatabaseReadTransaction, dict: NSMutableDictionary, _: String, _: String, object: Any) in diff --git a/SignalUtilitiesKit/Utilities/GeneralUtilities.swift b/SessionMessagingKit/Utilities/GeneralUtilities.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/GeneralUtilities.swift rename to SessionMessagingKit/Utilities/GeneralUtilities.swift diff --git a/SignalUtilitiesKit/OWSBackgroundTask.h b/SessionMessagingKit/Utilities/OWSBackgroundTask.h similarity index 100% rename from SignalUtilitiesKit/OWSBackgroundTask.h rename to SessionMessagingKit/Utilities/OWSBackgroundTask.h diff --git a/SignalUtilitiesKit/OWSBackgroundTask.m b/SessionMessagingKit/Utilities/OWSBackgroundTask.m similarity index 93% rename from SignalUtilitiesKit/OWSBackgroundTask.m rename to SessionMessagingKit/Utilities/OWSBackgroundTask.m index b9d8b17cc..cd14f1b5f 100644 --- a/SignalUtilitiesKit/OWSBackgroundTask.m +++ b/SessionMessagingKit/Utilities/OWSBackgroundTask.m @@ -5,7 +5,8 @@ #import "OWSBackgroundTask.h" #import "AppContext.h" #import -#import "SSKAsserts.h" +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -55,8 +56,6 @@ typedef NSNumber *OWSTaskId; - (instancetype)initDefault { - OWSAssertIsOnMainThread(); - self = [super init]; if (!self) { @@ -68,8 +67,6 @@ typedef NSNumber *OWSTaskId; self.idCounter = 0; self.isAppActive = CurrentAppContext().isMainAppAndActive; - OWSSingletonAssert(); - return self; } @@ -95,8 +92,6 @@ typedef NSNumber *OWSTaskId; - (void)applicationDidBecomeActive:(UIApplication *)application { - OWSAssertIsOnMainThread(); - @synchronized(self) { self.isAppActive = YES; @@ -107,8 +102,6 @@ typedef NSNumber *OWSTaskId; - (void)applicationWillResignActive:(UIApplication *)application { - OWSAssertIsOnMainThread(); - @synchronized(self) { self.isAppActive = NO; @@ -126,8 +119,6 @@ typedef NSNumber *OWSTaskId; // In that case expirationBlock will not be called. - (nullable OWSTaskId)addTaskWithExpirationBlock:(BackgroundTaskExpirationBlock)expirationBlock { - OWSAssertDebug(expirationBlock); - OWSTaskId _Nullable taskId; @synchronized(self) @@ -150,12 +141,8 @@ typedef NSNumber *OWSTaskId; - (void)removeTask:(OWSTaskId)taskId { - OWSAssertDebug(taskId); - @synchronized(self) { - OWSAssertDebug(self.expirationMap[taskId] != nil); - [self.expirationMap removeObjectForKey:taskId]; // This timer will ensure that we keep the background task active (if necessary) @@ -196,11 +183,9 @@ typedef NSNumber *OWSTaskId; // Current state is correct. return YES; } else if (shouldHaveBackgroundTask) { - OWSLogInfo(@"Starting background task."); return [self startBackgroundTask]; } else { // Need to end background task. - OWSLogInfo(@"Ending background task."); UIBackgroundTaskIdentifier backgroundTaskId = self.backgroundTaskId; self.backgroundTaskId = UIBackgroundTaskInvalid; [CurrentAppContext() endBackgroundTask:backgroundTaskId]; @@ -212,12 +197,8 @@ typedef NSNumber *OWSTaskId; // Returns NO if the background task cannot be begun. - (BOOL)startBackgroundTask { - OWSAssertDebug(CurrentAppContext().isMainApp); - @synchronized(self) { - OWSAssertDebug(self.backgroundTaskId == UIBackgroundTaskInvalid); - self.backgroundTaskId = [CurrentAppContext() beginBackgroundTaskWithExpirationHandler:^{ // Supposedly [UIApplication beginBackgroundTaskWithExpirationHandler]'s handler // will always be called on the main thread, but in practice we've observed @@ -225,15 +206,12 @@ typedef NSNumber *OWSTaskId; // // See: // https://developer.apple.com/documentation/uikit/uiapplication/1623031-beginbackgroundtaskwithexpiratio) - OWSAssertDebug([NSThread isMainThread]); [self backgroundTaskExpired]; }]; // If the background task could not begin, return NO to indicate that. if (self.backgroundTaskId == UIBackgroundTaskInvalid) { - OWSLogError(@"background task could not be started."); - return NO; } return YES; @@ -304,8 +282,6 @@ typedef NSNumber *OWSTaskId; + (OWSBackgroundTask *)backgroundTaskWithLabelStr:(const char *)labelStr { - OWSAssertDebug(labelStr); - NSString *label = [NSString stringWithFormat:@"%s", labelStr]; return [[OWSBackgroundTask alloc] initWithLabel:label completionBlock:nil]; } @@ -314,8 +290,6 @@ typedef NSNumber *OWSTaskId; completionBlock:(BackgroundTaskCompletionBlock)completionBlock { - OWSAssertDebug(labelStr); - NSString *label = [NSString stringWithFormat:@"%s", labelStr]; return [[OWSBackgroundTask alloc] initWithLabel:label completionBlock:completionBlock]; } @@ -339,8 +313,6 @@ typedef NSNumber *OWSTaskId; return self; } - OWSAssertDebug(label.length > 0); - _label = label; self.completionBlock = completionBlock; @@ -363,7 +335,6 @@ typedef NSNumber *OWSTaskId; if (!strongSelf) { return; } - OWSLogVerbose(@"task expired"); // Make a local copy of completionBlock to ensure that it is called // exactly once. @@ -374,7 +345,6 @@ typedef NSNumber *OWSTaskId; if (!strongSelf.taskId) { return; } - OWSLogInfo(@"%@ background task expired.", strongSelf.label); strongSelf.taskId = nil; completionBlock = strongSelf.completionBlock; @@ -389,7 +359,6 @@ typedef NSNumber *OWSTaskId; // If a background task could not be begun, call the completion block. if (!self.taskId) { - OWSLogError(@"%@ background task could not be started.", self.label); // Make a local copy of completionBlock to ensure that it is called // exactly once. diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.h b/SessionMessagingKit/Utilities/OWSDisappearingMessagesFinder.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.h rename to SessionMessagingKit/Utilities/OWSDisappearingMessagesFinder.h diff --git a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.m b/SessionMessagingKit/Utilities/OWSDisappearingMessagesFinder.m similarity index 91% rename from SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.m rename to SessionMessagingKit/Utilities/OWSDisappearingMessagesFinder.m index 7cb3b7d47..3cd9f7518 100644 --- a/SignalUtilitiesKit/Messaging/Disappearing Messages/OWSDisappearingMessagesFinder.m +++ b/SessionMessagingKit/Utilities/OWSDisappearingMessagesFinder.m @@ -25,8 +25,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess - (NSArray *)fetchUnstartedExpiringMessageIdsInThread:(TSThread *)thread transaction:(YapDatabaseReadTransaction *_Nonnull)transaction { - OWSAssertDebug(transaction); - NSMutableArray *messageIds = [NSMutableArray new]; NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = 0 AND %@ = \"%@\"", OWSDisappearingMessageFinderExpiresAtColumn, @@ -45,8 +43,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess - (NSArray *)fetchMessageIdsWhichFailedToStartExpiring:(YapDatabaseReadTransaction *_Nonnull)transaction { - OWSAssertDebug(transaction); - NSMutableArray *messageIds = [NSMutableArray new]; NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = 0", OWSDisappearingMessageFinderExpiresAtColumn]; @@ -56,13 +52,9 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess enumerateKeysAndObjectsMatchingQuery:query usingBlock:^void(NSString *collection, NSString *key, id object, BOOL *stop) { if (![object isKindOfClass:[TSMessage class]]) { - OWSFailDebug(@"Object was unexpected class: %@", [object class]); return; } - // We'll need to update if we ever support expiring other message types - OWSAssertDebug([object isKindOfClass:[TSOutgoingMessage class]] || [object isKindOfClass:[TSIncomingMessage class]]); - TSMessage *message = (TSMessage *)object; if ([message shouldStartExpireTimerWithTransaction:transaction]) { if ([message isKindOfClass:[TSIncomingMessage class]]) { @@ -80,8 +72,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess - (NSArray *)fetchExpiredMessageIdsWithTransaction:(YapDatabaseReadTransaction *_Nonnull)transaction { - OWSAssertDebug(transaction); - NSMutableArray *messageIds = [NSMutableArray new]; uint64_t now = [NSDate ows_millisecondTimeStamp]; @@ -102,8 +92,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess - (nullable NSNumber *)nextExpirationTimestampWithTransaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ > 0 ORDER BY %@ ASC", OWSDisappearingMessageFinderExpiresAtColumn, OWSDisappearingMessageFinderExpiresAtColumn]; @@ -128,15 +116,11 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess block:(void (^_Nonnull)(TSMessage *message))block transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - for (NSString *expiringMessageId in [self fetchUnstartedExpiringMessageIdsInThread:thread transaction:transaction]) { TSMessage *_Nullable message = [TSMessage fetchObjectWithUniqueID:expiringMessageId transaction:transaction]; if ([message isKindOfClass:[TSMessage class]]) { block(message); - } else { - OWSFailDebug(@"unexpected object: %@", [message class]); } } } @@ -144,18 +128,14 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess - (void)enumerateMessagesWhichFailedToStartExpiringWithBlock:(void (^_Nonnull)(TSMessage *message))block transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - for (NSString *expiringMessageId in [self fetchMessageIdsWhichFailedToStartExpiring:transaction]) { TSMessage *_Nullable message = [TSMessage fetchObjectWithUniqueID:expiringMessageId transaction:transaction]; if (![message isKindOfClass:[TSMessage class]]) { - OWSFailDebug(@"unexpected object: %@", [message class]); continue; } if (![message shouldStartExpireTimerWithTransaction:transaction]) { - OWSFailDebug(@"object: %@ shouldn't expire.", message); continue; } @@ -170,8 +150,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess - (NSArray *)fetchUnstartedExpiringMessagesInThread:(TSThread *)thread transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - NSMutableArray *messages = [NSMutableArray new]; [self enumerateUnstartedExpiringMessagesInThread:thread block:^(TSMessage *message) { @@ -186,16 +164,12 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess - (void)enumerateExpiredMessagesWithBlock:(void (^_Nonnull)(TSMessage *message))block transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - // Since we can't directly mutate the enumerated expired messages, we store only their ids in hopes of saving a // little memory and then enumerate the (larger) TSMessage objects one at a time. for (NSString *expiredMessageId in [self fetchExpiredMessageIdsWithTransaction:transaction]) { TSMessage *_Nullable message = [TSMessage fetchObjectWithUniqueID:expiredMessageId transaction:transaction]; if ([message isKindOfClass:[TSMessage class]]) { block(message); - } else { - OWSLogError(@"unexpected object: %@", message); } } } @@ -206,8 +180,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess */ - (NSArray *)fetchExpiredMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - NSMutableArray *messages = [NSMutableArray new]; [self enumerateExpiredMessagesWithBlock:^(TSMessage *message) { [messages addObject:message]; diff --git a/SignalUtilitiesKit/OWSIdentityManager.h b/SessionMessagingKit/Utilities/OWSIdentityManager.h similarity index 89% rename from SignalUtilitiesKit/OWSIdentityManager.h rename to SessionMessagingKit/Utilities/OWSIdentityManager.h index 149362b9a..cb7a23c72 100644 --- a/SignalUtilitiesKit/OWSIdentityManager.h +++ b/SessionMessagingKit/Utilities/OWSIdentityManager.h @@ -2,8 +2,10 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import #import +#import + +@class OWSPrimaryStorage; NS_ASSUME_NONNULL_BEGIN @@ -53,10 +55,6 @@ extern const NSUInteger kStoredIdentityKeyLength; */ - (nullable OWSRecipientIdentity *)untrustedIdentityForSendingToRecipientId:(NSString *)recipientId; -// This method can be called from any thread. -- (void)throws_processIncomingSyncMessage:(SNProtoVerified *)verified - transaction:(YapDatabaseReadWriteTransaction *)transaction; - - (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId; - (nullable ECKeyPair *)identityKeyPair; diff --git a/SignalUtilitiesKit/OWSIdentityManager.m b/SessionMessagingKit/Utilities/OWSIdentityManager.m similarity index 56% rename from SignalUtilitiesKit/OWSIdentityManager.m rename to SessionMessagingKit/Utilities/OWSIdentityManager.m index 46651537e..a2031410c 100644 --- a/SignalUtilitiesKit/OWSIdentityManager.m +++ b/SessionMessagingKit/Utilities/OWSIdentityManager.m @@ -22,7 +22,7 @@ #import #import #import -#import +#import #import #import "SSKAsserts.h" @@ -225,9 +225,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa verificationState:OWSVerificationStateDefault] saveWithTransaction:transaction]; - // Cancel any pending verification state sync messages for this recipient. - [self clearSyncMessageForRecipientId:recipientId transaction:transaction]; - [self fireIdentityStateChangeNotification]; return NO; @@ -249,7 +246,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa recipientId, OWSVerificationStateToString(existingIdentity.verificationState), OWSVerificationStateToString(verificationState)); - [self createIdentityChangeInfoMessageForRecipientId:recipientId transaction:transaction]; [[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId identityKey:identityKey @@ -259,9 +255,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa [self.primaryStorage archiveAllSessionsForContact:recipientId protocolContext:protocolContext]; - // Cancel any pending verification state sync messages for this recipient. - [self clearSyncMessageForRecipientId:recipientId transaction:transaction]; - [self fireIdentityStateChangeNotification]; return YES; @@ -407,286 +400,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa } } -- (void)createIdentityChangeInfoMessageForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - NSMutableArray *messages = [NSMutableArray new]; - - TSContactThread *contactThread = - [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; - OWSAssertDebug(contactThread != nil); - - TSErrorMessage *errorMessage = - [TSErrorMessage nonblockingIdentityChangeInThread:contactThread recipientId:recipientId]; - [messages addObject:errorMessage]; - - for (TSGroupThread *groupThread in [TSGroupThread groupThreadsWithRecipientId:recipientId transaction:transaction]) { - [messages addObject:[TSErrorMessage nonblockingIdentityChangeInThread:groupThread recipientId:recipientId]]; - } - - // MJK TODO - why not save immediately, why build up this array? - for (TSMessage *message in messages) { - [message saveWithTransaction:transaction]; - } - - [SSKEnvironment.shared.notificationsManager notifyUserForErrorMessage:errorMessage - thread:contactThread - transaction:transaction]; -} - -- (void)enqueueSyncMessageForVerificationStateForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - [transaction setObject:recipientId - forKey:recipientId - inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages]; - - dispatch_async(dispatch_get_main_queue(), ^{ - [self tryToSyncQueuedVerificationStates]; - }); -} - -- (void)tryToSyncQueuedVerificationStates -{ - OWSAssertIsOnMainThread(); - - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - [self syncQueuedVerificationStates]; - }]; -} - -- (void)syncQueuedVerificationStates -{ - /* - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSMutableArray *recipientIds = [NSMutableArray new]; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [transaction - enumerateKeysAndObjectsInCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages - usingBlock:^( - NSString *_Nonnull recipientId, id _Nonnull object, BOOL *_Nonnull stop) { - [recipientIds addObject:recipientId]; - }]; - }]; - - NSMutableArray *messages = [NSMutableArray new]; - for (NSString *recipientId in recipientIds) { - OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId]; - if (!recipientIdentity) { - OWSFailDebug(@"Could not load recipient identity for recipientId: %@", recipientId); - continue; - } - if (recipientIdentity.recipientId.length < 1) { - OWSFailDebug(@"Invalid recipient identity for recipientId: %@", recipientId); - continue; - } - - // Prepend key type for transit. - // TODO we should just be storing the key type so we don't have to juggle re-adding it. - NSData *identityKey = [recipientIdentity.identityKey prependKeyType]; - if (identityKey.length != kIdentityKeyLength) { - OWSFailDebug(@"Invalid recipient identitykey for recipientId: %@ key: %@", recipientId, identityKey); - continue; - } - if (recipientIdentity.verificationState == OWSVerificationStateNoLongerVerified) { - // We don't want to sync "no longer verified" state. Other clients can - // figure this out from the /profile/ endpoint, and this can cause data - // loss as a user's devices overwrite each other's verification. - OWSFailDebug(@"Queue verification state had unexpected value: %@ recipientId: %@", - OWSVerificationStateToString(recipientIdentity.verificationState), - recipientId); - continue; - } - OWSVerificationStateSyncMessage *message = - [[OWSVerificationStateSyncMessage alloc] initWithVerificationState:recipientIdentity.verificationState - identityKey:identityKey - verificationForRecipientId:recipientIdentity.recipientId]; - [messages addObject:message]; - } - if (messages.count > 0) { - for (OWSVerificationStateSyncMessage *message in messages) { - [self sendSyncVerificationStateMessage:message]; - } - } - }); - */ -} - -- (void)clearSyncMessageForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - [transaction removeObjectForKey:recipientId inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages]; -} - -- (void)throws_processIncomingSyncMessage:(SNProtoVerified *)verified - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(verified); - OWSAssertDebug(transaction); - - NSString *recipientId = verified.destination; - if (recipientId.length < 1) { - OWSFailDebug(@"Verification state sync message missing recipientId."); - return; - } - NSData *rawIdentityKey = verified.identityKey; - if (rawIdentityKey.length != kIdentityKeyLength) { - OWSFailDebug(@"Verification state sync message for recipient: %@ with malformed identityKey: %@", - recipientId, - rawIdentityKey); - return; - } - NSData *identityKey = [rawIdentityKey throws_removeKeyType]; - - switch (verified.state) { - case SNProtoVerifiedStateDefault: - [self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault - recipientId:recipientId - identityKey:identityKey - overwriteOnConflict:NO - transaction:transaction]; - break; - case SNProtoVerifiedStateVerified: - [self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified - recipientId:recipientId - identityKey:identityKey - overwriteOnConflict:YES - transaction:transaction]; - break; - case SNProtoVerifiedStateUnverified: - OWSFailDebug(@"Verification state sync message for recipientId: %@ has unexpected value: %@.", - recipientId, - OWSVerificationStateToString(OWSVerificationStateNoLongerVerified)); - return; - } - - [self fireIdentityStateChangeNotification]; -} - -- (void)tryToApplyVerificationStateFromSyncMessage:(OWSVerificationState)verificationState - recipientId:(NSString *)recipientId - identityKey:(NSData *)identityKey - overwriteOnConflict:(BOOL)overwriteOnConflict - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - - if (recipientId.length < 1) { - OWSFailDebug(@"Verification state sync message missing recipientId."); - return; - } - - if (identityKey.length != kStoredIdentityKeyLength) { - OWSFailDebug(@"Verification state sync message missing identityKey: %@", recipientId); - return; - } - - OWSRecipientIdentity *_Nullable recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId - transaction:transaction]; - if (!recipientIdentity) { - // There's no existing recipient identity for this recipient. - // We should probably create one. - - if (verificationState == OWSVerificationStateDefault) { - // There's no point in creating a new recipient identity just to - // set its verification state to default. - return; - } - - // Ensure a remote identity exists for this key. We may be learning about - // it for the first time. - [self saveRemoteIdentity:identityKey recipientId:recipientId protocolContext:transaction]; - - recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId - transaction:transaction]; - - if (recipientIdentity == nil) { - OWSFailDebug(@"Missing expected identity: %@", recipientId); - return; - } - - if (![recipientIdentity.recipientId isEqualToString:recipientId]) { - OWSFailDebug(@"recipientIdentity has unexpected recipientId: %@", recipientId); - return; - } - - if (![recipientIdentity.identityKey isEqualToData:identityKey]) { - OWSFailDebug(@"recipientIdentity has unexpected identityKey: %@", recipientId); - return; - } - - if (recipientIdentity.verificationState == verificationState) { - return; - } - - OWSLogInfo(@"setVerificationState: %@ (%@ -> %@)", - recipientId, - OWSVerificationStateToString(recipientIdentity.verificationState), - OWSVerificationStateToString(verificationState)); - - [recipientIdentity updateWithVerificationState:verificationState - transaction:transaction]; - - // No need to call [saveChangeMessagesForRecipientId:..] since this is - // a new recipient. - } else { - // There's an existing recipient identity for this recipient. - // We should update it. - if (![recipientIdentity.recipientId isEqualToString:recipientId]) { - OWSFailDebug(@"recipientIdentity has unexpected recipientId: %@", recipientId); - return; - } - - if (![recipientIdentity.identityKey isEqualToData:identityKey]) { - // The conflict case where we receive a verification sync message - // whose identity key disagrees with the local identity key for - // this recipient. - if (!overwriteOnConflict) { - OWSLogWarn(@"recipientIdentity has non-matching identityKey: %@", recipientId); - return; - } - - OWSLogWarn(@"recipientIdentity has non-matching identityKey; overwriting: %@", recipientId); - [self saveRemoteIdentity:identityKey recipientId:recipientId protocolContext:transaction]; - - recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId - transaction:transaction]; - - if (recipientIdentity == nil) { - OWSFailDebug(@"Missing expected identity: %@", recipientId); - return; - } - - if (![recipientIdentity.recipientId isEqualToString:recipientId]) { - OWSFailDebug(@"recipientIdentity has unexpected recipientId: %@", recipientId); - return; - } - - if (![recipientIdentity.identityKey isEqualToData:identityKey]) { - OWSFailDebug(@"recipientIdentity has unexpected identityKey: %@", recipientId); - return; - } - } - - if (recipientIdentity.verificationState == verificationState) { - return; - } - - [recipientIdentity updateWithVerificationState:verificationState - transaction:transaction]; - } -} - #pragma mark - Debug #if DEBUG @@ -749,13 +462,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (void)applicationDidBecomeActive:(NSNotification *)notification { - OWSAssertIsOnMainThread(); - - // We want to defer this so that we never call this method until - // [UIApplicationDelegate applicationDidBecomeActive:] is complete. - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self tryToSyncQueuedVerificationStates]; - }); + } @end diff --git a/SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.h b/SessionMessagingKit/Utilities/OWSIncomingMessageFinder.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.h rename to SessionMessagingKit/Utilities/OWSIncomingMessageFinder.h diff --git a/SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.m b/SessionMessagingKit/Utilities/OWSIncomingMessageFinder.m similarity index 94% rename from SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.m rename to SessionMessagingKit/Utilities/OWSIncomingMessageFinder.m index f9c60ca9d..3b9d32274 100644 --- a/SignalUtilitiesKit/Messaging/Utilities/OWSIncomingMessageFinder.m +++ b/SessionMessagingKit/Utilities/OWSIncomingMessageFinder.m @@ -32,8 +32,6 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess - (instancetype)init { - OWSAssertDebug([OWSPrimaryStorage sharedManager]); - return [self initWithPrimaryStorage:[OWSPrimaryStorage sharedManager]]; } @@ -100,7 +98,6 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess + (void)asyncRegisterExtensionWithPrimaryStorage:(OWSStorage *)storage { - OWSLogInfo(@"registering async."); [storage asyncRegisterExtension:self.indexExtension withName:OWSIncomingMessageFinderExtensionName]; } @@ -108,7 +105,6 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess // We should not normally hit this, as we should have prefer registering async, but it is useful for testing. - (void)registerExtension { - OWSLogError(@"registering SYNC. We should prefer async when possible."); [self.primaryStorage registerExtension:self.class.indexExtension withName:OWSIncomingMessageFinderExtensionName]; } #endif @@ -122,7 +118,6 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess { #ifdef DEBUG if (![self.primaryStorage registeredExtension:OWSIncomingMessageFinderExtensionName]) { - OWSFailDebug(@"but extension is not registered"); // we should be initializing this at startup rather than have an unexpectedly slow lazy setup at random. [self registerExtension]; @@ -139,7 +134,6 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess NSUInteger count; BOOL success = [[transaction ext:OWSIncomingMessageFinderExtensionName] getNumberOfRows:&count matchingQuery:query]; if (!success) { - OWSFailDebug(@"Could not execute query"); return NO; } diff --git a/SignalUtilitiesKit/OWSMediaGalleryFinder.h b/SessionMessagingKit/Utilities/OWSMediaGalleryFinder.h similarity index 100% rename from SignalUtilitiesKit/OWSMediaGalleryFinder.h rename to SessionMessagingKit/Utilities/OWSMediaGalleryFinder.h diff --git a/SignalUtilitiesKit/OWSMediaGalleryFinder.m b/SessionMessagingKit/Utilities/OWSMediaGalleryFinder.m similarity index 92% rename from SignalUtilitiesKit/OWSMediaGalleryFinder.m rename to SessionMessagingKit/Utilities/OWSMediaGalleryFinder.m index 55bd348cb..34face9e7 100644 --- a/SignalUtilitiesKit/OWSMediaGalleryFinder.m +++ b/SessionMessagingKit/Utilities/OWSMediaGalleryFinder.m @@ -12,7 +12,7 @@ #import #import #import -#import "TSAttachment+Albums.h" +#import "TSAttachment.h" NS_ASSUME_NONNULL_BEGIN @@ -60,8 +60,6 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin return nil; } - OWSAssertDebug([self.mediaGroup isEqual:groupId]); - return @(index); } @@ -89,7 +87,6 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin id _Nonnull object, NSUInteger index, BOOL *_Nonnull stop) { - OWSAssertDebug([object isKindOfClass:[TSAttachment class]]); attachmentBlock((TSAttachment *)object); }]; } @@ -98,7 +95,6 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin dbConnection:(YapDatabaseConnection *)dbConnection { YapDatabaseAutoViewConnection *extConnection = [dbConnection ext:OWSMediaGalleryFinderExtensionName]; - OWSAssert(extConnection); return [extConnection hasChangesForGroup:self.mediaGroup inNotifications:notifications]; } @@ -108,8 +104,7 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin - (YapDatabaseAutoViewTransaction *)galleryExtensionWithTransaction:(YapDatabaseReadTransaction *)transaction { YapDatabaseAutoViewTransaction *extension = [transaction extension:OWSMediaGalleryFinderExtensionName]; - OWSAssertDebug(extension); - + return extension; } @@ -148,13 +143,11 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin NSString *_Nonnull key2, id _Nonnull object2) { if (![object1 isKindOfClass:[TSAttachment class]]) { - OWSFailDebug(@"Unexpected object while sorting: %@", [object1 class]); return NSOrderedSame; } TSAttachment *attachment1 = (TSAttachment *)object1; if (![object2 isKindOfClass:[TSAttachment class]]) { - OWSFailDebug(@"Unexpected object while sorting: %@", [object2 class]); return NSOrderedSame; } TSAttachment *attachment2 = (TSAttachment *)object2; @@ -162,7 +155,6 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin TSMessage *_Nullable message1 = [attachment1 fetchAlbumMessageWithTransaction:transaction]; TSMessage *_Nullable message2 = [attachment2 fetchAlbumMessageWithTransaction:transaction]; if (message1 == nil || message2 == nil) { - OWSFailDebug(@"couldn't find albumMessage"); return NSOrderedSame; } @@ -171,7 +163,6 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin NSUInteger index2 = [message1.attachmentIds indexOfObject:attachment2.uniqueId]; if (index1 == NSNotFound || index2 == NSNotFound) { - OWSFailDebug(@"couldn't find attachmentId in it's albumMessage"); return NSOrderedSame; } return [@(index1) compare:@(index2)]; @@ -201,7 +192,6 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin TSMessage *message = [attachment fetchAlbumMessageWithTransaction:transaction]; if (message == nil) { - OWSFailDebug(@"message was unexpectedly nil"); return nil; } diff --git a/SignalUtilitiesKit/Utilities/ProtoUtils.h b/SessionMessagingKit/Utilities/ProtoUtils.h similarity index 71% rename from SignalUtilitiesKit/Utilities/ProtoUtils.h rename to SessionMessagingKit/Utilities/ProtoUtils.h index 74c6ae3a5..bda2a8e38 100644 --- a/SignalUtilitiesKit/Utilities/ProtoUtils.h +++ b/SessionMessagingKit/Utilities/ProtoUtils.h @@ -6,7 +6,6 @@ NS_ASSUME_NONNULL_BEGIN -@class SNProtoCallMessageBuilder; @class SNProtoDataMessageBuilder; @class TSThread; @@ -20,10 +19,6 @@ NS_ASSUME_NONNULL_BEGIN + (void)addLocalProfileKeyToDataMessageBuilder:(SNProtoDataMessageBuilder *)dataMessageBuilder; -+ (void)addLocalProfileKeyIfNecessary:(TSThread *)thread - recipientId:(NSString *)recipientId - callMessageBuilder:(SNProtoCallMessageBuilder *)callMessageBuilder; - @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Utilities/ProtoUtils.m b/SessionMessagingKit/Utilities/ProtoUtils.m similarity index 83% rename from SignalUtilitiesKit/Utilities/ProtoUtils.m rename to SessionMessagingKit/Utilities/ProtoUtils.m index 7e98369f7..871de391c 100644 --- a/SignalUtilitiesKit/Utilities/ProtoUtils.m +++ b/SessionMessagingKit/Utilities/ProtoUtils.m @@ -7,7 +7,7 @@ #import "SSKEnvironment.h" #import "TSThread.h" #import -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -28,7 +28,6 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)shouldMessageHaveLocalProfileKey:(TSThread *)thread recipientId:(NSString *_Nullable)recipientId { - OWSAssertDebug(thread); return YES; } @@ -36,9 +35,6 @@ NS_ASSUME_NONNULL_BEGIN recipientId:(NSString *_Nullable)recipientId dataMessageBuilder:(SNProtoDataMessageBuilder *)dataMessageBuilder { - OWSAssertDebug(thread); - OWSAssertDebug(dataMessageBuilder); - if ([self shouldMessageHaveLocalProfileKey:thread recipientId:recipientId]) { [dataMessageBuilder setProfileKey:self.localProfileKey.keyData]; } @@ -46,8 +42,6 @@ NS_ASSUME_NONNULL_BEGIN + (void)addLocalProfileKeyToDataMessageBuilder:(SNProtoDataMessageBuilder *)dataMessageBuilder { - OWSAssertDebug(dataMessageBuilder); - [dataMessageBuilder setProfileKey:self.localProfileKey.keyData]; } @@ -55,10 +49,6 @@ NS_ASSUME_NONNULL_BEGIN recipientId:(NSString *)recipientId callMessageBuilder:(SNProtoCallMessageBuilder *)callMessageBuilder { - OWSAssertDebug(thread); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(callMessageBuilder); - if ([self shouldMessageHaveLocalProfileKey:thread recipientId:recipientId]) { [callMessageBuilder setProfileKey:self.localProfileKey.keyData]; } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift b/SessionMessagingKit/Utilities/SNProtoEnvelope+Conversion.swift similarity index 100% rename from SignalUtilitiesKit/Messaging/Sending & Receiving/SNProtoEnvelope+Conversion.swift rename to SessionMessagingKit/Utilities/SNProtoEnvelope+Conversion.swift diff --git a/SignalUtilitiesKit/SSKEnvironment.h b/SessionMessagingKit/Utilities/SSKEnvironment.h similarity index 94% rename from SignalUtilitiesKit/SSKEnvironment.h rename to SessionMessagingKit/Utilities/SSKEnvironment.h index 09f9262d9..604bdafac 100644 --- a/SignalUtilitiesKit/SSKEnvironment.h +++ b/SessionMessagingKit/Utilities/SSKEnvironment.h @@ -47,8 +47,7 @@ NS_ASSUME_NONNULL_BEGIN readReceiptManager:(OWSReadReceiptManager *)readReceiptManager outgoingReceiptManager:(OWSOutgoingReceiptManager *)outgoingReceiptManager reachabilityManager:(id)reachabilityManager - typingIndicators:(id)typingIndicators - attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads NS_DESIGNATED_INITIALIZER; + typingIndicators:(id)typingIndicators NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE; @@ -72,7 +71,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) OWSOutgoingReceiptManager *outgoingReceiptManager; @property (nonatomic, readonly) id reachabilityManager; @property (nonatomic, readonly) id typingIndicators; -@property (nonatomic, readonly) OWSAttachmentDownloads *attachmentDownloads; // This property is configured after Environment is created. @property (atomic, nullable) id notificationsManager; diff --git a/SignalUtilitiesKit/SSKEnvironment.m b/SessionMessagingKit/Utilities/SSKEnvironment.m similarity index 82% rename from SignalUtilitiesKit/SSKEnvironment.m rename to SessionMessagingKit/Utilities/SSKEnvironment.m index 2430e125d..e511ce354 100644 --- a/SignalUtilitiesKit/SSKEnvironment.m +++ b/SessionMessagingKit/Utilities/SSKEnvironment.m @@ -24,7 +24,6 @@ static SSKEnvironment *sharedSSKEnvironment; @property (nonatomic) OWSOutgoingReceiptManager *outgoingReceiptManager; @property (nonatomic) id reachabilityManager; @property (nonatomic) id typingIndicators; -@property (nonatomic) OWSAttachmentDownloads *attachmentDownloads; @end @@ -49,7 +48,6 @@ static SSKEnvironment *sharedSSKEnvironment; outgoingReceiptManager:(OWSOutgoingReceiptManager *)outgoingReceiptManager reachabilityManager:(id)reachabilityManager typingIndicators:(id)typingIndicators - attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads { self = [super init]; @@ -57,19 +55,6 @@ static SSKEnvironment *sharedSSKEnvironment; return self; } - OWSAssertDebug(profileManager); - OWSAssertDebug(primaryStorage); - OWSAssertDebug(blockingManager); - OWSAssertDebug(identityManager); - OWSAssertDebug(udManager); - OWSAssertDebug(tsAccountManager); - OWSAssertDebug(disappearingMessagesJob); - OWSAssertDebug(readReceiptManager); - OWSAssertDebug(outgoingReceiptManager); - OWSAssertDebug(reachabilityManager); - OWSAssertDebug(typingIndicators); - OWSAssertDebug(attachmentDownloads); - _profileManager = profileManager; _primaryStorage = primaryStorage; _blockingManager = blockingManager; @@ -81,23 +66,17 @@ static SSKEnvironment *sharedSSKEnvironment; _outgoingReceiptManager = outgoingReceiptManager; _reachabilityManager = reachabilityManager; _typingIndicators = typingIndicators; - _attachmentDownloads = attachmentDownloads; return self; } + (instancetype)shared { - OWSAssertDebug(sharedSSKEnvironment); - return sharedSSKEnvironment; } + (void)setShared:(SSKEnvironment *)env { - OWSAssertDebug(env); - OWSAssertDebug(!sharedSSKEnvironment || CurrentAppContext().isRunningTests); - sharedSSKEnvironment = env; } @@ -111,8 +90,6 @@ static SSKEnvironment *sharedSSKEnvironment; - (nullable id)notificationsManager { @synchronized(self) { - OWSAssertDebug(_notificationsManager); - return _notificationsManager; } } @@ -120,9 +97,6 @@ static SSKEnvironment *sharedSSKEnvironment; - (void)setNotificationsManager:(nullable id)notificationsManager { @synchronized(self) { - OWSAssertDebug(notificationsManager); - OWSAssertDebug(!_notificationsManager); - _notificationsManager = notificationsManager; } } diff --git a/SignalUtilitiesKit/Utilities/SSKIncrementingIdFinder.swift b/SessionMessagingKit/Utilities/SSKIncrementingIdFinder.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/SSKIncrementingIdFinder.swift rename to SessionMessagingKit/Utilities/SSKIncrementingIdFinder.swift diff --git a/SignalUtilitiesKit/SSKJobRecord.h b/SessionMessagingKit/Utilities/SSKJobRecord.h similarity index 100% rename from SignalUtilitiesKit/SSKJobRecord.h rename to SessionMessagingKit/Utilities/SSKJobRecord.h diff --git a/SignalUtilitiesKit/SSKJobRecord.m b/SessionMessagingKit/Utilities/SSKJobRecord.m similarity index 98% rename from SignalUtilitiesKit/SSKJobRecord.m rename to SessionMessagingKit/Utilities/SSKJobRecord.m index 2285b567f..71ef09139 100644 --- a/SignalUtilitiesKit/SSKJobRecord.m +++ b/SessionMessagingKit/Utilities/SSKJobRecord.m @@ -3,7 +3,7 @@ // #import "SSKJobRecord.h" -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SessionMessagingKit/Utilities/SSKJobRecordFinder.swift b/SessionMessagingKit/Utilities/SSKJobRecordFinder.swift new file mode 100644 index 000000000..8b633019a --- /dev/null +++ b/SessionMessagingKit/Utilities/SSKJobRecordFinder.swift @@ -0,0 +1,108 @@ + +@objc(SSKJobRecordFinder) +public class JobRecordFinder: NSObject, Finder { + + public typealias ExtensionType = YapDatabaseSecondaryIndex + public typealias TransactionType = YapDatabaseSecondaryIndexTransaction + + public enum JobRecordField: String { + case status, label, sortId + } + + public func getNextReady(label: String, transaction: YapDatabaseReadTransaction) -> SSKJobRecord? { + var result: SSKJobRecord? + self.enumerateJobRecords(label: label, status: .ready, transaction: transaction) { jobRecord, stopPointer in + result = jobRecord + stopPointer.pointee = true + } + return result + } + + public func allRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction) -> [SSKJobRecord] { + var result: [SSKJobRecord] = [] + self.enumerateJobRecords(label: label, status: status, transaction: transaction) { jobRecord, _ in + result.append(jobRecord) + } + return result + } + + public func enumerateJobRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction, block: @escaping (SSKJobRecord, UnsafeMutablePointer) -> Void) { + let queryFormat = String(format: "WHERE %@ = ? AND %@ = ? ORDER BY %@", JobRecordField.status.rawValue, JobRecordField.label.rawValue, JobRecordField.sortId.rawValue) + let query = YapDatabaseQuery(string: queryFormat, parameters: [status.rawValue, label]) + + self.ext(transaction: transaction).enumerateKeysAndObjects(matching: query) { _, _, object, stopPointer in + guard let jobRecord = object as? SSKJobRecord else { + owsFailDebug("expecting jobRecord but found: \(object)") + return + } + block(jobRecord, stopPointer) + } + } + + public static var dbExtensionName: String { + return "SecondaryIndexJobRecord" + } + + @objc + public class func asyncRegisterDatabaseExtensionObjC(storage: OWSStorage) { + asyncRegisterDatabaseExtension(storage: storage) + } + + public static var dbExtensionConfig: YapDatabaseSecondaryIndex { + let setup = YapDatabaseSecondaryIndexSetup() + setup.addColumn(JobRecordField.sortId.rawValue, with: .integer) + setup.addColumn(JobRecordField.status.rawValue, with: .integer) + setup.addColumn(JobRecordField.label.rawValue, with: .text) + + let block: YapDatabaseSecondaryIndexWithObjectBlock = { transaction, dict, collection, key, object in + guard let jobRecord = object as? SSKJobRecord else { + return + } + + dict[JobRecordField.sortId.rawValue] = jobRecord.sortId + dict[JobRecordField.status.rawValue] = jobRecord.status.rawValue + dict[JobRecordField.label.rawValue] = jobRecord.label + } + + let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock(block) + + let options = YapDatabaseSecondaryIndexOptions() + let whitelist = YapWhitelistBlacklist(whitelist: Set([SSKJobRecord.collection()])) + options.allowedCollections = whitelist + + return YapDatabaseSecondaryIndex.init(setup: setup, handler: handler, versionTag: "2", options: options) + } +} + +protocol Finder { + associatedtype ExtensionType: YapDatabaseExtension + associatedtype TransactionType: YapDatabaseExtensionTransaction + + static var dbExtensionName: String { get } + static var dbExtensionConfig: ExtensionType { get } + + func ext(transaction: YapDatabaseReadTransaction) -> TransactionType + + static func asyncRegisterDatabaseExtension(storage: OWSStorage) + static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage) +} + +extension Finder { + + public func ext(transaction: YapDatabaseReadTransaction) -> TransactionType { + return transaction.ext(type(of: self).dbExtensionName) as! TransactionType + } + + public static func asyncRegisterDatabaseExtension(storage: OWSStorage) { + storage.asyncRegister(dbExtensionConfig, withName: dbExtensionName) + } + + // Only for testing. + public static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage) { + guard storage.registeredExtension(dbExtensionName) == nil else { + return + } + + storage.register(dbExtensionConfig, withName: dbExtensionName) + } +} diff --git a/SessionMessagingKit/Utilities/SSKReachabilityManager.swift b/SessionMessagingKit/Utilities/SSKReachabilityManager.swift new file mode 100644 index 000000000..9f6bea814 --- /dev/null +++ b/SessionMessagingKit/Utilities/SSKReachabilityManager.swift @@ -0,0 +1,15 @@ +import Reachability + +@objc(SSKReachabilityType) +public enum ReachabilityType: Int { + case any, wifi, cellular +} + +@objc +public protocol SSKReachabilityManager { + var observationContext: AnyObject { get } + func setup() + + var isReachable: Bool { get } + func isReachable(via reachabilityType: ReachabilityType) -> Bool +} diff --git a/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.h b/SessionMessagingKit/Utilities/YapDatabaseConnection+OWS.h similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.h rename to SessionMessagingKit/Utilities/YapDatabaseConnection+OWS.h diff --git a/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.m b/SessionMessagingKit/Utilities/YapDatabaseConnection+OWS.m similarity index 90% rename from SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.m rename to SessionMessagingKit/Utilities/YapDatabaseConnection+OWS.m index 27358c51c..b58c37f1d 100644 --- a/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseConnection+OWS.m +++ b/SessionMessagingKit/Utilities/YapDatabaseConnection+OWS.m @@ -13,17 +13,11 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)hasObjectForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return nil != [self objectForKey:key inCollection:collection]; } - (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - __block NSString *_Nullable object; [self readWithBlock:^(YapDatabaseReadTransaction *transaction) { @@ -36,7 +30,6 @@ NS_ASSUME_NONNULL_BEGIN - (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection ofExpectedType:(Class)class { id _Nullable value = [self objectForKey:key inCollection:collection]; - OWSAssertDebug(!value || [value isKindOfClass:class]); return value; } @@ -123,9 +116,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - [self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [transaction setObject:object forKey:key inCollection:collection]; }]; @@ -133,9 +123,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - NSNumber *_Nullable oldValue = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]]; if (oldValue && [@(value) isEqual:oldValue]) { // Skip redundant writes. @@ -147,17 +134,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)setDouble:(double)value forKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - [self setObject:@(value) forKey:key inCollection:collection]; } - (void)removeObjectForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - [self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [transaction removeObjectForKey:key inCollection:collection]; }]; @@ -165,9 +146,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)setInt:(int)value forKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - [self setObject:@(value) forKey:key inCollection:collection]; } diff --git a/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.h b/SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.h similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.h rename to SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.h diff --git a/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.m b/SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.m similarity index 77% rename from SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.m rename to SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.m index ef505701e..dbfad0a86 100644 --- a/SignalUtilitiesKit/Database/YapDatabase/YapDatabaseTransaction+OWS.m +++ b/SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.m @@ -11,93 +11,59 @@ NS_ASSUME_NONNULL_BEGIN @implementation YapDatabaseReadTransaction (OWS) - (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection ofExpectedType:(Class) class { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - id _Nullable value = [self objectForKey:key inCollection:collection]; - OWSAssertDebug(!value || [value isKindOfClass:class]); return value; } - (nullable NSDictionary *)dictionaryForKey : (NSString *)key inCollection : (NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return [self objectForKey:key inCollection:collection ofExpectedType:[NSDictionary class]]; } - (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return [self objectForKey:key inCollection:collection ofExpectedType:[NSString class]]; } - (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]]; return value ? [value boolValue] : defaultValue; } - (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return [self objectForKey:key inCollection:collection ofExpectedType:[NSData class]]; } - (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return [self objectForKey:key inCollection:collection ofExpectedType:[ECKeyPair class]]; } - (nullable PreKeyRecord *)preKeyRecordForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return [self objectForKey:key inCollection:collection ofExpectedType:[PreKeyRecord class]]; } - (nullable PreKeyBundle *)preKeyBundleForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return [self objectForKey:key inCollection:collection ofExpectedType:PreKeyBundle.class]; } - (nullable SignedPreKeyRecord *)signedPreKeyRecordForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - return [self objectForKey:key inCollection:collection ofExpectedType:[SignedPreKeyRecord class]]; } - (int)intForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - NSNumber *_Nullable number = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]]; return [number intValue]; } - (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]]; if (value) { return [NSDate dateWithTimeIntervalSince1970:value.doubleValue]; @@ -117,29 +83,20 @@ NS_ASSUME_NONNULL_BEGIN #if DEBUG - (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath { - OWSAssertDebug(collection.length > 0); - OWSAssertDebug(snapshotFilePath.length > 0); - NSMutableDictionary *snapshot = [NSMutableDictionary new]; [self enumerateKeysAndObjectsInCollection:collection usingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) { snapshot[key] = value; }]; NSData *_Nullable data = [NSKeyedArchiver archivedDataWithRootObject:snapshot]; - OWSAssertDebug(data); BOOL success = [data writeToFile:snapshotFilePath atomically:YES]; - OWSAssertDebug(success); } - (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath { - OWSAssertDebug(collection.length > 0); - OWSAssertDebug(snapshotFilePath.length > 0); NSData *_Nullable data = [NSData dataWithContentsOfFile:snapshotFilePath]; - OWSAssertDebug(data); NSMutableDictionary *_Nullable snapshot = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - OWSAssertDebug(snapshot); [self removeAllObjectsInCollection:collection]; [snapshot enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) { @@ -150,9 +107,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection { - OWSAssertDebug(key.length > 0); - OWSAssertDebug(collection.length > 0); - NSNumber *_Nullable oldValue = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]]; if (oldValue && [@(value) isEqual:oldValue]) { // Skip redundant writes. diff --git a/SessionProtocolKit/Meta/SessionProtocolKit.h b/SessionProtocolKit/Meta/SessionProtocolKit.h index ef52ae984..75a2d0606 100644 --- a/SessionProtocolKit/Meta/SessionProtocolKit.h +++ b/SessionProtocolKit/Meta/SessionProtocolKit.h @@ -7,6 +7,7 @@ FOUNDATION_EXPORT const unsigned char SessionProtocolKitVersionString[]; #import #import #import +#import #import #import #import diff --git a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h index 7ec01ed1e..4299a4862 100644 --- a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h +++ b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h @@ -20,7 +20,7 @@ #import #import #import -#import +#import #import #import -#import +#import diff --git a/SessionShareExtension/ShareAppExtensionContext.m b/SessionShareExtension/ShareAppExtensionContext.m index ba02a50cb..be237eac7 100644 --- a/SessionShareExtension/ShareAppExtensionContext.m +++ b/SessionShareExtension/ShareAppExtensionContext.m @@ -4,7 +4,7 @@ #import "ShareAppExtensionContext.h" #import -#import +#import #import #import diff --git a/SignalUtilitiesKit/Database/Storage/Storage+OnionRequests.swift b/SessionSnodeKit/Storage+OnionRequests.swift similarity index 98% rename from SignalUtilitiesKit/Database/Storage/Storage+OnionRequests.swift rename to SessionSnodeKit/Storage+OnionRequests.swift index e308b96b7..456507b7e 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+OnionRequests.swift +++ b/SessionSnodeKit/Storage+OnionRequests.swift @@ -1,3 +1,4 @@ +import SessionUtilitiesKit extension Storage { diff --git a/SignalUtilitiesKit/Database/Storage/Storage+SnodeAPI.swift b/SessionSnodeKit/Storage+SnodeAPI.swift similarity index 99% rename from SignalUtilitiesKit/Database/Storage/Storage+SnodeAPI.swift rename to SessionSnodeKit/Storage+SnodeAPI.swift index 0c681f71b..85cc28d29 100644 --- a/SignalUtilitiesKit/Database/Storage/Storage+SnodeAPI.swift +++ b/SessionSnodeKit/Storage+SnodeAPI.swift @@ -1,3 +1,4 @@ +import SessionUtilitiesKit extension Storage { diff --git a/SignalUtilitiesKit/Utilities/BuildConfiguration.swift b/SessionUtilitiesKit/BuildConfiguration.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/BuildConfiguration.swift rename to SessionUtilitiesKit/BuildConfiguration.swift diff --git a/SignalUtilitiesKit/ContentProxy.swift b/SessionUtilitiesKit/ContentProxy.swift similarity index 95% rename from SignalUtilitiesKit/ContentProxy.swift rename to SessionUtilitiesKit/ContentProxy.swift index 12cf3eb2a..4dd641ae4 100644 --- a/SignalUtilitiesKit/ContentProxy.swift +++ b/SessionUtilitiesKit/ContentProxy.swift @@ -2,6 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // +import AFNetworking import Foundation @objc @@ -33,7 +34,6 @@ public class ContentProxy: NSObject { return AFHTTPSessionManager(baseURL: nil, sessionConfiguration: sessionConfiguration()) } guard let baseUrl = URL(string: baseUrlString) else { - owsFailDebug("Invalid base URL.") return nil } let sessionManager = AFHTTPSessionManager(baseURL: baseUrl, @@ -44,7 +44,6 @@ public class ContentProxy: NSObject { @objc public class func jsonSessionManager(baseUrl: String) -> AFHTTPSessionManager? { guard let sessionManager = self.sessionManager(baseUrl: baseUrl) else { - owsFailDebug("Could not create session manager") return nil } sessionManager.requestSerializer = AFJSONRequestSerializer() @@ -77,14 +76,12 @@ public class ContentProxy: NSObject { forUrl urlString: String) -> Bool { guard let url = URL(string: urlString, relativeTo: sessionManager.baseURL) else { - owsFailDebug("Invalid URL query: \(urlString).") return false } var request = URLRequest(url: url) guard configureProxiedRequest(request: &request) else { - owsFailDebug("Invalid URL query: \(urlString).") return false } diff --git a/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift b/SessionUtilitiesKit/ECKeyPair+Hexadecimal.swift similarity index 97% rename from SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift rename to SessionUtilitiesKit/ECKeyPair+Hexadecimal.swift index aa563044e..2adc83430 100644 --- a/SignalUtilitiesKit/Utilities/ECKeyPair+Hexadecimal.swift +++ b/SessionUtilitiesKit/ECKeyPair+Hexadecimal.swift @@ -1,3 +1,4 @@ +import Curve25519Kit public extension ECKeyPair { diff --git a/SignalUtilitiesKit/Threads/LKGroupUtilities.h b/SessionUtilitiesKit/LKGroupUtilities.h similarity index 100% rename from SignalUtilitiesKit/Threads/LKGroupUtilities.h rename to SessionUtilitiesKit/LKGroupUtilities.h diff --git a/SignalUtilitiesKit/Threads/LKGroupUtilities.m b/SessionUtilitiesKit/LKGroupUtilities.m similarity index 95% rename from SignalUtilitiesKit/Threads/LKGroupUtilities.m rename to SessionUtilitiesKit/LKGroupUtilities.m index 78c79b86b..a291ec6d7 100644 --- a/SignalUtilitiesKit/Threads/LKGroupUtilities.m +++ b/SessionUtilitiesKit/LKGroupUtilities.m @@ -1,5 +1,4 @@ #import "LKGroupUtilities.h" -#import @implementation LKGroupUtilities @@ -44,7 +43,6 @@ +(NSString *)getDecodedGroupID:(NSData *)groupID { - OWSAssertDebug(groupID.length > 0); NSString *encodedGroupID = [[NSString alloc] initWithData:groupID encoding:NSUTF8StringEncoding]; if ([encodedGroupID componentsSeparatedByString:@"!"].count > 1) { return [encodedGroupID componentsSeparatedByString:@"!"][1]; diff --git a/SignalUtilitiesKit/Utilities/LKUserDefaults.swift b/SessionUtilitiesKit/LKUserDefaults.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/LKUserDefaults.swift rename to SessionUtilitiesKit/LKUserDefaults.swift diff --git a/SignalUtilitiesKit/Utilities/LRUCache.swift b/SessionUtilitiesKit/LRUCache.swift similarity index 95% rename from SignalUtilitiesKit/Utilities/LRUCache.swift rename to SessionUtilitiesKit/LRUCache.swift index 436b4e365..8e2dde882 100644 --- a/SignalUtilitiesKit/Utilities/LRUCache.swift +++ b/SessionUtilitiesKit/LRUCache.swift @@ -54,14 +54,10 @@ public class LRUCache { } @objc func didEnterBackground() { - AssertIsOnMainThread() - clear() } @objc func didReceiveMemoryWarning() { - AssertIsOnMainThread() - clear() } @@ -89,7 +85,6 @@ public class LRUCache { while cacheOrder.count > maxSize { guard let staleKey = cacheOrder.first else { - owsFailDebug("Cache ordering unexpectedly empty") return } cacheOrder.removeFirst() diff --git a/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h b/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h index 672951858..5f076cd3c 100644 --- a/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h +++ b/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h @@ -5,10 +5,14 @@ FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[]; #import #import +#import #import +#import #import #import +#import #import +#import #import #import #import diff --git a/SignalUtilitiesKit/Utilities/NSArray+Functional.h b/SessionUtilitiesKit/NSArray+Functional.h similarity index 100% rename from SignalUtilitiesKit/Utilities/NSArray+Functional.h rename to SessionUtilitiesKit/NSArray+Functional.h diff --git a/SignalUtilitiesKit/Utilities/NSArray+Functional.m b/SessionUtilitiesKit/NSArray+Functional.m similarity index 100% rename from SignalUtilitiesKit/Utilities/NSArray+Functional.m rename to SessionUtilitiesKit/NSArray+Functional.m diff --git a/SignalUtilitiesKit/NSNotificationCenter+OWS.h b/SessionUtilitiesKit/NSNotificationCenter+OWS.h similarity index 100% rename from SignalUtilitiesKit/NSNotificationCenter+OWS.h rename to SessionUtilitiesKit/NSNotificationCenter+OWS.h diff --git a/SignalUtilitiesKit/NSNotificationCenter+OWS.m b/SessionUtilitiesKit/NSNotificationCenter+OWS.m similarity index 100% rename from SignalUtilitiesKit/NSNotificationCenter+OWS.m rename to SessionUtilitiesKit/NSNotificationCenter+OWS.m diff --git a/SignalUtilitiesKit/Utilities/NSRegularExpression+SSK.swift b/SessionUtilitiesKit/NSRegularExpression+SSK.swift similarity index 93% rename from SignalUtilitiesKit/Utilities/NSRegularExpression+SSK.swift rename to SessionUtilitiesKit/NSRegularExpression+SSK.swift index 288f6f263..0704a86cb 100644 --- a/SignalUtilitiesKit/Utilities/NSRegularExpression+SSK.swift +++ b/SessionUtilitiesKit/NSRegularExpression+SSK.swift @@ -25,13 +25,11 @@ public extension NSRegularExpression { } let matchRange = match.range(at: 1) guard let textRange = Range(matchRange, in: text) else { - owsFailDebug("Invalid match.") return nil } let substring = String(text[textRange]) return substring } catch { - Logger.error("Error: \(error)") return nil } } @@ -46,7 +44,6 @@ public extension NSRegularExpression { } let matchRange = match.range(at: 1) guard let textRange = Range(matchRange, in: text) else { - owsFailDebug("Invalid match.") return nil } let substring = String(text[textRange]) diff --git a/SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.h b/SessionUtilitiesKit/NSUserDefaults+OWS.h similarity index 100% rename from SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.h rename to SessionUtilitiesKit/NSUserDefaults+OWS.h diff --git a/SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.m b/SessionUtilitiesKit/NSUserDefaults+OWS.m similarity index 88% rename from SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.m rename to SessionUtilitiesKit/NSUserDefaults+OWS.m index 4fa8b7b80..1bf02767e 100644 --- a/SignalUtilitiesKit/Utilities/NSUserDefaults+OWS.m +++ b/SessionUtilitiesKit/NSUserDefaults+OWS.m @@ -4,7 +4,6 @@ #import "NSUserDefaults+OWS.h" #import "AppContext.h" -#import "TSConstants.h" #import NS_ASSUME_NONNULL_BEGIN @@ -18,14 +17,11 @@ NS_ASSUME_NONNULL_BEGIN + (void)migrateToSharedUserDefaults { - OWSLogInfo(@""); - NSUserDefaults *appUserDefaults = self.appUserDefaults; NSDictionary *dictionary = [NSUserDefaults standardUserDefaults].dictionaryRepresentation; for (NSString *key in dictionary) { id value = dictionary[key]; - OWSAssertDebug(value); [appUserDefaults setObject:value forKey:key]; } } @@ -38,8 +34,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)removeAll { - OWSAssertDebug(CurrentAppContext().isMainApp); - NSDictionary *dictionary = self.dictionaryRepresentation; for (NSString *key in dictionary) { [self removeObjectForKey:key]; diff --git a/SignalUtilitiesKit/ProxiedContentDownloader.swift b/SessionUtilitiesKit/ProxiedContentDownloader.swift similarity index 90% rename from SignalUtilitiesKit/ProxiedContentDownloader.swift rename to SessionUtilitiesKit/ProxiedContentDownloader.swift index 5b6d2f23e..f01286dd6 100644 --- a/SignalUtilitiesKit/ProxiedContentDownloader.swift +++ b/SessionUtilitiesKit/ProxiedContentDownloader.swift @@ -28,7 +28,6 @@ open class ProxiedContentAssetDescription: NSObject { self.fileExtension = fileExtension } else { guard let pathExtension = url.pathExtension else { - owsFailDebug("URL has not path extension.") return nil } self.fileExtension = pathExtension @@ -57,11 +56,7 @@ public class ProxiedContentAssetSegment: NSObject { public let redundantLength: UInt // This state should only be accessed on the main thread. - public var state: ProxiedContentAssetSegmentState = .waiting { - didSet { - AssertIsOnMainThread() - } - } + public var state: ProxiedContentAssetSegmentState = .waiting // This state is accessed off the main thread. // @@ -88,7 +83,6 @@ public class ProxiedContentAssetSegment: NSObject { public func append(data: Data) { guard state == .downloading else { - owsFailDebug("appending data in invalid state: \(state)") return } @@ -97,11 +91,9 @@ public class ProxiedContentAssetSegment: NSObject { public func mergeData(assetData: inout Data) -> Bool { guard state == .complete else { - owsFailDebug("merging data in invalid state: \(state)") return false } guard UInt(segmentData.count) == segmentLength else { - owsFailDebug("segment data length: \(segmentData.count) doesn't match expected length: \(segmentLength)") return false } @@ -159,7 +151,6 @@ public class ProxiedContentAssetRequest: NSObject { public var state: ProxiedContentAssetRequestState = .waiting public var contentLength: Int = 0 { didSet { - AssertIsOnMainThread() assert(oldValue == 0) assert(contentLength > 0) } @@ -179,11 +170,9 @@ public class ProxiedContentAssetRequest: NSObject { } private func segmentSize() -> UInt { - AssertIsOnMainThread() let contentLength = UInt(self.contentLength) guard contentLength > 0 else { - owsFailDebug("asset missing contentLength") requestDidFail() return 0 } @@ -203,8 +192,6 @@ public class ProxiedContentAssetRequest: NSObject { } fileprivate func createSegments(withInitialData initialData: Data) { - AssertIsOnMainThread() - let segmentLength = segmentSize() guard segmentLength > 0 else { return @@ -245,11 +232,8 @@ public class ProxiedContentAssetRequest: NSObject { } private func firstSegmentWithState(state: ProxiedContentAssetSegmentState) -> ProxiedContentAssetSegment? { - AssertIsOnMainThread() - for segment in segments { guard segment.state != .failed else { - owsFailDebug("unexpected failed segment.") continue } if segment.state == state { @@ -260,18 +244,13 @@ public class ProxiedContentAssetRequest: NSObject { } public func firstWaitingSegment() -> ProxiedContentAssetSegment? { - AssertIsOnMainThread() - return firstSegmentWithState(state: .waiting) } public func downloadingSegmentsCount() -> UInt { - AssertIsOnMainThread() - var result: UInt = 0 for segment in segments { guard segment.state != .failed else { - owsFailDebug("unexpected failed segment.") continue } if segment.state == .downloading { @@ -282,8 +261,6 @@ public class ProxiedContentAssetRequest: NSObject { } public func areAllSegmentsComplete() -> Bool { - AssertIsOnMainThread() - for segment in segments { guard segment.state == .complete else { return false @@ -297,48 +274,37 @@ public class ProxiedContentAssetRequest: NSObject { var assetData = Data() for segment in segments { guard segment.state == .complete else { - owsFailDebug("unexpected incomplete segment.") return nil } guard segment.totalDataSize() > 0 else { - owsFailDebug("could not merge empty segment.") return nil } guard segment.mergeData(assetData: &assetData) else { - owsFailDebug("failed to merge segment data.") return nil } } guard assetData.count == contentLength else { - owsFailDebug("asset data has unexpected length.") return nil } guard assetData.count > 0 else { - owsFailDebug("could not write empty asset to disk.") return nil } let fileExtension = assetDescription.fileExtension let fileName = (NSUUID().uuidString as NSString).appendingPathExtension(fileExtension)! let filePath = (downloadFolderPath as NSString).appendingPathComponent(fileName) - - Logger.verbose("filePath: \(filePath).") - do { try assetData.write(to: NSURL.fileURL(withPath: filePath), options: .atomicWrite) let asset = ProxiedContentAsset(assetDescription: assetDescription, filePath: filePath) return asset } catch let error as NSError { - owsFailDebug("file write failed: \(filePath), \(error)") return nil } } public func cancel() { - AssertIsOnMainThread() - wasCancelled = true contentLengthTask?.cancel() contentLengthTask = nil @@ -352,15 +318,11 @@ public class ProxiedContentAssetRequest: NSObject { } private func clearCallbacks() { - AssertIsOnMainThread() - success = nil failure = nil } public func requestDidSucceed(asset: ProxiedContentAsset) { - AssertIsOnMainThread() - success?(self, asset) // Only one of the callbacks should be called, and only once. @@ -368,8 +330,6 @@ public class ProxiedContentAssetRequest: NSObject { } public func requestDidFail() { - AssertIsOnMainThread() - failure?(self) // Only one of the callbacks should be called, and only once. @@ -407,7 +367,7 @@ public class ProxiedContentAsset: NSObject { let fileManager = FileManager.default try fileManager.removeItem(atPath: filePathCopy) } catch let error as NSError { - owsFailDebug("file cleanup failed: \(filePathCopy), \(error)") + } } } @@ -454,14 +414,10 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Force usage as a singleton public required init(downloadFolderName: String) { - AssertIsOnMainThread() - self.downloadFolderName = downloadFolderName super.init() - SwiftSingletons.register(self) - ensureDownloadFolder() } @@ -470,8 +426,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio } private lazy var downloadSession: URLSession = { - AssertIsOnMainThread() - let configuration = ContentProxy.sessionConfiguration() // Don't use any caching to protect privacy of these requests. @@ -505,11 +459,8 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio priority: ProxiedContentRequestPriority, success:@escaping ((ProxiedContentAssetRequest?, ProxiedContentAsset) -> Void), failure:@escaping ((ProxiedContentAssetRequest) -> Void)) -> ProxiedContentAssetRequest? { - AssertIsOnMainThread() - if let asset = assetMap.get(key: assetDescription.url) { // Synchronous cache hit. - Logger.verbose("asset cache hit: \(assetDescription.url)") success(nil, asset) return nil } @@ -517,7 +468,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Cache miss. // // Asset requests are done queued and performed asynchronously. - Logger.verbose("asset cache miss: \(assetDescription.url)") let assetRequest = ProxiedContentAssetRequest(assetDescription: assetDescription, priority: priority, success: success, @@ -532,10 +482,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio } public func cancelAllRequests() { - AssertIsOnMainThread() - - Logger.verbose("cancelAllRequests") - self.assetRequestQueue.forEach { $0.cancel() } self.assetRequestQueue = [] } @@ -552,8 +498,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Returns true if the request is completed. private func tryToCompleteRequest(assetRequest: ProxiedContentAssetRequest) -> Bool { - AssertIsOnMainThread() - guard assetRequest.areAllSegmentsComplete() else { return false } @@ -565,7 +509,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Move write off main thread. DispatchQueue.global().async { guard let downloadFolderPath = self.downloadFolderPath else { - owsFailDebug("Missing downloadFolderPath") return } guard let asset = assetRequest.writeAssetToFile(downloadFolderPath: downloadFolderPath) else { @@ -607,10 +550,7 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio } private func removeAssetRequestFromQueue(assetRequest: ProxiedContentAssetRequest) { - AssertIsOnMainThread() - guard assetRequestQueue.contains(assetRequest) else { - Logger.warn("could not remove asset request from queue: \(assetRequest.assetDescription.url)") return } @@ -630,8 +570,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // * Complete/cancel asset requests if possible. // private func processRequestQueueSync() { - AssertIsOnMainThread() - guard let assetRequest = popNextAssetRequest() else { return } @@ -687,7 +625,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Start a download task. guard let assetSegment = assetRequest.firstWaitingSegment() else { - owsFailDebug("queued asset request does not have a waiting segment.") return } assetSegment.state = .downloading @@ -723,13 +660,11 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio } guard let data = data, data.count > 0 else { - owsFailDebug("Asset size response missing data.") assetRequest.state = .failed self.assetRequestDidFail(assetRequest: assetRequest) return } guard let httpResponse = response as? HTTPURLResponse else { - owsFailDebug("Asset size response is invalid.") assetRequest.state = .failed self.assetRequestDidFail(assetRequest: assetRequest) return @@ -737,7 +672,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio var firstContentRangeString: String? for header in httpResponse.allHeaderFields.keys { guard let headerString = header as? String else { - owsFailDebug("Invalid header: \(header)") continue } if headerString.lowercased() == "content-range" { @@ -745,7 +679,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio } } guard let contentRangeString = firstContentRangeString else { - owsFailDebug("Asset size response is missing content range.") assetRequest.state = .failed self.assetRequestDidFail(assetRequest: assetRequest) return @@ -753,21 +686,18 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Example: content-range: bytes 0-1023/7630 guard let contentLengthString = NSRegularExpression.parseFirstMatch(pattern: "^bytes \\d+\\-\\d+/(\\d+)$", - text: contentRangeString) else { - owsFailDebug("Asset size response has invalid content range.") + text: contentRangeString) else { assetRequest.state = .failed self.assetRequestDidFail(assetRequest: assetRequest) return } guard contentLengthString.count > 0, let contentLength = Int(contentLengthString) else { - owsFailDebug("Asset size response has unparsable content length.") assetRequest.state = .failed self.assetRequestDidFail(assetRequest: assetRequest) return } guard contentLength > 0 else { - owsFailDebug("Asset size response has invalid content length.") assetRequest.state = .failed self.assetRequestDidFail(assetRequest: assetRequest) return @@ -789,8 +719,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // * Need to download the content length. // * Need to download at least one of its segments. private func popNextAssetRequest() -> ProxiedContentAssetRequest? { - AssertIsOnMainThread() - let kMaxAssetRequestCount: UInt = 3 let kMaxAssetRequestsPerAssetCount: UInt = kMaxAssetRequestCount - 1 @@ -874,23 +802,19 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio return } if let error = error { - Logger.error("download failed with error: \(error)") segmentRequestDidFail(assetRequest: assetRequest, assetSegment: assetSegment) return } guard let httpResponse = task.response as? HTTPURLResponse else { - Logger.error("missing or unexpected response: \(String(describing: task.response))") segmentRequestDidFail(assetRequest: assetRequest, assetSegment: assetSegment) return } let statusCode = httpResponse.statusCode guard statusCode >= 200 && statusCode < 400 else { - Logger.error("response has invalid status code: \(statusCode)") segmentRequestDidFail(assetRequest: assetRequest, assetSegment: assetSegment) return } guard assetSegment.totalDataSize() == assetSegment.segmentLength else { - Logger.error("segment is missing data: \(statusCode)") segmentRequestDidFail(assetRequest: assetRequest, assetSegment: assetSegment) return } @@ -925,7 +849,6 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Don't back up ProxiedContent downloads. OWSFileSystem.protectFileOrFolder(atPath: dirPath) } catch let error as NSError { - owsFailDebug("ensureTempFolder failed: \(dirPath), \(error)") downloadFolderPath = tempDirPath } } diff --git a/SignalUtilitiesKit/Database/Keychain/SSKKeychainStorage.swift b/SessionUtilitiesKit/SSKKeychainStorage.swift similarity index 97% rename from SignalUtilitiesKit/Database/Keychain/SSKKeychainStorage.swift rename to SessionUtilitiesKit/SSKKeychainStorage.swift index 168609bed..e9243901f 100644 --- a/SignalUtilitiesKit/Database/Keychain/SSKKeychainStorage.swift +++ b/SessionUtilitiesKit/SSKKeychainStorage.swift @@ -34,8 +34,6 @@ public class SSKDefaultKeychainStorage: NSObject, SSKKeychainStorage { // Force usage as a singleton override private init() { super.init() - - SwiftSingletons.register(self) } @objc public func string(forService service: String, key: String) throws -> String { @@ -96,7 +94,6 @@ public class SSKDefaultKeychainStorage: NSObject, SSKKeychainStorage { if let error = error { // If deletion failed because the specified item could not be found in the keychain, consider it success. if error.code == errSecItemNotFound { - Logger.info("Keychain delete failed; item not found.") return } throw KeychainStorageError.failure(description: "\(logTag) error removing data: \(error)") diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 4df8c5640..0f4163221 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -238,13 +238,10 @@ B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408F239DD75000A248E7 /* RestoreVC.swift */; }; B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B4093239DF15900A248E7 /* ConversationTitleView.swift */; }; B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */; }; - B84072962565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */; }; - B84072A02565F1670037CB17 /* Quote+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B840729F2565F1670037CB17 /* Quote+Conversion.swift */; }; B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; }; B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; }; B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */; }; - B867665825663BBA00B197C5 /* MessageSenderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B867665725663BBA00B197C5 /* MessageSenderDelegate.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; @@ -265,21 +262,6 @@ B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF6422397711F0091D419 /* SettingsVC.swift */; }; B8D797B2256B25A1007C59DF /* TSAttachmentPointer+Backups.m in Sources */ = {isa = PBXBuildFile; fileRef = B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */; }; B8D797C3256B25A8007C59DF /* TSAttachmentPointer+Backups.h in Headers */ = {isa = PBXBuildFile; fileRef = B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B8D797D5256B2715007C59DF /* TSAttachment+Albums.m in Sources */ = {isa = PBXBuildFile; fileRef = B8D797D4256B2715007C59DF /* TSAttachment+Albums.m */; }; - B8D797DF256B2737007C59DF /* TSAttachment+Albums.h in Headers */ = {isa = PBXBuildFile; fileRef = B8D797DE256B2732007C59DF /* TSAttachment+Albums.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B8D8F0F32565F98E0092EF10 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; - B8D8F0F42565F98E0092EF10 /* PushNotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */; }; - B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */; }; - B8D8F16A256615DE0092EF10 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; }; - B8D8F16B256615DE0092EF10 /* Storage+VolumeSamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */; }; - B8D8F16C256615DE0092EF10 /* Storage+SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */; }; - B8D8F17725661AFA0092EF10 /* Storage+Jobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */; }; - B8D8F18925661BA50092EF10 /* Storage+OpenGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */; }; - B8D8F19325661BF80092EF10 /* Storage+Messaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */; }; - B8D8F1BD25661C6F0092EF10 /* Storage+OnionRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */; }; - B8D8F1E6256620DD0092EF10 /* MessageReceiverDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */; }; - B8D8F1F0256621180092EF10 /* MessageSenderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */; }; - B8D8F21A25662A4D0092EF10 /* OpenGroupAPIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */; }; B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; }; B9EB5ABD1884C002007CBB57 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EB5ABC1884C002007CBB57 /* MessageUI.framework */; }; C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */; }; @@ -299,6 +281,119 @@ C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */; }; C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */; }; C329FEEC24F7277900B1C64C /* LightModeSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C329FEEB24F7277900B1C64C /* LightModeSheet.swift */; }; + C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */; }; + C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */; }; + C32C59C0256DB41F003C73A2 /* TSThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD3255A580300E217F9 /* TSThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC01255A581C00E217F9 /* TSGroupThread.m */; }; + C32C59C2256DB41F003C73A2 /* TSContactThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB3255A580000E217F9 /* TSContactThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C59C3256DB41F003C73A2 /* TSGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB73255A581000E217F9 /* TSGroupModel.m */; }; + C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF9255A580600E217F9 /* TSContactThread.m */; }; + C32C59C5256DB41F003C73A2 /* TSGroupModel.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0A255A580700E217F9 /* TSGroupModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C59C6256DB41F003C73A2 /* TSGroupThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA79255A57FB00E217F9 /* TSGroupThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C59C7256DB41F003C73A2 /* TSThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB8255A581600E217F9 /* TSThread.m */; }; + C32C5A02256DB658003C73A2 /* MessageSender+Handling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1EF256621180092EF10 /* MessageSender+Handling.swift */; }; + C32C5A13256DB7A5003C73A2 /* PushNotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */; }; + C32C5A24256DB7DB003C73A2 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; + C32C5A2D256DB849003C73A2 /* LKGroupUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */; }; + C32C5A36256DB856003C73A2 /* LKGroupUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */; }; + C32C5A48256DB8F0003C73A2 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; }; + C32C5A75256DBBCF003C73A2 /* TSAttachmentPointer+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCFD25673DBC0002D4EB /* TSAttachmentPointer+Conversion.swift */; }; + C32C5A76256DBBCF003C73A2 /* SignalAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF224255B6D5D007E1867 /* SignalAttachment.swift */; }; + C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C32C5A87256DBCF9003C73A2 /* MessageReceiver+Handling.swift */; }; + C32C5AAA256DBE8F003C73A2 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */; }; + C32C5AAC256DBE8F003C73A2 /* TSInfoMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADD255A580400E217F9 /* TSInfoMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5AAD256DBE8F003C73A2 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */; }; + C32C5AAE256DBE8F003C73A2 /* TSInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE9255A581A00E217F9 /* TSInteraction.m */; }; + C32C5AAF256DBE8F003C73A2 /* TSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA70255A57FA00E217F9 /* TSMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */; }; + C32C5AB1256DBE8F003C73A2 /* TSIncomingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */; }; + C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB60255A580E00E217F9 /* TSMessage.m */; }; + C32C5AB3256DBE8F003C73A2 /* TSInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE6255A580400E217F9 /* TSInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5AB4256DBE8F003C73A2 /* TSOutgoingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5AB5256DBE8F003C73A2 /* TSOutgoingMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */; }; + C32C5ADF256DBFAA003C73A2 /* OWSReadTracking.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE1255A580400E217F9 /* OWSReadTracking.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5AF8256DC051003C73A2 /* OWSDisappearingMessagesConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */; }; + C32C5B0A256DC076003C73A2 /* OWSDisappearingMessagesConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5B1C256DC19D003C73A2 /* TSQuotedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB83255A581100E217F9 /* TSQuotedMessage.m */; }; + C32C5B2D256DC1A1003C73A2 /* TSQuotedMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5B3F256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C32C5B3E256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift */; }; + C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */; }; + C32C5B51256DC219003C73A2 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5B62256DC333003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */; }; + C32C5B6B256DC357003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5B84256DC54F003C73A2 /* SSKEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF4255A580600E217F9 /* SSKEnvironment.m */; }; + C32C5B8D256DC565003C73A2 /* SSKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB31255A580A00E217F9 /* SSKEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */; }; + C32C5BB0256DC73D003C73A2 /* OWSBlockingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5BBA256DC7E3003C73A2 /* ProfileManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5BCC256DC830003C73A2 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */; }; + C32C5BDD256DC88D003C73A2 /* OWSReadReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */; }; + C32C5BE6256DC891003C73A2 /* OWSReadReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5BEF256DC8EE003C73A2 /* OWSDisappearingMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */; }; + C32C5BF8256DC8F6003C73A2 /* OWSDisappearingMessagesJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */; }; + C32C5C0A256DC9B4003C73A2 /* OWSIdentityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5C1B256DC9E0003C73A2 /* GeneralUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */; }; + C32C5C24256DCB30003C73A2 /* NotificationsProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB75255A581000E217F9 /* AppReadiness.m */; }; + C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB01255A580700E217F9 /* AppReadiness.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */; }; + C32C5C88256DD0D2003C73A2 /* Storage+Messaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */; }; + C32C5C89256DD0D2003C73A2 /* Storage+Jobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */; }; + C32C5C93256DD12D003C73A2 /* OWSUDManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C32C5C92256DD12D003C73A2 /* OWSUDManager.swift */; }; + C32C5CA4256DD1DC003C73A2 /* TSAccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB88255A581200E217F9 /* TSAccountManager.m */; }; + C32C5CAD256DD1DF003C73A2 /* TSAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB94255A581300E217F9 /* TSAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5CBE256DD282003C73A2 /* Storage+OnionRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */; }; + C32C5CBF256DD282003C73A2 /* Storage+SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */; }; + C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; }; + C32C5D19256DD493003C73A2 /* OWSLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */; }; + C32C5D23256DD4C0003C73A2 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7E255A57FB00E217F9 /* Mention.swift */; }; + C32C5D24256DD4C0003C73A2 /* MentionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA81255A57FC00E217F9 /* MentionsManager.swift */; }; + C32C5D2E256DD4EA003C73A2 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */; }; + C32C5D37256DD4ED003C73A2 /* TSUnreadIndicatorInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5D40256DD51E003C73A2 /* Storage+VolumeSamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */; }; + C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */; }; + C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */; }; + C32C5DA5256DD6E5003C73A2 /* OWSOutgoingReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5DBE256DD743003C73A2 /* OpenGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */; }; + C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */; }; + C32C5DC0256DD743003C73A2 /* Poller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3A255A580B00E217F9 /* Poller.swift */; }; + C32C5DC9256DD935003C73A2 /* ProxiedContentDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */; }; + C32C5DD2256DD9E5003C73A2 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; }; + C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB68255A580F00E217F9 /* ContentProxy.swift */; }; + C32C5E0C256DDAFA003C73A2 /* NSRegularExpression+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */; }; + C32C5E15256DDC78003C73A2 /* SSKPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA69255A57F900E217F9 /* SSKPreferences.swift */; }; + C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; }; + C32C5E64256DDFD6003C73A2 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */; }; + C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */; }; + C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5EB9256DE130003C73A2 /* OWSQuotedReplyModel+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B840729F2565F1670037CB17 /* OWSQuotedReplyModel+Conversion.swift */; }; + C32C5EBA256DE130003C73A2 /* OWSQuotedReplyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */; }; + C32C5EC3256DE133003C73A2 /* OWSQuotedReplyModel.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */; }; + C32C5EE5256DF506003C73A2 /* YapDatabaseConnection+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5EEE256DF54E003C73A2 /* TSDatabaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB46255A580C00E217F9 /* TSDatabaseView.m */; }; + C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5F08256DF5C8003C73A2 /* DisplayNameUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */; }; + C32C5F11256DF79A003C73A2 /* SSKIncrementingIdFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */; }; + C32C5F1A256DFCAD003C73A2 /* TSErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE7255A580500E217F9 /* TSErrorMessage.m */; }; + C32C5F23256DFCC0003C73A2 /* TSErrorMessage_privateConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5F34256DFCC4003C73A2 /* TSErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB0255A581500E217F9 /* TSErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5F45256DFD2B003C73A2 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */; }; + C32C5F4E256DFD58003C73A2 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5F5F256DFD90003C73A2 /* TSInvalidIdentityKeyErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */; }; + C32C5F68256DFDAA003C73A2 /* TSInvalidIdentityKeyErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5FA1256DFED5003C73A2 /* NSArray+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB8255A580100E217F9 /* NSArray+Functional.m */; }; + C32C5FAA256DFED9003C73A2 /* NSArray+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */; }; + C32C5FC4256E0209003C73A2 /* OWSBackgroundTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C32C5FD6256E0346003C73A2 /* Notification+Thread.swift in Sources */ = {isa = PBXBuildFile; fileRef = C32C5FD5256E0346003C73A2 /* Notification+Thread.swift */; }; + C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */; }; + C32C6018256E07F9003C73A2 /* NSUserDefaults+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */; }; C33100092558FF6D00070591 /* UserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DDC25217014005D4DA8 /* UserCell.swift */; }; C33100142558FFC200070591 /* UIImage+Tinting.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33100132558FFC200070591 /* UIImage+Tinting.swift */; }; @@ -331,207 +426,104 @@ C33FD9C3255A54EF00E217F9 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C33FD9C4255A54EF00E217F9 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; }; C33FD9C5255A54EF00E217F9 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; }; - C33FDC21255A581F00E217F9 /* OWSPrimaryStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */; }; - C33FDC23255A581F00E217F9 /* SSKPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA69255A57F900E217F9 /* SSKPreferences.swift */; }; - C33FDC25255A581F00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */; }; - C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */; }; C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */; }; C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */; }; - C33FDC2A255A581F00E217F9 /* TSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA70255A57FA00E217F9 /* TSMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC2B255A581F00E217F9 /* OWSReadReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */; }; C33FDC2C255A581F00E217F9 /* OWSFailedAttachmentDownloadsJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA72255A57FA00E217F9 /* OWSFailedAttachmentDownloadsJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC2D255A581F00E217F9 /* ECKeyPair+Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */; }; C33FDC2F255A581F00E217F9 /* OWSSyncManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA75255A57FB00E217F9 /* OWSSyncManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC33255A581F00E217F9 /* TSGroupThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA79255A57FB00E217F9 /* TSGroupThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC34255A581F00E217F9 /* NSRegularExpression+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */; }; - C33FDC35255A581F00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC38255A581F00E217F9 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7E255A57FB00E217F9 /* Mention.swift */; }; C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */; }; - C33FDC3A255A581F00E217F9 /* OWSDisappearingMessagesJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA81255A57FC00E217F9 /* MentionsManager.swift */; }; - C33FDC40255A581F00E217F9 /* OWSDisappearingMessagesFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */; }; - C33FDC41255A581F00E217F9 /* TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */; }; - C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8B255A57FD00E217F9 /* AppVersion.m */; }; - C33FDC46255A581F00E217F9 /* OpenGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */; }; C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA96255A57FE00E217F9 /* OWSDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */; }; C33FDC52255A582000E217F9 /* RotateSignedKeyOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA98255A57FE00E217F9 /* RotateSignedKeyOperation.swift */; }; C33FDC53255A582000E217F9 /* OutageDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA99255A57FE00E217F9 /* OutageDetection.swift */; }; C33FDC57255A582000E217F9 /* OWSContactsOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */; }; - C33FDC5A255A582000E217F9 /* OWSRecipientIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; - C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; }; - C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB3255A580000E217F9 /* TSContactThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */; }; - C33FDC72255A582000E217F9 /* NSArray+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB8255A580100E217F9 /* NSArray+Functional.m */; }; C33FDC73255A582000E217F9 /* OWSStorage+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC75255A582000E217F9 /* OWSGroupsOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDABB255A580100E217F9 /* OWSGroupsOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC77255A582000E217F9 /* OWSOutgoingReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC78255A582000E217F9 /* TSConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDABE255A580100E217F9 /* TSConstants.m */; }; - C33FDC7A255A582000E217F9 /* OWSIncomingMessageFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC1255A580100E217F9 /* NSSet+Functional.m */; }; C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC3255A580200E217F9 /* OWSDispatch.m */; }; - C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; }; C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC8D255A582000E217F9 /* TSThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD3255A580300E217F9 /* TSThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC8F255A582000E217F9 /* TSQuotedMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC92255A582000E217F9 /* OWSGroupsOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAD8255A580300E217F9 /* OWSGroupsOutputStream.m */; }; - C33FDC93255A582000E217F9 /* OWSDisappearingMessagesConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC94255A582000E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC95255A582000E217F9 /* OWSFailedMessagesJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADB255A580400E217F9 /* OWSFailedMessagesJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC96255A582000E217F9 /* NSObject+Casting.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADC255A580400E217F9 /* NSObject+Casting.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDC97255A582000E217F9 /* TSInfoMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADD255A580400E217F9 /* TSInfoMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDADE255A580400E217F9 /* SwiftSingletons.swift */; }; C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDADF255A580400E217F9 /* PublicChatManager.swift */; }; C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE0255A580400E217F9 /* ByteParser.m */; }; - C33FDC9B255A582000E217F9 /* OWSReadTracking.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE1255A580400E217F9 /* OWSReadTracking.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE6255A580400E217F9 /* TSInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCA1255A582000E217F9 /* TSErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE7255A580500E217F9 /* TSErrorMessage.m */; }; C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA3255A582000E217F9 /* SSKMessageSenderJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */; }; C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEC255A580500E217F9 /* SignalRecipient.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCAC255A582000E217F9 /* ProxiedContentDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */; }; C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */; }; - C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF4255A580600E217F9 /* SSKEnvironment.m */; }; C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */; }; - C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF9255A580600E217F9 /* TSContactThread.m */; }; - C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; }; - C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */; }; - C33FDCBB255A582000E217F9 /* AppReadiness.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB01255A580700E217F9 /* AppReadiness.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; }; C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB09255A580700E217F9 /* NSError+MessageSending.m */; }; - C33FDCC4255A582000E217F9 /* TSGroupModel.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0A255A580700E217F9 /* TSGroupModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCC7255A582000E217F9 /* NSArray+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB0D255A580800E217F9 /* NSArray+OWS.m */; }; C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0E255A580800E217F9 /* NSError+MessageSending.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCCC255A582000E217F9 /* NSString+SSK.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB12255A580800E217F9 /* NSString+SSK.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB17255A580800E217F9 /* FunctionalUtil.m */; }; C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB19255A580900E217F9 /* GroupUtilities.swift */; }; - C33FDCD7255A582000E217F9 /* OWSReadReceiptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCD8255A582000E217F9 /* OWSIncomingMessageFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */; }; - C33FDCDA255A582000E217F9 /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; }; - C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCE6255A582000E217F9 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCEB255A582000E217F9 /* SSKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB31255A580A00E217F9 /* SSKEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */; }; - C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */; }; - C33FDCF2255A582000E217F9 /* OWSBackgroundTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCF4255A582000E217F9 /* Poller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3A255A580B00E217F9 /* Poller.swift */; }; - C33FDCF5255A582000E217F9 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3F255A580C00E217F9 /* String+SSK.swift */; }; C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */; }; - C33FDCFD255A582000E217F9 /* YapDatabaseConnection+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */; }; C33FDCFE255A582000E217F9 /* OWSContactsOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */; }; C33FDCFF255A582000E217F9 /* NSString+SSK.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB45255A580C00E217F9 /* NSString+SSK.m */; }; - C33FDD00255A582000E217F9 /* TSDatabaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB46255A580C00E217F9 /* TSDatabaseView.m */; }; C33FDD01255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD02255A582000E217F9 /* TSOutgoingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB49255A580C00E217F9 /* WeakTimer.swift */; }; C33FDD05255A582000E217F9 /* OWSChunkedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */; }; C33FDD06255A582000E217F9 /* AppVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4C255A580D00E217F9 /* AppVersion.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD09255A582000E217F9 /* SSKJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0A255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB50255A580D00E217F9 /* OWSPrimaryStorage+PreKeyStore.m */; }; - C33FDD0B255A582000E217F9 /* NSUserDefaults+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0C255A582000E217F9 /* OWSHTTPSecurityPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB52255A580D00E217F9 /* OWSHTTPSecurityPolicy.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0D255A582000E217F9 /* PreKeyBundle+jsonDict.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB53255A580D00E217F9 /* PreKeyBundle+jsonDict.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD0F255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */; }; - C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */; }; C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */; }; C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB59255A580E00E217F9 /* OWSFailedAttachmentDownloadsJob.m */; }; C33FDD14255A582000E217F9 /* OWSUDManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5A255A580E00E217F9 /* OWSUDManager.swift */; }; - C33FDD15255A582000E217F9 /* YapDatabaseTransaction+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */; }; - C33FDD16255A582000E217F9 /* NSArray+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD17255A582000E217F9 /* TSErrorMessage_privateConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD19255A582000E217F9 /* YapDatabaseConnection+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD1A255A582000E217F9 /* TSMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB60255A580E00E217F9 /* TSMessage.m */; }; C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */; }; - C33FDD21255A582000E217F9 /* OWSMediaGalleryFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD22255A582000E217F9 /* ContentProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB68255A580F00E217F9 /* ContentProxy.swift */; }; C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB69255A580F00E217F9 /* FeatureFlags.swift */; }; - C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */; }; C33FDD27255A582000E217F9 /* TSPreKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */; }; - C33FDD2B255A582000E217F9 /* OWSMediaGalleryFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */; }; - C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB73255A581000E217F9 /* TSGroupModel.m */; }; - C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */; }; - C33FDD2F255A582000E217F9 /* AppReadiness.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB75255A581000E217F9 /* AppReadiness.m */; }; - C33FDD31255A582000E217F9 /* NSUserDefaults+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */; }; C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB78255A581000E217F9 /* OWSOperation.m */; }; - C33FDD34255A582000E217F9 /* NotificationsProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD38255A582000E217F9 /* TSPreKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */; }; - C33FDD39255A582000E217F9 /* FullTextSearchFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */; }; C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB80255A581100E217F9 /* Notification+Loki.swift */; }; - C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB83255A581100E217F9 /* TSQuotedMessage.m */; }; C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB87255A581100E217F9 /* JobQueue.swift */; }; - C33FDD42255A582000E217F9 /* TSAccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB88255A581200E217F9 /* TSAccountManager.m */; }; C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */; }; - C33FDD46255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; }; - C33FDD4B255A582000E217F9 /* ProtoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB91255A581200E217F9 /* ProtoUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */; }; - C33FDD4E255A582000E217F9 /* TSAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB94255A581300E217F9 /* TSAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; }; - C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */; }; C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */; }; - C33FDD63255A582000E217F9 /* OWSIdentityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */; }; C33FDD67255A582000E217F9 /* OWSRecordTranscriptJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD68255A582000E217F9 /* SignalAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAE255A581500E217F9 /* SignalAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD6A255A582000E217F9 /* TSErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB0255A581500E217F9 /* TSErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */; }; C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB7255A581600E217F9 /* SignalRecipient.m */; }; - C33FDD72255A582000E217F9 /* TSThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB8255A581600E217F9 /* TSThread.m */; }; - C33FDD73255A582000E217F9 /* ProfileManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD74255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD76255A582000E217F9 /* SSKKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */; }; C33FDD79255A582000E217F9 /* OWSHTTPSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBF255A581700E217F9 /* OWSHTTPSecurityPolicy.m */; }; - C33FDD7B255A582000E217F9 /* GeneralUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */; }; C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC2255A581700E217F9 /* SSKAsserts.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */; }; - C33FDD84255A582000E217F9 /* LKGroupUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */; }; C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */; }; C33FDD90255A582000E217F9 /* OWSUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBD6255A581900E217F9 /* OWSUploadOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */; }; C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */; }; - C33FDD97255A582000E217F9 /* OWSDisappearingMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */; }; - C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */; }; - C33FDDA3255A582000E217F9 /* TSInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE9255A581A00E217F9 /* TSInteraction.m */; }; - C33FDDA5255A582000E217F9 /* OWSBlockingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */; }; C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDAB255A582000E217F9 /* OWSIdentityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */; }; C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB3255A582000E217F9 /* OWSError.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF9255A581C00E217F9 /* OWSError.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDBB255A582000E217F9 /* TSGroupThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC01255A581C00E217F9 /* TSGroupThread.m */; }; - C33FDDBC255A582000E217F9 /* OWSPrimaryStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */; }; C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC03255A581D00E217F9 /* ByteParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC06255A581D00E217F9 /* SignalAccount.m */; }; C33FDDC5255A582000E217F9 /* OWSError.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0B255A581D00E217F9 /* OWSError.m */; }; - C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */; }; C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC12255A581E00E217F9 /* TSConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDCD255A582000E217F9 /* OWSAttachmentDownloads.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */; }; C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC16255A581E00E217F9 /* FunctionalUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC19255A581F00E217F9 /* OWSQueues.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */; }; C33FDDD8255A582000E217F9 /* OWSUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1E255A581F00E217F9 /* OWSUploadOperation.m */; }; C33FDDD9255A582000E217F9 /* LokiSessionRestorationImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */; }; C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */; }; @@ -573,13 +565,11 @@ C37F54BA255BB2D8002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54CB255BB53F002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54DC255BB84A002AEA92 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; }; - C38EEF0A255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */; }; C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C38EF00E255B61DC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C38EF216255B6D3B007E1867 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF212255B6D3A007E1867 /* Theme.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF218255B6D3B007E1867 /* Theme.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF214255B6D3A007E1867 /* Theme.m */; }; C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF223255B6D5D007E1867 /* AttachmentSharing.m */; }; - C38EF229255B6D5D007E1867 /* SignalAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF224255B6D5D007E1867 /* SignalAttachment.swift */; }; C38EF22A255B6D5D007E1867 /* AttachmentSharing.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF225255B6D5D007E1867 /* AttachmentSharing.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */; }; C38EF22C255B6D5D007E1867 /* OWSVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */; }; @@ -616,8 +606,6 @@ C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */; }; C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */; }; C38EF2B4255B6D9C007E1867 /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */; }; - C38EF2C2255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF2C5255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */; }; C38EF2D4255B6DAF007E1867 /* OWSProfileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */; }; C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; C38EF2D7255B6DAF007E1867 /* OWSProfileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -681,8 +669,6 @@ C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */; }; C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */; }; C38EF39B255B6DDA007E1867 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */; }; - C38EF39C255B6DDA007E1867 /* OWSQuotedReplyModel.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF39E255B6DDA007E1867 /* OWSQuotedReplyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */; }; C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */; }; C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */; }; C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */; }; @@ -734,6 +720,23 @@ C396DAF32518408B00FF6DC5 /* Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAEC2518408A00FF6DC5 /* Description.swift */; }; C396DAF42518408B00FF6DC5 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAED2518408B00FF6DC5 /* Parser.swift */; }; C396DAF52518408B00FF6DC5 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAEE2518408B00FF6DC5 /* CSV.swift */; }; + C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */; }; + C3A3A099256E17B2004D228D /* SSKJobRecordFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */; }; + C3A3A0AA256E17E6004D228D /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; }; + C3A3A0B3256E17F2004D228D /* SSKJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */; }; + C3A3A0F5256E194C004D228D /* OWSRecipientIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; }; + C3A3A107256E1A5C004D228D /* OWSDisappearingMessagesFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */; }; + C3A3A108256E1A5C004D228D /* OWSIncomingMessageFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */; }; + C3A3A111256E1A93004D228D /* OWSIncomingMessageFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3A3A122256E1A97004D228D /* OWSDisappearingMessagesFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3A3A12B256E1AD5004D228D /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3A3A13C256E1B27004D228D /* OWSMediaGalleryFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */; }; + C3A3A145256E1B49004D228D /* OWSMediaGalleryFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */; }; + C3A3A15F256E1BB4004D228D /* ProtoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB91255A581200E217F9 /* ProtoUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C3A3A171256E1D25004D228D /* SSKReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */; }; C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D0A2558989C0043A11F /* MessageWrapper.swift */; }; C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1C25589AC30043A11F /* WebSocketProto.swift */; }; C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */; }; @@ -763,10 +766,8 @@ C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */; }; C3A7222A2558C1E40043A11F /* DotNetAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A722292558C1E40043A11F /* DotNetAPI.swift */; }; C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */; }; - C3A722922558C8940043A11F /* OpenGroupAPIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */; }; C3A7229C2558E4310043A11F /* OpenGroupMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */; }; C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Description.swift */; }; - C3B7845D25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */; }; C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; }; C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE07F2554CDD70050F1E3 /* Storage.swift */; }; C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */; }; @@ -881,11 +882,8 @@ C3CA3AB4255CDAE600F4C6D4 /* japanese.txt in Resources */ = {isa = PBXBuildFile; fileRef = C3CA3AB3255CDAE600F4C6D4 /* japanese.txt */; }; C3CA3ABE255CDB0D00F4C6D4 /* portuguese.txt in Resources */ = {isa = PBXBuildFile; fileRef = C3CA3ABD255CDB0D00F4C6D4 /* portuguese.txt */; }; C3CA3AC8255CDB2900F4C6D4 /* spanish.txt in Resources */ = {isa = PBXBuildFile; fileRef = C3CA3AC7255CDB2900F4C6D4 /* spanish.txt */; }; - C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */; }; - C3CA3B1D255CF3C800F4C6D4 /* MessageSender+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */; }; C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; - C3D697382564DCE6004AF766 /* MessageReceiverDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */; }; C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */; }; C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; }; C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -912,7 +910,6 @@ C3D9E4FD256778E30040E4F3 /* NSData+Image.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB29255A580A00E217F9 /* NSData+Image.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB54255A580D00E217F9 /* DataSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */; }; - C3D9E53925677F5E0040E4F3 /* Attachment+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; @@ -1346,14 +1343,13 @@ B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationButtonSet.swift; sourceTree = ""; }; B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSOutgoingMessage+Conversion.swift"; sourceTree = ""; }; - B840729F2565F1670037CB17 /* Quote+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Quote+Conversion.swift"; sourceTree = ""; }; + B840729F2565F1670037CB17 /* OWSQuotedReplyModel+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OWSQuotedReplyModel+Conversion.swift"; sourceTree = ""; }; B84664F4235022F30083A1CD /* MentionUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionUtilities.swift; sourceTree = ""; }; B847570023D568EB00759540 /* SignalServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SignalServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedReminderView.swift; sourceTree = ""; }; B85357C223A1BD1200AAF6CD /* SeedVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedVC.swift; sourceTree = ""; }; B8544E3023D16CA500299F14 /* DeviceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceUtilities.swift; sourceTree = ""; }; B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceUtilities.swift; sourceTree = ""; }; - B867665725663BBA00B197C5 /* MessageSenderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSenderDelegate.swift; sourceTree = ""; }; B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = ""; }; B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; @@ -1387,15 +1383,12 @@ B8CCF6422397711F0091D419 /* SettingsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsVC.swift; sourceTree = ""; }; B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TSAttachmentPointer+Backups.h"; sourceTree = ""; }; B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "TSAttachmentPointer+Backups.m"; sourceTree = ""; }; - B8D797D4256B2715007C59DF /* TSAttachment+Albums.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "TSAttachment+Albums.m"; sourceTree = ""; }; - B8D797DE256B2732007C59DF /* TSAttachment+Albums.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TSAttachment+Albums.h"; sourceTree = ""; }; B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = ""; }; B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Jobs.swift"; sourceTree = ""; }; B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = ""; }; B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Messaging.swift"; sourceTree = ""; }; B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OnionRequests.swift"; sourceTree = ""; }; - B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSenderDelegate.swift; sourceTree = ""; }; - B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIDelegate.swift; sourceTree = ""; }; + B8D8F1EF256621180092EF10 /* MessageSender+Handling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "MessageSender+Handling.swift"; path = "../../SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift"; sourceTree = ""; }; B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = ""; }; B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = ""; }; B9EB5ABC1884C002007CBB57 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; @@ -1419,6 +1412,10 @@ C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+VolumeSamples.swift"; sourceTree = ""; }; C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPairUtilities.swift; sourceTree = ""; }; C329FEEB24F7277900B1C64C /* LightModeSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightModeSheet.swift; sourceTree = ""; }; + C32C5A87256DBCF9003C73A2 /* MessageReceiver+Handling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Handling.swift"; sourceTree = ""; }; + C32C5B3E256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSQuotedMessage+Conversion.swift"; sourceTree = ""; }; + C32C5C92256DD12D003C73A2 /* OWSUDManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSUDManager.swift; sourceTree = ""; }; + C32C5FD5256E0346003C73A2 /* Notification+Thread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Thread.swift"; sourceTree = ""; }; C33100132558FFC200070591 /* UIImage+Tinting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Tinting.swift"; sourceTree = ""; }; C33100272559000A00070591 /* UIView+Rendering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Rendering.swift"; sourceTree = ""; }; C3310032255900A400070591 /* Notification+AppMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+AppMode.swift"; sourceTree = ""; }; @@ -1684,14 +1681,14 @@ C364534F252449260045C478 /* VoiceMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageView.swift; sourceTree = ""; }; C364535B252467900045C478 /* AudioUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUtilities.swift; sourceTree = ""; }; C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Attachment.swift"; sourceTree = ""; }; - C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Attachment+Conversion.swift"; sourceTree = ""; }; + C379DCFD25673DBC0002D4EB /* TSAttachmentPointer+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSAttachmentPointer+Conversion.swift"; sourceTree = ""; }; C37F53E8255BA9BB002AEA92 /* Environment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = ""; }; C37F5402255BA9ED002AEA92 /* Environment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = ""; }; C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SNProtoEnvelope+Conversion.swift"; sourceTree = ""; }; C38EF212255B6D3A007E1867 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Theme.h; path = SignalUtilitiesKit/UI/Theme.h; sourceTree = SOURCE_ROOT; }; C38EF214255B6D3A007E1867 /* Theme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Theme.m; path = SignalUtilitiesKit/UI/Theme.m; sourceTree = SOURCE_ROOT; }; C38EF223255B6D5D007E1867 /* AttachmentSharing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AttachmentSharing.m; path = SignalUtilitiesKit/Utilities/AttachmentSharing.m; sourceTree = SOURCE_ROOT; }; - C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = SignalUtilitiesKit/Messaging/Attachments/SignalAttachment.swift; sourceTree = SOURCE_ROOT; }; + C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = "SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift"; sourceTree = SOURCE_ROOT; }; C38EF225255B6D5D007E1867 /* AttachmentSharing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AttachmentSharing.h; path = SignalUtilitiesKit/Utilities/AttachmentSharing.h; sourceTree = SOURCE_ROOT; }; C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewDelegate.swift; path = SignalUtilitiesKit/Utilities/ShareViewDelegate.swift; sourceTree = SOURCE_ROOT; }; C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSVideoPlayer.swift; path = SignalUtilitiesKit/Utilities/OWSVideoPlayer.swift; sourceTree = SOURCE_ROOT; }; @@ -1715,10 +1712,10 @@ C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SignalUtilitiesKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; - C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; + C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/Database/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; C38EF283255B6D84007E1867 /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VersionMigrations.h; path = SignalUtilitiesKit/VersionMigrations.h; sourceTree = SOURCE_ROOT; }; C38EF284255B6D84007E1867 /* AppSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppSetup.h; path = SignalUtilitiesKit/AppSetup.h; sourceTree = SOURCE_ROOT; }; - C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalKeyingStorage.h; path = SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.h; sourceTree = SOURCE_ROOT; }; + C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalKeyingStorage.h; path = SignalUtilitiesKit/Database/SignalKeyingStorage.h; sourceTree = SOURCE_ROOT; }; C38EF286255B6D85007E1867 /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VersionMigrations.m; path = SignalUtilitiesKit/VersionMigrations.m; sourceTree = SOURCE_ROOT; }; C38EF287255B6D85007E1867 /* AppSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppSetup.m; path = SignalUtilitiesKit/AppSetup.m; sourceTree = SOURCE_ROOT; }; C38EF288255B6D85007E1867 /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSounds.h; path = SignalUtilitiesKit/OWSSounds.h; sourceTree = SOURCE_ROOT; }; @@ -1728,8 +1725,8 @@ C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SignalUtilitiesKit/UI/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; }; C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Utilities.swift"; path = "SignalUtilitiesKit/UI/UIView+Utilities.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = "SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.h"; sourceTree = SOURCE_ROOT; }; - C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = "SignalUtilitiesKit/Messaging/Read Tracking/TSUnreadIndicatorInteraction.m"; sourceTree = SOURCE_ROOT; }; + C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = "SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.h"; sourceTree = SOURCE_ROOT; }; + C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = "SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.m"; sourceTree = SOURCE_ROOT; }; C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = "SignalUtilitiesKit/To Do/OWSProfileManager.m"; sourceTree = SOURCE_ROOT; }; C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SignalUtilitiesKit/To Do/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = "SignalUtilitiesKit/To Do/OWSProfileManager.h"; sourceTree = SOURCE_ROOT; }; @@ -1796,8 +1793,8 @@ C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ApprovalRailCellView.swift; path = SignalUtilitiesKit/UI/ApprovalRailCellView.swift; sourceTree = SOURCE_ROOT; }; C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = "SignalUtilitiesKit/UI/Attachment Approval/AttachmentCaptionViewController.swift"; sourceTree = SOURCE_ROOT; }; C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadViewModel.swift; path = SignalUtilitiesKit/ThreadViewModel.swift; sourceTree = SOURCE_ROOT; }; - C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.h; sourceTree = SOURCE_ROOT; }; - C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = SignalUtilitiesKit/Messaging/Quotes/OWSQuotedReplyModel.m; sourceTree = SOURCE_ROOT; }; + C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSQuotedReplyModel.h; path = "SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.h"; sourceTree = SOURCE_ROOT; }; + C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSQuotedReplyModel.m; path = "SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m"; sourceTree = SOURCE_ROOT; }; C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorTextViewController.swift"; sourceTree = SOURCE_ROOT; }; C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorPinchGestureRecognizer.swift"; sourceTree = SOURCE_ROOT; }; C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorItem.swift"; sourceTree = SOURCE_ROOT; }; @@ -1814,8 +1811,8 @@ C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "OWSViewController+ImageEditor.swift"; path = "SignalUtilitiesKit/UI/OWSViewController+ImageEditor.swift"; sourceTree = SOURCE_ROOT; }; C38EF3B6255B6DE6007E1867 /* ImageEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorModel.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorModel.swift"; sourceTree = SOURCE_ROOT; }; C38EF3B7255B6DE6007E1867 /* ImageEditorCanvasView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorCanvasView.swift; path = "SignalUtilitiesKit/UI/Image Editing/ImageEditorCanvasView.swift"; sourceTree = SOURCE_ROOT; }; - C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadViewHelper.m; path = SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m; sourceTree = SOURCE_ROOT; }; - C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; + C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ThreadViewHelper.m; path = SignalUtilitiesKit/Database/ThreadViewHelper.m; sourceTree = SOURCE_ROOT; }; + C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadViewHelper.h; path = SignalUtilitiesKit/Database/ThreadViewHelper.h; sourceTree = SOURCE_ROOT; }; C38EF3D3255B6DEE007E1867 /* OWSSearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSearchBar.h; path = SignalUtilitiesKit/UI/OWSSearchBar.h; sourceTree = SOURCE_ROOT; }; C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisappearingTimerConfigurationView.swift; path = SignalUtilitiesKit/UI/DisappearingTimerConfigurationView.swift; sourceTree = SOURCE_ROOT; }; C38EF3D6255B6DEF007E1867 /* ContactCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactCellView.m; path = "SignalUtilitiesKit/To Do/ContactCellView.m"; sourceTree = SOURCE_ROOT; }; @@ -1854,6 +1851,8 @@ C396DAED2518408B00FF6DC5 /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = ""; }; C396DAEE2518408B00FF6DC5 /* CSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSV.swift; sourceTree = ""; }; C39DD28724F3318C008590FC /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; + C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKJobRecordFinder.swift; sourceTree = ""; }; + C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKReachabilityManager.swift; sourceTree = ""; }; C3A71D0A2558989C0043A11F /* MessageWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageWrapper.swift; sourceTree = ""; }; C3A71D1C25589AC30043A11F /* WebSocketProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketProto.swift; sourceTree = ""; }; C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketResources.pb.swift; sourceTree = ""; }; @@ -1883,7 +1882,6 @@ C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AnyPromise+Conversion.swift"; sourceTree = ""; }; C3A722292558C1E40043A11F /* DotNetAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotNetAPI.swift; sourceTree = ""; }; C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Retaining.swift"; sourceTree = ""; }; - C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIDelegate.swift; sourceTree = ""; }; C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupMessage+Conversion.swift"; sourceTree = ""; }; C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = "Migrating Translations from Android.md"; path = "Meta/Translations/Migrating Translations from Android.md"; sourceTree = ""; }; C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Localizable.strings; sourceTree = ""; }; @@ -2007,12 +2005,8 @@ C3CA3AB3255CDAE600F4C6D4 /* japanese.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = japanese.txt; sourceTree = ""; }; C3CA3ABD255CDB0D00F4C6D4 /* portuguese.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = portuguese.txt; sourceTree = ""; }; C3CA3AC7255CDB2900F4C6D4 /* spanish.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = spanish.txt; sourceTree = ""; }; - C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Destination+Conversion.swift"; sourceTree = ""; }; - C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Utilities.swift"; sourceTree = ""; }; C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NullMessage.swift; sourceTree = ""; }; C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = ""; }; - C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverDelegate.swift; sourceTree = ""; }; - C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverDelegate.swift; sourceTree = ""; }; C3D9E40B25676C100040E4F3 /* Storage+Conformances.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Conformances.swift"; sourceTree = ""; }; C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSPrimaryStorageProtocol.swift; sourceTree = ""; }; C3D9E43025676D3D0040E4F3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; @@ -2629,6 +2623,7 @@ children = ( C3C2A74325539EB700C340D1 /* Message.swift */, C352A30825574D8400338F3E /* Message+Destination.swift */, + C32C5A99256DBDC1003C73A2 /* Signal */, C300A5C62554B02D00555489 /* Visible Messages */, C300A5C72554B03900555489 /* Control Messages */, ); @@ -2638,8 +2633,8 @@ C300A5C62554B02D00555489 /* Visible Messages */ = { isa = PBXGroup; children = ( - C3D9E3B52567685D0040E4F3 /* Attachments */, C3C2A74C2553A39700C340D1 /* VisibleMessage.swift */, + C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */, C3C2A7552553A3AB00C340D1 /* VisibleMessage+Quote.swift */, C3C2A75E2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift */, C3C2A7672553A3D900C340D1 /* VisibleMessage+Contact.swift */, @@ -2664,13 +2659,23 @@ C300A5F02554B08500555489 /* Sending & Receiving */ = { isa = PBXGroup; children = ( + C3D9E3B52567685D0040E4F3 /* Attachments */, + C32C5B9E256DC720003C73A2 /* Blocking */, + C32C5B01256DC054003C73A2 /* Expiration */, + C32C5D22256DD496003C73A2 /* Link Previews */, + C32C5D2D256DD4C4003C73A2 /* Mentions */, + C379DC6825672B5E0002D4EB /* Notifications */, + C32C59F8256DB5A6003C73A2 /* Pollers */, + C32C5B1B256DC160003C73A2 /* Quotes */, + C32C5ADE256DBF7F003C73A2 /* Read Tracking */, + C32C5995256DAF85003C73A2 /* Typing Indicators */, C3471FA32555439E00297E91 /* Notification+MessageSender.swift */, C300A5F12554B09800555489 /* MessageSender.swift */, C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */, - B867665725663BBA00B197C5 /* MessageSenderDelegate.swift */, + B8D8F1EF256621180092EF10 /* MessageSender+Handling.swift */, C300A5FB2554B0A000555489 /* MessageReceiver.swift */, C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */, - C3D697372564DCE6004AF766 /* MessageReceiverDelegate.swift */, + C32C5A87256DBCF9003C73A2 /* MessageReceiver+Handling.swift */, ); path = "Sending & Receiving"; sourceTree = ""; @@ -2704,6 +2709,175 @@ path = Dependencies; sourceTree = ""; }; + C32C5995256DAF85003C73A2 /* Typing Indicators */ = { + isa = PBXGroup; + children = ( + C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */, + ); + path = "Typing Indicators"; + sourceTree = ""; + }; + C32C59AF256DB31A003C73A2 /* Threads */ = { + isa = PBXGroup; + children = ( + C32C5FD5256E0346003C73A2 /* Notification+Thread.swift */, + C33FDAB3255A580000E217F9 /* TSContactThread.h */, + C33FDAF9255A580600E217F9 /* TSContactThread.m */, + C33FDB0A255A580700E217F9 /* TSGroupModel.h */, + C33FDB73255A581000E217F9 /* TSGroupModel.m */, + C33FDA79255A57FB00E217F9 /* TSGroupThread.h */, + C33FDC01255A581C00E217F9 /* TSGroupThread.m */, + C33FDAD3255A580300E217F9 /* TSThread.h */, + C33FDBB8255A581600E217F9 /* TSThread.m */, + ); + path = Threads; + sourceTree = ""; + }; + C32C59F8256DB5A6003C73A2 /* Pollers */ = { + isa = PBXGroup; + children = ( + C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, + C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */, + C33FDB3A255A580B00E217F9 /* Poller.swift */, + ); + path = Pollers; + sourceTree = ""; + }; + C32C5A99256DBDC1003C73A2 /* Signal */ = { + isa = PBXGroup; + children = ( + C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, + C33FDBB0255A581500E217F9 /* TSErrorMessage.h */, + C33FDAE7255A580500E217F9 /* TSErrorMessage.m */, + C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */, + C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */, + C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, + C33FDADD255A580400E217F9 /* TSInfoMessage.h */, + C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */, + C33FDAE6255A580400E217F9 /* TSInteraction.h */, + C33FDBE9255A581A00E217F9 /* TSInteraction.m */, + C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */, + C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */, + C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */, + C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */, + C33FDA70255A57FA00E217F9 /* TSMessage.h */, + C33FDB60255A580E00E217F9 /* TSMessage.m */, + C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */, + C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */, + B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */, + ); + path = Signal; + sourceTree = ""; + }; + C32C5ADE256DBF7F003C73A2 /* Read Tracking */ = { + isa = PBXGroup; + children = ( + C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */, + C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */, + C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */, + C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */, + C33FDAE1255A580400E217F9 /* OWSReadTracking.h */, + C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, + C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, + ); + path = "Read Tracking"; + sourceTree = ""; + }; + C32C5B01256DC054003C73A2 /* Expiration */ = { + isa = PBXGroup; + children = ( + C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, + C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, + C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, + C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, + C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */, + C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */, + ); + path = Expiration; + sourceTree = ""; + }; + C32C5B1B256DC160003C73A2 /* Quotes */ = { + isa = PBXGroup; + children = ( + C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, + C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, + B840729F2565F1670037CB17 /* OWSQuotedReplyModel+Conversion.swift */, + C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */, + C33FDB83255A581100E217F9 /* TSQuotedMessage.m */, + C32C5B3E256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift */, + ); + path = Quotes; + sourceTree = ""; + }; + C32C5B9E256DC720003C73A2 /* Blocking */ = { + isa = PBXGroup; + children = ( + C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, + C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, + ); + path = Blocking; + sourceTree = ""; + }; + C32C5BB9256DC7C4003C73A2 /* To Do */ = { + isa = PBXGroup; + children = ( + C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, + C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */, + C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */, + C32C5C92256DD12D003C73A2 /* OWSUDManager.swift */, + C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, + C33FDB94255A581300E217F9 /* TSAccountManager.h */, + C33FDB88255A581200E217F9 /* TSAccountManager.m */, + ); + path = "To Do"; + sourceTree = ""; + }; + C32C5BCB256DC818003C73A2 /* Database */ = { + isa = PBXGroup; + children = ( + C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, + C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, + C33FDAFE255A580600E217F9 /* OWSStorage.h */, + C33FDAB1255A580000E217F9 /* OWSStorage.m */, + B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */, + B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */, + B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */, + B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */, + C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */, + C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, + C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, + C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */, + C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */, + C33FDB46255A580C00E217F9 /* TSDatabaseView.m */, + ); + path = Database; + sourceTree = ""; + }; + C32C5D22256DD496003C73A2 /* Link Previews */ = { + isa = PBXGroup; + children = ( + C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, + ); + path = "Link Previews"; + sourceTree = ""; + }; + C32C5D2D256DD4C4003C73A2 /* Mentions */ = { + isa = PBXGroup; + children = ( + C33FDA7E255A57FB00E217F9 /* Mention.swift */, + C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, + ); + path = Mentions; + sourceTree = ""; + }; + C32C5D49256DD522003C73A2 /* Database */ = { + isa = PBXGroup; + children = ( + C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */, + ); + path = Database; + sourceTree = ""; + }; C331FF1C2558F9D300070591 /* SessionUIKit */ = { isa = PBXGroup; children = ( @@ -2769,11 +2943,8 @@ C3851CE3256250FA0061EEB0 /* To Do */, C3CA3B11255CF17200F4C6D4 /* Utilities */, C3851CD225624B060061EEB0 /* UI */, - C38BBA0C255E32020041B9A3 /* Threads */, C38BBA0D255E321C0041B9A3 /* Messaging */, C38BBA0E255E32440041B9A3 /* Database */, - C33FDB01255A580700E217F9 /* AppReadiness.h */, - C33FDB75255A581000E217F9 /* AppReadiness.m */, C33FDB4C255A580D00E217F9 /* AppVersion.h */, C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */, C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */, @@ -2789,6 +2960,8 @@ C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */, C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */, + B8C2B33B2563770800551B4D /* ThreadUtil.h */, + B8C2B331256376F000551B4D /* ThreadUtil.m */, C38EF284255B6D84007E1867 /* AppSetup.h */, C38EF287255B6D85007E1867 /* AppSetup.m */, C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */, @@ -2798,21 +2971,14 @@ C38EF283255B6D84007E1867 /* VersionMigrations.h */, C38EF286255B6D85007E1867 /* VersionMigrations.m */, C33FDA8B255A57FD00E217F9 /* AppVersion.m */, - C33FDB68255A580F00E217F9 /* ContentProxy.swift */, C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, - C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, C33FDB87255A581100E217F9 /* JobQueue.swift */, - C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */, C33FDB0E255A580800E217F9 /* NSError+MessageSending.h */, C33FDB09255A580700E217F9 /* NSError+MessageSending.m */, - C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */, - C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */, C33FDA99255A57FE00E217F9 /* OutageDetection.swift */, C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */, C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */, - C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */, - C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */, C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */, C33FDB07255A580700E217F9 /* OWSBackupFragment.m */, C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */, @@ -2831,15 +2997,9 @@ C33FDAD8255A580300E217F9 /* OWSGroupsOutputStream.m */, C33FDB52255A580D00E217F9 /* OWSHTTPSecurityPolicy.h */, C33FDBBF255A581700E217F9 /* OWSHTTPSecurityPolicy.m */, - C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */, - C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */, - C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */, - C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */, C33FDBA1255A581400E217F9 /* OWSOperation.h */, C33FDB78255A581000E217F9 /* OWSOperation.m */, C33FDC19255A581F00E217F9 /* OWSQueues.h */, - C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */, - C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */, C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */, C33FDA7F255A57FC00E217F9 /* OWSRecordTranscriptJob.m */, C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */, @@ -2850,7 +3010,6 @@ C33FDB53255A580D00E217F9 /* PreKeyBundle+jsonDict.h */, C33FDB93255A581200E217F9 /* PreKeyBundle+jsonDict.m */, C33FDB64255A580E00E217F9 /* PreKeyRefreshOperation.swift */, - C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */, C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */, C33FDA98255A57FE00E217F9 /* RotateSignedKeyOperation.swift */, C33FDBAE255A581500E217F9 /* SignalAccount.h */, @@ -2859,14 +3018,8 @@ C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */, C33FDAEC255A580500E217F9 /* SignalRecipient.h */, C33FDBB7255A581600E217F9 /* SignalRecipient.m */, - C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, - C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, - C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */, - C33FDACD255A580200E217F9 /* SSKJobRecord.m */, C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */, C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */, - C33FDB94255A581300E217F9 /* TSAccountManager.h */, - C33FDB88255A581200E217F9 /* TSAccountManager.m */, C33FDC12255A581E00E217F9 /* TSConstants.h */, C33FDABE255A580100E217F9 /* TSConstants.m */, C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */, @@ -2914,216 +3067,12 @@ C379DC6825672B5E0002D4EB /* Notifications */ = { isa = PBXGroup; children = ( + C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */, C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */, ); path = Notifications; sourceTree = ""; }; - C379DC7125672B8F0002D4EB /* Utilities */ = { - isa = PBXGroup; - children = ( - C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, - C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, - C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, - C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */, - ); - path = Utilities; - sourceTree = ""; - }; - C379DC7A25672BDB0002D4EB /* Sending & Receiving */ = { - isa = PBXGroup; - children = ( - C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, - C3CA3B12255CF18200F4C6D4 /* Destination+Conversion.swift */, - C3D697492564DEDC004AF766 /* MessageReceiverDelegate.swift */, - B8D8F1EF256621180092EF10 /* MessageSenderDelegate.swift */, - C3CA3B1C255CF3C800F4C6D4 /* MessageSender+Utilities.swift */, - B8D8F21925662A4D0092EF10 /* OpenGroupAPIDelegate.swift */, - C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */, - C33FDB3A255A580B00E217F9 /* Poller.swift */, - C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, - ); - path = "Sending & Receiving"; - sourceTree = ""; - }; - C379DC7B25672C020002D4EB /* Mentions */ = { - isa = PBXGroup; - children = ( - C33FDA7E255A57FB00E217F9 /* Mention.swift */, - C33FDA81255A57FC00E217F9 /* MentionsManager.swift */, - ); - path = Mentions; - sourceTree = ""; - }; - C379DC8425672C3E0002D4EB /* Quotes */ = { - isa = PBXGroup; - children = ( - C38EF398255B6DD9007E1867 /* OWSQuotedReplyModel.h */, - C38EF39A255B6DD9007E1867 /* OWSQuotedReplyModel.m */, - B840729F2565F1670037CB17 /* Quote+Conversion.swift */, - C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */, - C33FDB83255A581100E217F9 /* TSQuotedMessage.m */, - ); - path = Quotes; - sourceTree = ""; - }; - C379DC8525672C790002D4EB /* Disappearing Messages */ = { - isa = PBXGroup; - children = ( - C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */, - C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */, - C33FDAD9255A580300E217F9 /* OWSDisappearingMessagesConfiguration.h */, - C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */, - C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, - C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */, - C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */, - C33FDBDD255A581900E217F9 /* OWSDisappearingMessagesJob.m */, - ); - path = "Disappearing Messages"; - sourceTree = ""; - }; - C379DC8625672CAF0002D4EB /* Link Previews */ = { - isa = PBXGroup; - children = ( - C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, - ); - path = "Link Previews"; - sourceTree = ""; - }; - C379DC8725672CD30002D4EB /* Read Tracking */ = { - isa = PBXGroup; - children = ( - C33FDABD255A580100E217F9 /* OWSOutgoingReceiptManager.h */, - C33FDB6F255A580F00E217F9 /* OWSOutgoingReceiptManager.m */, - C33FDB1D255A580900E217F9 /* OWSReadReceiptManager.h */, - C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */, - C33FDAE1255A580400E217F9 /* OWSReadTracking.h */, - C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */, - C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */, - ); - path = "Read Tracking"; - sourceTree = ""; - }; - C379DC9025672D490002D4EB /* Blocking */ = { - isa = PBXGroup; - children = ( - C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, - C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, - ); - path = Blocking; - sourceTree = ""; - }; - C379DCA925672DBD0002D4EB /* Typing Indicators */ = { - isa = PBXGroup; - children = ( - C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */, - ); - path = "Typing Indicators"; - sourceTree = ""; - }; - C379DCAA25672E7B0002D4EB /* Core Messages */ = { - isa = PBXGroup; - children = ( - C33FDB5D255A580E00E217F9 /* TSErrorMessage_privateConstructor.h */, - C33FDBB0255A581500E217F9 /* TSErrorMessage.h */, - C33FDAE7255A580500E217F9 /* TSErrorMessage.m */, - C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */, - C33FDA97255A57FE00E217F9 /* TSIncomingMessage.m */, - C3B7845C25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift */, - C33FDADD255A580400E217F9 /* TSInfoMessage.h */, - C33FDC0C255A581E00E217F9 /* TSInfoMessage.m */, - C33FDAE6255A580400E217F9 /* TSInteraction.h */, - C33FDBE9255A581A00E217F9 /* TSInteraction.m */, - C33FDB8C255A581200E217F9 /* TSInvalidIdentityKeyErrorMessage.h */, - C33FDB74255A581000E217F9 /* TSInvalidIdentityKeyErrorMessage.m */, - C33FDA7B255A57FB00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h */, - C33FDBCB255A581800E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m */, - C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */, - C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */, - C33FDA70255A57FA00E217F9 /* TSMessage.h */, - C33FDB60255A580E00E217F9 /* TSMessage.m */, - C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */, - C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */, - B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */, - ); - path = "Core Messages"; - sourceTree = ""; - }; - C379DCC3256732800002D4EB /* Storage */ = { - isa = PBXGroup; - children = ( - C3D9E40B25676C100040E4F3 /* Storage+Conformances.swift */, - B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */, - B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */, - B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */, - B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */, - B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */, - C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, - C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */, - C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */, - C31F812525258FB000DD9FD9 /* Storage+VolumeSamples.swift */, - ); - path = Storage; - sourceTree = ""; - }; - C379DCC4256732980002D4EB /* YapDatabase */ = { - isa = PBXGroup; - children = ( - C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, - C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, - C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, - C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */, - C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */, - ); - path = YapDatabase; - sourceTree = ""; - }; - C379DCC5256732B00002D4EB /* OWSStorage */ = { - isa = PBXGroup; - children = ( - C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, - C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, - C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */, - C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */, - C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */, - C33FDB50255A580D00E217F9 /* OWSPrimaryStorage+PreKeyStore.m */, - C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */, - C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */, - C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */, - C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */, - C33FDAFE255A580600E217F9 /* OWSStorage.h */, - C33FDAB1255A580000E217F9 /* OWSStorage.m */, - ); - path = OWSStorage; - sourceTree = ""; - }; - C379DCD6256732CE0002D4EB /* Keychain */ = { - isa = PBXGroup; - children = ( - C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, - ); - path = Keychain; - sourceTree = ""; - }; - C379DCE7256732EF0002D4EB /* Utilities */ = { - isa = PBXGroup; - children = ( - C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, - C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, - C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, - C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, - C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, - C33FDA69255A57F900E217F9 /* SSKPreferences.swift */, - C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */, - C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */, - C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */, - C33FDB46255A580C00E217F9 /* TSDatabaseView.m */, - C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, - C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, - ); - path = Utilities; - sourceTree = ""; - }; C379DCE82567330E0002D4EB /* Migration */ = { isa = PBXGroup; children = ( @@ -3263,9 +3212,7 @@ isa = PBXGroup; children = ( C33FDB19255A580900E217F9 /* GroupUtilities.swift */, - C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, - C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, C33FDADF255A580400E217F9 /* PublicChatManager.swift */, C38EF3E5255B6DF4007E1867 /* ContactCellView.h */, C38EF3D6255B6DEF007E1867 /* ContactCellView.m */, @@ -3281,53 +3228,15 @@ path = "To Do"; sourceTree = ""; }; - C38BBA0B255E31EC0041B9A3 /* Attachments */ = { - isa = PBXGroup; - children = ( - C379DCFD25673DBC0002D4EB /* Attachment+Conversion.swift */, - C38EF224255B6D5D007E1867 /* SignalAttachment.swift */, - B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */, - B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */, - B8D797DE256B2732007C59DF /* TSAttachment+Albums.h */, - B8D797D4256B2715007C59DF /* TSAttachment+Albums.m */, - ); - path = Attachments; - sourceTree = ""; - }; - C38BBA0C255E32020041B9A3 /* Threads */ = { - isa = PBXGroup; - children = ( - C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, - C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, - B8C2B33B2563770800551B4D /* ThreadUtil.h */, - B8C2B331256376F000551B4D /* ThreadUtil.m */, - C33FDAB3255A580000E217F9 /* TSContactThread.h */, - C33FDAF9255A580600E217F9 /* TSContactThread.m */, - C33FDB0A255A580700E217F9 /* TSGroupModel.h */, - C33FDB73255A581000E217F9 /* TSGroupModel.m */, - C33FDA79255A57FB00E217F9 /* TSGroupThread.h */, - C33FDC01255A581C00E217F9 /* TSGroupThread.m */, - C33FDAD3255A580300E217F9 /* TSThread.h */, - C33FDBB8255A581600E217F9 /* TSThread.m */, - ); - path = Threads; - sourceTree = ""; - }; C38BBA0D255E321C0041B9A3 /* Messaging */ = { isa = PBXGroup; children = ( - C38BBA0B255E31EC0041B9A3 /* Attachments */, - C379DC9025672D490002D4EB /* Blocking */, - C379DCAA25672E7B0002D4EB /* Core Messages */, - C379DC8525672C790002D4EB /* Disappearing Messages */, - C379DC8625672CAF0002D4EB /* Link Previews */, - C379DC7B25672C020002D4EB /* Mentions */, - C379DC6825672B5E0002D4EB /* Notifications */, - C379DC8425672C3E0002D4EB /* Quotes */, - C379DC8725672CD30002D4EB /* Read Tracking */, - C379DC7A25672BDB0002D4EB /* Sending & Receiving */, - C379DCA925672DBD0002D4EB /* Typing Indicators */, - C379DC7125672B8F0002D4EB /* Utilities */, + B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */, + B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */, + C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */, + C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */, + C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, + C33FDBD7255A581900E217F9 /* OWSMessageUtils.m */, ); path = Messaging; sourceTree = ""; @@ -3335,12 +3244,25 @@ C38BBA0E255E32440041B9A3 /* Database */ = { isa = PBXGroup; children = ( - C379DCD6256732CE0002D4EB /* Keychain */, C379DCE82567330E0002D4EB /* Migration */, - C379DCC5256732B00002D4EB /* OWSStorage */, - C379DCC3256732800002D4EB /* Storage */, - C379DCE7256732EF0002D4EB /* Utilities */, - C379DCC4256732980002D4EB /* YapDatabase */, + C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */, + C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */, + C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */, + C33FDB50255A580D00E217F9 /* OWSPrimaryStorage+PreKeyStore.m */, + C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */, + C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */, + C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */, + C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */, + C3D9E40B25676C100040E4F3 /* Storage+Conformances.swift */, + C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */, + C38EF3D2255B6DEE007E1867 /* ThreadViewHelper.h */, + C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, + C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, + C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, + C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, + C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, + C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, + C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, ); path = Database; sourceTree = ""; @@ -3385,7 +3307,6 @@ children = ( C3A721372558BDFA0043A11F /* OpenGroup.swift */, C3A721352558BDF90043A11F /* OpenGroupAPI.swift */, - C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */, C3A721362558BDFA0043A11F /* OpenGroupInfo.swift */, C3A721342558BDF90043A11F /* OpenGroupMessage.swift */, C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */, @@ -3404,10 +3325,38 @@ C3BBE0B32554F0D30050F1E3 /* Utilities */ = { isa = PBXGroup; children = ( + C33FDB01255A580700E217F9 /* AppReadiness.h */, + C33FDB75255A581000E217F9 /* AppReadiness.m */, C3A722292558C1E40043A11F /* DotNetAPI.swift */, C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */, + C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, + C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, C3A71D0A2558989C0043A11F /* MessageWrapper.swift */, + C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */, + C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */, + C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, + C33FDA86255A57FC00E217F9 /* OWSDisappearingMessagesFinder.m */, + C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */, + C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */, + C33FDAC0255A580100E217F9 /* OWSIncomingMessageFinder.h */, + C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, + C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */, + C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */, C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */, + C33FDB91255A581200E217F9 /* ProtoUtils.h */, + C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, + C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, + C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, + C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, + C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, + C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */, + C33FDACD255A580200E217F9 /* SSKJobRecord.m */, + C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */, + C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */, + C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, + C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, + C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */, + C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */, ); path = Utilities; sourceTree = ""; @@ -3424,6 +3373,8 @@ C3C2A5BE255385EE00C340D1 /* SnodeAPI.swift */, C3C2A5B6255385EC00C340D1 /* SnodeMessage.swift */, C3C2A5B8255385EC00C340D1 /* Storage.swift */, + B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */, + C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */, C3C2A5CD255385F300C340D1 /* Utilities */, ); path = SessionSnodeKit; @@ -3459,24 +3410,38 @@ C33FDB8A255A581200E217F9 /* AppContext.h */, C33FDB85255A581100E217F9 /* AppContext.m */, C3C2A5D12553860800C340D1 /* Array+Description.swift */, + C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */, C3D9E43025676D3D0040E4F3 /* Configuration.swift */, + C33FDB68255A580F00E217F9 /* ContentProxy.swift */, C33FDB54255A580D00E217F9 /* DataSource.h */, C33FDBB6255A581600E217F9 /* DataSource.m */, C3C2ABD12553C6C900C340D1 /* Data+SecureRandom.swift */, C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */, C3A71D662558A0170043A11F /* DiffieHellman.swift */, + C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, C3C2A5BC255385EE00C340D1 /* HTTP.swift */, C3C2A5D92553860B00C340D1 /* JSON.swift */, + C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, + C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */, + C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, C3C2A5CE2553860700C340D1 /* Logging.swift */, + C33FDAFD255A580600E217F9 /* LRUCache.swift */, C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */, C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */, C3A71F882558BA9F0043A11F /* Mnemonic.swift */, + C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */, + C33FDAB8255A580100E217F9 /* NSArray+Functional.m */, C33FDB29255A580A00E217F9 /* NSData+Image.h */, C33FDAEF255A580500E217F9 /* NSData+Image.m */, C300A6302554B68200555489 /* NSDate+Timestamp.h */, C300A6312554B6D100555489 /* NSDate+Timestamp.mm */, + C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */, + C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */, + C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */, C352A3762557859C00338F3E /* NSTimer+Proxying.h */, C352A36C2557858D00338F3E /* NSTimer+Proxying.m */, + C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */, + C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */, C33FDBAB255A581500E217F9 /* OWSFileSystem.h */, C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */, C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */, @@ -3484,6 +3449,8 @@ C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */, C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */, C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */, + C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */, + C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, C33FDB36255A580B00E217F9 /* Storage.swift */, C3C2AC2D2553CBEB00C340D1 /* String+Trimming.swift */, C352A3A42557B5F000338F3E /* TSRequest.h */, @@ -3510,9 +3477,12 @@ children = ( C3C2A7802553AA6300C340D1 /* Protos */, C3C2A70A25539DF900C340D1 /* Meta */, + C32C5BB9256DC7C4003C73A2 /* To Do */, C3BBE0752554CDA60050F1E3 /* Configuration.swift */, C3BBE07F2554CDD70050F1E3 /* Storage.swift */, + C32C5BCB256DC818003C73A2 /* Database */, C300A5BB2554AFFB00555489 /* Messages */, + C32C59AF256DB31A003C73A2 /* Threads */, C300A5F02554B08500555489 /* Sending & Receiving */, C352A2F325574B3300338F3E /* Jobs */, C3A7215C2558C0AC0043A11F /* File Server */, @@ -3731,39 +3701,26 @@ C3CA3B11255CF17200F4C6D4 /* Utilities */ = { isa = PBXGroup; children = ( - C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */, C33FDB80255A581100E217F9 /* Notification+Loki.swift */, - C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, - C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, - C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */, C33FDC16255A581E00E217F9 /* FunctionalUtil.h */, C33FDB17255A580800E217F9 /* FunctionalUtil.m */, C33FDB8F255A581200E217F9 /* ParamParser.swift */, - C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, C33FDB49255A580C00E217F9 /* WeakTimer.swift */, C33FDB3F255A580C00E217F9 /* String+SSK.swift */, C33FDBC2255A581700E217F9 /* SSKAsserts.h */, C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */, - C33FDB91255A581200E217F9 /* ProtoUtils.h */, - C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, C33FDB14255A580800E217F9 /* OWSMath.h */, C33FDADC255A580400E217F9 /* NSObject+Casting.h */, C33FDAAA255A580000E217F9 /* NSObject+Casting.m */, - C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */, C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */, C33FDAC1255A580100E217F9 /* NSSet+Functional.m */, C33FDB12255A580800E217F9 /* NSString+SSK.h */, C33FDB45255A580C00E217F9 /* NSString+SSK.m */, C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */, C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */, - C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */, - C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */, - C33FDB5C255A580E00E217F9 /* NSArray+Functional.h */, - C33FDAB8255A580100E217F9 /* NSArray+Functional.m */, C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */, C33FDB0D255A580800E217F9 /* NSArray+OWS.m */, - C33FDAFD255A580600E217F9 /* LRUCache.swift */, C33FDC03255A581D00E217F9 /* ByteParser.h */, C33FDAE0255A580400E217F9 /* ByteParser.m */, C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */, @@ -3795,13 +3752,14 @@ isa = PBXGroup; children = ( C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */, + C38EF224255B6D5D007E1867 /* SignalAttachment.swift */, C33FDC15255A581E00E217F9 /* TSAttachment.h */, C33FDAC2255A580200E217F9 /* TSAttachment.m */, C33FDC18255A581F00E217F9 /* TSAttachmentPointer.h */, C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */, + C379DCFD25673DBC0002D4EB /* TSAttachmentPointer+Conversion.swift */, C33FDAE4255A580400E217F9 /* TSAttachmentStream.h */, C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */, - C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */, ); path = Attachments; sourceTree = ""; @@ -3921,6 +3879,7 @@ C3F0A58F255C8E3D007BE2A3 /* Meta */, C3F0A5EB255C970D007BE2A3 /* Configuration.swift */, B8CCF63B239757C10091D419 /* Components */, + C32C5D49256DD522003C73A2 /* Database */, C32B405424A961E1001117B5 /* Dependencies */, 76EB03C118170B33006006FC /* Signal */, B8CCF63C239757DB0091D419 /* Utilities */, @@ -3947,81 +3906,51 @@ C33FDD74255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.h in Headers */, C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */, C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */, - C33FDD46255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.h in Headers */, C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */, C38EF311255B6DBF007E1867 /* OWSScrubbingLogFormatter.h in Headers */, - C33FDC77255A582000E217F9 /* OWSOutgoingReceiptManager.h in Headers */, B8C2B3442563782400551B4D /* ThreadUtil.h in Headers */, - C33FDCBB255A582000E217F9 /* AppReadiness.h in Headers */, C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */, C38EF32D255B6DBF007E1867 /* BlockListUIUtils.h in Headers */, C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */, C38EF291255B6D86007E1867 /* SignalKeyingStorage.h in Headers */, C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */, - C33FDD73255A582000E217F9 /* ProfileManagerProtocol.h in Headers */, C38EF2D8255B6DAF007E1867 /* OWSUserProfile.h in Headers */, - C33FDD17255A582000E217F9 /* TSErrorMessage_privateConstructor.h in Headers */, - C33FDC93255A582000E217F9 /* OWSDisappearingMessagesConfiguration.h in Headers */, - C38EF2C2255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h in Headers */, C33FDCCC255A582000E217F9 /* NSString+SSK.h in Headers */, C38EF313255B6DBF007E1867 /* OWSUnreadIndicator.h in Headers */, C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, - C33FDC9B255A582000E217F9 /* OWSReadTracking.h in Headers */, - C33FDC97255A582000E217F9 /* TSInfoMessage.h in Headers */, - C33FDC6D255A582000E217F9 /* TSContactThread.h in Headers */, - C33FDC3A255A581F00E217F9 /* OWSDisappearingMessagesJob.h in Headers */, B8D797C3256B25A8007C59DF /* TSAttachmentPointer+Backups.h in Headers */, - C33FDD6A255A582000E217F9 /* TSErrorMessage.h in Headers */, C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */, - C33FDC7A255A582000E217F9 /* OWSIncomingMessageFinder.h in Headers */, C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */, - C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */, C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */, C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */, - C33FDD4E255A582000E217F9 /* TSAccountManager.h in Headers */, - C33FDDAB255A582000E217F9 /* OWSIdentityManager.h in Headers */, C33FDC2C255A581F00E217F9 /* OWSFailedAttachmentDownloadsJob.h in Headers */, C38EF22A255B6D5D007E1867 /* AttachmentSharing.h in Headers */, C33FDD67255A582000E217F9 /* OWSRecordTranscriptJob.h in Headers */, C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */, C33FDC2F255A581F00E217F9 /* OWSSyncManagerProtocol.h in Headers */, C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */, - C33FDCDF255A582000E217F9 /* TSDatabaseSecondaryIndexes.h in Headers */, C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */, C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */, C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */, C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */, - C33FDDBF255A582000E217F9 /* OWSDisappearingMessagesFinder.h in Headers */, - C33FDCC4255A582000E217F9 /* TSGroupModel.h in Headers */, C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */, - C33FDD4B255A582000E217F9 /* ProtoUtils.h in Headers */, - C33FDD19255A582000E217F9 /* YapDatabaseConnection+OWS.h in Headers */, C38EF216255B6D3B007E1867 /* Theme.h in Headers */, C38EF31B255B6DBF007E1867 /* OWSPreferences.h in Headers */, C33FDD0C255A582000E217F9 /* OWSHTTPSecurityPolicy.h in Headers */, C33FDC57255A582000E217F9 /* OWSContactsOutputStream.h in Headers */, C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */, C38EF3F0255B6DF7007E1867 /* ThreadViewHelper.h in Headers */, - C33FDCD7255A582000E217F9 /* OWSReadReceiptManager.h in Headers */, - C33FDD21255A582000E217F9 /* OWSMediaGalleryFinder.h in Headers */, C38EF274255B6D7A007E1867 /* OWSResaveCollectionDBMigration.h in Headers */, - C33FDD02255A582000E217F9 /* TSOutgoingMessage.h in Headers */, C33FDC95255A582000E217F9 /* OWSFailedMessagesJob.h in Headers */, C38EF3F1255B6DF7007E1867 /* OWSSearchBar.h in Headers */, C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */, - C33FDC5A255A582000E217F9 /* OWSRecipientIdentity.h in Headers */, - C33FDC42255A581F00E217F9 /* YapDatabaseTransaction+OWS.h in Headers */, C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */, C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */, C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */, C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */, C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */, C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */, - C33FDD84255A582000E217F9 /* LKGroupUtilities.h in Headers */, - C33FDC8D255A582000E217F9 /* TSThread.h in Headers */, - C33FDDA5255A582000E217F9 /* OWSBlockingManager.h in Headers */, C38EF366255B6DCC007E1867 /* ScreenLockViewController.h in Headers */, - C33FDD16255A582000E217F9 /* NSArray+Functional.h in Headers */, C38EF35B255B6DCC007E1867 /* SelectThreadViewController.h in Headers */, C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */, C33FDC96255A582000E217F9 /* NSObject+Casting.h in Headers */, @@ -4029,51 +3958,34 @@ C33FDDB3255A582000E217F9 /* OWSError.h in Headers */, C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */, C38EF403255B6DF7007E1867 /* ContactCellView.h in Headers */, - C33FDCA0255A582000E217F9 /* TSInteraction.h in Headers */, - B8D797DF256B2737007C59DF /* TSAttachment+Albums.h in Headers */, C33FDD68255A582000E217F9 /* SignalAccount.h in Headers */, C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */, C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */, C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */, C38EF325255B6DBF007E1867 /* OWSWindowManager.h in Headers */, - C33FDCF2255A582000E217F9 /* OWSBackgroundTask.h in Headers */, - C38EF39C255B6DDA007E1867 /* OWSQuotedReplyModel.h in Headers */, C38EF404255B6DF7007E1867 /* ContactTableViewCell.h in Headers */, C38EF24A255B6D67007E1867 /* UIView+OWS.h in Headers */, C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */, C38EF322255B6DBF007E1867 /* DebugLogger.h in Headers */, - C33FDC2A255A581F00E217F9 /* TSMessage.h in Headers */, - C33FDD09255A582000E217F9 /* SSKJobRecord.h in Headers */, - C33FDC94255A582000E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */, C38EF2D7255B6DAF007E1867 /* OWSProfileManager.h in Headers */, - C33FDC21255A581F00E217F9 /* OWSPrimaryStorage.h in Headers */, C38EF290255B6D86007E1867 /* AppSetup.h in Headers */, C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */, C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */, C38EF367255B6DCC007E1867 /* OWSTableViewController.h in Headers */, - C33FDCEB255A582000E217F9 /* SSKEnvironment.h in Headers */, C38EF246255B6D67007E1867 /* UIFont+OWS.h in Headers */, C37F53A7255B96E0002AEA92 /* OWSAudioPlayer.h in Headers */, - C33FDC35255A581F00E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */, C33FDD0D255A582000E217F9 /* PreKeyBundle+jsonDict.h in Headers */, C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */, - C33FDCF5255A582000E217F9 /* NSNotificationCenter+OWS.h in Headers */, - C33FDD34255A582000E217F9 /* NotificationsProtocol.h in Headers */, C33FD9AF255A548A00E217F9 /* SignalUtilitiesKit.h in Headers */, C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */, C33FDD06255A582000E217F9 /* AppVersion.h in Headers */, C33FDD90255A582000E217F9 /* OWSUploadOperation.h in Headers */, - C33FDC8F255A582000E217F9 /* TSQuotedMessage.h in Headers */, C33FDC73255A582000E217F9 /* OWSStorage+Subclass.h in Headers */, C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */, C33FDD27255A582000E217F9 /* TSPreKeyManager.h in Headers */, - C33FDD0B255A582000E217F9 /* NSUserDefaults+OWS.h in Headers */, - C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */, C37F53E9255BA9CE002AEA92 /* Environment.h in Headers */, - C33FDCE6255A582000E217F9 /* TSDatabaseView.h in Headers */, C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */, C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */, - C33FDC33255A581F00E217F9 /* TSGroupThread.h in Headers */, C33FDD01255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.h in Headers */, C38EF28F255B6D86007E1867 /* VersionMigrations.h in Headers */, ); @@ -4091,17 +4003,21 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + C32C5FAA256DFED9003C73A2 /* NSArray+Functional.h in Headers */, C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */, C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */, C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */, C352A3B72557B6ED00338F3E /* TSRequest.h in Headers */, + C32C5A36256DB856003C73A2 /* LKGroupUtilities.h in Headers */, C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */, C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */, C3D9E4FD256778E30040E4F3 /* NSData+Image.h in Headers */, C300A63B2554B72200555489 /* NSDate+Timestamp.h in Headers */, C3D9E4E3256778720040E4F3 /* UIImage+OWS.h in Headers */, C352A3772557864000338F3E /* NSTimer+Proxying.h in Headers */, + C32C5B51256DC219003C73A2 /* NSNotificationCenter+OWS.h in Headers */, C3C2A67D255388CC00C340D1 /* SessionUtilitiesKit.h in Headers */, + C32C6018256E07F9003C73A2 /* NSUserDefaults+OWS.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4110,9 +4026,51 @@ buildActionMask = 2147483647; files = ( C3D9E485256775D20040E4F3 /* TSAttachment.h in Headers */, + C32C5EE5256DF506003C73A2 /* YapDatabaseConnection+OWS.h in Headers */, + C32C5AAF256DBE8F003C73A2 /* TSMessage.h in Headers */, + C32C5B8D256DC565003C73A2 /* SSKEnvironment.h in Headers */, + C32C5F34256DFCC4003C73A2 /* TSErrorMessage.h in Headers */, + C32C59C6256DB41F003C73A2 /* TSGroupThread.h in Headers */, C3C2A6F425539DE700C340D1 /* SessionMessagingKit.h in Headers */, + C32C59C2256DB41F003C73A2 /* TSContactThread.h in Headers */, + C32C5B2D256DC1A1003C73A2 /* TSQuotedMessage.h in Headers */, + C32C59C5256DB41F003C73A2 /* TSGroupModel.h in Headers */, + C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */, C3D9E487256775D20040E4F3 /* TSAttachmentStream.h in Headers */, + C3A3A122256E1A97004D228D /* OWSDisappearingMessagesFinder.h in Headers */, + C32C5F4E256DFD58003C73A2 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */, + C3A3A12B256E1AD5004D228D /* TSDatabaseSecondaryIndexes.h in Headers */, + C32C5FC4256E0209003C73A2 /* OWSBackgroundTask.h in Headers */, + C32C5C24256DCB30003C73A2 /* NotificationsProtocol.h in Headers */, + C32C59C0256DB41F003C73A2 /* TSThread.h in Headers */, + C32C5AB3256DBE8F003C73A2 /* TSInteraction.h in Headers */, + C32C5DA5256DD6E5003C73A2 /* OWSOutgoingReceiptManager.h in Headers */, + C32C5B0A256DC076003C73A2 /* OWSDisappearingMessagesConfiguration.h in Headers */, + C32C5D37256DD4ED003C73A2 /* TSUnreadIndicatorInteraction.h in Headers */, + C32C5ADF256DBFAA003C73A2 /* OWSReadTracking.h in Headers */, C3D9E486256775D20040E4F3 /* TSAttachmentPointer.h in Headers */, + C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */, + C3A3A0B3256E17F2004D228D /* SSKJobRecord.h in Headers */, + C32C5BE6256DC891003C73A2 /* OWSReadReceiptManager.h in Headers */, + C32C5EC3256DE133003C73A2 /* OWSQuotedReplyModel.h in Headers */, + C32C5BF8256DC8F6003C73A2 /* OWSDisappearingMessagesJob.h in Headers */, + C32C5AAA256DBE8F003C73A2 /* TSIncomingMessage.h in Headers */, + C32C5B6B256DC357003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */, + C32C5F23256DFCC0003C73A2 /* TSErrorMessage_privateConstructor.h in Headers */, + C32C5BBA256DC7E3003C73A2 /* ProfileManagerProtocol.h in Headers */, + C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */, + C32C5CAD256DD1DF003C73A2 /* TSAccountManager.h in Headers */, + C3A3A0F5256E194C004D228D /* OWSRecipientIdentity.h in Headers */, + C32C5AB4256DBE8F003C73A2 /* TSOutgoingMessage.h in Headers */, + C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */, + C3A3A111256E1A93004D228D /* OWSIncomingMessageFinder.h in Headers */, + C32C5AAC256DBE8F003C73A2 /* TSInfoMessage.h in Headers */, + C32C5BB0256DC73D003C73A2 /* OWSBlockingManager.h in Headers */, + C3A3A15F256E1BB4004D228D /* ProtoUtils.h in Headers */, + C3A3A145256E1B49004D228D /* OWSMediaGalleryFinder.h in Headers */, + C32C5C0A256DC9B4003C73A2 /* OWSIdentityManager.h in Headers */, + C32C5F68256DFDAA003C73A2 /* TSInvalidIdentityKeyErrorMessage.h in Headers */, + C32C5E64256DDFD6003C73A2 /* OWSStorage.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4963,26 +4921,19 @@ C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */, C33FDCA3255A582000E217F9 /* SSKMessageSenderJobRecord.m in Sources */, C38EF3C3255B6DE7007E1867 /* ImageEditorTextItem.swift in Sources */, - B8D8F16B256615DE0092EF10 /* Storage+VolumeSamples.swift in Sources */, - C33FDC41255A581F00E217F9 /* TypingIndicators.swift in Sources */, C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */, - B84072962565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift in Sources */, C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */, C33FDC99255A582000E217F9 /* PublicChatManager.swift in Sources */, - C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */, C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */, - B8D8F19325661BF80092EF10 /* Storage+Messaging.swift in Sources */, C38EF35F255B6DCC007E1867 /* SelectRecipientViewController.m in Sources */, C38EF3C5255B6DE7007E1867 /* OWSViewController+ImageEditor.swift in Sources */, C33FDDCD255A582000E217F9 /* OWSAttachmentDownloads.m in Sources */, - C33FDD97255A582000E217F9 /* OWSDisappearingMessagesJob.m in Sources */, C33FDD0F255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m in Sources */, C38EF320255B6DBF007E1867 /* OWSScrubbingLogFormatter.m in Sources */, C38EF39B255B6DDA007E1867 /* ThreadViewModel.swift in Sources */, C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */, C38EF330255B6DBF007E1867 /* OWSWindowManager.m in Sources */, C33FDD79255A582000E217F9 /* OWSHTTPSecurityPolicy.m in Sources */, - C33FDD3D255A582000E217F9 /* TSQuotedMessage.m in Sources */, C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */, C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */, C3D9E40C25676C100040E4F3 /* Storage+Conformances.swift in Sources */, @@ -4990,85 +4941,60 @@ C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */, C38EF244255B6D67007E1867 /* UIDevice+featureSupport.swift in Sources */, C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */, - C33FDC87255A582000E217F9 /* SSKJobRecord.m in Sources */, C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */, C38EF297255B6D86007E1867 /* OWSSounds.m in Sources */, - B8D8F18925661BA50092EF10 /* Storage+OpenGroups.swift in Sources */, - C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */, C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */, C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */, C33FDD0A255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.m in Sources */, - C33FDD1A255A582000E217F9 /* TSMessage.m in Sources */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */, - C33FDD26255A582000E217F9 /* NSNotificationCenter+OWS.m in Sources */, C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */, - C33FDD42255A582000E217F9 /* TSAccountManager.m in Sources */, - B8D8F1E6256620DD0092EF10 /* MessageReceiverDelegate.swift in Sources */, C38EF3FB255B6DF7007E1867 /* UIAlertController+OWS.swift in Sources */, C33FDC53255A582000E217F9 /* OutageDetection.swift in Sources */, C38EF30C255B6DBF007E1867 /* OWSScreenLock.swift in Sources */, C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */, C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */, - C33FDD00255A582000E217F9 /* TSDatabaseView.m in Sources */, C33FDD83255A582000E217F9 /* CreatePreKeysOperation.swift in Sources */, - C33FDDD5255A582000E217F9 /* OWSBackgroundTask.m in Sources */, - B84072A02565F1670037CB17 /* Quote+Conversion.swift in Sources */, - C33FDC62255A582000E217F9 /* BuildConfiguration.swift in Sources */, C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */, C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */, C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */, C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */, C33FDCC7255A582000E217F9 /* NSArray+OWS.m in Sources */, C38EF3EF255B6DF7007E1867 /* ThreadViewHelper.m in Sources */, - C33FDD72255A582000E217F9 /* TSThread.m in Sources */, C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */, C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */, C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */, C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */, C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */, - C38EF2C5255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m in Sources */, C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */, C38EF388255B6DD2007E1867 /* AttachmentApprovalViewController.swift in Sources */, C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */, - C33FDC72255A582000E217F9 /* NSArray+Functional.m in Sources */, C33FDD38255A582000E217F9 /* TSPreKeyManager.m in Sources */, C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */, C38EF22C255B6D5D007E1867 /* OWSVideoPlayer.swift in Sources */, C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */, C38EF407255B6DF7007E1867 /* Toast.swift in Sources */, C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */, - B8D8F0F32565F98E0092EF10 /* LKUserDefaults.swift in Sources */, C38EF409255B6DF7007E1867 /* ContactTableViewCell.m in Sources */, C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */, C38EF333255B6DBF007E1867 /* DeviceSleepManager.swift in Sources */, C33FDC52255A582000E217F9 /* RotateSignedKeyOperation.swift in Sources */, - C33FDCDA255A582000E217F9 /* TSDatabaseSecondaryIndexes.m in Sources */, C38EF335255B6DBF007E1867 /* BlockListCache.swift in Sources */, C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */, C38EF316255B6DBF007E1867 /* ProximityMonitoringManager.swift in Sources */, C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */, C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */, - C33FDD39255A582000E217F9 /* FullTextSearchFinder.swift in Sources */, - C38EEF0A255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift in Sources */, C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */, - C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */, C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */, - B8D8F16A256615DE0092EF10 /* Storage+Shared.swift in Sources */, - C33FDC46255A581F00E217F9 /* OpenGroupPoller.swift in Sources */, C38EF400255B6DF7007E1867 /* GalleryRailView.swift in Sources */, C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */, - C33FDC34255A581F00E217F9 /* NSRegularExpression+SSK.swift in Sources */, C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */, C38EF218255B6D3B007E1867 /* Theme.m in Sources */, C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */, - B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */, C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */, - C33FDD76255A582000E217F9 /* SSKKeychainStorage.swift in Sources */, - C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */, C37F5403255BA9ED002AEA92 /* Environment.m in Sources */, C38EF2D4255B6DAF007E1867 /* OWSProfileManager.m in Sources */, C38EF248255B6D67007E1867 /* UIViewController+OWS.m in Sources */, @@ -5078,114 +5004,69 @@ C38EF370255B6DCC007E1867 /* OWSNavigationController.m in Sources */, C38EF24E255B6D67007E1867 /* Collection+OWS.swift in Sources */, C33FDD05255A582000E217F9 /* OWSChunkedOutputStream.m in Sources */, - C33FDD10255A582000E217F9 /* TSOutgoingMessage.m in Sources */, C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */, C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */, - C33FDD2D255A582000E217F9 /* TSGroupModel.m in Sources */, - C33FDD9B255A582000E217F9 /* LKGroupUtilities.m in Sources */, - C38EF229255B6D5D007E1867 /* SignalAttachment.swift in Sources */, C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */, C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */, - C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */, C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */, C38EF24B255B6D67007E1867 /* UIView+OWS.m in Sources */, - C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */, C38EF408255B6DF7007E1867 /* OWSSearchBar.m in Sources */, C38EF327255B6DBF007E1867 /* BlockListUIUtils.m in Sources */, C33FDCFF255A582000E217F9 /* NSString+SSK.m in Sources */, - C33FDD22255A582000E217F9 /* ContentProxy.swift in Sources */, C38EF310255B6DBF007E1867 /* DebugLogger.m in Sources */, C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */, - C33FDD2F255A582000E217F9 /* AppReadiness.m in Sources */, - C33FDCEC255A582000E217F9 /* SSKIncrementingIdFinder.swift in Sources */, C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */, - C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */, - B8D8F1F0256621180092EF10 /* MessageSenderDelegate.swift in Sources */, C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */, C38EF3C4255B6DE7007E1867 /* ImageEditorContents.swift in Sources */, - C33FDC3B255A581F00E217F9 /* MentionsManager.swift in Sources */, - C33FDCFD255A582000E217F9 /* YapDatabaseConnection+OWS.m in Sources */, C38EF3BC255B6DE7007E1867 /* ImageEditorPanGestureRecognizer.swift in Sources */, - C33FDC23255A581F00E217F9 /* SSKPreferences.swift in Sources */, C38EF372255B6DCC007E1867 /* MediaMessageView.swift in Sources */, C38EF387255B6DD2007E1867 /* AttachmentItemCollection.swift in Sources */, C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */, - C33FDC38255A581F00E217F9 /* Mention.swift in Sources */, C38EF3BF255B6DE7007E1867 /* ImageEditorView.swift in Sources */, C38EF365255B6DCC007E1867 /* OWSTableViewController.m in Sources */, - C33FDC25255A581F00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */, C38EF36B255B6DCC007E1867 /* ScreenLockViewController.m in Sources */, C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */, C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */, - B8D8F16C256615DE0092EF10 /* Storage+SnodeAPI.swift in Sources */, C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */, - C3B7845D25649DA600ADB2E7 /* TSIncomingMessage+Conversion.swift in Sources */, - C33FDCF4255A582000E217F9 /* Poller.swift in Sources */, C38EF332255B6DBF007E1867 /* OWSPreferences.m in Sources */, - C33FDC26255A581F00E217F9 /* ProtoUtils.m in Sources */, - C38EF39E255B6DDA007E1867 /* OWSQuotedReplyModel.m in Sources */, - B8D8F17725661AFA0092EF10 /* Storage+Jobs.swift in Sources */, - C33FDD85255A582000E217F9 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, - C33FDD2E255A582000E217F9 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, - C33FDDBB255A582000E217F9 /* TSGroupThread.m in Sources */, C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */, C33FDD14255A582000E217F9 /* OWSUDManager.swift in Sources */, - C33FDC6B255A582000E217F9 /* OWSStorage.m in Sources */, C38EF28D255B6D86007E1867 /* OWSAudioSession.swift in Sources */, - C33FDD7B255A582000E217F9 /* GeneralUtilities.swift in Sources */, C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */, C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */, - C33FDD15255A582000E217F9 /* YapDatabaseTransaction+OWS.m in Sources */, - C33FDD63255A582000E217F9 /* OWSIdentityManager.m in Sources */, C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */, C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */, C38EF30E255B6DBF007E1867 /* FullTextSearcher.swift in Sources */, C33FDDD9255A582000E217F9 /* LokiSessionRestorationImplementation.swift in Sources */, - C33FDD31255A582000E217F9 /* NSUserDefaults+OWS.m in Sources */, C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */, C38EF3BB255B6DE7007E1867 /* ImageEditorStrokeItem.swift in Sources */, - C33FDCA1255A582000E217F9 /* TSErrorMessage.m in Sources */, C38EF3C0255B6DE7007E1867 /* ImageEditorCropViewController.swift in Sources */, C38EF401255B6DF7007E1867 /* VideoPlayerView.swift in Sources */, - C33FDC22255A581F00E217F9 /* OWSBlockingManager.m in Sources */, C38EF3FE255B6DF7007E1867 /* OWSTextField.m in Sources */, - C33FDC40255A581F00E217F9 /* OWSDisappearingMessagesFinder.m in Sources */, - B8D8F21A25662A4D0092EF10 /* OpenGroupAPIDelegate.swift in Sources */, - C33FDCEE255A582000E217F9 /* ClosedGroupPoller.swift in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */, - B8D797D5256B2715007C59DF /* TSAttachment+Albums.m in Sources */, C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */, C38EF293255B6D86007E1867 /* AppSetup.m in Sources */, C33FDDC0255A582000E217F9 /* SignalAccount.m in Sources */, C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */, - C3D9E53925677F5E0040E4F3 /* Attachment+Conversion.swift in Sources */, C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */, - C33FDD29255A582000E217F9 /* OWSOutgoingReceiptManager.m in Sources */, - B8D8F0F42565F98E0092EF10 /* PushNotificationAPI.swift in Sources */, C33FDC78255A582000E217F9 /* TSConstants.m in Sources */, C38EF324255B6DBF007E1867 /* Bench.swift in Sources */, C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */, - C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */, C38EF3F2255B6DF7007E1867 /* DisappearingTimerConfigurationView.swift in Sources */, - C33FDCD8255A582000E217F9 /* OWSIncomingMessageFinder.m in Sources */, C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, - C33FDCAC255A582000E217F9 /* ProxiedContentDownloader.swift in Sources */, C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */, C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */, C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */, C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */, C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */, C33FDCFE255A582000E217F9 /* OWSContactsOutputStream.m in Sources */, - C33FDDBC255A582000E217F9 /* OWSPrimaryStorage.m in Sources */, C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */, - C33FDC2B255A581F00E217F9 /* OWSReadReceiptManager.m in Sources */, C38EF326255B6DBF007E1867 /* ConversationStyle.swift in Sources */, C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */, C33FDD91255A582000E217F9 /* OWSMessageUtils.m in Sources */, B8C2B332256376F000551B4D /* ThreadUtil.m in Sources */, C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */, - C3CA3B1D255CF3C800F4C6D4 /* MessageSender+Utilities.swift in Sources */, C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */, C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */, C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */, @@ -5194,22 +5075,16 @@ C38EF28E255B6D86007E1867 /* SignalKeyingStorage.m in Sources */, B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */, C38EF406255B6DF7007E1867 /* OWSAlerts.swift in Sources */, - C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */, - C33FDDA3255A582000E217F9 /* TSInteraction.m in Sources */, C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */, C33FDDD8255A582000E217F9 /* OWSUploadOperation.m in Sources */, C33FDDC5255A582000E217F9 /* OWSError.m in Sources */, C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */, - C33FDC2D255A581F00E217F9 /* ECKeyPair+Hexadecimal.swift in Sources */, - C33FDDC6255A582000E217F9 /* TSInfoMessage.m in Sources */, B8D797B2256B25A1007C59DF /* TSAttachmentPointer+Backups.m in Sources */, C38EF319255B6DBF007E1867 /* Weak.swift in Sources */, C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */, C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */, C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */, - B8D8F1BD25661C6F0092EF10 /* Storage+OnionRequests.swift in Sources */, C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */, - C33FDD2B255A582000E217F9 /* OWSMediaGalleryFinder.m in Sources */, C38EF2B4255B6D9C007E1867 /* UIView+Utilities.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5222,7 +5097,9 @@ C3C2A5BF255385EE00C340D1 /* SnodeMessage.swift in Sources */, C3C2A5C0255385EE00C340D1 /* Snode.swift in Sources */, C3C2A5C7255385EE00C340D1 /* SnodeAPI.swift in Sources */, + C32C5CBF256DD282003C73A2 /* Storage+SnodeAPI.swift in Sources */, C3C2A5C6255385EE00C340D1 /* Notification+OnionRequestAPI.swift in Sources */, + C32C5CBE256DD282003C73A2 /* Storage+OnionRequests.swift in Sources */, C3C2A5DC2553860B00C340D1 /* Promise+Threading.swift in Sources */, C3C2A5C4255385EE00C340D1 /* OnionRequestAPI+Encryption.swift in Sources */, C3C2A5DE2553860B00C340D1 /* String+Utilities.swift in Sources */, @@ -5239,29 +5116,41 @@ buildActionMask = 2147483647; files = ( C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */, + C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */, C3D9E41525676C320040E4F3 /* Storage.swift in Sources */, + C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */, C3D9E39B256763C20040E4F3 /* AppContext.m in Sources */, C3BBE0A82554D4DE0050F1E3 /* JSON.swift in Sources */, C352A36D2557858E00338F3E /* NSTimer+Proxying.m in Sources */, + C32C5A2D256DB849003C73A2 /* LKGroupUtilities.m in Sources */, C3C2ABD22553C6C900C340D1 /* Data+SecureRandom.swift in Sources */, + C32C5DC9256DD935003C73A2 /* ProxiedContentDownloader.swift in Sources */, C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */, C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */, + C32C5DD2256DD9E5003C73A2 /* LRUCache.swift in Sources */, C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */, + C32C5FA1256DFED5003C73A2 /* NSArray+Functional.m in Sources */, C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */, C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */, C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Description.swift in Sources */, C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */, + C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */, C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */, C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */, + C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */, C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */, C352A3A62557B60D00338F3E /* TSRequest.m in Sources */, C3471ED42555386B00297E91 /* AESGCM.swift in Sources */, + C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */, C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */, C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */, + C32C5A24256DB7DB003C73A2 /* LKUserDefaults.swift in Sources */, C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */, C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */, C3D9E4F4256778AF0040E4F3 /* NSData+Image.m in Sources */, + C32C5E0C256DDAFA003C73A2 /* NSRegularExpression+SSK.swift in Sources */, C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */, + C32C5A48256DB8F0003C73A2 /* BuildConfiguration.swift in Sources */, C300A60D2554B31900555489 /* Logging.swift in Sources */, C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */, C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */, @@ -5274,56 +5163,122 @@ buildActionMask = 2147483647; files = ( C3A7229C2558E4310043A11F /* OpenGroupMessage+Conversion.swift in Sources */, + C32C5DBE256DD743003C73A2 /* OpenGroupPoller.swift in Sources */, C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */, C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */, + C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */, C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */, C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */, C352A32F2557549C00338F3E /* NotifyPNServerJob.swift in Sources */, C300A5F22554B09800555489 /* MessageSender.swift in Sources */, C3C2A74D2553A39700C340D1 /* VisibleMessage.swift in Sources */, + C32C5AAD256DBE8F003C73A2 /* TSInfoMessage.m in Sources */, + C32C5A13256DB7A5003C73A2 /* PushNotificationAPI.swift in Sources */, C352A3932557883D00338F3E /* JobDelegate.swift in Sources */, + C32C5B84256DC54F003C73A2 /* SSKEnvironment.m in Sources */, + C3A3A108256E1A5C004D228D /* OWSIncomingMessageFinder.m in Sources */, C352A31325574F5200338F3E /* MessageReceiveJob.swift in Sources */, + C32C5BDD256DC88D003C73A2 /* OWSReadReceiptManager.m in Sources */, C3D9E3BF25676AD70040E4F3 /* TSAttachmentStream.m in Sources */, - C3A722922558C8940043A11F /* OpenGroupAPIDelegate.swift in Sources */, C3C2A7562553A3AB00C340D1 /* VisibleMessage+Quote.swift in Sources */, + C32C5C89256DD0D2003C73A2 /* Storage+Jobs.swift in Sources */, C300A5FC2554B0A000555489 /* MessageReceiver.swift in Sources */, + C32C5A76256DBBCF003C73A2 /* SignalAttachment.swift in Sources */, + C32C5CA4256DD1DC003C73A2 /* TSAccountManager.m in Sources */, C3A7213B2558BDFA0043A11F /* OpenGroup.swift in Sources */, C352A3892557876500338F3E /* JobQueue.swift in Sources */, C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */, C3A721902558C0CD0043A11F /* FileServerAPI.swift in Sources */, + C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */, + C32C5F45256DFD2B003C73A2 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, + C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */, + C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */, C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */, + C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */, C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */, C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */, + C32C5AB1256DBE8F003C73A2 /* TSIncomingMessage.m in Sources */, + C3A3A107256E1A5C004D228D /* OWSDisappearingMessagesFinder.m in Sources */, + C32C59C3256DB41F003C73A2 /* TSGroupModel.m in Sources */, C3C2A7842553AAF300C340D1 /* SNProto.swift in Sources */, + C32C5DC0256DD743003C73A2 /* Poller.swift in Sources */, C3C2A7682553A3D900C340D1 /* VisibleMessage+Contact.swift in Sources */, + C3A3A171256E1D25004D228D /* SSKReachabilityManager.swift in Sources */, C3A721392558BDFA0043A11F /* OpenGroupAPI.swift in Sources */, C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */, - B867665825663BBA00B197C5 /* MessageSenderDelegate.swift in Sources */, + C32C5D24256DD4C0003C73A2 /* MentionsManager.swift in Sources */, C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */, C3A721382558BDFA0043A11F /* OpenGroupMessage.swift in Sources */, C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */, + C32C5B3F256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift in Sources */, C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */, + C32C5D19256DD493003C73A2 /* OWSLinkPreview.swift in Sources */, + C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */, C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */, + C32C5AB5256DBE8F003C73A2 /* TSOutgoingMessage+Conversion.swift in Sources */, + C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */, + C32C5E15256DDC78003C73A2 /* SSKPreferences.swift in Sources */, + C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */, + C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */, + C3A3A099256E17B2004D228D /* SSKJobRecordFinder.swift in Sources */, + C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */, C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */, + C32C5F5F256DFD90003C73A2 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */, + C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */, + C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */, + C32C5C1B256DC9E0003C73A2 /* GeneralUtilities.swift in Sources */, + C32C5A02256DB658003C73A2 /* MessageSender+Handling.swift in Sources */, + C32C5D2E256DD4EA003C73A2 /* TSUnreadIndicatorInteraction.m in Sources */, + C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */, C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */, C3471FA42555439E00297E91 /* Notification+MessageSender.swift in Sources */, + C32C5BEF256DC8EE003C73A2 /* OWSDisappearingMessagesJob.m in Sources */, C3A7222A2558C1E40043A11F /* DotNetAPI.swift in Sources */, + C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */, + C32C5EB9256DE130003C73A2 /* OWSQuotedReplyModel+Conversion.swift in Sources */, C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */, + C32C5BCC256DC830003C73A2 /* Storage+ClosedGroups.swift in Sources */, + C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */, + C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */, + C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */, + C32C5B1C256DC19D003C73A2 /* TSQuotedMessage.m in Sources */, C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */, C352A30925574D8500338F3E /* Message+Destination.swift in Sources */, C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */, C3D9E3C025676AD70040E4F3 /* TSAttachment.m in Sources */, - C3D697382564DCE6004AF766 /* MessageReceiverDelegate.swift in Sources */, + C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */, C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */, C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */, + C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */, + C32C5C93256DD12D003C73A2 /* OWSUDManager.swift in Sources */, + C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */, C3C2A74425539EB700C340D1 /* Message.swift in Sources */, + C32C5F11256DF79A003C73A2 /* SSKIncrementingIdFinder.swift in Sources */, + C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */, + C32C5EEE256DF54E003C73A2 /* TSDatabaseView.m in Sources */, C300A5C92554B04E00555489 /* SessionRequest.swift in Sources */, C3A7213A2558BDFA0043A11F /* OpenGroupInfo.swift in Sources */, C352A35B2557824E00338F3E /* AttachmentUploadJob.swift in Sources */, + C3A3A13C256E1B27004D228D /* OWSMediaGalleryFinder.m in Sources */, + C32C5AAE256DBE8F003C73A2 /* TSInteraction.m in Sources */, + C32C5D23256DD4C0003C73A2 /* Mention.swift in Sources */, + C32C5FD6256E0346003C73A2 /* Notification+Thread.swift in Sources */, C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */, + C32C5C88256DD0D2003C73A2 /* Storage+Messaging.swift in Sources */, + C32C59C7256DB41F003C73A2 /* TSThread.m in Sources */, + C32C5F08256DF5C8003C73A2 /* DisplayNameUtilities.swift in Sources */, C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */, + C32C5F1A256DFCAD003C73A2 /* TSErrorMessage.m in Sources */, + C32C5A75256DBBCF003C73A2 /* TSAttachmentPointer+Conversion.swift in Sources */, + C32C5AF8256DC051003C73A2 /* OWSDisappearingMessagesConfiguration.m in Sources */, + C32C5EBA256DE130003C73A2 /* OWSQuotedReplyModel.m in Sources */, + C32C5B62256DC333003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */, C352A2F525574B4700338F3E /* Job.swift in Sources */, + C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */, + C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */, + C3A3A0AA256E17E6004D228D /* SSKJobRecord.m in Sources */, + C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5500,6 +5455,7 @@ 4CFE6B6C21F92BA700006701 /* LegacyNotificationsAdaptee.swift in Sources */, B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */, C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */, + C32C5D40256DD51E003C73A2 /* Storage+VolumeSamples.swift in Sources */, 3441FD9F21A3604F00BB9542 /* BackupRestoreViewController.swift in Sources */, 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */, 45C0DC1B1E68FE9000E04C47 /* UIApplication+OWS.swift in Sources */, diff --git a/SignalUtilitiesKit/AppSetup.m b/SignalUtilitiesKit/AppSetup.m index 189933e35..1266dd04a 100644 --- a/SignalUtilitiesKit/AppSetup.m +++ b/SignalUtilitiesKit/AppSetup.m @@ -9,18 +9,17 @@ #import #import #import -#import -#import -#import -#import -#import -#import +#import +#import +#import +#import +#import +#import #import -#import -#import +#import +#import #import - NS_ASSUME_NONNULL_BEGIN @implementation AppSetup @@ -67,7 +66,6 @@ NS_ASSUME_NONNULL_BEGIN [[OWSOutgoingReceiptManager alloc] initWithPrimaryStorage:primaryStorage]; id reachabilityManager = [SSKReachabilityManagerImpl new]; id typingIndicators = [[OWSTypingIndicatorsImpl alloc] init]; - OWSAttachmentDownloads *attachmentDownloads = [[OWSAttachmentDownloads alloc] init]; OWSAudioSession *audioSession = [OWSAudioSession new]; OWSSounds *sounds = [[OWSSounds alloc] initWithPrimaryStorage:primaryStorage]; @@ -90,8 +88,7 @@ NS_ASSUME_NONNULL_BEGIN readReceiptManager:readReceiptManager outgoingReceiptManager:outgoingReceiptManager reachabilityManager:reachabilityManager - typingIndicators:typingIndicators - attachmentDownloads:attachmentDownloads]]; + typingIndicators:typingIndicators]]; appSpecificSingletonBlock(); diff --git a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m index edd205151..5e78fa2b9 100644 --- a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m +++ b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m @@ -3,8 +3,8 @@ // #import "OWSDatabaseMigration.h" -#import -#import +#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.h similarity index 90% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.h index 19733f962..abbc0a555 100644 --- a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.h +++ b/SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+PreKeyStore.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+PreKeyStore.m diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h similarity index 92% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h index 25a043bcc..3f60b1a97 100644 --- a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.h +++ b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SessionStore.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.m diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.h similarity index 95% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.h index 2082d9509..a994d2e18 100644 --- a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.h +++ b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+SignedPreKeyStore.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+SignedPreKeyStore.m diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.h similarity index 81% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.h rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.h index 2f13afe30..bb84530c0 100644 --- a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.h +++ b/SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.m b/SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.m similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage/OWSPrimaryStorage+keyFromIntLong.m rename to SignalUtilitiesKit/Database/OWSPrimaryStorage+keyFromIntLong.m diff --git a/SignalUtilitiesKit/Database/Utilities/OWSStorage+Subclass.h b/SignalUtilitiesKit/Database/OWSStorage+Subclass.h similarity index 93% rename from SignalUtilitiesKit/Database/Utilities/OWSStorage+Subclass.h rename to SignalUtilitiesKit/Database/OWSStorage+Subclass.h index ac1e88ec7..9f3fd0be1 100644 --- a/SignalUtilitiesKit/Database/Utilities/OWSStorage+Subclass.h +++ b/SignalUtilitiesKit/Database/OWSStorage+Subclass.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.h b/SignalUtilitiesKit/Database/SignalKeyingStorage.h similarity index 100% rename from SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.h rename to SignalUtilitiesKit/Database/SignalKeyingStorage.h diff --git a/SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.m b/SignalUtilitiesKit/Database/SignalKeyingStorage.m similarity index 95% rename from SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.m rename to SignalUtilitiesKit/Database/SignalKeyingStorage.m index c8ad2a659..21e06a677 100644 --- a/SignalUtilitiesKit/Database/Utilities/SignalKeyingStorage.m +++ b/SignalUtilitiesKit/Database/SignalKeyingStorage.m @@ -3,8 +3,8 @@ // #import "SignalKeyingStorage.h" -#import -#import +#import +#import #import #define SignalKeyingCollection @"SignalKeyingCollection" diff --git a/SignalUtilitiesKit/Database/Storage/Storage+Conformances.swift b/SignalUtilitiesKit/Database/Storage+Conformances.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage/Storage+Conformances.swift rename to SignalUtilitiesKit/Database/Storage+Conformances.swift diff --git a/SignalUtilitiesKit/Database/Storage/Storage+SessionManagement.swift b/SignalUtilitiesKit/Database/Storage+SessionManagement.swift similarity index 100% rename from SignalUtilitiesKit/Database/Storage/Storage+SessionManagement.swift rename to SignalUtilitiesKit/Database/Storage+SessionManagement.swift diff --git a/SignalUtilitiesKit/Database/Utilities/TSStorageHeaders.h b/SignalUtilitiesKit/Database/TSStorageHeaders.h similarity index 79% rename from SignalUtilitiesKit/Database/Utilities/TSStorageHeaders.h rename to SignalUtilitiesKit/Database/TSStorageHeaders.h index d9cea198b..ddbbd179b 100644 --- a/SignalUtilitiesKit/Database/Utilities/TSStorageHeaders.h +++ b/SignalUtilitiesKit/Database/TSStorageHeaders.h @@ -4,11 +4,11 @@ #ifndef Signal_TSStorageHeaders_h #define Signal_TSStorageHeaders_h -#import +#import #import #import #import #import -#import +#import #endif diff --git a/SignalUtilitiesKit/Database/Utilities/TSStorageKeys.h b/SignalUtilitiesKit/Database/TSStorageKeys.h similarity index 100% rename from SignalUtilitiesKit/Database/Utilities/TSStorageKeys.h rename to SignalUtilitiesKit/Database/TSStorageKeys.h diff --git a/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.h b/SignalUtilitiesKit/Database/ThreadViewHelper.h similarity index 100% rename from SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.h rename to SignalUtilitiesKit/Database/ThreadViewHelper.h diff --git a/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m b/SignalUtilitiesKit/Database/ThreadViewHelper.m similarity index 97% rename from SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m rename to SignalUtilitiesKit/Database/ThreadViewHelper.m index 970b55803..f70aa319a 100644 --- a/SignalUtilitiesKit/Database/Utilities/ThreadViewHelper.m +++ b/SignalUtilitiesKit/Database/ThreadViewHelper.m @@ -4,10 +4,10 @@ #import "ThreadViewHelper.h" #import -#import -#import -#import -#import +#import +#import +#import +#import #import #import #import diff --git a/SignalUtilitiesKit/Database/YapDatabase/YapDatabase+Promise.swift b/SignalUtilitiesKit/Database/YapDatabase+Promise.swift similarity index 100% rename from SignalUtilitiesKit/Database/YapDatabase/YapDatabase+Promise.swift rename to SignalUtilitiesKit/Database/YapDatabase+Promise.swift diff --git a/SignalUtilitiesKit/JobQueue.swift b/SignalUtilitiesKit/JobQueue.swift index 366c9992c..7c4f90f92 100644 --- a/SignalUtilitiesKit/JobQueue.swift +++ b/SignalUtilitiesKit/JobQueue.swift @@ -301,111 +301,3 @@ public extension JobQueue { operation.jobRecord.saveAsPermanentlyFailed(transaction: transaction) } } - -@objc(SSKJobRecordFinder) -public class JobRecordFinder: NSObject, Finder { - - typealias ExtensionType = YapDatabaseSecondaryIndex - typealias TransactionType = YapDatabaseSecondaryIndexTransaction - - enum JobRecordField: String { - case status, label, sortId - } - - func getNextReady(label: String, transaction: YapDatabaseReadTransaction) -> SSKJobRecord? { - var result: SSKJobRecord? - self.enumerateJobRecords(label: label, status: .ready, transaction: transaction) { jobRecord, stopPointer in - result = jobRecord - stopPointer.pointee = true - } - return result - } - - func allRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction) -> [SSKJobRecord] { - var result: [SSKJobRecord] = [] - self.enumerateJobRecords(label: label, status: status, transaction: transaction) { jobRecord, _ in - result.append(jobRecord) - } - return result - } - - func enumerateJobRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction, block: @escaping (SSKJobRecord, UnsafeMutablePointer) -> Void) { - let queryFormat = String(format: "WHERE %@ = ? AND %@ = ? ORDER BY %@", JobRecordField.status.rawValue, JobRecordField.label.rawValue, JobRecordField.sortId.rawValue) - let query = YapDatabaseQuery(string: queryFormat, parameters: [status.rawValue, label]) - - self.ext(transaction: transaction).enumerateKeysAndObjects(matching: query) { _, _, object, stopPointer in - guard let jobRecord = object as? SSKJobRecord else { - owsFailDebug("expecting jobRecord but found: \(object)") - return - } - block(jobRecord, stopPointer) - } - } - - static var dbExtensionName: String { - return "SecondaryIndexJobRecord" - } - - @objc - public class func asyncRegisterDatabaseExtensionObjC(storage: OWSStorage) { - asyncRegisterDatabaseExtension(storage: storage) - } - - static var dbExtensionConfig: YapDatabaseSecondaryIndex { - let setup = YapDatabaseSecondaryIndexSetup() - setup.addColumn(JobRecordField.sortId.rawValue, with: .integer) - setup.addColumn(JobRecordField.status.rawValue, with: .integer) - setup.addColumn(JobRecordField.label.rawValue, with: .text) - - let block: YapDatabaseSecondaryIndexWithObjectBlock = { transaction, dict, collection, key, object in - guard let jobRecord = object as? SSKJobRecord else { - return - } - - dict[JobRecordField.sortId.rawValue] = jobRecord.sortId - dict[JobRecordField.status.rawValue] = jobRecord.status.rawValue - dict[JobRecordField.label.rawValue] = jobRecord.label - } - - let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock(block) - - let options = YapDatabaseSecondaryIndexOptions() - let whitelist = YapWhitelistBlacklist(whitelist: Set([SSKJobRecord.collection()])) - options.allowedCollections = whitelist - - return YapDatabaseSecondaryIndex.init(setup: setup, handler: handler, versionTag: "2", options: options) - } -} - -protocol Finder { - associatedtype ExtensionType: YapDatabaseExtension - associatedtype TransactionType: YapDatabaseExtensionTransaction - - static var dbExtensionName: String { get } - static var dbExtensionConfig: ExtensionType { get } - - func ext(transaction: YapDatabaseReadTransaction) -> TransactionType - - static func asyncRegisterDatabaseExtension(storage: OWSStorage) - static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage) -} - -extension Finder { - - func ext(transaction: YapDatabaseReadTransaction) -> TransactionType { - return transaction.ext(type(of: self).dbExtensionName) as! TransactionType - } - - static func asyncRegisterDatabaseExtension(storage: OWSStorage) { - storage.asyncRegister(dbExtensionConfig, withName: dbExtensionName) - } - - // Only for testing. - static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage) { - guard storage.registeredExtension(dbExtensionName) == nil else { - return - } - - storage.register(dbExtensionConfig, withName: dbExtensionName) - } -} diff --git a/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift b/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift index 720723ca9..c828082b5 100644 --- a/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift +++ b/SignalUtilitiesKit/LokiSessionRestorationImplementation.swift @@ -29,7 +29,7 @@ public final class SessionRestorationImplementation : NSObject, SessionRestorati Storage.read { transaction in thread = TSContactThread.getWithContactId(publicKey, transaction: transaction) } - return thread?.sessionRestorationStatus ?? .none + return .none } public func handleNewSessionAdopted(for publicKey: String, using transaction: Any) { @@ -42,7 +42,6 @@ public final class SessionRestorationImplementation : NSObject, SessionRestorati let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetDone) infoMessage.save(with: transaction) // Update the session reset status - thread.sessionRestorationStatus = .none thread.save(with: transaction) } } diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h deleted file mode 100644 index 946791856..000000000 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.h +++ /dev/null @@ -1,18 +0,0 @@ -#import -#import "TSMessage.h" - -#ifndef TSAttachment_Albums_h -#define TSAttachment_Albums_h - -@interface TSAttachment (Albums) - -- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction; - -// `migrateAlbumMessageId` is only used in the migration to the new multi-attachment message scheme, -// and shouldn't be used as a general purpose setter. Instead, `albumMessageId` should be passed as -// an initializer param. -- (void)migrateAlbumMessageId:(NSString *)albumMesssageId; - -@end - -#endif diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m b/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m deleted file mode 100644 index 83999453c..000000000 --- a/SignalUtilitiesKit/Messaging/Attachments/TSAttachment+Albums.m +++ /dev/null @@ -1,18 +0,0 @@ -#import "TSAttachment+Albums.h" - -@implementation TSAttachment (Albums) - -- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - if (self.albumMessageId == nil) { - return nil; - } - return [TSMessage fetchObjectWithUniqueID:self.albumMessageId transaction:transaction]; -} - -- (void)migrateAlbumMessageId:(NSString *)albumMesssageId -{ - self.albumMessageId = albumMesssageId; -} - -@end diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m b/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m deleted file mode 100644 index 53ab3c0b5..000000000 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSMessage.m +++ /dev/null @@ -1,437 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "TSMessage.h" -#import "AppContext.h" -#import "MIMETypeUtil.h" -#import "NSString+SSK.h" - -#import "OWSDisappearingMessagesConfiguration.h" -#import "TSAttachment.h" -#import "TSAttachmentStream.h" -#import "TSQuotedMessage.h" -#import "TSThread.h" -#import -#import -#import -#import -#import "OWSPrimaryStorage+Loki.h" -#import "TSContactThread.h" - -NS_ASSUME_NONNULL_BEGIN - -static const NSUInteger OWSMessageSchemaVersion = 4; - -#pragma mark - - -@interface TSMessage () - -@property (nonatomic, nullable) NSString *body; -@property (nonatomic) uint32_t expiresInSeconds; -@property (nonatomic) uint64_t expireStartedAt; - -/** - * The version of the model class's schema last used to serialize this model. Use this to manage data migrations during - * object de/serialization. - * - * e.g. - * - * - (id)initWithCoder:(NSCoder *)coder - * { - * self = [super initWithCoder:coder]; - * if (!self) { return self; } - * if (_schemaVersion < 2) { - * _newName = [coder decodeObjectForKey:@"oldName"] - * } - * ... - * _schemaVersion = 2; - * } - */ -@property (nonatomic, readonly) NSUInteger schemaVersion; - -@end - -#pragma mark - - -@implementation TSMessage - -- (instancetype)initMessageWithTimestamp:(uint64_t)timestamp - inThread:(nullable TSThread *)thread - messageBody:(nullable NSString *)body - attachmentIds:(NSArray *)attachmentIds - expiresInSeconds:(uint32_t)expiresInSeconds - expireStartedAt:(uint64_t)expireStartedAt - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - linkPreview:(nullable OWSLinkPreview *)linkPreview -{ - self = [super initInteractionWithTimestamp:timestamp inThread:thread]; - - if (!self) { - return self; - } - - _schemaVersion = OWSMessageSchemaVersion; - - _body = body; - _attachmentIds = attachmentIds ? [attachmentIds mutableCopy] : [NSMutableArray new]; - _expiresInSeconds = expiresInSeconds; - _expireStartedAt = expireStartedAt; - [self updateExpiresAt]; - _quotedMessage = quotedMessage; - _linkPreview = linkPreview; - _openGroupServerMessageID = -1; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - self = [super initWithCoder:coder]; - if (!self) { - return self; - } - - if (_schemaVersion < 2) { - // renamed _attachments to _attachmentIds - if (!_attachmentIds) { - _attachmentIds = [coder decodeObjectForKey:@"attachments"]; - } - } - - if (_schemaVersion < 3) { - _expiresInSeconds = 0; - _expireStartedAt = 0; - _expiresAt = 0; - } - - if (_schemaVersion < 4) { - // Wipe out the body field on these legacy attachment messages. - // - // Explantion: Historically, a message sent from iOS could be an attachment XOR a text message, - // but now we support sending an attachment+caption as a single message. - // - // Other clients have supported sending attachment+caption in a single message for a long time. - // So the way we used to handle receiving them was to make it look like they'd sent two messages: - // first the attachment+caption (we'd ignore this caption when rendering), followed by a separate - // message with just the caption (which we'd render as a simple independent text message), for - // which we'd offset the timestamp by a little bit to get the desired ordering. - // - // Now that we can properly render an attachment+caption message together, these legacy "dummy" text - // messages are not only unnecessary, but worse, would be rendered redundantly. For safety, rather - // than building the logic to try to find and delete the redundant "dummy" text messages which users - // have been seeing and interacting with, we delete the body field from the attachment message, - // which iOS users have never seen directly. - if (_attachmentIds.count > 0) { - _body = nil; - } - } - - if (!_attachmentIds) { - _attachmentIds = [NSMutableArray new]; - } - - _schemaVersion = OWSMessageSchemaVersion; - - return self; -} - -- (void)setExpiresInSeconds:(uint32_t)expiresInSeconds -{ - uint32_t maxExpirationDuration = [OWSDisappearingMessagesConfiguration maxDurationSeconds]; - if (expiresInSeconds > maxExpirationDuration) { - OWSFailDebug(@"using `maxExpirationDuration` instead of: %u", maxExpirationDuration); - } - - _expiresInSeconds = MIN(expiresInSeconds, maxExpirationDuration); - [self updateExpiresAt]; -} - -- (void)setExpireStartedAt:(uint64_t)expireStartedAt -{ - if (_expireStartedAt != 0 && _expireStartedAt < expireStartedAt) { - OWSLogDebug(@"ignoring later startedAt time"); - return; - } - - uint64_t now = [NSDate ows_millisecondTimeStamp]; - if (expireStartedAt > now) { - OWSLogWarn(@"using `now` instead of future time"); - } - - _expireStartedAt = MIN(now, expireStartedAt); - [self updateExpiresAt]; -} - -- (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - return self.isExpiringMessage; -} - -// TODO a downloaded media doesn't start counting until download is complete. -- (void)updateExpiresAt -{ - if (_expiresInSeconds > 0 && _expireStartedAt > 0) { - _expiresAt = _expireStartedAt + _expiresInSeconds * 1000; - } else { - _expiresAt = 0; - } -} - -- (BOOL)hasAttachments -{ - return self.attachmentIds ? (self.attachmentIds.count > 0) : NO; -} - -- (NSArray *)allAttachmentIds -{ - NSMutableArray *result = [NSMutableArray new]; - if (self.attachmentIds.count > 0) { - [result addObjectsFromArray:self.attachmentIds]; - } - - if (self.quotedMessage) { - [result addObjectsFromArray:self.quotedMessage.thumbnailAttachmentStreamIds]; - } - - if (self.linkPreview.imageAttachmentId) { - [result addObject:self.linkPreview.imageAttachmentId]; - } - - return [result copy]; -} - -- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - NSMutableArray *attachments = [NSMutableArray new]; - for (NSString *attachmentId in self.attachmentIds) { - TSAttachment *_Nullable attachment = - [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; - if (attachment) { - [attachments addObject:attachment]; - } - } - return [attachments copy]; -} - -- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction - contentType:(NSString *)contentType -{ - NSArray *attachments = [self attachmentsWithTransaction:transaction]; - return [attachments filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TSAttachment *evaluatedObject, - NSDictionary *_Nullable bindings) { - return [evaluatedObject.contentType isEqualToString:contentType]; - }]]; -} - -- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction - exceptContentType:(NSString *)contentType -{ - NSArray *attachments = [self attachmentsWithTransaction:transaction]; - return [attachments filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TSAttachment *evaluatedObject, - NSDictionary *_Nullable bindings) { - return ![evaluatedObject.contentType isEqualToString:contentType]; - }]]; -} - -- (void)removeAttachment:(TSAttachment *)attachment transaction:(YapDatabaseReadWriteTransaction *)transaction; -{ - OWSAssertDebug([self.attachmentIds containsObject:attachment.uniqueId]); - [attachment removeWithTransaction:transaction]; - - [self.attachmentIds removeObject:attachment.uniqueId]; - - [self saveWithTransaction:transaction]; -} - -- (void)addAttachmentWithID:(NSString *)attachmentID in:(YapDatabaseReadWriteTransaction *)transaction { - if (!self.attachmentIds) { return; } - [self.attachmentIds addObject:attachmentID]; - [self saveWithTransaction:transaction]; -} - -- (NSString *)debugDescription -{ - if ([self hasAttachments] && self.body.length > 0) { - NSString *attachmentId = self.attachmentIds[0]; - return [NSString - stringWithFormat:@"Media Message with attachmentId: %@ and caption: '%@'", attachmentId, self.body]; - } else if ([self hasAttachments]) { - NSString *attachmentId = self.attachmentIds[0]; - return [NSString stringWithFormat:@"Media Message with attachmentId: %@", attachmentId]; - } else { - return [NSString stringWithFormat:@"%@ with body: %@", [self class], self.body]; - } -} - -- (nullable TSAttachment *)oversizeTextAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - return [self attachmentsWithTransaction:transaction contentType:OWSMimeTypeOversizeTextMessage].firstObject; -} - -- (NSArray *)mediaAttachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - return [self attachmentsWithTransaction:transaction exceptContentType:OWSMimeTypeOversizeTextMessage]; -} - -- (nullable NSString *)oversizeTextWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - TSAttachment *_Nullable attachment = [self oversizeTextAttachmentWithTransaction:transaction]; - if (!attachment) { - return nil; - } - - if (![attachment isKindOfClass:TSAttachmentStream.class]) { - return nil; - } - - TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; - - NSData *_Nullable data = [NSData dataWithContentsOfFile:attachmentStream.originalFilePath]; - if (!data) { - OWSFailDebug(@"Can't load oversize text data."); - return nil; - } - NSString *_Nullable text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (!text) { - OWSFailDebug(@"Can't parse oversize text data."); - return nil; - } - return text.filterStringForDisplay; -} - -- (nullable NSString *)bodyTextWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - NSString *_Nullable oversizeText = [self oversizeTextWithTransaction:transaction]; - if (oversizeText) { - return oversizeText; - } - - if (self.body.length > 0) { - return self.body.filterStringForDisplay; - } - - return nil; -} - -// TODO: This method contains view-specific logic and probably belongs in NotificationsManager, not in SSK. -- (NSString *)previewTextWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - NSString *_Nullable bodyDescription = nil; - if (self.body.length > 0) { - bodyDescription = self.body; - } - - if (bodyDescription == nil) { - TSAttachment *_Nullable oversizeTextAttachment = [self oversizeTextAttachmentWithTransaction:transaction]; - if ([oversizeTextAttachment isKindOfClass:[TSAttachmentStream class]]) { - TSAttachmentStream *oversizeTextAttachmentStream = (TSAttachmentStream *)oversizeTextAttachment; - NSData *_Nullable data = [NSData dataWithContentsOfFile:oversizeTextAttachmentStream.originalFilePath]; - if (data) { - NSString *_Nullable text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (text) { - bodyDescription = text.filterStringForDisplay; - } - } - } - } - - NSString *_Nullable attachmentDescription = nil; - TSAttachment *_Nullable mediaAttachment = [self mediaAttachmentsWithTransaction:transaction].firstObject; - if (mediaAttachment != nil) { - attachmentDescription = mediaAttachment.description; - } - - if (attachmentDescription.length > 0 && bodyDescription.length > 0) { - // Attachment with caption. - if ([CurrentAppContext() isRTL]) { - return [[bodyDescription stringByAppendingString:@": "] stringByAppendingString:attachmentDescription]; - } else { - return [[attachmentDescription stringByAppendingString:@": "] stringByAppendingString:bodyDescription]; - } - } else if (bodyDescription.length > 0) { - return bodyDescription; - } else if (attachmentDescription.length > 0) { - return attachmentDescription; - } else { - // TODO: We should do better here. - return @""; - } -} - -- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [super removeWithTransaction:transaction]; - - for (NSString *attachmentId in self.allAttachmentIds) { - // We need to fetch each attachment, since [TSAttachment removeWithTransaction:] does important work. - TSAttachment *_Nullable attachment = - [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; - if (!attachment) { - OWSFailDebug(@"couldn't load interaction's attachment for deletion."); - continue; - } - [attachment removeWithTransaction:transaction]; - }; -} - -- (BOOL)isExpiringMessage -{ - return self.expiresInSeconds > 0; -} - -- (uint64_t)timestampForLegacySorting -{ - if ([self shouldUseReceiptDateForSorting] && self.receivedAtTimestamp > 0) { - return self.receivedAtTimestamp; - } else { - OWSAssertDebug(self.timestamp > 0); - return self.timestamp; - } -} - -- (BOOL)shouldUseReceiptDateForSorting -{ - return YES; -} - -- (nullable NSString *)body -{ - return _body.filterStringForDisplay; -} - -- (void)setQuotedMessageThumbnailAttachmentStream:(TSAttachmentStream *)attachmentStream -{ - OWSAssertDebug([attachmentStream isKindOfClass:[TSAttachmentStream class]]); - OWSAssertDebug(self.quotedMessage); - OWSAssertDebug(self.quotedMessage.quotedAttachments.count == 1); - - [self.quotedMessage setThumbnailAttachmentStream:attachmentStream]; -} - -#pragma mark - Update With... Methods - -- (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(expireStartedAt > 0); - - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSMessage *message) { - [message setExpireStartedAt:expireStartedAt]; - }]; -} - -- (void)updateWithLinkPreview:(OWSLinkPreview *)linkPreview transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(linkPreview); - OWSAssertDebug(transaction); - - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSMessage *message) { - [message setLinkPreview:linkPreview]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.h b/SignalUtilitiesKit/Messaging/OWSMessageUtils.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.h rename to SignalUtilitiesKit/Messaging/OWSMessageUtils.h diff --git a/SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.m b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m similarity index 100% rename from SignalUtilitiesKit/Messaging/Utilities/OWSMessageUtils.m rename to SignalUtilitiesKit/Messaging/OWSMessageUtils.m diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/Destination+Conversion.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/Destination+Conversion.swift deleted file mode 100644 index 8e7358635..000000000 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/Destination+Conversion.swift +++ /dev/null @@ -1,18 +0,0 @@ - -public extension Message.Destination { - - static func from(_ thread: TSThread) -> Message.Destination { - if let thread = thread as? TSContactThread { - return .contact(publicKey: thread.contactIdentifier()) - } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys { - let groupID = thread.groupModel.groupId - let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) - return .closedGroup(groupPublicKey: groupPublicKey) - } else if let thread = thread as? TSGroupThread, thread.isOpenGroup { - let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!)! - return .openGroup(channel: openGroup.channel, server: openGroup.server) - } else { - preconditionFailure("TODO: Handle legacy closed groups.") - } - } -} diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift similarity index 87% rename from SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift rename to SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index bf9d2b33a..21ed34b6f 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -1,42 +1,44 @@ +import SessionProtocolKit import PromiseKit -@objc(SNMessageSenderDelegate) -public final class MessageSenderDelegate : NSObject, SessionMessagingKit.MessageSenderDelegate, SharedSenderKeysDelegate { +extension MessageSender : SharedSenderKeysDelegate { - // MARK: Error - public enum Error : LocalizedError { - case noThread - case noPrivateKey - case invalidUpdate - - public var errorDescription: String? { - switch self { - case .noThread: return "Couldn't find a thread associated with the given group public key." - case .noPrivateKey: return "Couldn't find a private key associated with the given group public key." - case .invalidUpdate: return "Invalid group update." + @objc(send:withAttachments:inThread:usingTransaction:) + static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + if let message = message as? VisibleMessage { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { + #if DEBUG + preconditionFailure() + #endif + return } + var streams: [TSAttachmentStream] = [] + attachments.forEach { + let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, + caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) + streams.append(stream) + stream.write($0.dataSource) + stream.save(with: transaction) + } + message.attachmentIDs = streams.map { $0.uniqueId! } } - } - - // MARK: Initialization - public static let shared = MessageSenderDelegate() - - private override init() { } - - // MARK: Sending - public func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } - tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 - tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 - tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) + message.threadID = thread.uniqueId! + let destination = Message.Destination.from(thread) + let job = MessageSendJob(message: message, destination: destination) + JobQueue.shared.add(job, using: transaction) } - public func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } - tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction) + @objc(sendNonDurably:inThread:usingTransaction:) + static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) } - - // MARK: Closed Groups + + static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + message.threadID = thread.uniqueId! + let destination = Message.Destination.from(thread) + return MessageSender.send(message, to: destination, using: transaction) + } + public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { // Prepare var members = members @@ -110,7 +112,7 @@ public final class MessageSenderDelegate : NSObject, SessionMessagingKit.Message if wasAnyUserRemoved { if isUserLeaving && removedMembers.count != 1 { SNLog("Can't remove self and others simultaneously.") - return Promise(error: Error.invalidUpdate) + return Promise(error: Error.invalidClosedGroupUpdate) } // Send the update to the existing members using established channels (don't include new ratchets as everyone should regenerate new ratchets individually) let promises: [Promise] = oldMembers.map { member in @@ -229,7 +231,7 @@ public final class MessageSenderDelegate : NSObject, SessionMessagingKit.Message return update(groupPublicKey, with: newMembers, name: group.groupName!, transaction: transaction) } - public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { + public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { // FIXME: This should be static SNLog("Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") let transaction = transaction as! YapDatabaseReadWriteTransaction let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift deleted file mode 100644 index b473294fe..000000000 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Utilities.swift +++ /dev/null @@ -1,40 +0,0 @@ -import PromiseKit - -public extension MessageSender { - - @objc(send:withAttachments:inThread:usingTransaction:) - static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { - if let message = message as? VisibleMessage { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { - #if DEBUG - preconditionFailure() - #endif - return - } - var streams: [TSAttachmentStream] = [] - attachments.forEach { - let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, - caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) - streams.append(stream) - stream.write($0.dataSource) - stream.save(with: transaction) - } - message.attachmentIDs = streams.map { $0.uniqueId! } - } - message.threadID = thread.uniqueId! - let destination = Message.Destination.from(thread) - let job = MessageSendJob(message: message, destination: destination) - SessionMessagingKit.JobQueue.shared.add(job, using: transaction) - } - - @objc(sendNonDurably:inThread:usingTransaction:) - static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { - return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) - } - - static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { - message.threadID = thread.uniqueId! - let destination = Message.Destination.from(thread) - return MessageSender.send(message, to: destination, using: transaction) - } -} diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift deleted file mode 100644 index e13fae704..000000000 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/OpenGroupAPIDelegate.swift +++ /dev/null @@ -1,38 +0,0 @@ - -public final class OpenGroupAPIDelegate : SessionMessagingKit.OpenGroupAPIDelegate { - - public static let shared = OpenGroupAPIDelegate() - - public func updateProfileIfNeeded(for channel: UInt64, on server: String, from info: OpenGroupInfo) { - let openGroupID = "\(server).\(channel)" - Storage.write { transaction in - // Update user count - Storage.shared.setUserCount(to: info.memberCount, forOpenGroupWithID: openGroupID, using: transaction) - let thread = TSGroupThread.getOrCreateThread(withGroupId: openGroupID.data(using: .utf8)!, groupType: .openGroup, transaction: transaction) - // Update display name if needed - let model = thread.groupModel - if model.groupName != info.displayName { - let newGroupModel = TSGroupModel(title: info.displayName, memberIds: model.groupMemberIds, image: model.groupImage, groupId: model.groupId, groupType: model.groupType, adminIds: model.groupAdminIds) - thread.groupModel = newGroupModel - thread.save(with: transaction) - } - // Download and update profile picture if needed - let oldProfilePictureURL = Storage.shared.getProfilePictureURL(forOpenGroupWithID: openGroupID) - if oldProfilePictureURL != info.profilePictureURL || model.groupImage == nil { - Storage.shared.setProfilePictureURL(to: info.profilePictureURL, forOpenGroupWithID: openGroupID, using: transaction) - if let profilePictureURL = info.profilePictureURL { - var sanitizedServerURL = server - while sanitizedServerURL.hasSuffix("/") { sanitizedServerURL.removeLast() } - var sanitizedProfilePictureURL = profilePictureURL - while sanitizedProfilePictureURL.hasPrefix("/") { sanitizedProfilePictureURL.removeFirst() } - let url = "\(sanitizedServerURL)/\(sanitizedProfilePictureURL)" - FileServerAPI.downloadAttachment(from: url).map2 { data in - let attachmentStream = TSAttachmentStream(contentType: OWSMimeTypeImageJpeg, byteCount: UInt32(data.count), sourceFilename: nil, caption: nil, albumMessageId: nil) - try attachmentStream.write(data) - thread.updateAvatar(with: attachmentStream) - } - } - } - } - } -} diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.h b/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.h similarity index 100% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.h rename to SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.h diff --git a/SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.m b/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.m similarity index 100% rename from SignalUtilitiesKit/Messaging/Attachments/TSAttachmentPointer+Backups.m rename to SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.m diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.h b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.h similarity index 90% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.h rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.h index e16dea665..3357153ca 100644 --- a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.h +++ b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.m b/SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.m similarity index 100% rename from SignalUtilitiesKit/Messaging/Core Messages/TSInvalidIdentityKeySendingErrorMessage.m rename to SignalUtilitiesKit/Messaging/TSInvalidIdentityKeySendingErrorMessage.m diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 2a123cb5f..4594d9af8 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -8,47 +8,32 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; @import SessionSnodeKit; @import SessionUtilitiesKit; -#import #import #import #import #import #import -#import -#import -#import #import #import -#import #import #import -#import #import #import #import -#import #import -#import -#import -#import -#import #import #import #import #import -#import #import #import #import #import -#import #import #import #import #import #import -#import -#import #import #import #import @@ -58,7 +43,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import @@ -66,29 +50,14 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import -#import #import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import +#import #import -#import -#import #import #import #import #import #import -#import -#import diff --git a/SignalUtilitiesKit/OWSFailedAttachmentDownloadsJob.m b/SignalUtilitiesKit/OWSFailedAttachmentDownloadsJob.m index c8483d415..e653a69c1 100644 --- a/SignalUtilitiesKit/OWSFailedAttachmentDownloadsJob.m +++ b/SignalUtilitiesKit/OWSFailedAttachmentDownloadsJob.m @@ -25,11 +25,6 @@ static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"i @implementation OWSFailedAttachmentDownloadsJob -- (OWSAttachmentDownloads *)attachmentDownloads -{ - return SSKEnvironment.shared.attachmentDownloads; -} - - (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage { self = [super init]; diff --git a/SignalUtilitiesKit/OWSPreferences.m b/SignalUtilitiesKit/OWSPreferences.m index c1bf374ec..1b3fb3b5f 100644 --- a/SignalUtilitiesKit/OWSPreferences.m +++ b/SignalUtilitiesKit/OWSPreferences.m @@ -4,13 +4,13 @@ #import "OWSPreferences.h" #import -#import -#import +#import +#import #import -#import +#import #import -#import -#import +#import +#import #import #import "SSKAsserts.h" diff --git a/SignalUtilitiesKit/OWSRecordTranscriptJob.m b/SignalUtilitiesKit/OWSRecordTranscriptJob.m index 165734e75..e98fe2cd8 100644 --- a/SignalUtilitiesKit/OWSRecordTranscriptJob.m +++ b/SignalUtilitiesKit/OWSRecordTranscriptJob.m @@ -37,11 +37,6 @@ NS_ASSUME_NONNULL_BEGIN return SSKEnvironment.shared.readReceiptManager; } -+ (OWSAttachmentDownloads *)attachmentDownloads -{ - return SSKEnvironment.shared.attachmentDownloads; -} - #pragma mark - + (void)processIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)transcript diff --git a/SignalUtilitiesKit/OWSSounds.m b/SignalUtilitiesKit/OWSSounds.m index edff6751d..59d5cca10 100644 --- a/SignalUtilitiesKit/OWSSounds.m +++ b/SignalUtilitiesKit/OWSSounds.m @@ -7,9 +7,9 @@ #import "OWSAudioPlayer.h" #import #import -#import -#import -#import +#import +#import +#import #import #import "SSKAsserts.h" diff --git a/SignalUtilitiesKit/OWSUDManager.swift b/SignalUtilitiesKit/OWSUDManager.swift index 3e46d010f..f9a5106b9 100644 --- a/SignalUtilitiesKit/OWSUDManager.swift +++ b/SignalUtilitiesKit/OWSUDManager.swift @@ -21,14 +21,6 @@ public enum OWSUDCertificateExpirationPolicy: Int { case permissive } -@objc -public enum UnidentifiedAccessMode: Int { - case unknown - case enabled - case disabled - case unrestricted -} - private func string(forUnidentifiedAccessMode mode: UnidentifiedAccessMode) -> String { switch mode { case .unknown: @@ -42,69 +34,6 @@ private func string(forUnidentifiedAccessMode mode: UnidentifiedAccessMode) -> S } } -@objc -public class OWSUDAccess: NSObject { - @objc - public let udAccessKey: SMKUDAccessKey - - @objc - public let udAccessMode: UnidentifiedAccessMode - - @objc - public let isRandomKey: Bool - - @objc - public required init(udAccessKey: SMKUDAccessKey, - udAccessMode: UnidentifiedAccessMode, - isRandomKey: Bool) { - self.udAccessKey = udAccessKey - self.udAccessMode = udAccessMode - self.isRandomKey = isRandomKey - } -} - -@objc public protocol OWSUDManager: class { - - @objc func setup() - - @objc func trustRoot() -> ECPublicKey - - @objc func isUDVerboseLoggingEnabled() -> Bool - - // MARK: - Recipient State - - @objc - func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String) - - @objc - func unidentifiedAccessMode(forRecipientId recipientId: String) -> UnidentifiedAccessMode - - @objc - func udAccessKey(forRecipientId recipientId: String) -> SMKUDAccessKey? - - @objc - func udAccess(forRecipientId recipientId: String, - requireSyncAccess: Bool) -> OWSUDAccess? - - // MARK: Sender Certificate - - // We use completion handlers instead of a promise so that message sending - // logic can access the strongly typed certificate data. - @objc - func ensureSenderCertificate(success:@escaping (SMKSenderCertificate) -> Void, - failure:@escaping (Error) -> Void) - - // MARK: Unrestricted Access - - @objc - func shouldAllowUnrestrictedAccessLocal() -> Bool - @objc - func setShouldAllowUnrestrictedAccessLocal(_ value: Bool) - - @objc - func getSenderCertificate() -> SMKSenderCertificate? -} - // MARK: - @objc diff --git a/SignalUtilitiesKit/ReachabilityManager.swift b/SignalUtilitiesKit/ReachabilityManager.swift index bea630d5c..90e7d2e34 100644 --- a/SignalUtilitiesKit/ReachabilityManager.swift +++ b/SignalUtilitiesKit/ReachabilityManager.swift @@ -5,20 +5,6 @@ import Foundation import Reachability -@objc(SSKReachabilityType) -public enum ReachabilityType: Int { - case any, wifi, cellular -} - -@objc -public protocol SSKReachabilityManager { - var observationContext: AnyObject { get } - func setup() - - var isReachable: Bool { get } - func isReachable(via reachabilityType: ReachabilityType) -> Bool -} - @objc public class SSKReachabilityManagerImpl: NSObject, SSKReachabilityManager { diff --git a/SignalUtilitiesKit/SSKMessageSenderJobRecord.h b/SignalUtilitiesKit/SSKMessageSenderJobRecord.h index 2f0f9c983..75d831ce3 100644 --- a/SignalUtilitiesKit/SSKMessageSenderJobRecord.h +++ b/SignalUtilitiesKit/SSKMessageSenderJobRecord.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/TSPreKeyManager.h b/SignalUtilitiesKit/TSPreKeyManager.h index f6e76f45a..76c0cdaed 100644 --- a/SignalUtilitiesKit/TSPreKeyManager.h +++ b/SignalUtilitiesKit/TSPreKeyManager.h @@ -2,7 +2,7 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/Threads/ThreadUtil.h b/SignalUtilitiesKit/ThreadUtil.h similarity index 100% rename from SignalUtilitiesKit/Threads/ThreadUtil.h rename to SignalUtilitiesKit/ThreadUtil.h diff --git a/SignalUtilitiesKit/Threads/ThreadUtil.m b/SignalUtilitiesKit/ThreadUtil.m similarity index 97% rename from SignalUtilitiesKit/Threads/ThreadUtil.m rename to SignalUtilitiesKit/ThreadUtil.m index b42ffda76..2fcd05655 100644 --- a/SignalUtilitiesKit/Threads/ThreadUtil.m +++ b/SignalUtilitiesKit/ThreadUtil.m @@ -7,16 +7,16 @@ #import "OWSUnreadIndicator.h" #import "TSUnreadIndicatorInteraction.h" #import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import #import diff --git a/SignalUtilitiesKit/To Do/ContactCellView.m b/SignalUtilitiesKit/To Do/ContactCellView.m index 38a45d2cb..e94959315 100644 --- a/SignalUtilitiesKit/To Do/ContactCellView.m +++ b/SignalUtilitiesKit/To Do/ContactCellView.m @@ -6,11 +6,11 @@ #import "UIFont+OWS.h" #import "UIView+OWS.h" #import -#import +#import #import -#import -#import -#import +#import +#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.h b/SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.h index 686cf092c..9dd7bef9d 100644 --- a/SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.h +++ b/SignalUtilitiesKit/To Do/OWSPrimaryStorage+Loki.h @@ -1,4 +1,4 @@ -#import +#import #import #import diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.h b/SignalUtilitiesKit/To Do/OWSProfileManager.h index 5741620aa..05e4dad1b 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.h +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m index 07bf55f90..292ee2f05 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -9,21 +9,21 @@ #import #import "UIUtil.h" #import -#import +#import #import #import -#import +#import #import -#import +#import #import #import -#import -#import -#import -#import +#import +#import +#import +#import #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/To Do/OWSUserProfile.m b/SignalUtilitiesKit/To Do/OWSUserProfile.m index 36113d034..8d308ae8e 100644 --- a/SignalUtilitiesKit/To Do/OWSUserProfile.m +++ b/SignalUtilitiesKit/To Do/OWSUserProfile.m @@ -7,13 +7,13 @@ #import -#import +#import #import #import -#import -#import +#import +#import #import -#import +#import #import #import diff --git a/SignalUtilitiesKit/UI/BlockListUIUtils.m b/SignalUtilitiesKit/UI/BlockListUIUtils.m index 179384411..c6c9ab310 100644 --- a/SignalUtilitiesKit/UI/BlockListUIUtils.m +++ b/SignalUtilitiesKit/UI/BlockListUIUtils.m @@ -4,10 +4,10 @@ #import "BlockListUIUtils.h" #import "TSContactThread.h" -#import +#import #import -#import -#import +#import +#import #import #import #import "UIView+OWS.h" diff --git a/SignalUtilitiesKit/UI/SelectRecipientViewController.m b/SignalUtilitiesKit/UI/SelectRecipientViewController.m index 35571e317..74b4a7c61 100644 --- a/SignalUtilitiesKit/UI/SelectRecipientViewController.m +++ b/SignalUtilitiesKit/UI/SelectRecipientViewController.m @@ -12,7 +12,7 @@ #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/UI/SelectThreadViewController.m b/SignalUtilitiesKit/UI/SelectThreadViewController.m index c697301cf..415b0074c 100644 --- a/SignalUtilitiesKit/UI/SelectThreadViewController.m +++ b/SignalUtilitiesKit/UI/SelectThreadViewController.m @@ -14,9 +14,9 @@ #import #import #import -#import -#import -#import +#import +#import +#import #import #import diff --git a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index 50e9c85ae..2d36a09c3 100644 --- a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -10,7 +10,7 @@ #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/UI/Theme.m b/SignalUtilitiesKit/UI/Theme.m index f12849ef0..7f298eb6d 100644 --- a/SignalUtilitiesKit/UI/Theme.m +++ b/SignalUtilitiesKit/UI/Theme.m @@ -5,9 +5,9 @@ #import "Theme.h" #import "UIColor+OWS.h" #import "UIUtil.h" -#import -#import -#import +#import +#import +#import #import diff --git a/SignalUtilitiesKit/Utilities/Notification+Loki.swift b/SignalUtilitiesKit/Utilities/Notification+Loki.swift index e696caf26..5f1d9f101 100644 --- a/SignalUtilitiesKit/Utilities/Notification+Loki.swift +++ b/SignalUtilitiesKit/Utilities/Notification+Loki.swift @@ -4,7 +4,6 @@ public extension Notification.Name { // State changes static let blockedContactsUpdated = Notification.Name("blockedContactsUpdated") static let contactOnlineStatusChanged = Notification.Name("contactOnlineStatusChanged") - static let groupThreadUpdated = Notification.Name("groupThreadUpdated") static let threadDeleted = Notification.Name("threadDeleted") static let threadSessionRestoreDevicesChanged = Notification.Name("threadSessionRestoreDevicesChanged") // Onboarding @@ -18,7 +17,6 @@ public extension Notification.Name { // State changes @objc static let blockedContactsUpdated = Notification.Name.blockedContactsUpdated.rawValue as NSString @objc static let contactOnlineStatusChanged = Notification.Name.contactOnlineStatusChanged.rawValue as NSString - @objc static let groupThreadUpdated = Notification.Name.groupThreadUpdated.rawValue as NSString @objc static let threadDeleted = Notification.Name.threadDeleted.rawValue as NSString @objc static let threadSessionRestoreDevicesChanged = Notification.Name.threadSessionRestoreDevicesChanged.rawValue as NSString // Onboarding diff --git a/SignalUtilitiesKit/VersionMigrations.m b/SignalUtilitiesKit/VersionMigrations.m index 53d4fe530..d77495b2e 100644 --- a/SignalUtilitiesKit/VersionMigrations.m +++ b/SignalUtilitiesKit/VersionMigrations.m @@ -7,11 +7,11 @@ #import "SignalKeyingStorage.h" #import #import -#import +#import #import -#import -#import -#import +#import +#import +#import #import #import From 1037ce51139b4408606c9c7a27ccc00a39756965 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 25 Nov 2020 16:21:04 +1100 Subject: [PATCH 035/177] WIP --- .../ConversationView/ConversationViewItem.h | 1 - SessionMessagingKit/Database/TSDatabaseView.m | 1 - ...SInvalidIdentityKeyReceivingErrorMessage.m | 1 - .../Messages/Signal/TSMessage.m | 416 ++++++++++++++++++ .../Meta/SessionMessagingKit.h | 1 + ...sappearingConfigurationUpdateInfoMessage.m | 1 - .../OWSDisappearingMessagesConfiguration.m | 1 - SessionMessagingKit/To Do/TSAccountManager.m | 4 - .../Utilities}/SignalRecipient.h | 0 .../Utilities}/SignalRecipient.m | 46 +- SessionUtilitiesKit/NSUserDefaults+OWS.m | 1 - Signal.xcodeproj/project.pbxproj | 12 +- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 1 - 13 files changed, 425 insertions(+), 61 deletions(-) create mode 100644 SessionMessagingKit/Messages/Signal/TSMessage.m rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/SignalRecipient.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/SignalRecipient.m (83%) diff --git a/Session/Signal/ConversationView/ConversationViewItem.h b/Session/Signal/ConversationView/ConversationViewItem.h index 3464d077d..e26701080 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.h +++ b/Session/Signal/ConversationView/ConversationViewItem.h @@ -3,7 +3,6 @@ // #import "ConversationViewLayout.h" -#import "OWSAudioPlayer.h" NS_ASSUME_NONNULL_BEGIN diff --git a/SessionMessagingKit/Database/TSDatabaseView.m b/SessionMessagingKit/Database/TSDatabaseView.m index 876063959..b59d16054 100644 --- a/SessionMessagingKit/Database/TSDatabaseView.m +++ b/SessionMessagingKit/Database/TSDatabaseView.m @@ -3,7 +3,6 @@ // #import "TSDatabaseView.h" -#import "TSAttachmentPointer+Backups.h" #import "OWSReadTracking.h" #import "TSAttachment.h" #import "TSAttachmentPointer.h" diff --git a/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.m b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.m index c85c57276..1f2a562c1 100644 --- a/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -4,7 +4,6 @@ #import "TSInvalidIdentityKeyReceivingErrorMessage.h" #import "OWSIdentityManager.h" -#import "OWSPrimaryStorage+SessionStore.h" #import "OWSPrimaryStorage.h" #import "SSKEnvironment.h" #import "TSContactThread.h" diff --git a/SessionMessagingKit/Messages/Signal/TSMessage.m b/SessionMessagingKit/Messages/Signal/TSMessage.m new file mode 100644 index 000000000..2fac7a6e6 --- /dev/null +++ b/SessionMessagingKit/Messages/Signal/TSMessage.m @@ -0,0 +1,416 @@ +// +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// + +#import "TSMessage.h" +#import "AppContext.h" +#import "MIMETypeUtil.h" +#import "OWSDisappearingMessagesConfiguration.h" +#import "TSAttachment.h" +#import "TSAttachmentStream.h" +#import "TSQuotedMessage.h" +#import "TSThread.h" +#import +#import +#import +#import +#import "OWSPrimaryStorage+Loki.h" +#import "TSContactThread.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +static const NSUInteger OWSMessageSchemaVersion = 4; +const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; + +#pragma mark - + +@interface TSMessage () + +@property (nonatomic, nullable) NSString *body; +@property (nonatomic) uint32_t expiresInSeconds; +@property (nonatomic) uint64_t expireStartedAt; + +/** + * The version of the model class's schema last used to serialize this model. Use this to manage data migrations during + * object de/serialization. + * + * e.g. + * + * - (id)initWithCoder:(NSCoder *)coder + * { + * self = [super initWithCoder:coder]; + * if (!self) { return self; } + * if (_schemaVersion < 2) { + * _newName = [coder decodeObjectForKey:@"oldName"] + * } + * ... + * _schemaVersion = 2; + * } + */ +@property (nonatomic, readonly) NSUInteger schemaVersion; + +@end + +#pragma mark - + +@implementation TSMessage + +- (instancetype)initMessageWithTimestamp:(uint64_t)timestamp + inThread:(nullable TSThread *)thread + messageBody:(nullable NSString *)body + attachmentIds:(NSArray *)attachmentIds + expiresInSeconds:(uint32_t)expiresInSeconds + expireStartedAt:(uint64_t)expireStartedAt + quotedMessage:(nullable TSQuotedMessage *)quotedMessage + linkPreview:(nullable OWSLinkPreview *)linkPreview +{ + self = [super initInteractionWithTimestamp:timestamp inThread:thread]; + + if (!self) { + return self; + } + + _schemaVersion = OWSMessageSchemaVersion; + + _body = body; + _attachmentIds = attachmentIds ? [attachmentIds mutableCopy] : [NSMutableArray new]; + _expiresInSeconds = expiresInSeconds; + _expireStartedAt = expireStartedAt; + [self updateExpiresAt]; + _quotedMessage = quotedMessage; + _linkPreview = linkPreview; + _openGroupServerMessageID = -1; + + return self; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (!self) { + return self; + } + + if (_schemaVersion < 2) { + // renamed _attachments to _attachmentIds + if (!_attachmentIds) { + _attachmentIds = [coder decodeObjectForKey:@"attachments"]; + } + } + + if (_schemaVersion < 3) { + _expiresInSeconds = 0; + _expireStartedAt = 0; + _expiresAt = 0; + } + + if (_schemaVersion < 4) { + // Wipe out the body field on these legacy attachment messages. + // + // Explantion: Historically, a message sent from iOS could be an attachment XOR a text message, + // but now we support sending an attachment+caption as a single message. + // + // Other clients have supported sending attachment+caption in a single message for a long time. + // So the way we used to handle receiving them was to make it look like they'd sent two messages: + // first the attachment+caption (we'd ignore this caption when rendering), followed by a separate + // message with just the caption (which we'd render as a simple independent text message), for + // which we'd offset the timestamp by a little bit to get the desired ordering. + // + // Now that we can properly render an attachment+caption message together, these legacy "dummy" text + // messages are not only unnecessary, but worse, would be rendered redundantly. For safety, rather + // than building the logic to try to find and delete the redundant "dummy" text messages which users + // have been seeing and interacting with, we delete the body field from the attachment message, + // which iOS users have never seen directly. + if (_attachmentIds.count > 0) { + _body = nil; + } + } + + if (!_attachmentIds) { + _attachmentIds = [NSMutableArray new]; + } + + _schemaVersion = OWSMessageSchemaVersion; + + return self; +} + +- (void)setExpiresInSeconds:(uint32_t)expiresInSeconds +{ + uint32_t maxExpirationDuration = [OWSDisappearingMessagesConfiguration maxDurationSeconds]; + + _expiresInSeconds = MIN(expiresInSeconds, maxExpirationDuration); + [self updateExpiresAt]; +} + +- (void)setExpireStartedAt:(uint64_t)expireStartedAt +{ + if (_expireStartedAt != 0 && _expireStartedAt < expireStartedAt) { + return; + } + + uint64_t now = [NSDate ows_millisecondTimeStamp]; + + _expireStartedAt = MIN(now, expireStartedAt); + [self updateExpiresAt]; +} + +- (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + return self.isExpiringMessage; +} + +// TODO a downloaded media doesn't start counting until download is complete. +- (void)updateExpiresAt +{ + if (_expiresInSeconds > 0 && _expireStartedAt > 0) { + _expiresAt = _expireStartedAt + _expiresInSeconds * 1000; + } else { + _expiresAt = 0; + } +} + +- (BOOL)hasAttachments +{ + return self.attachmentIds ? (self.attachmentIds.count > 0) : NO; +} + +- (NSArray *)allAttachmentIds +{ + NSMutableArray *result = [NSMutableArray new]; + if (self.attachmentIds.count > 0) { + [result addObjectsFromArray:self.attachmentIds]; + } + + if (self.quotedMessage) { + [result addObjectsFromArray:self.quotedMessage.thumbnailAttachmentStreamIds]; + } + + if (self.linkPreview.imageAttachmentId) { + [result addObject:self.linkPreview.imageAttachmentId]; + } + + return [result copy]; +} + +- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + NSMutableArray *attachments = [NSMutableArray new]; + for (NSString *attachmentId in self.attachmentIds) { + TSAttachment *_Nullable attachment = + [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; + if (attachment) { + [attachments addObject:attachment]; + } + } + return [attachments copy]; +} + +- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction + contentType:(NSString *)contentType +{ + NSArray *attachments = [self attachmentsWithTransaction:transaction]; + return [attachments filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TSAttachment *evaluatedObject, + NSDictionary *_Nullable bindings) { + return [evaluatedObject.contentType isEqualToString:contentType]; + }]]; +} + +- (NSArray *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction + exceptContentType:(NSString *)contentType +{ + NSArray *attachments = [self attachmentsWithTransaction:transaction]; + return [attachments filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TSAttachment *evaluatedObject, + NSDictionary *_Nullable bindings) { + return ![evaluatedObject.contentType isEqualToString:contentType]; + }]]; +} + +- (void)removeAttachment:(TSAttachment *)attachment transaction:(YapDatabaseReadWriteTransaction *)transaction; +{ + [attachment removeWithTransaction:transaction]; + + [self.attachmentIds removeObject:attachment.uniqueId]; + + [self saveWithTransaction:transaction]; +} + +- (void)addAttachmentWithID:(NSString *)attachmentID in:(YapDatabaseReadWriteTransaction *)transaction { + if (!self.attachmentIds) { return; } + [self.attachmentIds addObject:attachmentID]; + [self saveWithTransaction:transaction]; +} + +- (NSString *)debugDescription +{ + if ([self hasAttachments] && self.body.length > 0) { + NSString *attachmentId = self.attachmentIds[0]; + return [NSString + stringWithFormat:@"Media Message with attachmentId: %@ and caption: '%@'", attachmentId, self.body]; + } else if ([self hasAttachments]) { + NSString *attachmentId = self.attachmentIds[0]; + return [NSString stringWithFormat:@"Media Message with attachmentId: %@", attachmentId]; + } else { + return [NSString stringWithFormat:@"%@ with body: %@", [self class], self.body]; + } +} + +- (nullable TSAttachment *)oversizeTextAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + return [self attachmentsWithTransaction:transaction contentType:OWSMimeTypeOversizeTextMessage].firstObject; +} + +- (NSArray *)mediaAttachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + return [self attachmentsWithTransaction:transaction exceptContentType:OWSMimeTypeOversizeTextMessage]; +} + +- (nullable NSString *)oversizeTextWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + TSAttachment *_Nullable attachment = [self oversizeTextAttachmentWithTransaction:transaction]; + if (!attachment) { + return nil; + } + + if (![attachment isKindOfClass:TSAttachmentStream.class]) { + return nil; + } + + TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; + + NSData *_Nullable data = [NSData dataWithContentsOfFile:attachmentStream.originalFilePath]; + if (!data) { + return nil; + } + NSString *_Nullable text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (!text) { + return nil; + } + return text.filterStringForDisplay; +} + +- (nullable NSString *)bodyTextWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + NSString *_Nullable oversizeText = [self oversizeTextWithTransaction:transaction]; + if (oversizeText) { + return oversizeText; + } + + if (self.body.length > 0) { + return self.body.filterStringForDisplay; + } + + return nil; +} + +// TODO: This method contains view-specific logic and probably belongs in NotificationsManager, not in SSK. +- (NSString *)previewTextWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + NSString *_Nullable bodyDescription = nil; + if (self.body.length > 0) { + bodyDescription = self.body; + } + + if (bodyDescription == nil) { + TSAttachment *_Nullable oversizeTextAttachment = [self oversizeTextAttachmentWithTransaction:transaction]; + if ([oversizeTextAttachment isKindOfClass:[TSAttachmentStream class]]) { + TSAttachmentStream *oversizeTextAttachmentStream = (TSAttachmentStream *)oversizeTextAttachment; + NSData *_Nullable data = [NSData dataWithContentsOfFile:oversizeTextAttachmentStream.originalFilePath]; + if (data) { + NSString *_Nullable text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (text) { + bodyDescription = text.filterStringForDisplay; + } + } + } + } + + NSString *_Nullable attachmentDescription = nil; + TSAttachment *_Nullable mediaAttachment = [self mediaAttachmentsWithTransaction:transaction].firstObject; + if (mediaAttachment != nil) { + attachmentDescription = mediaAttachment.description; + } + + if (attachmentDescription.length > 0 && bodyDescription.length > 0) { + // Attachment with caption. + if ([CurrentAppContext() isRTL]) { + return [[bodyDescription stringByAppendingString:@": "] stringByAppendingString:attachmentDescription]; + } else { + return [[attachmentDescription stringByAppendingString:@": "] stringByAppendingString:bodyDescription]; + } + } else if (bodyDescription.length > 0) { + return bodyDescription; + } else if (attachmentDescription.length > 0) { + return attachmentDescription; + } else { + // TODO: We should do better here. + return @""; + } +} + +- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + [super removeWithTransaction:transaction]; + + for (NSString *attachmentId in self.allAttachmentIds) { + // We need to fetch each attachment, since [TSAttachment removeWithTransaction:] does important work. + TSAttachment *_Nullable attachment = + [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; + if (!attachment) { + continue; + } + [attachment removeWithTransaction:transaction]; + }; +} + +- (BOOL)isExpiringMessage +{ + return self.expiresInSeconds > 0; +} + +- (uint64_t)timestampForLegacySorting +{ + if ([self shouldUseReceiptDateForSorting] && self.receivedAtTimestamp > 0) { + return self.receivedAtTimestamp; + } else { + return self.timestamp; + } +} + +- (BOOL)shouldUseReceiptDateForSorting +{ + return YES; +} + +- (nullable NSString *)body +{ + return _body.filterStringForDisplay; +} + +- (void)setQuotedMessageThumbnailAttachmentStream:(TSAttachmentStream *)attachmentStream +{ + [self.quotedMessage setThumbnailAttachmentStream:attachmentStream]; +} + +#pragma mark - Update With... Methods + +- (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + [self applyChangeToSelfAndLatestCopy:transaction + changeBlock:^(TSMessage *message) { + [message setExpireStartedAt:expireStartedAt]; + }]; +} + +- (void)updateWithLinkPreview:(OWSLinkPreview *)linkPreview transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + [self applyChangeToSelfAndLatestCopy:transaction + changeBlock:^(TSMessage *message) { + [message setLinkPreview:linkPreview]; + }]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index 07bef159a..b02e7609e 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -23,6 +23,7 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; #import #import #import +#import #import #import #import diff --git a/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.m b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.m index 3b1c7250b..82c3071ae 100644 --- a/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.m +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingConfigurationUpdateInfoMessage.m @@ -3,7 +3,6 @@ // #import "OWSDisappearingConfigurationUpdateInfoMessage.h" -#import "NSString+SSK.h" #import "OWSDisappearingMessagesConfiguration.h" #import diff --git a/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.m b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.m index 88e0ee576..9e93fbbff 100644 --- a/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.m +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesConfiguration.m @@ -3,7 +3,6 @@ // #import "OWSDisappearingMessagesConfiguration.h" -#import "NSString+SSK.h" #import #import diff --git a/SessionMessagingKit/To Do/TSAccountManager.m b/SessionMessagingKit/To Do/TSAccountManager.m index e30b00917..dc41c5c48 100644 --- a/SessionMessagingKit/To Do/TSAccountManager.m +++ b/SessionMessagingKit/To Do/TSAccountManager.m @@ -6,12 +6,8 @@ #import "AppContext.h" #import "AppReadiness.h" #import "NSNotificationCenter+OWS.h" -#import "NSURLSessionDataTask+StatusCode.h" -#import "OWSError.h" -#import "OWSPrimaryStorage+SessionStore.h" #import "ProfileManagerProtocol.h" #import "SSKEnvironment.h" -#import "TSPreKeyManager.h" #import "YapDatabaseConnection+OWS.h" #import "YapDatabaseTransaction+OWS.h" #import diff --git a/SignalUtilitiesKit/SignalRecipient.h b/SessionMessagingKit/Utilities/SignalRecipient.h similarity index 100% rename from SignalUtilitiesKit/SignalRecipient.h rename to SessionMessagingKit/Utilities/SignalRecipient.h diff --git a/SignalUtilitiesKit/SignalRecipient.m b/SessionMessagingKit/Utilities/SignalRecipient.m similarity index 83% rename from SignalUtilitiesKit/SignalRecipient.m rename to SessionMessagingKit/Utilities/SignalRecipient.m index 60932e04b..796105514 100644 --- a/SignalUtilitiesKit/SignalRecipient.m +++ b/SessionMessagingKit/Utilities/SignalRecipient.m @@ -3,11 +3,9 @@ // #import "SignalRecipient.h" - #import "ProfileManagerProtocol.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" - #import NS_ASSUME_NONNULL_BEGIN @@ -36,8 +34,6 @@ NS_ASSUME_NONNULL_BEGIN - (TSAccountManager *)tsAccountManager { - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - return SSKEnvironment.shared.tsAccountManager; } @@ -46,9 +42,6 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)getOrBuildUnsavedRecipientForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(recipientId.length > 0); - SignalRecipient *_Nullable recipient = [self registeredRecipientForRecipientId:recipientId mustHaveDevices:NO transaction:transaction]; if (!recipient) { @@ -84,7 +77,6 @@ NS_ASSUME_NONNULL_BEGIN // ensure the local user always has at least *this* device. if (![_devices containsObject:@(1)]) { if ([self.uniqueId isEqualToString:self.tsAccountManager.localNumber]) { - DDLogInfo(@"Adding primary device to self recipient."); [self addDevices:[NSSet setWithObject:@(1)]]; } } @@ -96,9 +88,6 @@ NS_ASSUME_NONNULL_BEGIN mustHaveDevices:(BOOL)mustHaveDevices transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(recipientId.length > 0); - SignalRecipient *_Nullable signalRecipient = [self fetchObjectWithUniqueID:recipientId transaction:transaction]; if (mustHaveDevices && signalRecipient.devices.count < 1) { return nil; @@ -108,8 +97,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)addDevices:(NSSet *)devices { - OWSAssertDebug(devices.count > 0); - NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy]; [updatedDevices unionSet:devices]; self.devices = [updatedDevices copy]; @@ -117,8 +104,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)removeDevices:(NSSet *)devices { - OWSAssertDebug(devices.count > 0); - NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy]; [updatedDevices minusSet:devices]; self.devices = [updatedDevices copy]; @@ -127,9 +112,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateRegisteredRecipientWithDevicesToAdd:(nullable NSArray *)devicesToAdd devicesToRemove:(nullable NSArray *)devicesToRemove transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(devicesToAdd.count > 0 || devicesToRemove.count > 0); - // Add before we remove, since removeDevicesFromRecipient:... // can markRecipientAsUnregistered:... if the recipient has // no devices left. @@ -143,10 +125,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)addDevicesToRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(devices.count > 0); - OWSLogDebug(@"adding devices: %@, to recipient: %@", devices, self); - [self reloadWithTransaction:transaction]; [self addDevices:devices]; [self saveWithTransaction_internal:transaction]; @@ -154,10 +132,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)removeDevicesFromRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(devices.count > 0); - - OWSLogDebug(@"removing devices: %@, from registered recipient: %@", devices, self); [self reloadWithTransaction:transaction ignoreMissing:YES]; [self removeDevices:devices]; [self saveWithTransaction_internal:transaction]; @@ -181,8 +155,7 @@ NS_ASSUME_NONNULL_BEGIN // correspond to an instance of SignalRecipient in the database (although // they may correspond to an "unsaved" instance of SignalRecipient built // by getOrBuildUnsavedRecipientForRecipientId. - OWSFailDebug(@"Don't call removeWithTransaction."); - + [super removeWithTransaction:transaction]; } @@ -194,16 +167,13 @@ NS_ASSUME_NONNULL_BEGIN // be strict about using persisted SignalRecipients as a cache to // reflect "last known registration status". Forcing our codebase to // use those methods helps ensure that we update the cache deliberately. - OWSFailDebug(@"Don't call saveWithTransaction from outside this class."); - + [self saveWithTransaction_internal:transaction]; } - (void)saveWithTransaction_internal:(YapDatabaseReadWriteTransaction *)transaction { [super saveWithTransaction:transaction]; - - OWSLogVerbose(@"saved signal recipient: %@ (%lu)", self.recipientId, (unsigned long) self.devices.count); } + (BOOL)isRegisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction @@ -214,14 +184,10 @@ NS_ASSUME_NONNULL_BEGIN + (SignalRecipient *)markRecipientAsRegisteredAndGet:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(recipientId.length > 0); - SignalRecipient *_Nullable instance = [self registeredRecipientForRecipientId:recipientId mustHaveDevices:YES transaction:transaction]; if (!instance) { - OWSLogDebug(@"creating recipient: %@", recipientId); instance = [[self alloc] initWithTextSecureIdentifier:recipientId]; [instance saveWithTransaction_internal:transaction]; @@ -233,12 +199,8 @@ NS_ASSUME_NONNULL_BEGIN deviceId:(UInt32)deviceId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(recipientId.length > 0); - SignalRecipient *recipient = [self markRecipientAsRegisteredAndGet:recipientId transaction:transaction]; if (![recipient.devices containsObject:@(deviceId)]) { - OWSLogDebug(@"Adding device %u to existing recipient.", (unsigned int)deviceId); [recipient addDevices:[NSSet setWithObject:@(deviceId)]]; [recipient saveWithTransaction_internal:transaction]; @@ -247,12 +209,8 @@ NS_ASSUME_NONNULL_BEGIN + (void)markRecipientAsUnregistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - OWSAssertDebug(recipientId.length > 0); - SignalRecipient *instance = [self getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction]; - OWSLogDebug(@"Marking recipient as not registered: %@", recipientId); if (instance.devices.count > 0) { [instance removeDevices:instance.devices.set]; } diff --git a/SessionUtilitiesKit/NSUserDefaults+OWS.m b/SessionUtilitiesKit/NSUserDefaults+OWS.m index 1bf02767e..a500f28b7 100644 --- a/SessionUtilitiesKit/NSUserDefaults+OWS.m +++ b/SessionUtilitiesKit/NSUserDefaults+OWS.m @@ -4,7 +4,6 @@ #import "NSUserDefaults+OWS.h" #import "AppContext.h" -#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 0f4163221..4d2f02407 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -456,7 +456,6 @@ C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA3255A582000E217F9 /* SSKMessageSenderJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */; }; C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEC255A580500E217F9 /* SignalRecipient.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */; }; C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */; }; @@ -501,7 +500,6 @@ C33FDD67255A582000E217F9 /* OWSRecordTranscriptJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAD255A581500E217F9 /* OWSRecordTranscriptJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD68255A582000E217F9 /* SignalAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAE255A581500E217F9 /* SignalAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */; }; - C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB7255A581600E217F9 /* SignalRecipient.m */; }; C33FDD74255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBBA255A581600E217F9 /* OWSPrimaryStorage+keyFromIntLong.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD79255A582000E217F9 /* OWSHTTPSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBF255A581700E217F9 /* OWSHTTPSecurityPolicy.m */; }; @@ -737,6 +735,8 @@ C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */; }; C3A3A15F256E1BB4004D228D /* ProtoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB91255A581200E217F9 /* ProtoUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3A3A171256E1D25004D228D /* SSKReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */; }; + C3A3A18A256E2092004D228D /* SignalRecipient.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB7255A581600E217F9 /* SignalRecipient.m */; }; + C3A3A193256E20D4004D228D /* SignalRecipient.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEC255A580500E217F9 /* SignalRecipient.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D0A2558989C0043A11F /* MessageWrapper.swift */; }; C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1C25589AC30043A11F /* WebSocketProto.swift */; }; C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */; }; @@ -3016,8 +3016,6 @@ C33FDC06255A581D00E217F9 /* SignalAccount.m */, C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */, C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */, - C33FDAEC255A580500E217F9 /* SignalRecipient.h */, - C33FDBB7255A581600E217F9 /* SignalRecipient.m */, C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */, C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */, C33FDC12255A581E00E217F9 /* TSConstants.h */, @@ -3345,6 +3343,8 @@ C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */, C33FDB91255A581200E217F9 /* ProtoUtils.h */, C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, + C33FDAEC255A580500E217F9 /* SignalRecipient.h */, + C33FDBB7255A581600E217F9 /* SignalRecipient.m */, C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, @@ -3944,7 +3944,6 @@ C33FDC95255A582000E217F9 /* OWSFailedMessagesJob.h in Headers */, C38EF3F1255B6DF7007E1867 /* OWSSearchBar.h in Headers */, C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */, - C33FDCA6255A582000E217F9 /* SignalRecipient.h in Headers */, C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */, C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */, C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */, @@ -4058,6 +4057,7 @@ C32C5B6B256DC357003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */, C32C5F23256DFCC0003C73A2 /* TSErrorMessage_privateConstructor.h in Headers */, C32C5BBA256DC7E3003C73A2 /* ProfileManagerProtocol.h in Headers */, + C3A3A193256E20D4004D228D /* SignalRecipient.h in Headers */, C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */, C32C5CAD256DD1DF003C73A2 /* TSAccountManager.h in Headers */, C3A3A0F5256E194C004D228D /* OWSRecipientIdentity.h in Headers */, @@ -4985,7 +4985,6 @@ C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */, C38EF316255B6DBF007E1867 /* ProximityMonitoringManager.swift in Sources */, C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */, - C33FDD71255A582000E217F9 /* SignalRecipient.m in Sources */, C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */, C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */, @@ -5253,6 +5252,7 @@ C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */, C32C5C93256DD12D003C73A2 /* OWSUDManager.swift in Sources */, C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */, + C3A3A18A256E2092004D228D /* SignalRecipient.m in Sources */, C3C2A74425539EB700C340D1 /* Message.swift in Sources */, C32C5F11256DF79A003C73A2 /* SSKIncrementingIdFinder.swift in Sources */, C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */, diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 4594d9af8..7516c76f9 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -48,7 +48,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import From ac6baec6f24a5bbcfd9aceb2478cf4b70b095625 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 10:37:56 +1100 Subject: [PATCH 036/177] Make things compile again --- Podfile | 2 + Podfile.lock | 2 +- Session/Configuration.swift | 9 +- Session/Meta/Signal-Bridging-Header.h | 26 +-- Session/Meta/Signal-Prefix.pch | 2 +- Session/Signal/AboutTableViewController.m | 4 +- Session/Signal/AppDelegate.m | 7 +- Session/Signal/AvatarViewHelper.m | 2 +- .../Cells/AttachmentUploadView.m | 2 +- .../Cells/ConversationMediaView.swift | 8 +- .../Cells/MediaDownloadView.swift | 19 +- .../Cells/OWSBubbleShapeView.m | 2 +- .../ConversationView/Cells/OWSBubbleView.m | 2 +- .../Cells/OWSGenericAttachmentView.m | 2 +- .../Cells/OWSMessageBubbleView.m | 13 +- .../Cells/OWSMessageHeaderView.m | 2 +- .../Cells/OWSMessageTextView.m | 2 +- .../Cells/OWSQuotedMessageView.m | 4 +- .../Cells/OWSSystemMessageCell.m | 8 +- .../ConversationInputTextView.m | 2 +- .../ConversationInputToolbar.m | 4 +- .../ConversationViewController.m | 73 ++++--- .../ConversationView/ConversationViewItem.h | 1 + .../ConversationView/ConversationViewItem.m | 13 +- .../ConversationView/ConversationViewModel.m | 2 +- Session/Signal/DateUtil.m | 2 +- Session/Signal/MainAppContext.m | 2 +- ...otificationSettingsOptionsViewController.m | 2 +- .../NotificationSettingsViewController.m | 6 +- Session/Signal/OWSBackupExportJob.m | 2 +- Session/Signal/OWSBackupImportJob.m | 2 +- Session/Signal/OWSBackupJob.h | 2 +- .../Signal/OWSBackupSettingsViewController.m | 4 +- .../OWSConversationSettingsViewController.m | 8 +- Session/Signal/OWSOrphanDataCleaner.m | 6 +- Session/Signal/OWSProgressView.m | 4 +- Session/Signal/OWSScreenLockUI.m | 2 +- .../Signal/OWSSoundSettingsViewController.m | 4 +- .../PrivacySettingsTableViewController.m | 6 +- Session/Signal/SignalApp.m | 2 +- .../View Controllers/EditClosedGroupVC.swift | 2 +- Session/View Controllers/HomeVC.swift | 2 +- .../View Controllers/NewClosedGroupVC.swift | 2 +- .../Database}/OWSBackupFragment.h | 0 .../Database}/OWSBackupFragment.m | 0 .../Database/OWSPrimaryStorage.m | 56 +----- .../Database/OWSStorage+Subclass.h | 0 .../Messages/Signal/TSMessage.m | 1 - .../Meta/SessionMessagingKit.h | 7 + .../Attachments/TSAttachmentPointer.h | 7 + .../Attachments/TSAttachmentPointer.m | 25 +++ .../Blocking/OWSBlockingManager.m | 39 ---- .../Expiration/OWSDisappearingMessagesJob.m | 51 ----- SessionMessagingKit/To Do/TSAccountManager.m | 39 +--- SessionMessagingKit/Utilities/AppReadiness.m | 17 -- .../Utilities}/DeviceSleepManager.swift | 10 - .../Utilities}/Environment.h | 0 .../Utilities}/Environment.m | 15 +- .../Utilities/OWSAudioPlayer.h | 5 +- .../Utilities/OWSAudioPlayer.m | 40 +--- .../Utilities/OWSAudioSession.swift | 0 .../Utilities/OWSIdentityManager.m | 70 +------ .../Utilities}/OWSPreferences.h | 2 + .../Utilities}/OWSPreferences.m | 33 +-- .../Utilities}/OWSSounds.h | 3 +- .../Utilities}/OWSSounds.m | 27 +-- .../Utilities}/OWSWindowManager.h | 2 + .../Utilities}/OWSWindowManager.m | 121 +---------- .../ProximityMonitoringManager.swift | 0 .../SignalShareExtension-Bridging-Header.h | 9 +- .../ShareAppExtensionContext.m | 1 + .../Meta/SessionUtilitiesKit.h | 3 + .../NSString+SSK.h | 2 + .../NSString+SSK.m | 3 - .../OWSMath.h | 0 .../String+SSK.swift | 5 - .../UIDevice+featureSupport.swift | 2 +- .../UI => SessionUtilitiesKit}/UIView+OWS.h | 9 - .../UI => SessionUtilitiesKit}/UIView+OWS.m | 73 ------- .../Weak.swift | 0 Signal.xcodeproj/project.pbxproj | 190 +++++++++--------- SignalUtilitiesKit/AppSetup.m | 2 +- .../MessageSender+Handling.swift | 6 +- .../Messaging/TSAttachmentPointer+Backups.h | 19 -- .../Messaging/TSAttachmentPointer+Backups.m | 34 ---- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 8 - SignalUtilitiesKit/{UI => }/OWSAlerts.swift | 0 SignalUtilitiesKit/To Do/OWSProfileManager.m | 2 +- SignalUtilitiesKit/To Do/OWSUserProfile.m | 2 +- SignalUtilitiesKit/UI/MediaMessageView.swift | 4 + .../UI/SelectRecipientViewController.m | 2 +- .../UI/SelectThreadViewController.m | 2 +- .../UI/SharingThreadPickerViewController.m | 2 +- 93 files changed, 323 insertions(+), 900 deletions(-) rename {SignalUtilitiesKit => SessionMessagingKit/Database}/OWSBackupFragment.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Database}/OWSBackupFragment.m (100%) rename {SignalUtilitiesKit => SessionMessagingKit}/Database/OWSStorage+Subclass.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/DeviceSleepManager.swift (93%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/Environment.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/Environment.m (78%) rename {SignalUtilitiesKit => SessionMessagingKit}/Utilities/OWSAudioPlayer.h (93%) rename {SignalUtilitiesKit => SessionMessagingKit}/Utilities/OWSAudioPlayer.m (85%) rename {SignalUtilitiesKit => SessionMessagingKit}/Utilities/OWSAudioSession.swift (100%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSPreferences.h (98%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSPreferences.m (90%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSSounds.h (96%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/OWSSounds.m (91%) rename {SignalUtilitiesKit/UI => SessionMessagingKit/Utilities}/OWSWindowManager.h (98%) rename {SignalUtilitiesKit/UI => SessionMessagingKit/Utilities}/OWSWindowManager.m (83%) rename {SignalUtilitiesKit => SessionMessagingKit/Utilities}/ProximityMonitoringManager.swift (100%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSString+SSK.h (85%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/NSString+SSK.m (84%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/OWSMath.h (100%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/String+SSK.swift (87%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/UIDevice+featureSupport.swift (97%) rename {SignalUtilitiesKit/UI => SessionUtilitiesKit}/UIView+OWS.h (95%) rename {SignalUtilitiesKit/UI => SessionUtilitiesKit}/UIView+OWS.m (91%) rename {SignalUtilitiesKit/Utilities => SessionUtilitiesKit}/Weak.swift (100%) delete mode 100644 SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.h delete mode 100644 SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.m rename SignalUtilitiesKit/{UI => }/OWSAlerts.swift (100%) diff --git a/Podfile b/Podfile index 05252c6c5..d3d2d1b36 100644 --- a/Podfile +++ b/Podfile @@ -72,6 +72,7 @@ target 'SessionMessagingKit' do pod 'HKDFKit', :inhibit_warnings => true pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true + pod 'PureLayout', '~> 3.1.4', :inhibit_warnings => true pod 'Reachability', :inhibit_warnings => true pod 'SAMKeychain', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true @@ -104,6 +105,7 @@ target 'SessionUtilitiesKit' do pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true + pod 'PureLayout', '~> 3.1.4', :inhibit_warnings => true pod 'SAMKeychain', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true diff --git a/Podfile.lock b/Podfile.lock index 2b4ff5437..b348a5ae6 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: b12682bc3bf974c758ec8e4b9838639f7ec51d5e +PODFILE CHECKSUM: f65f7b4344906f219fb7e1e4ca93b4ed1ac3132a COCOAPODS: 1.10.0.rc.1 diff --git a/Session/Configuration.swift b/Session/Configuration.swift index c100c7d96..930229983 100644 --- a/Session/Configuration.swift +++ b/Session/Configuration.swift @@ -10,17 +10,12 @@ final class Configuration : NSObject { @objc static func performMainSetup() { SNMessagingKit.configure( storage: Storage.shared, - messageSenderDelegate: MessageSenderDelegate.shared, - messageReceiverDelegate: MessageReceiverDelegate.shared, signalStorage: OWSPrimaryStorage.shared(), identityKeyStore: OWSIdentityManager.shared(), sessionRestorationImplementation: SessionRestorationImplementation(), - certificateValidator: SMKCertificateDefaultValidator(trustRoot: OWSUDManagerImpl.trustRoot()), - openGroupAPIDelegate: OpenGroupAPIDelegate.shared, - pnServerURL: PushNotificationAPI.server, - pnServerPublicKey: PushNotificationAPI.serverPublicKey + certificateValidator: SMKCertificateDefaultValidator(trustRoot: OWSUDManagerImpl.trustRoot()) ) - SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: MessageSenderDelegate.shared) + SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: MessageSender.shared) SessionSnodeKit.configure(storage: Storage.shared) SessionUtilitiesKit.configure(owsPrimaryStorage: OWSPrimaryStorage.shared(), maxFileSize: UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier)) } diff --git a/Session/Meta/Signal-Bridging-Header.h b/Session/Meta/Signal-Bridging-Header.h index 93706eb46..279565e34 100644 --- a/Session/Meta/Signal-Bridging-Header.h +++ b/Session/Meta/Signal-Bridging-Header.h @@ -49,49 +49,49 @@ #import #import #import -#import -#import +#import +#import #import -#import +#import #import -#import -#import +#import +#import #import #import #import #import -#import +#import #import #import #import #import #import #import -#import +#import #import #import #import #import #import #import -#import +#import #import -#import +#import #import -#import +#import #import #import #import #import #import -#import +#import #import #import -#import +#import #import #import #import -#import +#import #import #import #import diff --git a/Session/Meta/Signal-Prefix.pch b/Session/Meta/Signal-Prefix.pch index bede98c9f..10b6b0f33 100644 --- a/Session/Meta/Signal-Prefix.pch +++ b/Session/Meta/Signal-Prefix.pch @@ -18,7 +18,7 @@ #import #import #import - #import + #import #import #import #import diff --git a/Session/Signal/AboutTableViewController.m b/Session/Signal/AboutTableViewController.m index 0c32a1dba..451eb379c 100644 --- a/Session/Signal/AboutTableViewController.m +++ b/Session/Signal/AboutTableViewController.m @@ -5,8 +5,8 @@ #import "AboutTableViewController.h" #import "Session-Swift.h" #import "UIView+OWS.h" -#import -#import +#import +#import #import #import #import diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 569f8783f..09bc074f7 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -13,9 +13,9 @@ #import #import #import -#import +#import #import -#import +#import #import #import #import @@ -23,7 +23,7 @@ #import #import #import -#import +#import #import #import #import @@ -776,7 +776,6 @@ static NSTimeInterval launchStartedAt; - (void)startOpenGroupPollersIfNeeded { [LKPublicChatManager.shared startPollersIfNeeded]; - [SSKEnvironment.shared.attachmentDownloads continueDownloadIfPossible]; } - (void)stopOpenGroupPollers { [LKPublicChatManager.shared stopPollers]; } diff --git a/Session/Signal/AvatarViewHelper.m b/Session/Signal/AvatarViewHelper.m index 1b2c41163..d62d16c49 100644 --- a/Session/Signal/AvatarViewHelper.m +++ b/Session/Signal/AvatarViewHelper.m @@ -9,7 +9,7 @@ #import -#import +#import #import #import #import diff --git a/Session/Signal/ConversationView/Cells/AttachmentUploadView.m b/Session/Signal/ConversationView/Cells/AttachmentUploadView.m index 6672ffa8e..bb951f800 100644 --- a/Session/Signal/ConversationView/Cells/AttachmentUploadView.m +++ b/Session/Signal/ConversationView/Cells/AttachmentUploadView.m @@ -6,7 +6,7 @@ #import "OWSBezierPathView.h" #import "OWSProgressView.h" #import -#import +#import #import #import #import diff --git a/Session/Signal/ConversationView/Cells/ConversationMediaView.swift b/Session/Signal/ConversationView/Cells/ConversationMediaView.swift index 5fa530c01..fc57923a8 100644 --- a/Session/Signal/ConversationView/Cells/ConversationMediaView.swift +++ b/Session/Signal/ConversationView/Cells/ConversationMediaView.swift @@ -13,12 +13,6 @@ public class ConversationMediaView: UIView { case failed } - // MARK: - Dependencies - - private var attachmentDownloads: OWSAttachmentDownloads { - return SSKEnvironment.shared.attachmentDownloads - } - // MARK: - private let mediaCache: NSCache @@ -163,11 +157,13 @@ public class ConversationMediaView: UIView { configure(forError: .invalid) return } + /* guard nil != attachmentDownloads.downloadProgress(forAttachmentId: attachmentId) else { // Not being downloaded. configure(forError: .missing) return } + */ backgroundColor = (Theme.isDarkThemeEnabled ? .ows_gray90 : .ows_gray05) let view: UIView diff --git a/Session/Signal/ConversationView/Cells/MediaDownloadView.swift b/Session/Signal/ConversationView/Cells/MediaDownloadView.swift index 65102dd3b..01d680eb7 100644 --- a/Session/Signal/ConversationView/Cells/MediaDownloadView.swift +++ b/Session/Signal/ConversationView/Cells/MediaDownloadView.swift @@ -7,12 +7,6 @@ import Foundation @objc public class MediaDownloadView: UIView { - // MARK: - Dependencies - - private var attachmentDownloads: OWSAttachmentDownloads { - return SSKEnvironment.shared.attachmentDownloads - } - // MARK: - private let attachmentId: String @@ -75,13 +69,13 @@ public class MediaDownloadView: UIView { shapeLayer1.frame = self.bounds shapeLayer2.frame = self.bounds - guard let progress = attachmentDownloads.downloadProgress(forAttachmentId: attachmentId) else { - Logger.warn("No progress for attachment.") - shapeLayer1.path = nil - shapeLayer2.path = nil - return - } + shapeLayer1.path = nil + shapeLayer2.path = nil + return + + // We can't display download progress yet + /* // Prevent the shape layer from animating changes. CATransaction.begin() CATransaction.setDisableActions(true) @@ -115,5 +109,6 @@ public class MediaDownloadView: UIView { shapeLayer2.fillColor = fillColor2.cgColor CATransaction.commit() + */ } } diff --git a/Session/Signal/ConversationView/Cells/OWSBubbleShapeView.m b/Session/Signal/ConversationView/Cells/OWSBubbleShapeView.m index bdefe0898..405ec2efc 100644 --- a/Session/Signal/ConversationView/Cells/OWSBubbleShapeView.m +++ b/Session/Signal/ConversationView/Cells/OWSBubbleShapeView.m @@ -4,7 +4,7 @@ #import "OWSBubbleShapeView.h" #import "OWSBubbleView.h" -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSBubbleView.m b/Session/Signal/ConversationView/Cells/OWSBubbleView.m index 992a4becf..1f6148f98 100644 --- a/Session/Signal/ConversationView/Cells/OWSBubbleView.m +++ b/Session/Signal/ConversationView/Cells/OWSBubbleView.m @@ -4,7 +4,7 @@ #import "OWSBubbleView.h" #import "MainAppContext.h" -#import +#import #import "Session-Swift.h" NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m index 55ea4cd7d..90a8e8fcd 100644 --- a/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m +++ b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m @@ -11,7 +11,7 @@ #import #import #import -#import +#import #import #import diff --git a/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m index 8c736cee4..73384fe01 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m @@ -14,7 +14,7 @@ #import "OWSQuotedMessageView.h" #import "Session-Swift.h" #import "UIColor+OWS.h" -#import +#import NS_ASSUME_NONNULL_BEGIN @@ -52,13 +52,6 @@ NS_ASSUME_NONNULL_BEGIN @implementation OWSMessageBubbleView -#pragma mark - Dependencies - -- (OWSAttachmentDownloads *)attachmentDownloads -{ - return SSKEnvironment.shared.attachmentDownloads; -} - #pragma mark - - (instancetype)initWithFrame:(CGRect)frame @@ -846,10 +839,6 @@ NS_ASSUME_NONNULL_BEGIN OWSFailDebug(@"Missing uniqueId."); return; } - if ([self.attachmentDownloads downloadProgressForAttachmentId:uniqueId] == nil) { - OWSFailDebug(@"Missing download progress."); - return; - } UIView *overlayView = [UIView new]; overlayView.backgroundColor = [self.bubbleColor colorWithAlphaComponent:0.5]; diff --git a/Session/Signal/ConversationView/Cells/OWSMessageHeaderView.m b/Session/Signal/ConversationView/Cells/OWSMessageHeaderView.m index d803840b9..3b9ad7235 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageHeaderView.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageHeaderView.m @@ -8,7 +8,7 @@ #import #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSMessageTextView.m b/Session/Signal/ConversationView/Cells/OWSMessageTextView.m index 1782bf9d4..c6a318b85 100644 --- a/Session/Signal/ConversationView/Cells/OWSMessageTextView.m +++ b/Session/Signal/ConversationView/Cells/OWSMessageTextView.m @@ -3,7 +3,7 @@ // #import "OWSMessageTextView.h" -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m index 9ae9cdd14..ae44305ed 100644 --- a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m @@ -11,9 +11,9 @@ #import #import -#import +#import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m index 7f12a6ae6..8441a4366 100644 --- a/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m +++ b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m @@ -9,10 +9,10 @@ #import "UIColor+OWS.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" -#import -#import -#import -#import +#import +#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/ConversationInputTextView.m b/Session/Signal/ConversationView/ConversationInputTextView.m index 406d8c9cd..1a7e86721 100644 --- a/Session/Signal/ConversationView/ConversationInputTextView.m +++ b/Session/Signal/ConversationView/ConversationInputTextView.m @@ -4,7 +4,7 @@ #import "ConversationInputTextView.h" #import "Session-Swift.h" -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/ConversationInputToolbar.m b/Session/Signal/ConversationView/ConversationInputToolbar.m index 731e3af3e..05a1a00f4 100644 --- a/Session/Signal/ConversationView/ConversationInputToolbar.m +++ b/Session/Signal/ConversationView/ConversationInputToolbar.m @@ -12,8 +12,8 @@ #import #import #import -#import -#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 180490268..b4139b10e 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -42,7 +42,7 @@ #import #import #import -#import +#import #import #import #import @@ -51,7 +51,7 @@ #import #import #import -#import +#import #import #import #import @@ -62,9 +62,9 @@ #import #import #import -#import -#import -#import +#import +#import +#import #import #import #import @@ -271,11 +271,6 @@ typedef enum : NSUInteger { return SSKEnvironment.shared.typingIndicators; } -- (OWSAttachmentDownloads *)attachmentDownloads -{ - return SSKEnvironment.shared.attachmentDownloads; -} - - (TSAccountManager *)tsAccountManager { OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); @@ -1457,16 +1452,18 @@ typedef enum : NSUInteger { { OWSAssert(message); - [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [self.attachmentDownloads downloadAttachmentsForMessage:message - transaction:transaction - success:^(NSArray *attachmentStreams) { - OWSLogInfo(@"Successfully redownloaded attachment in thread: %@", message.thread); - } - failure:^(NSError *error) { - OWSLogWarn(@"Failed to redownload message with error: %@", error); - }]; - }]; + // TODO TODO TODO + +// [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { +// [self.attachmentDownloads downloadAttachmentsForMessage:message +// transaction:transaction +// success:^(NSArray *attachmentStreams) { +// OWSLogInfo(@"Successfully redownloaded attachment in thread: %@", message.thread); +// } +// failure:^(NSError *error) { +// OWSLogWarn(@"Failed to redownload message with error: %@", error); +// }]; +// }]; } - (void)handleUnsentMessageTap:(TSOutgoingMessage *)message @@ -1914,23 +1911,25 @@ typedef enum : NSUInteger { return; } - [self.uiDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { - [self.attachmentDownloads downloadAttachmentPointer:attachmentPointer - success:^(NSArray *attachmentStreams) { - OWSAssertDebug(attachmentStreams.count == 1); - TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) { - [message setQuotedMessageThumbnailAttachmentStream:attachmentStream]; - [message saveWithTransaction:postSuccessTransaction]; - }]; - } - failure:^(NSError *error) { - OWSLogWarn(@"Failed to redownload thumbnail with error: %@", error); - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) { - [message touchWithTransaction:postSuccessTransaction]; - }]; - }]; - }]; + // TODO TODO TODO + +// [self.uiDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { +// [self.attachmentDownloads downloadAttachmentPointer:attachmentPointer +// success:^(NSArray *attachmentStreams) { +// OWSAssertDebug(attachmentStreams.count == 1); +// TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; +// [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) { +// [message setQuotedMessageThumbnailAttachmentStream:attachmentStream]; +// [message saveWithTransaction:postSuccessTransaction]; +// }]; +// } +// failure:^(NSError *error) { +// OWSLogWarn(@"Failed to redownload thumbnail with error: %@", error); +// [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) { +// [message touchWithTransaction:postSuccessTransaction]; +// }]; +// }]; +// }]; } - (void)didTapConversationItem:(id)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply diff --git a/Session/Signal/ConversationView/ConversationViewItem.h b/Session/Signal/ConversationView/ConversationViewItem.h index e26701080..2d45d5eea 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.h +++ b/Session/Signal/ConversationView/ConversationViewItem.h @@ -3,6 +3,7 @@ // #import "ConversationViewLayout.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index 371c55eb8..6583ffce5 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -12,9 +12,9 @@ #import "AnyPromise.h" #import #import -#import +#import -#import +#import #import #import @@ -449,6 +449,15 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) [self.lastAudioMessageView setProgress:progress / duration]; } +- (void)showInvalidAudioFileAlert +{ + OWSAssertIsOnMainThread(); + + [OWSAlerts + showErrorAlertWithMessage:NSLocalizedString(@"INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE", + @"Message for the alert indicating that an audio file is invalid.")]; +} + #pragma mark - Displayable Text // TODO: Now that we're caching the displayable text on the view items, diff --git a/Session/Signal/ConversationView/ConversationViewModel.m b/Session/Signal/ConversationView/ConversationViewModel.m index eaef14c18..cf50fcf4d 100644 --- a/Session/Signal/ConversationView/ConversationViewModel.m +++ b/Session/Signal/ConversationView/ConversationViewModel.m @@ -19,7 +19,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/DateUtil.m b/Session/Signal/DateUtil.m index 530a700c8..70776e9f0 100644 --- a/Session/Signal/DateUtil.m +++ b/Session/Signal/DateUtil.m @@ -5,7 +5,7 @@ #import "DateUtil.h" #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/MainAppContext.m b/Session/Signal/MainAppContext.m index 48b2cd22b..af13c0326 100644 --- a/Session/Signal/MainAppContext.m +++ b/Session/Signal/MainAppContext.m @@ -5,7 +5,7 @@ #import "MainAppContext.h" #import "Session-Swift.h" #import -#import +#import #import #import #import diff --git a/Session/Signal/NotificationSettingsOptionsViewController.m b/Session/Signal/NotificationSettingsOptionsViewController.m index 8f675bd10..ebb120b40 100644 --- a/Session/Signal/NotificationSettingsOptionsViewController.m +++ b/Session/Signal/NotificationSettingsOptionsViewController.m @@ -5,7 +5,7 @@ #import "NotificationSettingsOptionsViewController.h" #import "Session-Swift.h" #import "SignalApp.h" -#import +#import #import @implementation NotificationSettingsOptionsViewController diff --git a/Session/Signal/NotificationSettingsViewController.m b/Session/Signal/NotificationSettingsViewController.m index 6a274e31b..30bb229fb 100644 --- a/Session/Signal/NotificationSettingsViewController.m +++ b/Session/Signal/NotificationSettingsViewController.m @@ -7,9 +7,9 @@ #import "NotificationSettingsViewController.h" #import "NotificationSettingsOptionsViewController.h" #import "OWSSoundSettingsViewController.h" -#import -#import -#import +#import +#import +#import #import #import "Session-Swift.h" diff --git a/Session/Signal/OWSBackupExportJob.m b/Session/Signal/OWSBackupExportJob.m index a2156a81f..d538d9a79 100644 --- a/Session/Signal/OWSBackupExportJob.m +++ b/Session/Signal/OWSBackupExportJob.m @@ -15,7 +15,7 @@ #import #import #import -#import +#import #import @import CloudKit; diff --git a/Session/Signal/OWSBackupImportJob.m b/Session/Signal/OWSBackupImportJob.m index e746d4a51..46233da19 100644 --- a/Session/Signal/OWSBackupImportJob.m +++ b/Session/Signal/OWSBackupImportJob.m @@ -12,7 +12,7 @@ #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSBackupJob.h b/Session/Signal/OWSBackupJob.h index 4847ceee2..a426dea57 100644 --- a/Session/Signal/OWSBackupJob.h +++ b/Session/Signal/OWSBackupJob.h @@ -3,7 +3,7 @@ // #import "TSYapDatabaseObject.h" -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSBackupSettingsViewController.m b/Session/Signal/OWSBackupSettingsViewController.m index 1d27fff3e..575d4a281 100644 --- a/Session/Signal/OWSBackupSettingsViewController.m +++ b/Session/Signal/OWSBackupSettingsViewController.m @@ -8,11 +8,11 @@ #import #import -#import +#import #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index 7e178370a..ef205476a 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -15,14 +15,14 @@ #import "UIView+OWS.h" #import #import -#import +#import #import -#import +#import #import #import #import -#import +#import #import #import @@ -950,7 +950,7 @@ static CGRect oldframe; if (gThread.usesSharedSenderKeys) { NSString *groupPublicKey = [LKGroupUtilities getDecodedGroupID:gThread.groupModel.groupId]; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [[SNMessageSenderDelegate leaveGroupWithPublicKey:groupPublicKey transaction:transaction] retainUntilComplete]; + [[SNMessageSender leaveGroupWithPublicKey:groupPublicKey transaction:transaction] retainUntilComplete]; }]; } diff --git a/Session/Signal/OWSOrphanDataCleaner.m b/Session/Signal/OWSOrphanDataCleaner.m index 2d7ca614f..29490b5b0 100644 --- a/Session/Signal/OWSOrphanDataCleaner.m +++ b/Session/Signal/OWSOrphanDataCleaner.m @@ -13,9 +13,9 @@ #import #import #import -#import -#import -#import +#import +#import +#import #import #import #import diff --git a/Session/Signal/OWSProgressView.m b/Session/Signal/OWSProgressView.m index 737930855..0aaf688d0 100644 --- a/Session/Signal/OWSProgressView.m +++ b/Session/Signal/OWSProgressView.m @@ -3,8 +3,8 @@ // #import "OWSProgressView.h" -#import -#import +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSScreenLockUI.m b/Session/Signal/OWSScreenLockUI.m index b79a7ed4a..65bf6f28e 100644 --- a/Session/Signal/OWSScreenLockUI.m +++ b/Session/Signal/OWSScreenLockUI.m @@ -7,7 +7,7 @@ #import "Session-Swift.h" #import #import -#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Session/Signal/OWSSoundSettingsViewController.m b/Session/Signal/OWSSoundSettingsViewController.m index 0ee7b412a..4c086577a 100644 --- a/Session/Signal/OWSSoundSettingsViewController.m +++ b/Session/Signal/OWSSoundSettingsViewController.m @@ -4,8 +4,8 @@ #import "OWSSoundSettingsViewController.h" #import -#import -#import +#import +#import #import #import #import "Session-Swift.h" diff --git a/Session/Signal/PrivacySettingsTableViewController.m b/Session/Signal/PrivacySettingsTableViewController.m index b18449d1e..f4ba3942b 100644 --- a/Session/Signal/PrivacySettingsTableViewController.m +++ b/Session/Signal/PrivacySettingsTableViewController.m @@ -6,12 +6,12 @@ #import "Session-Swift.h" #import -#import -#import +#import +#import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/SignalApp.m b/Session/Signal/SignalApp.m index 0061f9a77..21dd15d32 100644 --- a/Session/Signal/SignalApp.m +++ b/Session/Signal/SignalApp.m @@ -8,7 +8,7 @@ #import "Session-Swift.h" #import #import -#import +#import #import #import #import diff --git a/Session/View Controllers/EditClosedGroupVC.swift b/Session/View Controllers/EditClosedGroupVC.swift index fc05185a8..f50c012fc 100644 --- a/Session/View Controllers/EditClosedGroupVC.swift +++ b/Session/View Controllers/EditClosedGroupVC.swift @@ -253,7 +253,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega } ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in Storage.writeSync { [weak self] transaction in - MessageSenderDelegate.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) { + MessageSender.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) { guard let self = self else { return } self.dismiss(animated: true, completion: nil) // Dismiss the loader popToConversationVC(self) diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index 20f9f3d30..a11422071 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -384,7 +384,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys == true { let groupID = thread.groupModel.groupId let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) - let _ = MessageSenderDelegate.leave(groupPublicKey, using: transaction).ensure { + let _ = MessageSender.leave(groupPublicKey, using: transaction).ensure { Storage.writeSync { transaction in thread.removeAllThreadInteractions(with: transaction) thread.remove(with: transaction) diff --git a/Session/View Controllers/NewClosedGroupVC.swift b/Session/View Controllers/NewClosedGroupVC.swift index d81ba17f7..aa3d9327b 100644 --- a/Session/View Controllers/NewClosedGroupVC.swift +++ b/Session/View Controllers/NewClosedGroupVC.swift @@ -170,7 +170,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in var promise: Promise! Storage.writeSync { transaction in - promise = MessageSenderDelegate.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) + promise = MessageSender.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) } let _ = promise.done(on: DispatchQueue.main) { thread in self?.presentingViewController?.dismiss(animated: true, completion: nil) diff --git a/SignalUtilitiesKit/OWSBackupFragment.h b/SessionMessagingKit/Database/OWSBackupFragment.h similarity index 100% rename from SignalUtilitiesKit/OWSBackupFragment.h rename to SessionMessagingKit/Database/OWSBackupFragment.h diff --git a/SignalUtilitiesKit/OWSBackupFragment.m b/SessionMessagingKit/Database/OWSBackupFragment.m similarity index 100% rename from SignalUtilitiesKit/OWSBackupFragment.m rename to SessionMessagingKit/Database/OWSBackupFragment.m diff --git a/SessionMessagingKit/Database/OWSPrimaryStorage.m b/SessionMessagingKit/Database/OWSPrimaryStorage.m index 69b39cdc0..1bc9b97ff 100644 --- a/SessionMessagingKit/Database/OWSPrimaryStorage.m +++ b/SessionMessagingKit/Database/OWSPrimaryStorage.m @@ -8,13 +8,14 @@ #import "OWSFileSystem.h" #import "OWSIncomingMessageFinder.h" #import "OWSMediaGalleryFinder.h" +#import +#import "OWSStorage.h" #import "OWSStorage+Subclass.h" #import "SSKEnvironment.h" #import "TSDatabaseSecondaryIndexes.h" #import "TSDatabaseView.h" #import #import -#import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN @@ -27,15 +28,10 @@ NSString *const OWSUIDatabaseConnectionNotificationsKey = @"OWSUIDatabaseConnect void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) { - OWSCAssertDebug(storage); - [[storage newDatabaseConnection] asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { for (NSString *extensionName in storage.registeredExtensionNames) { - OWSLogVerbose(@"Verifying database extension: %@", extensionName); YapDatabaseViewTransaction *_Nullable viewTransaction = [transaction ext:extensionName]; if (!viewTransaction) { - OWSCFailDebug(@"VerifyRegistrationsForPrimaryStorage missing database extension: %@", extensionName); - [OWSStorage incrementVersionOfDatabaseExtension:extensionName]; } } @@ -60,8 +56,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) + (instancetype)sharedManager { - OWSAssertDebug(SSKEnvironment.shared.primaryStorage); - return SSKEnvironment.shared.primaryStorage; } @@ -88,8 +82,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) selector:@selector(yapDatabaseModifiedExternally:) name:YapDatabaseModifiedExternallyNotification object:nil]; - - OWSSingletonAssert(); } return self; @@ -97,9 +89,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) - (void)dealloc { - // Surface memory leaks by logging the deallocation of this class. - OWSLogVerbose(@"Dealloc: %@", self.class); - [[NSNotificationCenter defaultCenter] removeObserver:self]; } @@ -121,16 +110,11 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) - (void)yapDatabaseModified:(NSNotification *)notification { - OWSAssertIsOnMainThread(); - - OWSLogVerbose(@""); [self updateUIDatabaseConnectionToLatest]; } - (void)updateUIDatabaseConnectionToLatest { - OWSAssertIsOnMainThread(); - // Notify observers we're about to update the database connection [[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateNotification object:self.dbNotificationObject]; @@ -147,7 +131,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) - (YapDatabaseConnection *)uiDatabaseConnection { - OWSAssertIsOnMainThread(); return _uiDatabaseConnection; } @@ -171,17 +154,12 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) // seeing, this issue only seems to affect sync and not async registrations. We've always // been opening write transactions before the async registrations complete without negative // consequences. - OWSAssertDebug(!self.areSyncRegistrationsComplete); + self.areSyncRegistrationsComplete = YES; } - (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion { - OWSAssertDebug(completion); - OWSAssertDebug(self.database); - - OWSLogVerbose(@"async registrations enqueuing."); - // Asynchronously register other extensions. // // All sync registrations must be done before all async registrations, @@ -207,9 +185,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) [self.database flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) completionBlock:^{ - OWSAssertDebug(!self.areAsyncRegistrationsComplete); - OWSLogVerbose(@"async registrations complete."); - self.areAsyncRegistrationsComplete = YES; completion(); @@ -225,10 +200,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) + (void)protectFiles { - OWSLogInfo(@"Database file size: %@", [OWSFileSystem fileSizeOfPath:self.sharedDataDatabaseFilePath]); - OWSLogInfo(@"\t SHM file size: %@", [OWSFileSystem fileSizeOfPath:self.sharedDataDatabaseFilePath_SHM]); - OWSLogInfo(@"\t WAL file size: %@", [OWSFileSystem fileSizeOfPath:self.sharedDataDatabaseFilePath_WAL]); - // Protect the entire new database directory. [OWSFileSystem protectFileOrFolderAtPath:self.sharedDataDatabaseDirPath]; } @@ -242,9 +213,7 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) { NSString *databaseDirPath = [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"]; - if (![OWSFileSystem ensureDirectoryExists:databaseDirPath]) { - OWSFail(@"Could not create new database directory"); - } + [OWSFileSystem ensureDirectoryExists:databaseDirPath]; return databaseDirPath; } @@ -295,8 +264,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) + (nullable NSError *)migrateToSharedData { - OWSLogInfo(@""); - // Given how sensitive this migration is, we verbosely // log the contents of all involved paths before and after. NSArray *paths = @[ @@ -308,11 +275,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) self.sharedDataDatabaseFilePath_WAL, ]; NSFileManager *fileManager = [NSFileManager defaultManager]; - for (NSString *path in paths) { - if ([fileManager fileExistsAtPath:path]) { - OWSLogInfo(@"before migrateToSharedData: %@, %@", path, [OWSFileSystem fileSizeOfPath:path]); - } - } // We protect the db files here, which is somewhat redundant with what will happen in // `moveAppFilePath:` which also ensures file protection. @@ -361,19 +323,11 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) return error; } - for (NSString *path in paths) { - if ([fileManager fileExistsAtPath:path]) { - OWSLogInfo(@"after migrateToSharedData: %@, %@", path, [OWSFileSystem fileSizeOfPath:path]); - } - } - return nil; } + (NSString *)databaseFilePath { - OWSLogVerbose(@"databasePath: %@", OWSPrimaryStorage.sharedDataDatabaseFilePath); - return self.sharedDataDatabaseFilePath; } @@ -431,8 +385,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) - (void)touchDbAsync { - OWSLogInfo(@""); - // There appears to be a bug in YapDatabase that sometimes delays modifications // made in another process (e.g. the SAE) from showing up in other processes. // There's a simple workaround: a trivial write to the database flushes changes diff --git a/SignalUtilitiesKit/Database/OWSStorage+Subclass.h b/SessionMessagingKit/Database/OWSStorage+Subclass.h similarity index 100% rename from SignalUtilitiesKit/Database/OWSStorage+Subclass.h rename to SessionMessagingKit/Database/OWSStorage+Subclass.h diff --git a/SessionMessagingKit/Messages/Signal/TSMessage.m b/SessionMessagingKit/Messages/Signal/TSMessage.m index 2fac7a6e6..dc9a1f0fe 100644 --- a/SessionMessagingKit/Messages/Signal/TSMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSMessage.m @@ -14,7 +14,6 @@ #import #import #import -#import "OWSPrimaryStorage+Loki.h" #import "TSContactThread.h" #import diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index b02e7609e..1a44bbacf 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -4,8 +4,11 @@ FOUNDATION_EXPORT double SessionMessagingKitVersionNumber; FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; #import +#import #import +#import #import +#import #import #import #import @@ -15,12 +18,16 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; #import #import #import +#import #import #import #import #import #import +#import #import +#import +#import #import #import #import diff --git a/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.h b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.h index 66ae2d8d8..f72a8178f 100644 --- a/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.h +++ b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.h @@ -60,6 +60,13 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { (NSArray *)attachmentProtos albumMessage:(TSMessage *)message; +// Non-nil for attachments which need "lazy backup restore." +- (nullable OWSBackupFragment *)lazyRestoreFragment; + +// Marks attachment as needing "lazy backup restore." +- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment + transaction:(YapDatabaseReadWriteTransaction *)transaction; + @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.m b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.m index 666904683..6a675fa64 100644 --- a/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.m +++ b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer.m @@ -176,6 +176,31 @@ NS_ASSUME_NONNULL_BEGIN } } +#pragma mark - Backups + +- (nullable OWSBackupFragment *)lazyRestoreFragment +{ + if (!self.lazyRestoreFragmentId) { + return nil; + } + OWSBackupFragment *_Nullable backupFragment = + [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId]; + return backupFragment; +} + +- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + if (!lazyRestoreFragment.uniqueId) { + // If metadata hasn't been saved yet, save now. + [lazyRestoreFragment saveWithTransaction:transaction]; + } + [self applyChangeToSelfAndLatestCopy:transaction + changeBlock:^(TSAttachmentPointer *attachment) { + [attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId]; + }]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m index cdb20550c..7ed42eb79 100644 --- a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m +++ b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m @@ -12,7 +12,6 @@ #import "TSGroupThread.h" #import "YapDatabaseConnection+OWS.h" #import -#import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN @@ -46,8 +45,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan + (instancetype)sharedManager { - OWSAssertDebug(SSKEnvironment.shared.blockingManager); - return SSKEnvironment.shared.blockingManager; } @@ -59,12 +56,8 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan return self; } - OWSAssertDebug(primaryStorage); - _dbConnection = primaryStorage.newDatabaseConnection; - OWSSingletonAssert(); - return self; } @@ -92,7 +85,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan TSGroupThread *groupThread = (TSGroupThread *)thread; return [self isGroupIdBlocked:groupThread.groupModel.groupId]; } else { - OWSFailDebug(@"%@ failure unexpected thread type", self.logTag); return NO; } } @@ -101,10 +93,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)addBlockedPhoneNumber:(NSString *)phoneNumber { - OWSAssertDebug(phoneNumber.length > 0); - - OWSLogInfo(@"addBlockedPhoneNumber: %@", phoneNumber); - @synchronized(self) { [self ensureLazyInitialization]; @@ -122,10 +110,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)removeBlockedPhoneNumber:(NSString *)phoneNumber { - OWSAssertDebug(phoneNumber.length > 0); - - OWSLogInfo(@"removeBlockedPhoneNumber: %@", phoneNumber); - @synchronized(self) { [self ensureLazyInitialization]; @@ -143,10 +127,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)setBlockedPhoneNumbers:(NSArray *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage { - OWSAssertDebug(blockedPhoneNumbers != nil); - - OWSLogInfo(@"setBlockedPhoneNumbers: %d", (int)blockedPhoneNumbers.count); - @synchronized(self) { [self ensureLazyInitialization]; @@ -210,9 +190,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)addBlockedGroup:(TSGroupModel *)groupModel { NSData *groupId = groupModel.groupId; - OWSAssertDebug(groupId.length > 0); - - OWSLogInfo(@"groupId: %@", groupId); @synchronized(self) { [self ensureLazyInitialization]; @@ -229,10 +206,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)removeBlockedGroupId:(NSData *)groupId { - OWSAssertDebug(groupId.length > 0); - - OWSLogInfo(@"groupId: %@", groupId); - @synchronized(self) { [self ensureLazyInitialization]; @@ -307,7 +280,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)ensureLazyInitialization { if (_blockedPhoneNumberSet) { - OWSAssertDebug(_blockedGroupMap); // already loaded return; @@ -333,8 +305,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)syncBlockList { - OWSAssertDebug(_blockedPhoneNumberSet); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self sendBlockListSyncMessageWithPhoneNumbers:self.blockedPhoneNumbers groupIds:self.blockedGroupIds]; }); @@ -343,8 +313,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan // This method should only be called from within a synchronized block. - (void)syncBlockListIfNecessary { - OWSAssertDebug(_blockedPhoneNumberSet); - // If we haven't yet successfully synced the current "block list" changes, // try again to sync now. NSArray *syncedBlockedPhoneNumbers = @@ -363,11 +331,9 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan if ([self.blockedPhoneNumberSet isEqualToSet:syncedBlockedPhoneNumberSet] && [localBlockedGroupIdSet isEqualToSet:syncedBlockedGroupIdSet]) { - OWSLogVerbose(@"Ignoring redundant block list sync"); return; } - OWSLogInfo(@"retrying sync of block list"); [self sendBlockListSyncMessageWithPhoneNumbers:self.blockedPhoneNumbers groupIds:localBlockedGroupIds]; } @@ -401,9 +367,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)saveSyncedBlockListWithPhoneNumbers:(NSArray *)blockedPhoneNumbers groupIds:(NSArray *)blockedGroupIds { - OWSAssertDebug(blockedPhoneNumbers); - OWSAssertDebug(blockedGroupIds); - [self.dbConnection setObject:blockedPhoneNumbers forKey:kOWSBlockingManager_SyncedBlockedPhoneNumbersKey inCollection:kOWSBlockingManager_BlockListCollection]; @@ -417,8 +380,6 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)applicationDidBecomeActive:(NSNotification *)notification { - OWSAssertIsOnMainThread(); - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ @synchronized(self) { diff --git a/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.m b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.m index 8ebcadb59..126e3c44c 100644 --- a/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.m +++ b/SessionMessagingKit/Sending & Receiving/Expiration/OWSDisappearingMessagesJob.m @@ -17,7 +17,6 @@ #import #import #import -#import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN @@ -53,8 +52,6 @@ void AssertIsOnDisappearingMessagesQueue() + (instancetype)sharedJob { - OWSAssertDebug(SSKEnvironment.shared.disappearingMessagesJob); - return SSKEnvironment.shared.disappearingMessagesJob; } @@ -80,8 +77,6 @@ void AssertIsOnDisappearingMessagesQueue() } }]; - OWSSingletonAssert(); - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:OWSApplicationDidBecomeActiveNotification @@ -124,20 +119,15 @@ void AssertIsOnDisappearingMessagesQueue() [self.disappearingMessagesFinder enumerateExpiredMessagesWithBlock:^(TSMessage *message) { // sanity check if (message.expiresAt > now) { - OWSFailDebug(@"Refusing to remove message which doesn't expire until: %lld", message.expiresAt); return; } - OWSLogInfo(@"Removing message which expired at: %lld", message.expiresAt); [message removeWithTransaction:transaction]; expirationCount++; } transaction:transaction]; }]; - OWSLogDebug(@"Removed %lu expired messages", (unsigned long)expirationCount); - - OWSAssertDebug(backgroundTask); backgroundTask = nil; return expirationCount; } @@ -145,7 +135,6 @@ void AssertIsOnDisappearingMessagesQueue() // deletes any expired messages and schedules the next run. - (NSUInteger)runLoop { - OWSLogVerbose(@"in runLoop"); AssertIsOnDisappearingMessagesQueue(); NSUInteger deletedCount = [self deleteExpiredMessages]; @@ -157,7 +146,6 @@ void AssertIsOnDisappearingMessagesQueue() }]; if (!nextExpirationTimestampNumber) { - OWSLogDebug(@"No more expiring messages."); return deletedCount; } @@ -172,14 +160,11 @@ void AssertIsOnDisappearingMessagesQueue() expirationStartedAt:(uint64_t)expirationStartedAt transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction { - OWSAssertDebug(transaction); - if (!message.isExpiringMessage) { return; } NSTimeInterval startedSecondsAgo = ([NSDate ows_millisecondTimeStamp] - expirationStartedAt) / 1000.0; - OWSLogDebug(@"Starting expiration for message read %f seconds ago", startedSecondsAgo); // Don't clobber if multiple actions simultaneously triggered expiration. if (message.expireStartedAt == 0 || message.expireStartedAt > expirationStartedAt) { @@ -202,9 +187,6 @@ void AssertIsOnDisappearingMessagesQueue() createdInExistingGroup:(BOOL)createdInExistingGroup transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(thread); - OWSAssertDebug(transaction); - OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; NSString *_Nullable remoteContactName = nil; @@ -228,9 +210,6 @@ void AssertIsOnDisappearingMessagesQueue() return; } - OWSLogInfo(@"becoming consistent with disappearing message configuration: %@", - disappearingMessagesConfiguration.dictionaryValue); - [disappearingMessagesConfiguration saveWithTransaction:transaction]; // MJK TODO - should be safe to remove this senderTimestamp @@ -242,7 +221,6 @@ void AssertIsOnDisappearingMessagesQueue() createdInExistingGroup:createdInExistingGroup]; [infoMessage saveWithTransaction:transaction]; - OWSAssertDebug(backgroundTask); backgroundTask = nil; } @@ -284,8 +262,6 @@ void AssertIsOnDisappearingMessagesQueue() - (void)scheduleRunByDate:(NSDate *)date { - OWSAssertDebug(date); - dispatch_async(dispatch_get_main_queue(), ^{ if (!CurrentAppContext().isMainAppAndActive) { // Don't schedule run when inactive or not in main app. @@ -297,18 +273,10 @@ void AssertIsOnDisappearingMessagesQueue() NSTimeInterval delaySeconds = MAX(kMinDelaySeconds, date.timeIntervalSinceNow); NSDate *newTimerScheduleDate = [NSDate dateWithTimeIntervalSinceNow:delaySeconds]; if (self.nextDisappearanceDate && [self.nextDisappearanceDate isBeforeDate:newTimerScheduleDate]) { - OWSLogVerbose(@"Request to run at %@ (%d sec.) ignored due to earlier scheduled run at %@ (%d sec.)", - [self.dateFormatter stringFromDate:date], - (int)round(MAX(0, [date timeIntervalSinceDate:[NSDate new]])), - [self.dateFormatter stringFromDate:self.nextDisappearanceDate], - (int)round(MAX(0, [self.nextDisappearanceDate timeIntervalSinceDate:[NSDate new]]))); return; } // Update Schedule - OWSLogVerbose(@"Scheduled run at %@ (%d sec.)", - [self.dateFormatter stringFromDate:newTimerScheduleDate], - (int)round(MAX(0, [newTimerScheduleDate timeIntervalSinceDate:[NSDate new]]))); [self resetNextDisappearanceTimer]; self.nextDisappearanceDate = newTimerScheduleDate; self.nextDisappearanceTimer = [NSTimer weakScheduledTimerWithTimeInterval:delaySeconds @@ -321,12 +289,8 @@ void AssertIsOnDisappearingMessagesQueue() - (void)disappearanceTimerDidFire { - OWSAssertIsOnMainThread(); - OWSLogDebug(@""); - if (!CurrentAppContext().isMainAppAndActive) { // Don't schedule run when inactive or not in main app. - OWSFailDebug(@"Disappearing messages job timer fired while main app inactive."); return; } @@ -339,16 +303,12 @@ void AssertIsOnDisappearingMessagesQueue() - (void)fallbackTimerDidFire { - OWSAssertIsOnMainThread(); - OWSLogDebug(@""); - BOOL recentlyScheduledDisappearanceTimer = NO; if (fabs(self.nextDisappearanceDate.timeIntervalSinceNow) < 1.0) { recentlyScheduledDisappearanceTimer = YES; } if (!CurrentAppContext().isMainAppAndActive) { - OWSLogInfo(@"Ignoring fallbacktimer for app which is not main and active."); return; } @@ -359,16 +319,11 @@ void AssertIsOnDisappearingMessagesQueue() // So, if we're deleting something via this fallback timer, something may have gone wrong. The // exception is if we're in close proximity to the disappearanceTimer, in which case a race condition // is inevitable. - if (!recentlyScheduledDisappearanceTimer && deletedCount > 0) { - OWSFailDebug(@"unexpectedly deleted disappearing messages via fallback timer."); - } }); } - (void)resetNextDisappearanceTimer { - OWSAssertIsOnMainThread(); - [self.nextDisappearanceTimer invalidate]; self.nextDisappearanceTimer = nil; self.nextDisappearanceDate = nil; @@ -380,8 +335,6 @@ void AssertIsOnDisappearingMessagesQueue() { [self.disappearingMessagesFinder enumerateMessagesWhichFailedToStartExpiringWithBlock:^(TSMessage *_Nonnull message) { - OWSFailDebug(@"starting old timer for message timestamp: %lu", (unsigned long)message.timestamp); - // We don't know when it was actually read, so assume it was read as soon as it was received. uint64_t readTimeBestGuess = message.receivedAtTimestamp; [self startAnyExpirationForMessage:message expirationStartedAt:readTimeBestGuess transaction:transaction]; @@ -393,8 +346,6 @@ void AssertIsOnDisappearingMessagesQueue() - (void)applicationDidBecomeActive:(NSNotification *)notification { - OWSAssertIsOnMainThread(); - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ dispatch_async(OWSDisappearingMessagesJob.serialQueue, ^{ [self runLoop]; @@ -404,8 +355,6 @@ void AssertIsOnDisappearingMessagesQueue() - (void)applicationWillResignActive:(NSNotification *)notification { - OWSAssertIsOnMainThread(); - [self resetNextDisappearanceTimer]; } diff --git a/SessionMessagingKit/To Do/TSAccountManager.m b/SessionMessagingKit/To Do/TSAccountManager.m index dc41c5c48..43d697fa5 100644 --- a/SessionMessagingKit/To Do/TSAccountManager.m +++ b/SessionMessagingKit/To Do/TSAccountManager.m @@ -16,7 +16,6 @@ #import #import #import -#import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN @@ -66,8 +65,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa _dbConnection = [primaryStorage newDatabaseConnection]; self.reachability = [Reachability reachabilityForInternetConnection]; - OWSSingletonAssert(); - if (!CurrentAppContext().isMainApp) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yapDatabaseModifiedExternally:) @@ -94,16 +91,12 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa + (instancetype)sharedInstance { - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - return SSKEnvironment.shared.tsAccountManager; } #pragma mark - Dependencies - (id)profileManager { - OWSAssertDebug(SSKEnvironment.shared.profileManager); - return SSKEnvironment.shared.profileManager; } @@ -155,13 +148,8 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa - (void)didRegister { - OWSLogInfo(@"didRegister"); NSString *phoneNumber = self.phoneNumberAwaitingVerification; - if (!phoneNumber) { - OWSFail(@"phoneNumber was unexpectedly nil"); - } - [self storeLocalNumber:phoneNumber]; // Warm these cached values. @@ -257,7 +245,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa if (registrationID == 0) { registrationID = (uint32_t)arc4random_uniform(16380) + 1; - OWSLogWarn(@"Generated a new registrationID: %u", registrationID); [transaction setObject:[NSNumber numberWithUnsignedInteger:registrationID] forKey:TSAccountManager_LocalRegistrationIdKey @@ -311,7 +298,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa { // TODO: Can we remove phoneNumberAwaitingVerification? NSString *number = self.phoneNumberAwaitingVerification; - OWSAssertDebug(number); [self registerWithPhoneNumber:number captchaToken:captchaToken @@ -325,7 +311,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa failure:(void (^)(NSError *error))failureBlock { NSString *number = self.phoneNumberAwaitingVerification; - OWSAssertDebug(number); [self registerWithPhoneNumber:number captchaToken:captchaToken @@ -375,10 +360,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa - (void)yapDatabaseModifiedExternally:(NSNotification *)notification { - OWSAssertIsOnMainThread(); - - OWSLogVerbose(@""); - // Any database write by the main app might reflect a deregistration, // so clear the cached "is registered" state. This will significantly // erode the value of this cache in the SAE. @@ -400,7 +381,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa defaultValue:NO]); } - OWSAssertDebug(self.cachedIsDeregistered); return self.cachedIsDeregistered.boolValue; } } @@ -412,8 +392,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa return; } - OWSLogWarn(@"isDeregistered: %d", isDeregistered); - self.cachedIsDeregistered = @(isDeregistered); } @@ -433,7 +411,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa @synchronized(self) { NSString *_Nullable localNumber = self.localNumber; if (!localNumber) { - OWSFailDebug(@"can't re-register without valid local number."); return NO; } @@ -444,7 +421,8 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [transaction removeAllObjectsInCollection:TSAccountManager_UserAccountCollection]; - [[OWSPrimaryStorage sharedManager] resetSessionStore:transaction]; + // TODO TODO TODO +// [[OWSPrimaryStorage sharedManager] resetSessionStore:transaction]; [transaction setObject:localNumber forKey:TSAccountManager_ReregisteringPhoneNumberKey @@ -459,11 +437,8 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa - (nullable NSString *)reregisterationPhoneNumber { - OWSAssertDebug([self isReregistering]); - NSString *_Nullable result = [self.dbConnection stringForKey:TSAccountManager_ReregisteringPhoneNumberKey inCollection:TSAccountManager_UserAccountCollection]; - OWSAssertDebug(result); return result; } @@ -483,8 +458,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa - (void)setHasPendingBackupRestoreDecision:(BOOL)value { - OWSLogInfo(@"%d", value); - [self.dbConnection setBool:value forKey:TSAccountManager_HasPendingRestoreDecisionKey inCollection:TSAccountManager_UserAccountCollection]; @@ -509,9 +482,7 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa } - (void)registerForTestsWithLocalNumber:(NSString *)localNumber -{ - OWSAssertDebug(localNumber.length > 0); - +{ [self storeLocalNumber:localNumber]; } @@ -557,8 +528,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa } - (void)reachabilityChanged { - OWSAssertIsOnMainThread(); - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ [[self updateAccountAttributesIfNecessary] retainUntilComplete]; }]; @@ -568,8 +537,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa - (void)postRegistrationStateDidChangeNotification { - OWSAssertIsOnMainThread(); - [[NSNotificationCenter defaultCenter] postNotificationNameAsync:RegistrationStateDidChangeNotification object:nil userInfo:nil]; diff --git a/SessionMessagingKit/Utilities/AppReadiness.m b/SessionMessagingKit/Utilities/AppReadiness.m index 7370141b1..46ee6c2b9 100755 --- a/SessionMessagingKit/Utilities/AppReadiness.m +++ b/SessionMessagingKit/Utilities/AppReadiness.m @@ -4,7 +4,6 @@ #import "AppReadiness.h" #import "AppContext.h" -#import "SSKAsserts.h" #import #import @@ -41,8 +40,6 @@ NS_ASSUME_NONNULL_BEGIN return self; } - OWSSingletonAssert(); - self.appWillBecomeReadyBlocks = [NSMutableArray new]; self.appDidBecomeReadyBlocks = [NSMutableArray new]; @@ -63,9 +60,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)runNowOrWhenAppWillBecomeReady:(AppReadyBlock)block { - OWSAssertIsOnMainThread(); - OWSAssertDebug(block); - if (CurrentAppContext().isRunningTests) { // We don't need to do any "on app ready" work in the tests. return; @@ -88,9 +82,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)runNowOrWhenAppDidBecomeReady:(AppReadyBlock)block { - OWSAssertIsOnMainThread(); - OWSAssertDebug(block); - if (CurrentAppContext().isRunningTests) { // We don't need to do any "on app ready" work in the tests. return; @@ -111,11 +102,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)setAppIsReady { - OWSAssertIsOnMainThread(); - OWSAssertDebug(!self.isAppReady); - - OWSLogInfo(@""); - self.isAppReady = YES; [self runAppReadyBlocks]; @@ -123,9 +109,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)runAppReadyBlocks { - OWSAssertIsOnMainThread(); - OWSAssertDebug(self.isAppReady); - NSArray *appWillBecomeReadyBlocks = [self.appWillBecomeReadyBlocks copy]; [self.appWillBecomeReadyBlocks removeAllObjects]; NSArray *appDidBecomeReadyBlocks = [self.appDidBecomeReadyBlocks copy]; diff --git a/SignalUtilitiesKit/DeviceSleepManager.swift b/SessionMessagingKit/Utilities/DeviceSleepManager.swift similarity index 93% rename from SignalUtilitiesKit/DeviceSleepManager.swift rename to SessionMessagingKit/Utilities/DeviceSleepManager.swift index 89211e010..05ee60834 100644 --- a/SignalUtilitiesKit/DeviceSleepManager.swift +++ b/SessionMessagingKit/Utilities/DeviceSleepManager.swift @@ -37,8 +37,6 @@ public class DeviceSleepManager: NSObject { private override init() { super.init() - SwiftSingletons.register(self) - NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: NSNotification.Name.OWSApplicationDidEnterBackground, @@ -51,15 +49,11 @@ public class DeviceSleepManager: NSObject { @objc private func didEnterBackground() { - AssertIsOnMainThread() - ensureSleepBlocking() } @objc public func addBlock(blockObject: NSObject) { - AssertIsOnMainThread() - blocks.append(SleepBlock(blockObject: blockObject)) ensureSleepBlocking() @@ -67,8 +61,6 @@ public class DeviceSleepManager: NSObject { @objc public func removeBlock(blockObject: NSObject) { - AssertIsOnMainThread() - blocks = blocks.filter { $0.blockObject != nil && $0.blockObject != blockObject } @@ -77,8 +69,6 @@ public class DeviceSleepManager: NSObject { } private func ensureSleepBlocking() { - AssertIsOnMainThread() - // Cull expired blocks. blocks = blocks.filter { $0.blockObject != nil diff --git a/SignalUtilitiesKit/Environment.h b/SessionMessagingKit/Utilities/Environment.h similarity index 100% rename from SignalUtilitiesKit/Environment.h rename to SessionMessagingKit/Utilities/Environment.h diff --git a/SignalUtilitiesKit/Environment.m b/SessionMessagingKit/Utilities/Environment.m similarity index 78% rename from SignalUtilitiesKit/Environment.m rename to SessionMessagingKit/Utilities/Environment.m index 2f282d3cc..e4abb4602 100644 --- a/SignalUtilitiesKit/Environment.m +++ b/SessionMessagingKit/Utilities/Environment.m @@ -1,8 +1,7 @@ #import -#import "SSKAsserts.h" #import "OWSWindowManager.h" -#import +#import #import "OWSPreferences.h" #import "OWSSounds.h" @@ -24,8 +23,6 @@ static Environment *sharedEnvironment = nil; + (Environment *)shared { - OWSAssertDebug(sharedEnvironment); - return sharedEnvironment; } @@ -35,8 +32,6 @@ static Environment *sharedEnvironment = nil; // // App extensions may be opened multiple times in the same process, // so statics will persist. - OWSAssertDebug(!sharedEnvironment || !CurrentAppContext().isMainApp); - OWSAssertDebug(environment); sharedEnvironment = environment; } @@ -58,20 +53,12 @@ static Environment *sharedEnvironment = nil; return self; } - OWSAssertDebug(audioSession); - OWSAssertDebug(preferences); - OWSAssertDebug(proximityMonitoringManager); - OWSAssertDebug(sounds); - OWSAssertDebug(windowManager); - _audioSession = audioSession; _preferences = preferences; _proximityMonitoringManager = proximityMonitoringManager; _sounds = sounds; _windowManager = windowManager; - OWSSingletonAssert(); - return self; } diff --git a/SignalUtilitiesKit/Utilities/OWSAudioPlayer.h b/SessionMessagingKit/Utilities/OWSAudioPlayer.h similarity index 93% rename from SignalUtilitiesKit/Utilities/OWSAudioPlayer.h rename to SessionMessagingKit/Utilities/OWSAudioPlayer.h index 698358425..5a9ccc2e9 100644 --- a/SignalUtilitiesKit/Utilities/OWSAudioPlayer.h +++ b/SessionMessagingKit/Utilities/OWSAudioPlayer.h @@ -2,6 +2,9 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +#import +#import + NS_ASSUME_NONNULL_BEGIN typedef NS_ENUM(NSInteger, AudioPlaybackState) { @@ -14,8 +17,8 @@ typedef NS_ENUM(NSInteger, AudioPlaybackState) { - (AudioPlaybackState)audioPlaybackState; - (void)setAudioPlaybackState:(AudioPlaybackState)state; - - (void)setAudioProgress:(CGFloat)progress duration:(CGFloat)duration; +- (void)showInvalidAudioFileAlert; @end diff --git a/SignalUtilitiesKit/Utilities/OWSAudioPlayer.m b/SessionMessagingKit/Utilities/OWSAudioPlayer.m similarity index 85% rename from SignalUtilitiesKit/Utilities/OWSAudioPlayer.m rename to SessionMessagingKit/Utilities/OWSAudioPlayer.m index 0b1a0aef1..740da5f6a 100644 --- a/SignalUtilitiesKit/Utilities/OWSAudioPlayer.m +++ b/SessionMessagingKit/Utilities/OWSAudioPlayer.m @@ -5,7 +5,8 @@ #import "OWSAudioPlayer.h" #import "TSAttachmentStream.h" #import -#import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -22,7 +23,12 @@ NS_ASSUME_NONNULL_BEGIN - (void)setAudioProgress:(CGFloat)progress duration:(CGFloat)duration { - // Do nothing; + // Do nothing +} + +- (void)showInvalidAudioFileAlert +{ + // Do nothing } @end @@ -57,13 +63,10 @@ NS_ASSUME_NONNULL_BEGIN return self; } - OWSAssertDebug(mediaUrl); - OWSAssertDebug(delegate); - _mediaUrl = mediaUrl; _delegate = delegate; - NSString *audioActivityDescription = [NSString stringWithFormat:@"%@ %@", self.logTag, self.mediaUrl]; + NSString *audioActivityDescription = [NSString stringWithFormat:@"%@ %@", @"OWSAudioPlayer", self.mediaUrl]; _audioActivity = [[OWSAudioActivity alloc] initWithAudioDescription:audioActivityDescription behavior:audioBehavior]; [[NSNotificationCenter defaultCenter] addObserver:self @@ -103,19 +106,12 @@ NS_ASSUME_NONNULL_BEGIN { // get current audio activity - OWSAssertIsOnMainThread(); [self playWithAudioActivity:self.audioActivity]; } - (void)playWithAudioActivity:(OWSAudioActivity *)audioActivity { - OWSAssertIsOnMainThread(); - BOOL success = [self.audioSession startAudioActivity:audioActivity]; - OWSAssertDebug(success); - - OWSAssertDebug(self.mediaUrl); - OWSAssertDebug([self.delegate audioPlaybackState] != AudioPlaybackState_Playing); [self.audioPlayerPoller invalidate]; @@ -125,14 +121,11 @@ NS_ASSUME_NONNULL_BEGIN NSError *error; self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.mediaUrl error:&error]; if (error) { - OWSLogError(@"error: %@", error); [self stop]; if ([error.domain isEqualToString:NSOSStatusErrorDomain] && (error.code == kAudioFileInvalidFileError || error.code == kAudioFileStreamError_InvalidFile)) { - [OWSAlerts - showErrorAlertWithMessage:NSLocalizedString(@"INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE", - @"Message for the alert indicating that an audio file is invalid.")]; + [self.delegate showInvalidAudioFileAlert]; } return; @@ -162,8 +155,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)pause { - OWSAssertIsOnMainThread(); - self.delegate.audioPlaybackState = AudioPlaybackState_Paused; [self.audioPlayer pause]; [self.audioPlayerPoller invalidate]; @@ -175,8 +166,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)stop { - OWSAssertIsOnMainThread(); - self.delegate.audioPlaybackState = AudioPlaybackState_Stopped; [self.audioPlayer pause]; [self.audioPlayerPoller invalidate]; @@ -193,8 +182,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)togglePlayState { - OWSAssertIsOnMainThread(); - if (self.delegate.audioPlaybackState == AudioPlaybackState_Playing) { [self pause]; } else { @@ -206,18 +193,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)audioPlayerUpdated:(NSTimer *)timer { - OWSAssertIsOnMainThread(); - - OWSAssertDebug(self.audioPlayer); - OWSAssertDebug(self.audioPlayerPoller); - [self.delegate setAudioProgress:(CGFloat)[self.audioPlayer currentTime] duration:(CGFloat)[self.audioPlayer duration]]; } - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { - OWSAssertIsOnMainThread(); - [self stop]; } diff --git a/SignalUtilitiesKit/Utilities/OWSAudioSession.swift b/SessionMessagingKit/Utilities/OWSAudioSession.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/OWSAudioSession.swift rename to SessionMessagingKit/Utilities/OWSAudioSession.swift diff --git a/SessionMessagingKit/Utilities/OWSIdentityManager.m b/SessionMessagingKit/Utilities/OWSIdentityManager.m index a2031410c..3158122c3 100644 --- a/SessionMessagingKit/Utilities/OWSIdentityManager.m +++ b/SessionMessagingKit/Utilities/OWSIdentityManager.m @@ -7,11 +7,10 @@ #import "AppReadiness.h" #import "NSNotificationCenter+OWS.h" #import "NotificationsProtocol.h" -#import "OWSError.h" #import "OWSFileSystem.h" -#import "OWSPrimaryStorage+SessionStore.h" #import "OWSPrimaryStorage.h" #import "OWSRecipientIdentity.h" +#import "OWSIdentityManager.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" #import "TSContactThread.h" @@ -23,8 +22,8 @@ #import #import #import +#import #import -#import "SSKAsserts.h" NS_ASSUME_NONNULL_BEGIN @@ -66,8 +65,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa + (instancetype)sharedManager { - OWSAssertDebug(SSKEnvironment.shared.identityManager); - return SSKEnvironment.shared.identityManager; } @@ -79,14 +76,10 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa return self; } - OWSAssertDebug(primaryStorage); - _primaryStorage = primaryStorage; _dbConnection = primaryStorage.newDatabaseConnection; self.dbConnection.objectCacheEnabled = NO; - OWSSingletonAssert(); - [self observeNotifications]; return self; @@ -130,8 +123,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext { - OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadTransaction class]]); - YapDatabaseReadTransaction *transaction = protocolContext; return [self identityKeyForRecipientId:recipientId transaction:transaction]; @@ -140,9 +131,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(transaction); - return [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId transaction:transaction].identityKey; } @@ -159,8 +147,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa // Whenever possible, prefer to call the strongly typed variant: `identityKeyPairWithTransaction:`. - (nullable ECKeyPair *)identityKeyPair:(nullable id)protocolContext { - OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadTransaction class]]); - YapDatabaseReadTransaction *transaction = protocolContext; return [self identityKeyPairWithTransaction:transaction]; @@ -168,8 +154,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (nullable ECKeyPair *)identityKeyPairWithTransaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(transaction); - ECKeyPair *_Nullable identityKeyPair = [transaction keyPairForKey:OWSPrimaryStorageIdentityKeyStoreIdentityKey inCollection:OWSPrimaryStorageIdentityKeyStoreCollection]; return identityKeyPair; @@ -177,8 +161,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (int)localRegistrationId:(nullable id)protocolContext { - OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); - YapDatabaseReadWriteTransaction *transaction = protocolContext; return (int)[TSAccountManager getOrGenerateRegistrationId:transaction]; @@ -186,9 +168,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId { - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - OWSAssertDebug(recipientId.length > 0); - __block BOOL result; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { result = [self saveRemoteIdentity:identityKey recipientId:recipientId protocolContext:transaction]; @@ -201,10 +180,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa recipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext { - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); - YapDatabaseReadWriteTransaction *transaction = protocolContext; // Deprecated. We actually no longer use the OWSPrimaryStorageTrustedKeysCollection for trust @@ -217,7 +192,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId transaction:transaction]; if (existingIdentity == nil) { - OWSLogInfo(@"saving first use identity for recipient: %@", recipientId); [[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId identityKey:identityKey isFirstKnownKey:YES @@ -242,18 +216,15 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa break; } - OWSLogInfo(@"replacing identity for existing recipient: %@ (%@ -> %@)", - recipientId, - OWSVerificationStateToString(existingIdentity.verificationState), - OWSVerificationStateToString(verificationState)); - [[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId identityKey:identityKey isFirstKnownKey:NO createdAt:[NSDate new] verificationState:verificationState] saveWithTransaction:transaction]; - [self.primaryStorage archiveAllSessionsForContact:recipientId protocolContext:protocolContext]; + // TODO TODO TODO + +// [self.primaryStorage archiveAllSessionsForContact:recipientId protocolContext:protocolContext]; [self fireIdentityStateChangeNotification]; @@ -265,8 +236,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (nullable OWSRecipientIdentity *)recipientIdentityForRecipientId:(NSString *)recipientId { - OWSAssertDebug(recipientId.length > 0); - __block OWSRecipientIdentity *_Nullable result; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { result = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId transaction:transaction]; @@ -276,8 +245,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (nullable OWSRecipientIdentity *)untrustedIdentityForSendingToRecipientId:(NSString *)recipientId { - OWSAssertDebug(recipientId.length > 0); - __block OWSRecipientIdentity *_Nullable result; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { OWSRecipientIdentity *_Nullable recipientIdentity = @@ -313,11 +280,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa direction:(TSMessageDirection)direction protocolContext:(nullable id)protocolContext { - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(direction != TSMessageDirectionUnknown); - OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); - YapDatabaseReadWriteTransaction *transaction = protocolContext; return [self isTrustedIdentityKey:identityKey recipientId:recipientId direction:direction transaction:transaction]; @@ -328,21 +290,12 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa direction:(TSMessageDirection)direction transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - OWSAssertDebug(recipientId.length > 0); - OWSAssertDebug(direction != TSMessageDirectionUnknown); - OWSAssertDebug(transaction); - if ([[TSAccountManager localNumber] isEqualToString:recipientId]) { ECKeyPair *_Nullable localIdentityKeyPair = [self identityKeyPairWithTransaction:transaction]; if ([localIdentityKeyPair.publicKey isEqualToData:identityKey]) { return YES; } else { - OWSFailDebug(@"Wrong identity: %@ for local key: %@, recipientId: %@", - identityKey, - localIdentityKeyPair.publicKey, - recipientId); return NO; } } @@ -357,7 +310,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa return [self isTrustedKey:identityKey forSendingToIdentity:existingIdentity]; } default: { - OWSFailDebug(@"unexpected message direction: %ld", (long)direction); return NO; } } @@ -365,15 +317,11 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (BOOL)isTrustedKey:(NSData *)identityKey forSendingToIdentity:(nullable OWSRecipientIdentity *)recipientIdentity { - OWSAssertDebug(identityKey.length == kStoredIdentityKeyLength); - if (recipientIdentity == nil) { return YES; } - OWSAssertDebug(recipientIdentity.identityKey.length == kStoredIdentityKeyLength); if (![recipientIdentity.identityKey isEqualToData:identityKey]) { - OWSLogWarn(@"key mismatch for recipient: %@", recipientIdentity.recipientId); return NO; } @@ -386,7 +334,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa BOOL isNew = (fabs([recipientIdentity.createdAt timeIntervalSinceNow]) < kIdentityKeyStoreNonBlockingSecondsThreshold); if (isNew) { - OWSLogWarn(@"not trusting new identity for recipient: %@", recipientIdentity.recipientId); return NO; } else { return YES; @@ -395,7 +342,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa case OWSVerificationStateVerified: return YES; case OWSVerificationStateNoLongerVerified: - OWSLogWarn(@"not trusting no longer verified identity for recipient: %@", recipientIdentity.recipientId); return NO; } } @@ -405,8 +351,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa #if DEBUG - (void)clearIdentityState:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - NSMutableArray *identityKeysToRemove = [NSMutableArray new]; [transaction enumerateKeysInCollection:OWSPrimaryStorageIdentityKeyStoreCollection usingBlock:^(NSString *_Nonnull key, BOOL *_Nonnull stop) { @@ -438,8 +382,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (void)snapshotIdentityState:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - [transaction snapshotCollection:OWSPrimaryStorageIdentityKeyStoreCollection snapshotFilePath:self.identityKeySnapshotFilePath]; [transaction snapshotCollection:OWSPrimaryStorageTrustedKeysCollection @@ -448,8 +390,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (void)restoreIdentityState:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - [transaction restoreSnapshotOfCollection:OWSPrimaryStorageIdentityKeyStoreCollection snapshotFilePath:self.identityKeySnapshotFilePath]; [transaction restoreSnapshotOfCollection:OWSPrimaryStorageTrustedKeysCollection diff --git a/SignalUtilitiesKit/OWSPreferences.h b/SessionMessagingKit/Utilities/OWSPreferences.h similarity index 98% rename from SignalUtilitiesKit/OWSPreferences.h rename to SessionMessagingKit/Utilities/OWSPreferences.h index a13ae4d1d..f69dbb286 100644 --- a/SignalUtilitiesKit/OWSPreferences.h +++ b/SessionMessagingKit/Utilities/OWSPreferences.h @@ -2,6 +2,8 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // +#import + NS_ASSUME_NONNULL_BEGIN /** diff --git a/SignalUtilitiesKit/OWSPreferences.m b/SessionMessagingKit/Utilities/OWSPreferences.m similarity index 90% rename from SignalUtilitiesKit/OWSPreferences.m rename to SessionMessagingKit/Utilities/OWSPreferences.m index 1b3fb3b5f..645b73a02 100644 --- a/SignalUtilitiesKit/OWSPreferences.m +++ b/SessionMessagingKit/Utilities/OWSPreferences.m @@ -3,16 +3,10 @@ // #import "OWSPreferences.h" -#import -#import -#import -#import #import -#import #import #import -#import -#import "SSKAsserts.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -30,7 +24,6 @@ NSString *NSStringForNotificationType(NotificationType value) NSString *const OWSPreferencesSignalDatabaseCollection = @"SignalPreferences"; NSString *const OWSPreferencesCallLoggingDidChangeNotification = @"OWSPreferencesCallLoggingDidChangeNotification"; - NSString *const OWSPreferencesKeyScreenSecurity = @"Screen Security Key"; NSString *const OWSPreferencesKeyEnableDebugLog = @"Debugging Log Enabled Key"; NSString *const OWSPreferencesKeyNotificationPreviewType = @"Notification Preview Type Key"; @@ -58,8 +51,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste return self; } - OWSSingletonAssert(); - return self; } @@ -72,10 +63,8 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (nullable id)tryGetValueForKey:(NSString *)key { - OWSAssertDebug(key != nil); - __block id result; - [OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) { result = [self tryGetValueForKey:key transaction:transaction]; }]; return result; @@ -83,7 +72,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (nullable id)tryGetValueForKey:(NSString *)key transaction:(YapDatabaseReadTransaction *)transaction { - OWSAssertDebug(key != nil); return [transaction objectForKey:key inCollection:OWSPreferencesSignalDatabaseCollection]; } @@ -98,8 +86,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste toValue:(nullable id)value transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(key != nil); - [transaction setObject:value forKey:key inCollection:OWSPreferencesSignalDatabaseCollection]; } @@ -118,8 +104,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste + (void)setIsReadyForAppExtensions { - OWSAssertDebug(CurrentAppContext().isMainApp); - [NSUserDefaults.appUserDefaults setObject:@(YES) forKey:OWSPreferencesKey_IsReadyForAppExtensions]; [NSUserDefaults.appUserDefaults synchronize]; } @@ -158,8 +142,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste + (void)setIsLoggingEnabled:(BOOL)flag { - OWSAssertDebug(CurrentAppContext().isMainApp); - // Logging preferences are stored in UserDefaults instead of the database, so that we can (optionally) start // logging before the database is initialized. This is important because sometimes there are problems *with* the // database initialization, and without logging it would be hard to track down. @@ -226,7 +208,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste if (@available(iOS 11, *)) { // do nothing } else { - OWSFailDebug(@"Call Logging can only be configured on iOS11+"); return NO; } @@ -239,7 +220,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste if (@available(iOS 11, *)) { // do nothing } else { - OWSFailDebug(@"Call Logging can only be configured on iOS11+"); return; } @@ -282,7 +262,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste } }(); - OWSLogInfo(@"Migrating setting - System Call Log Enabled: %d", shouldLogCallsInRecents); [self setValueForKey:OWSPreferencesKeySystemCallLogEnabled toValue:@(shouldLogCallsInRecents) transaction:transaction]; @@ -296,7 +275,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (BOOL)isCallKitEnabled { if (@available(iOS 11, *)) { - OWSFailDebug(@"CallKit is always enabled for iOS11+"); return YES; } @@ -307,7 +285,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (void)setIsCallKitEnabled:(BOOL)flag { if (@available(iOS 11, *)) { - OWSFailDebug(@"CallKit is always enabled for iOS11+"); return; } @@ -318,7 +295,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (BOOL)isCallKitEnabledSet { if (@available(iOS 11, *)) { - OWSFailDebug(@"CallKit is always enabled for iOS11+"); return NO; } @@ -329,7 +305,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (BOOL)isCallKitPrivacyEnabled { if (@available(iOS 11, *)) { - OWSFailDebug(@"CallKit privacy is irrelevant for iOS11+"); return NO; } @@ -345,7 +320,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (void)setIsCallKitPrivacyEnabled:(BOOL)flag { if (@available(iOS 11, *)) { - OWSFailDebug(@"CallKit privacy is irrelevant for iOS11+"); return; } @@ -355,7 +329,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (BOOL)isCallKitPrivacySet { if (@available(iOS 11, *)) { - OWSFailDebug(@"CallKit privacy is irrelevant for iOS11+"); return NO; } @@ -421,7 +394,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste case NotificationNoNameNoPreview: return NSLocalizedString(@"NOTIFICATIONS_NONE", nil); default: - OWSLogWarn(@"Undefined NotificationType in Settings"); return @""; } } @@ -450,7 +422,6 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (void)unsetRecordedAPNSTokens { - OWSLogWarn(@"Forgetting recorded APNS tokens"); [self setValueForKey:OWSPreferencesKeyLastRecordedPushToken toValue:nil]; [self setValueForKey:OWSPreferencesKeyLastRecordedVoipToken toValue:nil]; } diff --git a/SignalUtilitiesKit/OWSSounds.h b/SessionMessagingKit/Utilities/OWSSounds.h similarity index 96% rename from SignalUtilitiesKit/OWSSounds.h rename to SessionMessagingKit/Utilities/OWSSounds.h index e96c6a429..22e576ca6 100644 --- a/SignalUtilitiesKit/OWSSounds.h +++ b/SessionMessagingKit/Utilities/OWSSounds.h @@ -2,8 +2,9 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // -#import #import +#import +#import "OWSAudioPlayer.h" NS_ASSUME_NONNULL_BEGIN diff --git a/SignalUtilitiesKit/OWSSounds.m b/SessionMessagingKit/Utilities/OWSSounds.m similarity index 91% rename from SignalUtilitiesKit/OWSSounds.m rename to SessionMessagingKit/Utilities/OWSSounds.m index 59d5cca10..95b7edd20 100644 --- a/SignalUtilitiesKit/OWSSounds.m +++ b/SessionMessagingKit/Utilities/OWSSounds.m @@ -5,13 +5,11 @@ #import "OWSSounds.h" #import "Environment.h" #import "OWSAudioPlayer.h" -#import -#import +#import #import #import #import #import -#import "SSKAsserts.h" NSString *const kOWSSoundsStorageNotificationCollection = @"kOWSSoundsStorageNotificationCollection"; NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlobalNotificationKey"; @@ -36,13 +34,10 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob return self; } - OWSLogDebug(@"creating system sound for %@", url.lastPathComponent); _soundURL = url; SystemSoundID newSoundID; OSStatus status = AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &newSoundID); - OWSAssertDebug(status == kAudioServicesNoError); - OWSAssertDebug(newSoundID); _soundID = newSoundID; return self; @@ -50,9 +45,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob - (void)dealloc { - OWSLogDebug(@"in dealloc disposing sound: %@", _soundURL.lastPathComponent); OSStatus status = AudioServicesDisposeSystemSoundID(_soundID); - OWSAssertDebug(status == kAudioServicesNoError); } @end @@ -70,8 +63,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob + (instancetype)sharedManager { - OWSAssertDebug(Environment.shared.sounds); - return Environment.shared.sounds; } @@ -83,15 +74,11 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob return self; } - OWSAssertDebug(primaryStorage); - _dbConnection = primaryStorage.newDatabaseConnection; // Don't store too many sounds in memory. Most users will only use 1 or 2 sounds anyway. _cachedSystemSounds = [[AnyLRUCache alloc] initWithMaxSize:4]; - OWSSingletonAssert(); - return self; } @@ -121,7 +108,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob // TODO: Should we localize these sound names? switch (sound) { case OWSSound_Default: - OWSFailDebug(@"invalid argument."); return @""; // Notification Sounds @@ -183,7 +169,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob { switch (sound) { case OWSSound_Default: - OWSFailDebug(@"invalid argument."); return @""; // Notification Sounds @@ -244,7 +229,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob } NSURL *_Nullable url = [[NSBundle mainBundle] URLForResource:filename.stringByDeletingPathExtension withExtension:filename.pathExtension]; - OWSAssertDebug(url); return url; } @@ -259,7 +243,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob OWSSystemSound *_Nullable cachedSound = (OWSSystemSound *)[self.cachedSystemSounds getWithKey:cacheKey]; if (cachedSound) { - OWSAssertDebug([cachedSound isKindOfClass:[OWSSystemSound class]]); return cachedSound.soundID; } @@ -305,10 +288,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob - (void)setGlobalNotificationSound:(OWSSound)sound transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(transaction); - - OWSLogInfo(@"Setting global notification sound to: %@", [[self class] displayNameForSound:sound]); - // Fallback push notifications play a sound specified by the server, but we don't want to store this configuration // on the server. Instead, we create a file with the same name as the default to be played when receiving // a fallback notification. @@ -319,15 +298,12 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob NSString *kDefaultNotificationSoundFilename = @"NewMessage.aifc"; NSString *defaultSoundPath = [dirPath stringByAppendingPathComponent:kDefaultNotificationSoundFilename]; - OWSLogDebug(@"writing new default sound to %@", defaultSoundPath); - NSURL *_Nullable soundURL = [OWSSounds soundURLForSound:sound quiet:NO]; NSData *soundData = ^{ if (soundURL) { return [NSData dataWithContentsOfURL:soundURL]; } else { - OWSAssertDebug(sound == OWSSound_None); return [NSData new]; } }(); @@ -341,7 +317,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob [OWSFileSystem protectFileOrFolderAtPath:defaultSoundPath fileProtectionType:NSFileProtectionNone]; if (!success) { - OWSFailDebug(@"Unable to write new default sound data from: %@ to :%@", soundURL, defaultSoundPath); return; } diff --git a/SignalUtilitiesKit/UI/OWSWindowManager.h b/SessionMessagingKit/Utilities/OWSWindowManager.h similarity index 98% rename from SignalUtilitiesKit/UI/OWSWindowManager.h rename to SessionMessagingKit/Utilities/OWSWindowManager.h index 78195032b..a4aed979e 100644 --- a/SignalUtilitiesKit/UI/OWSWindowManager.h +++ b/SessionMessagingKit/Utilities/OWSWindowManager.h @@ -2,6 +2,8 @@ // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // +#import + NS_ASSUME_NONNULL_BEGIN extern NSString *const OWSWindowManagerCallDidChangeNotification; diff --git a/SignalUtilitiesKit/UI/OWSWindowManager.m b/SessionMessagingKit/Utilities/OWSWindowManager.m similarity index 83% rename from SignalUtilitiesKit/UI/OWSWindowManager.m rename to SessionMessagingKit/Utilities/OWSWindowManager.m index faf6a286e..9083d9fb4 100644 --- a/SignalUtilitiesKit/UI/OWSWindowManager.m +++ b/SessionMessagingKit/Utilities/OWSWindowManager.m @@ -3,11 +3,8 @@ // #import "OWSWindowManager.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import "AppContext.h" -#import +#import "Environment.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -156,8 +153,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) + (instancetype)sharedManager { - OWSAssertDebug(Environment.shared.windowManager); - return Environment.shared.windowManager; } @@ -169,20 +164,11 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) return self; } - OWSAssertIsOnMainThread(); - OWSSingletonAssert(); - return self; } - (void)setupWithRootWindow:(UIWindow *)rootWindow screenBlockingWindow:(UIWindow *)screenBlockingWindow { - OWSAssertIsOnMainThread(); - OWSAssertDebug(rootWindow); - OWSAssertDebug(!self.rootWindow); - OWSAssertDebug(screenBlockingWindow); - OWSAssertDebug(!self.screenBlockingWindow); - self.rootWindow = rootWindow; self.screenBlockingWindow = screenBlockingWindow; @@ -235,18 +221,15 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (UIWindow *)createCallViewWindow:(UIWindow *)rootWindow { - OWSAssertIsOnMainThread(); - OWSAssertDebug(rootWindow); - UIWindow *window = [[UIWindow alloc] initWithFrame:rootWindow.bounds]; window.hidden = YES; window.windowLevel = UIWindowLevel_CallView(); window.opaque = YES; // TODO: What's the right color to use here? - window.backgroundColor = [UIColor ows_materialBlueColor]; + window.backgroundColor = [UIColor blackColor]; UIViewController *viewController = [OWSWindowRootViewController new]; - viewController.view.backgroundColor = [UIColor ows_materialBlueColor]; + viewController.view.backgroundColor = [UIColor blackColor]; // NOTE: Do not use OWSNavigationController for call window. // It adjusts the size of the navigation bar to reflect the @@ -255,7 +238,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) OWSWindowRootNavigationViewController *navigationController = [[OWSWindowRootNavigationViewController alloc] initWithRootViewController:viewController]; navigationController.navigationBarHidden = YES; - OWSAssertDebug(!self.callNavigationController); self.callNavigationController = navigationController; window.rootViewController = navigationController; @@ -265,8 +247,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)setIsScreenBlockActive:(BOOL)isScreenBlockActive { - OWSAssertIsOnMainThread(); - _isScreenBlockActive = isScreenBlockActive; [self ensureWindowState]; @@ -278,8 +258,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (BOOL)isAppWindow:(UIWindow *)window { - OWSAssertDebug(window); - return (window == self.rootWindow || window == self.callViewWindow || window == self.menuActionsWindow || window == self.screenBlockingWindow); } @@ -293,8 +271,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)showMenuActionsWindow:(UIViewController *)menuActionsViewController { - OWSAssertDebug(self.menuActionsViewController == nil); - self.menuActionsViewController = menuActionsViewController; self.menuActionsWindow.rootViewController = menuActionsViewController; @@ -313,8 +289,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)setCallViewController:(nullable UIViewController *)callViewController { - OWSAssertIsOnMainThread(); - if (callViewController == _callViewController) { return; } @@ -326,10 +300,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)startCall:(UIViewController *)callViewController { - OWSAssertIsOnMainThread(); - OWSAssertDebug(callViewController); - OWSAssertDebug(!self.callViewController); - self.callViewController = callViewController; // Attach callViewController to window. @@ -344,12 +314,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)endCall:(UIViewController *)callViewController { - OWSAssertIsOnMainThread(); - OWSAssertDebug(callViewController); - OWSAssertDebug(self.callViewController); - if (self.callViewController != callViewController) { - OWSLogWarn(@"Ignoring end call request from obsolete call view controller."); return; } @@ -364,10 +329,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)leaveCallView { - OWSAssertIsOnMainThread(); - OWSAssertDebug(self.callViewController); - OWSAssertDebug(self.shouldShowCallView); - self.shouldShowCallView = NO; [self ensureWindowState]; @@ -375,10 +336,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)showCallView { - OWSAssertIsOnMainThread(); - OWSAssertDebug(self.callViewController); - OWSAssertDebug(!self.shouldShowCallView); - self.shouldShowCallView = YES; [self ensureWindowState]; @@ -386,8 +343,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (BOOL)hasCall { - OWSAssertIsOnMainThread(); - return self.callViewController != nil; } @@ -395,11 +350,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)ensureWindowState { - OWSAssertIsOnMainThread(); - OWSAssertDebug(self.rootWindow); - OWSAssertDebug(self.callViewWindow); - OWSAssertDebug(self.screenBlockingWindow); - // To avoid bad frames, we never want to hide the blocking window, so we manipulate // its window level to "hide" it behind other windows. The other windows have fixed // window level and are shown/hidden as necessary. @@ -430,9 +380,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) // Add "Message Actions" action sheet [self ensureMessageActionsWindowShown]; - - // Don't hide rootWindow so as not to dismiss keyboard. - OWSAssertDebug(!self.rootWindow.isHidden); } else { [self ensureMessageActionsWindowHidden]; } @@ -441,12 +388,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)ensureRootWindowShown { - OWSAssertIsOnMainThread(); - - if (self.rootWindow.hidden) { - OWSLogInfo(@"showing root window."); - } - // By calling makeKeyAndVisible we ensure the rootViewController becomes first responder. // In the normal case, that means the SignalViewController will call `becomeFirstResponder` // on the vc on top of its navigation stack. @@ -457,80 +398,38 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (void)ensureRootWindowHidden { - OWSAssertIsOnMainThread(); - - if (!self.rootWindow.hidden) { - OWSLogInfo(@"hiding root window."); - } - self.rootWindow.hidden = YES; } - (void)ensureCallViewWindowShown { - OWSAssertIsOnMainThread(); - - if (self.callViewWindow.hidden) { - OWSLogInfo(@"showing call window."); - } - [self.callViewWindow makeKeyAndVisible]; } - (void)ensureCallViewWindowHidden { - OWSAssertIsOnMainThread(); - - if (!self.callViewWindow.hidden) { - OWSLogInfo(@"hiding call window."); - } - self.callViewWindow.hidden = YES; } - (void)ensureMessageActionsWindowShown { - OWSAssertIsOnMainThread(); - - if (self.menuActionsWindow.hidden) { - OWSLogInfo(@"showing message actions window."); - } - // Do not make key, we want the keyboard to stay popped. self.menuActionsWindow.hidden = NO; } - (void)ensureMessageActionsWindowHidden { - OWSAssertIsOnMainThread(); - - if (!self.menuActionsWindow.hidden) { - OWSLogInfo(@"hiding message actions window."); - } - self.menuActionsWindow.hidden = YES; } - (void)ensureScreenBlockWindowShown { - OWSAssertIsOnMainThread(); - - if (self.screenBlockingWindow.windowLevel != UIWindowLevel_ScreenBlocking()) { - OWSLogInfo(@"showing block window."); - } - self.screenBlockingWindow.windowLevel = UIWindowLevel_ScreenBlocking(); [self.screenBlockingWindow makeKeyAndVisible]; } - (void)ensureScreenBlockWindowHidden { - OWSAssertIsOnMainThread(); - - if (self.screenBlockingWindow.windowLevel != UIWindowLevel_Background) { - OWSLogInfo(@"hiding block window."); - } - // Never hide the blocking window (that can lead to bad frames). // Instead, manipulate its window level to move it in front of // or behind the root window. @@ -586,13 +485,11 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) NSString *encodedSelectorString1 = @"egVaAAZ2BHdydHZSBwYBBAEGcgZ6AQBVegVyc312dQ=="; NSString *_Nullable selectorString1 = encodedSelectorString1.decodedForSelector; if (selectorString1 == nil) { - OWSFailDebug(@"selectorString1 was unexpectedly nil"); return; } SEL selector1 = NSSelectorFromString(selectorString1); if (![self.rootWindow respondsToSelector:selector1]) { - OWSFailDebug(@"failure: doesn't respond to selector1"); return; } IMP imp1 = [self.rootWindow methodForSelector:selector1]; @@ -600,8 +497,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) BOOL isDisabled = func1(self.rootWindow, selector1); if (isDisabled) { - OWSLogInfo(@"autorotation is disabled."); - // The remainder of this method calls: // [[UIScrollToDismissSupport supportForScreen:UIScreen.main] finishScrollViewTransition] // after verifying the methods/classes exist. @@ -610,12 +505,10 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) NSString *encodedKlassString = @"ZlpkdAQBfX1lAVV6BX56BQVkBwICAQQG"; NSString *_Nullable klassString = encodedKlassString.decodedForSelector; if (klassString == nil) { - OWSFailDebug(@"klassString was unexpectedly nil"); return; } id klass = NSClassFromString(klassString); if (klass == nil) { - OWSFailDebug(@"klass was unexpectedly nil"); return; } @@ -623,12 +516,10 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) NSString *encodedSelector2String = @"BQcCAgEEBlcBBGR0BHZ2AEs="; NSString *_Nullable selector2String = encodedSelector2String.decodedForSelector; if (selector2String == nil) { - OWSFailDebug(@"selector2String was unexpectedly nil"); return; } SEL selector2 = NSSelectorFromString(selector2String); if (![klass respondsToSelector:selector2]) { - OWSFailDebug(@"klass didn't respond to selector"); return; } IMP imp2 = [klass methodForSelector:selector2]; @@ -639,19 +530,15 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) NSString *encodedSelector3String = @"d3oAegV5ZHQEAX19Z3p2CWUEcgAFegZ6AQA="; NSString *_Nullable selector3String = encodedSelector3String.decodedForSelector; if (selector3String == nil) { - OWSFailDebug(@"selector3String was unexpectedly nil"); return; } SEL selector3 = NSSelectorFromString(selector3String); if (![dismissSupport respondsToSelector:selector3]) { - OWSFailDebug(@"dismissSupport didn't respond to selector"); return; } IMP imp3 = [dismissSupport methodForSelector:selector3]; void (*func3)(id, SEL) = (void *)imp3; func3(dismissSupport, selector3); - - OWSLogInfo(@"finished scrollView transition"); } } diff --git a/SignalUtilitiesKit/ProximityMonitoringManager.swift b/SessionMessagingKit/Utilities/ProximityMonitoringManager.swift similarity index 100% rename from SignalUtilitiesKit/ProximityMonitoringManager.swift rename to SessionMessagingKit/Utilities/ProximityMonitoringManager.swift diff --git a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h index 4299a4862..5b372672e 100644 --- a/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h +++ b/SessionShareExtension/Meta/SignalShareExtension-Bridging-Header.h @@ -12,15 +12,14 @@ #import #import #import -#import - -#import +#import +#import #import #import -#import +#import #import #import #import #import -#import +#import #import diff --git a/SessionShareExtension/ShareAppExtensionContext.m b/SessionShareExtension/ShareAppExtensionContext.m index be237eac7..52e3621df 100644 --- a/SessionShareExtension/ShareAppExtensionContext.m +++ b/SessionShareExtension/ShareAppExtensionContext.m @@ -7,6 +7,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h b/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h index 5f076cd3c..c4aca0f08 100644 --- a/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h +++ b/SessionUtilitiesKit/Meta/SessionUtilitiesKit.h @@ -11,10 +11,13 @@ FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[]; #import #import #import +#import #import #import #import +#import #import #import #import +#import diff --git a/SignalUtilitiesKit/Utilities/NSString+SSK.h b/SessionUtilitiesKit/NSString+SSK.h similarity index 85% rename from SignalUtilitiesKit/Utilities/NSString+SSK.h rename to SessionUtilitiesKit/NSString+SSK.h index 5f105ba13..48c43f466 100644 --- a/SignalUtilitiesKit/Utilities/NSString+SSK.h +++ b/SessionUtilitiesKit/NSString+SSK.h @@ -2,6 +2,8 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +#import + NS_ASSUME_NONNULL_BEGIN @interface NSString (SSK) diff --git a/SignalUtilitiesKit/Utilities/NSString+SSK.m b/SessionUtilitiesKit/NSString+SSK.m similarity index 84% rename from SignalUtilitiesKit/Utilities/NSString+SSK.m rename to SessionUtilitiesKit/NSString+SSK.m index 6f6ff0aa2..c69067838 100644 --- a/SignalUtilitiesKit/Utilities/NSString+SSK.m +++ b/SessionUtilitiesKit/NSString+SSK.m @@ -4,7 +4,6 @@ #import "NSString+SSK.h" #import "AppContext.h" -#import NS_ASSUME_NONNULL_BEGIN @@ -12,8 +11,6 @@ NS_ASSUME_NONNULL_BEGIN - (NSString *)rtlSafeAppend:(NSString *)string { - OWSAssertDebug(string); - if (CurrentAppContext().isRTL) { return [string stringByAppendingString:self]; } else { diff --git a/SignalUtilitiesKit/Utilities/OWSMath.h b/SessionUtilitiesKit/OWSMath.h similarity index 100% rename from SignalUtilitiesKit/Utilities/OWSMath.h rename to SessionUtilitiesKit/OWSMath.h diff --git a/SignalUtilitiesKit/Utilities/String+SSK.swift b/SessionUtilitiesKit/String+SSK.swift similarity index 87% rename from SignalUtilitiesKit/Utilities/String+SSK.swift rename to SessionUtilitiesKit/String+SSK.swift index e63f6e427..3d13c9180 100644 --- a/SignalUtilitiesKit/Utilities/String+SSK.swift +++ b/SessionUtilitiesKit/String+SSK.swift @@ -35,7 +35,6 @@ public extension String { func caesar(shift: UInt32) throws -> String { let shiftedScalars: [UnicodeScalar] = try unicodeScalars.map { c in guard let shiftedScalar = UnicodeScalar((c.value + shift) % 127) else { - owsFailDebug("invalidCharacterShift") throw StringError.invalidCharacterShift } return shiftedScalar @@ -45,12 +44,10 @@ public extension String { var encodedForSelector: String? { guard let shifted = try? self.caesar(shift: selectorOffset) else { - owsFailDebug("shifted was unexpectedly nil") return nil } guard let data = shifted.data(using: .utf8) else { - owsFailDebug("data was unexpectedly nil") return nil } @@ -59,12 +56,10 @@ public extension String { var decodedForSelector: String? { guard let data = Data(base64Encoded: self) else { - owsFailDebug("data was unexpectedly nil") return nil } guard let shifted = String(data: data, encoding: .utf8) else { - owsFailDebug("shifted was unexpectedly nil") return nil } diff --git a/SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift b/SessionUtilitiesKit/UIDevice+featureSupport.swift similarity index 97% rename from SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift rename to SessionUtilitiesKit/UIDevice+featureSupport.swift index 4ff5524a1..20d723e13 100644 --- a/SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift +++ b/SessionUtilitiesKit/UIDevice+featureSupport.swift @@ -6,6 +6,7 @@ import Foundation @objc public extension UIDevice { + var supportsCallKit: Bool { return ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 0)) } @@ -36,7 +37,6 @@ public extension UIDevice { return true default: // Verify all our IOS_DEVICE_CONSTANT tags make sense when adding a new device size. - owsFailDebug("unknown device format") return false } } diff --git a/SignalUtilitiesKit/UI/UIView+OWS.h b/SessionUtilitiesKit/UIView+OWS.h similarity index 95% rename from SignalUtilitiesKit/UI/UIView+OWS.h rename to SessionUtilitiesKit/UIView+OWS.h index 4b3dddf5c..738c9779b 100644 --- a/SignalUtilitiesKit/UI/UIView+OWS.h +++ b/SessionUtilitiesKit/UIView+OWS.h @@ -3,7 +3,6 @@ // #import -#import #import NS_ASSUME_NONNULL_BEGIN @@ -128,14 +127,6 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value); // Add red border to self, and all subviews recursively. - (void)addRedBorderRecursively; -#ifdef DEBUG -- (void)logFrame; -- (void)logFrameWithLabel:(NSString *)label; -- (void)logFrameLater; -- (void)logFrameLaterWithLabel:(NSString *)label; -- (void)logHierarchyUpwardLaterWithLabel:(NSString *)label; -#endif - @end #pragma mark - diff --git a/SignalUtilitiesKit/UI/UIView+OWS.m b/SessionUtilitiesKit/UIView+OWS.m similarity index 91% rename from SignalUtilitiesKit/UI/UIView+OWS.m rename to SessionUtilitiesKit/UIView+OWS.m index 79fe83339..d4d8ae493 100644 --- a/SignalUtilitiesKit/UI/UIView+OWS.m +++ b/SessionUtilitiesKit/UIView+OWS.m @@ -123,16 +123,12 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (void)autoPinWidthToWidthOfView:(UIView *)view { - OWSAssertDebug(view); - [self autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:view]; [self autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:view]; } - (void)autoPinHeightToHeightOfView:(UIView *)view { - OWSAssertDebug(view); - [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:view]; [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:view]; } @@ -155,9 +151,6 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) { // Clamp to ensure view has reasonable aspect ratio. CGFloat clampedRatio = CGFloatClamp(ratio, 0.05f, 95.0f); - if (clampedRatio != ratio) { - OWSFailDebug(@"Invalid aspect ratio: %f for view: %@", ratio, self); - } self.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self @@ -271,8 +264,6 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (void)centerOnSuperview { - OWSAssertDebug(self.superview); - CGFloat x = (CGFloat)round((self.superview.width - self.width) * 0.5f); CGFloat y = (CGFloat)round((self.superview.height - self.height) * 0.5f); self.frame = CGRectMake(x, y, self.width, self.height); @@ -342,15 +333,11 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (NSLayoutConstraint *)autoPinLeadingToTrailingEdgeOfView:(UIView *)view { - OWSAssertDebug(view); - return [self autoPinLeadingToTrailingEdgeOfView:view offset:0]; } - (NSLayoutConstraint *)autoPinLeadingToTrailingEdgeOfView:(UIView *)view offset:(CGFloat)offset { - OWSAssertDebug(view); - self.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *constraint = [self.leadingAnchor constraintEqualToAnchor:view.trailingAnchor constant:offset]; @@ -360,15 +347,11 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (NSLayoutConstraint *)autoPinTrailingToLeadingEdgeOfView:(UIView *)view { - OWSAssertDebug(view); - return [self autoPinTrailingToLeadingEdgeOfView:view offset:0]; } - (NSLayoutConstraint *)autoPinTrailingToLeadingEdgeOfView:(UIView *)view offset:(CGFloat)offset { - OWSAssertDebug(view); - self.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *constraint = [self.trailingAnchor constraintEqualToAnchor:view.leadingAnchor constant:-offset]; @@ -378,15 +361,11 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (NSLayoutConstraint *)autoPinLeadingToEdgeOfView:(UIView *)view { - OWSAssertDebug(view); - return [self autoPinLeadingToEdgeOfView:view offset:0]; } - (NSLayoutConstraint *)autoPinLeadingToEdgeOfView:(UIView *)view offset:(CGFloat)offset { - OWSAssertDebug(view); - self.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *constraint = [self.leadingAnchor constraintEqualToAnchor:view.leadingAnchor constant:offset]; @@ -396,15 +375,11 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (NSLayoutConstraint *)autoPinTrailingToEdgeOfView:(UIView *)view { - OWSAssertDebug(view); - return [self autoPinTrailingToEdgeOfView:view offset:0]; } - (NSLayoutConstraint *)autoPinTrailingToEdgeOfView:(UIView *)view offset:(CGFloat)margin { - OWSAssertDebug(view); - self.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *constraint = [self.trailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margin]; @@ -427,8 +402,6 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (NSArray *)autoPinToEdgesOfView:(UIView *)view { - OWSAssertDebug(view); - return @[ [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:view], [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:view], @@ -487,54 +460,8 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) } } -- (void)logFrame -{ - [self logFrameWithLabel:@""]; -} - -- (void)logFrameWithLabel:(NSString *)label -{ - OWSLogVerbose(@"%@ frame: %@, hidden: %d, opacity: %f, layoutMargins: %@", - label, - NSStringFromCGRect(self.frame), - self.hidden, - self.layer.opacity, - NSStringFromUIEdgeInsets(self.layoutMargins)); -} - -- (void)logFrameLater -{ - [self logFrameLaterWithLabel:@""]; -} - -- (void)logFrameLaterWithLabel:(NSString *)label -{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self logFrameWithLabel:label]; - }); -} - -- (void)logHierarchyUpwardLaterWithLabel:(NSString *)label -{ - dispatch_async(dispatch_get_main_queue(), ^{ - OWSLogVerbose(@"%@ ----", label); - }); - - UIResponder *responder = self; - while (responder) { - if ([responder isKindOfClass:[UIView class]]) { - UIView *view = (UIView *)responder; - [view logFrameLaterWithLabel:@"\t"]; - } - responder = responder.nextResponder; - } -} - - (void)traverseViewHierarchyWithVisitor:(UIViewVisitorBlock)visitor { - OWSAssertIsOnMainThread(); - OWSAssertDebug(visitor); - visitor(self); for (UIView *subview in self.subviews) { diff --git a/SignalUtilitiesKit/Utilities/Weak.swift b/SessionUtilitiesKit/Weak.swift similarity index 100% rename from SignalUtilitiesKit/Utilities/Weak.swift rename to SessionUtilitiesKit/Weak.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 4d2f02407..422377e07 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -246,6 +246,31 @@ B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; B879D449247E1BE300DB3608 /* PathVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B879D448247E1BE300DB3608 /* PathVC.swift */; }; + B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; }; + B8856CB1256F0F47001CE70E /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */; }; + B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */; }; + B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF281255B6D84007E1867 /* OWSAudioSession.swift */; }; + B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */; }; + B8856D23256F116B001CE70E /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EF255B6DBB007E1867 /* Weak.swift */; }; + B8856D34256F1192001CE70E /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = C37F5402255BA9ED002AEA92 /* Environment.m */; }; + B8856D3D256F11B2001CE70E /* Environment.h in Headers */ = {isa = PBXBuildFile; fileRef = C37F53E8255BA9BB002AEA92 /* Environment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856D60256F129B001CE70E /* OWSAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8856D5F256F129B001CE70E /* OWSAlerts.swift */; }; + B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF306255B6DBE007E1867 /* OWSWindowManager.m */; }; + B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856D7B256F14F4001CE70E /* UIView+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF23E255B6D66007E1867 /* UIView+OWS.m */; }; + B8856D8D256F1502001CE70E /* UIView+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF23D255B6D66007E1867 /* UIView+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3F255A580C00E217F9 /* String+SSK.swift */; }; + B8856DEF256F161F001CE70E /* NSString+SSK.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB45255A580C00E217F9 /* NSString+SSK.m */; }; + B8856DF8256F1633001CE70E /* NSString+SSK.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB12255A580800E217F9 /* NSString+SSK.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856E09256F1676001CE70E /* UIDevice+featureSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */; }; + B8856E1A256F1700001CE70E /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856E94256F1C37001CE70E /* OWSSounds.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF28B255B6D86007E1867 /* OWSSounds.m */; }; + B8856E9D256F1C3D001CE70E /* OWSSounds.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF288255B6D85007E1867 /* OWSSounds.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B8856ECE256F1E58001CE70E /* OWSPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF308255B6DBE007E1867 /* OWSPreferences.m */; }; + B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; }; B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A62398B23E00211ABE /* QRCodeVC.swift */; }; B886B4A92398BA1500211ABE /* QRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A82398BA1500211ABE /* QRCode.swift */; }; B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */; }; @@ -260,8 +285,6 @@ B8CCF63723961D6D0091D419 /* NewPrivateChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */; }; B8CCF63F23975CFB0091D419 /* JoinPublicChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */; }; B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CCF6422397711F0091D419 /* SettingsVC.swift */; }; - B8D797B2256B25A1007C59DF /* TSAttachmentPointer+Backups.m in Sources */ = {isa = PBXBuildFile; fileRef = B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */; }; - B8D797C3256B25A8007C59DF /* TSAttachmentPointer+Backups.h in Headers */ = {isa = PBXBuildFile; fileRef = B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */; settings = {ATTRIBUTES = (Public, ); }; }; B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; }; B9EB5ABD1884C002007CBB57 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EB5ABC1884C002007CBB57 /* MessageUI.framework */; }; C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */; }; @@ -441,7 +464,6 @@ C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA7255A57FF00E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAAA255A580000E217F9 /* NSObject+Casting.m */; }; C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */; }; - C33FDC73255A582000E217F9 /* OWSStorage+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC75255A582000E217F9 /* OWSGroupsOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDABB255A580100E217F9 /* OWSGroupsOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDC78255A582000E217F9 /* TSConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDABE255A580100E217F9 /* TSConstants.m */; }; C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC1255A580100E217F9 /* NSSet+Functional.m */; }; @@ -455,23 +477,17 @@ C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE0255A580400E217F9 /* ByteParser.m */; }; C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA3255A582000E217F9 /* SSKMessageSenderJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE9255A580500E217F9 /* SSKMessageSenderJobRecord.m */; }; - C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAED255A580500E217F9 /* SSKMessageSenderJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCAD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF3255A580500E217F9 /* OWSPrimaryStorage+SessionStore.m */; }; C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */; }; C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB03255A580700E217F9 /* OWSPrimaryStorage+SessionStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; }; C33FDCC3255A582000E217F9 /* NSError+MessageSending.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB09255A580700E217F9 /* NSError+MessageSending.m */; }; C33FDCC7255A582000E217F9 /* NSArray+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB0D255A580800E217F9 /* NSArray+OWS.m */; }; C33FDCC8255A582000E217F9 /* NSError+MessageSending.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0E255A580800E217F9 /* NSError+MessageSending.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCCC255A582000E217F9 /* NSString+SSK.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB12255A580800E217F9 /* NSString+SSK.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB17255A580800E217F9 /* FunctionalUtil.m */; }; C33FDCD3255A582000E217F9 /* GroupUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB19255A580900E217F9 /* GroupUtilities.swift */; }; - C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB3F255A580C00E217F9 /* String+SSK.swift */; }; C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */; }; C33FDCFE255A582000E217F9 /* OWSContactsOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB44255A580C00E217F9 /* OWSContactsOutputStream.m */; }; - C33FDCFF255A582000E217F9 /* NSString+SSK.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB45255A580C00E217F9 /* NSString+SSK.m */; }; C33FDD01255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB47255A580C00E217F9 /* OWSPrimaryStorage+PreKeyStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB49255A580C00E217F9 /* WeakTimer.swift */; }; C33FDD05255A582000E217F9 /* OWSChunkedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */; }; @@ -555,9 +571,6 @@ C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */; }; C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C37F53A7255B96E0002AEA92 /* OWSAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C37F53E9255BA9CE002AEA92 /* Environment.h in Headers */ = {isa = PBXBuildFile; fileRef = C37F53E8255BA9BB002AEA92 /* Environment.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C37F5403255BA9ED002AEA92 /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = C37F5402255BA9ED002AEA92 /* Environment.m */; }; C37F5414255BAFA7002AEA92 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C37F54B9255BB2D4002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54BA255BB2D8002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; @@ -572,14 +585,11 @@ C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */; }; C38EF22C255B6D5D007E1867 /* OWSVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */; }; C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF236255B6D65007E1867 /* UIViewController+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF244255B6D67007E1867 /* UIDevice+featureSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */; }; C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF238255B6D66007E1867 /* UIFont+OWS.m */; }; C38EF246255B6D67007E1867 /* UIFont+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF239255B6D66007E1867 /* UIFont+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */; }; C38EF248255B6D67007E1867 /* UIViewController+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */; }; C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF23C255B6D66007E1867 /* UIColor+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF24A255B6D67007E1867 /* UIView+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF23D255B6D66007E1867 /* UIView+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF24B255B6D67007E1867 /* UIView+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF23E255B6D66007E1867 /* UIView+OWS.m */; }; C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF240255B6D67007E1867 /* UIView+OWS.swift */; }; C38EF24E255B6D67007E1867 /* Collection+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF241255B6D67007E1867 /* Collection+OWS.swift */; }; @@ -590,15 +600,12 @@ C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF276255B6D7A007E1867 /* OWSDatabaseMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */; }; C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF28D255B6D86007E1867 /* OWSAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF281255B6D84007E1867 /* OWSAudioSession.swift */; }; C38EF28E255B6D86007E1867 /* SignalKeyingStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */; }; C38EF28F255B6D86007E1867 /* VersionMigrations.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF283255B6D84007E1867 /* VersionMigrations.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF290255B6D86007E1867 /* AppSetup.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF284255B6D84007E1867 /* AppSetup.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF291255B6D86007E1867 /* SignalKeyingStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF286255B6D85007E1867 /* VersionMigrations.m */; }; C38EF293255B6D86007E1867 /* AppSetup.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF287255B6D85007E1867 /* AppSetup.m */; }; - C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF288255B6D85007E1867 /* OWSSounds.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF297255B6D86007E1867 /* OWSSounds.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF28B255B6D86007E1867 /* OWSSounds.m */; }; C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */; }; C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */; }; C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */; }; @@ -615,18 +622,13 @@ C38EF310255B6DBF007E1867 /* DebugLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E6255B6DBA007E1867 /* DebugLogger.m */; }; C38EF311255B6DBF007E1867 /* OWSScrubbingLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF313255B6DBF007E1867 /* OWSUnreadIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF316255B6DBF007E1867 /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */; }; C38EF317255B6DBF007E1867 /* DisplayableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2ED255B6DBB007E1867 /* DisplayableText.swift */; }; - C38EF319255B6DBF007E1867 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EF255B6DBB007E1867 /* Weak.swift */; }; C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */; }; - C38EF31B255B6DBF007E1867 /* OWSPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F2255B6DBC007E1867 /* Searcher.swift */; }; C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */; }; C38EF320255B6DBF007E1867 /* OWSScrubbingLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */; }; - C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */; }; C38EF322255B6DBF007E1867 /* DebugLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F8255B6DBC007E1867 /* DebugLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF324255B6DBF007E1867 /* Bench.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FA255B6DBD007E1867 /* Bench.swift */; }; - C38EF325255B6DBF007E1867 /* OWSWindowManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF326255B6DBF007E1867 /* ConversationStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */; }; C38EF327255B6DBF007E1867 /* BlockListUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */; }; C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF300255B6DBD007E1867 /* UIUtil.m */; }; @@ -634,10 +636,7 @@ C38EF32D255B6DBF007E1867 /* BlockListUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF304255B6DBE007E1867 /* ImageCache.swift */; }; C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF305255B6DBE007E1867 /* OWSFormat.m */; }; - C38EF330255B6DBF007E1867 /* OWSWindowManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF306255B6DBE007E1867 /* OWSWindowManager.m */; }; C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */; }; - C38EF332255B6DBF007E1867 /* OWSPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF308255B6DBE007E1867 /* OWSPreferences.m */; }; - C38EF333255B6DBF007E1867 /* DeviceSleepManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */; }; C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF30A255B6DBE007E1867 /* UIUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF335255B6DBF007E1867 /* BlockListCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF30B255B6DBE007E1867 /* BlockListCache.swift */; }; C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF33F255B6DC5007E1867 /* SheetViewController.swift */; }; @@ -703,7 +702,6 @@ C38EF403255B6DF7007E1867 /* ContactCellView.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF3E5255B6DF4007E1867 /* ContactCellView.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF404255B6DF7007E1867 /* ContactTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E7255B6DF5007E1867 /* OWSButton.swift */; }; - C38EF406255B6DF7007E1867 /* OWSAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */; }; C38EF407255B6DF7007E1867 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E9255B6DF6007E1867 /* Toast.swift */; }; C38EF408255B6DF7007E1867 /* OWSSearchBar.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */; }; C38EF409255B6DF7007E1867 /* ContactTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */; }; @@ -1355,6 +1353,7 @@ B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; B879D448247E1BE300DB3608 /* PathVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathVC.swift; sourceTree = ""; }; B879D44A247E1D9200DB3608 /* PathStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathStatusView.swift; sourceTree = ""; }; + B8856D5F256F129B001CE70E /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSAlerts.swift; sourceTree = ""; }; B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraints.swift"; sourceTree = ""; }; B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = ""; }; B886B4A82398BA1500211ABE /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = ""; }; @@ -1381,8 +1380,6 @@ B8CCF638239721E20091D419 /* TabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = ""; }; B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinPublicChatVC.swift; sourceTree = ""; }; B8CCF6422397711F0091D419 /* SettingsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsVC.swift; sourceTree = ""; }; - B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TSAttachmentPointer+Backups.h"; sourceTree = ""; }; - B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "TSAttachmentPointer+Backups.m"; sourceTree = ""; }; B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = ""; }; B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Jobs.swift"; sourceTree = ""; }; B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = ""; }; @@ -1693,14 +1690,14 @@ C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewDelegate.swift; path = SignalUtilitiesKit/Utilities/ShareViewDelegate.swift; sourceTree = SOURCE_ROOT; }; C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSVideoPlayer.swift; path = SignalUtilitiesKit/Utilities/OWSVideoPlayer.swift; sourceTree = SOURCE_ROOT; }; C38EF236255B6D65007E1867 /* UIViewController+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+OWS.h"; path = "SignalUtilitiesKit/UI/UIViewController+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIDevice+featureSupport.swift"; path = "SignalUtilitiesKit/Utilities/UIDevice+featureSupport.swift"; sourceTree = SOURCE_ROOT; }; + C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIDevice+featureSupport.swift"; path = "SessionUtilitiesKit/UIDevice+featureSupport.swift"; sourceTree = SOURCE_ROOT; }; C38EF238255B6D66007E1867 /* UIFont+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIFont+OWS.m"; path = "SignalUtilitiesKit/UI/UIFont+OWS.m"; sourceTree = SOURCE_ROOT; }; C38EF239255B6D66007E1867 /* UIFont+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIFont+OWS.h"; path = "SignalUtilitiesKit/UI/UIFont+OWS.h"; sourceTree = SOURCE_ROOT; }; C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributedString+OWS.m"; path = "SignalUtilitiesKit/Utilities/NSAttributedString+OWS.m"; sourceTree = SOURCE_ROOT; }; C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+OWS.m"; path = "SignalUtilitiesKit/UI/UIViewController+OWS.m"; sourceTree = SOURCE_ROOT; }; C38EF23C255B6D66007E1867 /* UIColor+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIColor+OWS.h"; path = "SignalUtilitiesKit/UI/UIColor+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF23D255B6D66007E1867 /* UIView+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+OWS.h"; path = "SignalUtilitiesKit/UI/UIView+OWS.h"; sourceTree = SOURCE_ROOT; }; - C38EF23E255B6D66007E1867 /* UIView+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+OWS.m"; path = "SignalUtilitiesKit/UI/UIView+OWS.m"; sourceTree = SOURCE_ROOT; }; + C38EF23D255B6D66007E1867 /* UIView+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+OWS.h"; path = "SessionUtilitiesKit/UIView+OWS.h"; sourceTree = SOURCE_ROOT; }; + C38EF23E255B6D66007E1867 /* UIView+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+OWS.m"; path = "SessionUtilitiesKit/UIView+OWS.m"; sourceTree = SOURCE_ROOT; }; C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSAttributedString+OWS.h"; path = "SignalUtilitiesKit/Utilities/NSAttributedString+OWS.h"; sourceTree = SOURCE_ROOT; }; C38EF240255B6D67007E1867 /* UIView+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+OWS.swift"; path = "SignalUtilitiesKit/UI/UIView+OWS.swift"; sourceTree = SOURCE_ROOT; }; C38EF241255B6D67007E1867 /* Collection+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Collection+OWS.swift"; path = "SignalUtilitiesKit/Utilities/Collection+OWS.swift"; sourceTree = SOURCE_ROOT; }; @@ -1711,15 +1708,15 @@ C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigrationRunner.h; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.h; sourceTree = SOURCE_ROOT; }; C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/Migration/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; - C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SignalUtilitiesKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; + C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SessionMessagingKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalKeyingStorage.m; path = SignalUtilitiesKit/Database/SignalKeyingStorage.m; sourceTree = SOURCE_ROOT; }; C38EF283255B6D84007E1867 /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VersionMigrations.h; path = SignalUtilitiesKit/VersionMigrations.h; sourceTree = SOURCE_ROOT; }; C38EF284255B6D84007E1867 /* AppSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppSetup.h; path = SignalUtilitiesKit/AppSetup.h; sourceTree = SOURCE_ROOT; }; C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalKeyingStorage.h; path = SignalUtilitiesKit/Database/SignalKeyingStorage.h; sourceTree = SOURCE_ROOT; }; C38EF286255B6D85007E1867 /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VersionMigrations.m; path = SignalUtilitiesKit/VersionMigrations.m; sourceTree = SOURCE_ROOT; }; C38EF287255B6D85007E1867 /* AppSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppSetup.m; path = SignalUtilitiesKit/AppSetup.m; sourceTree = SOURCE_ROOT; }; - C38EF288255B6D85007E1867 /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSounds.h; path = SignalUtilitiesKit/OWSSounds.h; sourceTree = SOURCE_ROOT; }; - C38EF28B255B6D86007E1867 /* OWSSounds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSounds.m; path = SignalUtilitiesKit/OWSSounds.m; sourceTree = SOURCE_ROOT; }; + C38EF288255B6D85007E1867 /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSSounds.h; path = SessionMessagingKit/Utilities/OWSSounds.h; sourceTree = SOURCE_ROOT; }; + C38EF28B255B6D86007E1867 /* OWSSounds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSounds.m; path = SessionMessagingKit/Utilities/OWSSounds.m; sourceTree = SOURCE_ROOT; }; C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Identicon+ObjC.swift"; path = "SignalUtilitiesKit/UI/Identicon+ObjC.swift"; sourceTree = SOURCE_ROOT; }; C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = SignalUtilitiesKit/UI/PlaceholderIcon.swift; sourceTree = SOURCE_ROOT; }; C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SignalUtilitiesKit/UI/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; }; @@ -1738,19 +1735,19 @@ C38EF2E6255B6DBA007E1867 /* DebugLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DebugLogger.m; path = SignalUtilitiesKit/Utilities/DebugLogger.m; sourceTree = SOURCE_ROOT; }; C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSScrubbingLogFormatter.h; path = SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.h; sourceTree = SOURCE_ROOT; }; C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUnreadIndicator.h; path = SignalUtilitiesKit/OWSUnreadIndicator.h; sourceTree = SOURCE_ROOT; }; - C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProximityMonitoringManager.swift; path = SignalUtilitiesKit/ProximityMonitoringManager.swift; sourceTree = SOURCE_ROOT; }; + C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProximityMonitoringManager.swift; path = SessionMessagingKit/Utilities/ProximityMonitoringManager.swift; sourceTree = SOURCE_ROOT; }; C38EF2ED255B6DBB007E1867 /* DisplayableText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DisplayableText.swift; path = SignalUtilitiesKit/UI/DisplayableText.swift; sourceTree = SOURCE_ROOT; }; - C38EF2EF255B6DBB007E1867 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SignalUtilitiesKit/Utilities/Weak.swift; sourceTree = SOURCE_ROOT; }; + C38EF2EF255B6DBB007E1867 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SessionUtilitiesKit/Weak.swift; sourceTree = SOURCE_ROOT; }; C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAnyTouchGestureRecognizer.m; path = SignalUtilitiesKit/UI/OWSAnyTouchGestureRecognizer.m; sourceTree = SOURCE_ROOT; }; - C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSPreferences.h; path = SignalUtilitiesKit/OWSPreferences.h; sourceTree = SOURCE_ROOT; }; + C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSPreferences.h; path = SessionMessagingKit/Utilities/OWSPreferences.h; sourceTree = SOURCE_ROOT; }; C38EF2F2255B6DBC007E1867 /* Searcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Searcher.swift; path = SignalUtilitiesKit/Searcher.swift; sourceTree = SOURCE_ROOT; }; C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+OWS.swift"; path = "SignalUtilitiesKit/UI/UIImage+OWS.swift"; sourceTree = SOURCE_ROOT; }; - C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SignalUtilitiesKit/Utilities/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; }; + C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SessionMessagingKit/Utilities/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; }; C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSScrubbingLogFormatter.m; path = SignalUtilitiesKit/Utilities/OWSScrubbingLogFormatter.m; sourceTree = SOURCE_ROOT; }; - C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAudioPlayer.m; path = SignalUtilitiesKit/Utilities/OWSAudioPlayer.m; sourceTree = SOURCE_ROOT; }; + C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAudioPlayer.m; path = SessionMessagingKit/Utilities/OWSAudioPlayer.m; sourceTree = SOURCE_ROOT; }; C38EF2F8255B6DBC007E1867 /* DebugLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebugLogger.h; path = SignalUtilitiesKit/Utilities/DebugLogger.h; sourceTree = SOURCE_ROOT; }; C38EF2FA255B6DBD007E1867 /* Bench.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bench.swift; path = SignalUtilitiesKit/Utilities/Bench.swift; sourceTree = SOURCE_ROOT; }; - C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSWindowManager.h; path = SignalUtilitiesKit/UI/OWSWindowManager.h; sourceTree = SOURCE_ROOT; }; + C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSWindowManager.h; path = SessionMessagingKit/Utilities/OWSWindowManager.h; sourceTree = SOURCE_ROOT; }; C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationStyle.swift; path = SignalUtilitiesKit/UI/ConversationStyle.swift; sourceTree = SOURCE_ROOT; }; C38EF2FD255B6DBD007E1867 /* BlockListUIUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BlockListUIUtils.m; path = SignalUtilitiesKit/UI/BlockListUIUtils.m; sourceTree = SOURCE_ROOT; }; C38EF300255B6DBD007E1867 /* UIUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UIUtil.m; path = SignalUtilitiesKit/UI/UIUtil.m; sourceTree = SOURCE_ROOT; }; @@ -1759,10 +1756,10 @@ C38EF303255B6DBE007E1867 /* BlockListUIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlockListUIUtils.h; path = SignalUtilitiesKit/UI/BlockListUIUtils.h; sourceTree = SOURCE_ROOT; }; C38EF304255B6DBE007E1867 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = SignalUtilitiesKit/ImageCache.swift; sourceTree = SOURCE_ROOT; }; C38EF305255B6DBE007E1867 /* OWSFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSFormat.m; path = SignalUtilitiesKit/Utilities/OWSFormat.m; sourceTree = SOURCE_ROOT; }; - C38EF306255B6DBE007E1867 /* OWSWindowManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSWindowManager.m; path = SignalUtilitiesKit/UI/OWSWindowManager.m; sourceTree = SOURCE_ROOT; }; + C38EF306255B6DBE007E1867 /* OWSWindowManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSWindowManager.m; path = SessionMessagingKit/Utilities/OWSWindowManager.m; sourceTree = SOURCE_ROOT; }; C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+OWS.swift"; path = "SignalUtilitiesKit/UI/UIGestureRecognizer+OWS.swift"; sourceTree = SOURCE_ROOT; }; - C38EF308255B6DBE007E1867 /* OWSPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSPreferences.m; path = SignalUtilitiesKit/OWSPreferences.m; sourceTree = SOURCE_ROOT; }; - C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceSleepManager.swift; path = SignalUtilitiesKit/DeviceSleepManager.swift; sourceTree = SOURCE_ROOT; }; + C38EF308255B6DBE007E1867 /* OWSPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSPreferences.m; path = SessionMessagingKit/Utilities/OWSPreferences.m; sourceTree = SOURCE_ROOT; }; + C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceSleepManager.swift; path = SessionMessagingKit/Utilities/DeviceSleepManager.swift; sourceTree = SOURCE_ROOT; }; C38EF30A255B6DBE007E1867 /* UIUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UIUtil.h; path = SignalUtilitiesKit/UI/UIUtil.h; sourceTree = SOURCE_ROOT; }; C38EF30B255B6DBE007E1867 /* BlockListCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockListCache.swift; path = SignalUtilitiesKit/BlockListCache.swift; sourceTree = SOURCE_ROOT; }; C38EF33F255B6DC5007E1867 /* SheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SheetViewController.swift; path = SignalUtilitiesKit/UI/SheetViewController.swift; sourceTree = SOURCE_ROOT; }; @@ -1831,7 +1828,6 @@ C38EF3E5255B6DF4007E1867 /* ContactCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactCellView.h; path = "SignalUtilitiesKit/To Do/ContactCellView.h"; sourceTree = SOURCE_ROOT; }; C38EF3E6255B6DF4007E1867 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactTableViewCell.h; path = "SignalUtilitiesKit/To Do/ContactTableViewCell.h"; sourceTree = SOURCE_ROOT; }; C38EF3E7255B6DF5007E1867 /* OWSButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSButton.swift; path = SignalUtilitiesKit/UI/OWSButton.swift; sourceTree = SOURCE_ROOT; }; - C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAlerts.swift; path = SignalUtilitiesKit/UI/OWSAlerts.swift; sourceTree = SOURCE_ROOT; }; C38EF3E9255B6DF6007E1867 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = SignalUtilitiesKit/UI/Toast.swift; sourceTree = SOURCE_ROOT; }; C38EF3EA255B6DF6007E1867 /* OWSSearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSSearchBar.m; path = SignalUtilitiesKit/UI/OWSSearchBar.m; sourceTree = SOURCE_ROOT; }; C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactTableViewCell.m; path = "SignalUtilitiesKit/To Do/ContactTableViewCell.m"; sourceTree = SOURCE_ROOT; }; @@ -2835,9 +2831,12 @@ C32C5BCB256DC818003C73A2 /* Database */ = { isa = PBXGroup; children = ( + C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */, + C33FDB07255A580700E217F9 /* OWSBackupFragment.m */, C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */, C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */, C33FDAFE255A580600E217F9 /* OWSStorage.h */, + C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, C33FDAB1255A580000E217F9 /* OWSStorage.m */, B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */, B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */, @@ -2950,23 +2949,18 @@ C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */, C38EF2E5255B6DB9007E1867 /* AppPreferences.swift */, C38EF30B255B6DBE007E1867 /* BlockListCache.swift */, - C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */, C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */, C38EF304255B6DBE007E1867 /* ImageCache.swift */, - C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */, - C38EF308255B6DBE007E1867 /* OWSPreferences.m */, C38EF2E2255B6DB9007E1867 /* OWSScreenLock.swift */, C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */, C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */, - C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */, B8C2B33B2563770800551B4D /* ThreadUtil.h */, B8C2B331256376F000551B4D /* ThreadUtil.m */, C38EF284255B6D84007E1867 /* AppSetup.h */, C38EF287255B6D85007E1867 /* AppSetup.m */, + B8856D5F256F129B001CE70E /* OWSAlerts.swift */, C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */, - C38EF288255B6D85007E1867 /* OWSSounds.h */, - C38EF28B255B6D86007E1867 /* OWSSounds.m */, C33FDC1F255A581F00E217F9 /* LokiSessionRestorationImplementation.swift */, C38EF283255B6D84007E1867 /* VersionMigrations.h */, C38EF286255B6D85007E1867 /* VersionMigrations.m */, @@ -2979,8 +2973,6 @@ C33FDA99255A57FE00E217F9 /* OutageDetection.swift */, C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */, C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */, - C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */, - C33FDB07255A580700E217F9 /* OWSBackupFragment.m */, C33FDA95255A57FE00E217F9 /* OWSChunkedOutputStream.h */, C33FDB4B255A580C00E217F9 /* OWSChunkedOutputStream.m */, C33FDA9D255A57FF00E217F9 /* OWSContactsOutputStream.h */, @@ -3022,8 +3014,6 @@ C33FDABE255A580100E217F9 /* TSConstants.m */, C33FDB6D255A580F00E217F9 /* TSPreKeyManager.h */, C33FDB7E255A581100E217F9 /* TSPreKeyManager.m */, - C37F53E8255BA9BB002AEA92 /* Environment.h */, - C37F5402255BA9ED002AEA92 /* Environment.m */, ); path = SignalUtilitiesKit; sourceTree = ""; @@ -3136,8 +3126,6 @@ C379DCE9256733390002D4EB /* Image Editing */, C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */, B8C2B2C72563685C00551B4D /* CircleView.swift */, - C38EF23D255B6D66007E1867 /* UIView+OWS.h */, - C38EF23E255B6D66007E1867 /* UIView+OWS.m */, C38EF240255B6D67007E1867 /* UIView+OWS.swift */, C38EF236255B6D65007E1867 /* UIViewController+OWS.h */, C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */, @@ -3164,7 +3152,6 @@ C38EF33F255B6DC5007E1867 /* SheetViewController.swift */, C38EF3B5255B6DE6007E1867 /* OWSViewController+ImageEditor.swift */, C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */, - C38EF3E8255B6DF6007E1867 /* OWSAlerts.swift */, C38EF3E7255B6DF5007E1867 /* OWSButton.swift */, C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */, C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */, @@ -3198,8 +3185,6 @@ C38EF3E3255B6DF4007E1867 /* VideoPlayerView.swift */, C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */, C38EF3E1255B6DF3007E1867 /* TappableView.swift */, - C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */, - C38EF306255B6DBE007E1867 /* OWSWindowManager.m */, C38EF239255B6D66007E1867 /* UIFont+OWS.h */, C38EF238255B6D66007E1867 /* UIFont+OWS.m */, ); @@ -3229,8 +3214,6 @@ C38BBA0D255E321C0041B9A3 /* Messaging */ = { isa = PBXGroup; children = ( - B8D797B0256B2590007C59DF /* TSAttachmentPointer+Backups.h */, - B8D797B1256B25A1007C59DF /* TSAttachmentPointer+Backups.m */, C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */, C33FDB55255A580D00E217F9 /* TSInvalidIdentityKeySendingErrorMessage.m */, C33FDAE8255A580500E217F9 /* OWSMessageUtils.h */, @@ -3257,7 +3240,6 @@ C38EF3D1255B6DEE007E1867 /* ThreadViewHelper.m */, C38EF285255B6D84007E1867 /* SignalKeyingStorage.h */, C38EF282255B6D84007E1867 /* SignalKeyingStorage.m */, - C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */, C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */, C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */, C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */, @@ -3325,11 +3307,17 @@ children = ( C33FDB01255A580700E217F9 /* AppReadiness.h */, C33FDB75255A581000E217F9 /* AppReadiness.m */, + C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */, C3A722292558C1E40043A11F /* DotNetAPI.swift */, + C37F53E8255BA9BB002AEA92 /* Environment.h */, + C37F5402255BA9ED002AEA92 /* Environment.m */, C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */, C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, C3A71D0A2558989C0043A11F /* MessageWrapper.swift */, + C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */, + C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */, + C38EF281255B6D84007E1867 /* OWSAudioSession.swift */, C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */, C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */, C33FDC05255A581D00E217F9 /* OWSDisappearingMessagesFinder.h */, @@ -3340,6 +3328,13 @@ C33FDB1E255A580900E217F9 /* OWSIncomingMessageFinder.m */, C33FDB67255A580F00E217F9 /* OWSMediaGalleryFinder.h */, C33FDB71255A581000E217F9 /* OWSMediaGalleryFinder.m */, + C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */, + C38EF308255B6DBE007E1867 /* OWSPreferences.m */, + C38EF288255B6D85007E1867 /* OWSSounds.h */, + C38EF28B255B6D86007E1867 /* OWSSounds.m */, + C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */, + C38EF306255B6DBE007E1867 /* OWSWindowManager.m */, + C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */, C33FDB91255A581200E217F9 /* ProtoUtils.h */, C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, @@ -3438,12 +3433,15 @@ C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */, C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */, C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */, + C33FDB12255A580800E217F9 /* NSString+SSK.h */, + C33FDB45255A580C00E217F9 /* NSString+SSK.m */, C352A3762557859C00338F3E /* NSTimer+Proxying.h */, C352A36C2557858D00338F3E /* NSTimer+Proxying.m */, C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */, C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */, C33FDBAB255A581500E217F9 /* OWSFileSystem.h */, C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */, + C33FDB14255A580800E217F9 /* OWSMath.h */, C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */, C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */, C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */, @@ -3452,13 +3450,18 @@ C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */, C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */, C33FDB36255A580B00E217F9 /* Storage.swift */, + C33FDB3F255A580C00E217F9 /* String+SSK.swift */, C3C2AC2D2553CBEB00C340D1 /* String+Trimming.swift */, C352A3A42557B5F000338F3E /* TSRequest.h */, C352A3A52557B60D00338F3E /* TSRequest.m */, C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */, C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */, + C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */, C33FDB1C255A580900E217F9 /* UIImage+OWS.h */, C33FDB81255A581100E217F9 /* UIImage+OWS.m */, + C38EF23D255B6D66007E1867 /* UIView+OWS.h */, + C38EF23E255B6D66007E1867 /* UIView+OWS.m */, + C38EF2EF255B6DBB007E1867 /* Weak.swift */, ); path = SessionUtilitiesKit; sourceTree = ""; @@ -3707,16 +3710,12 @@ C33FDB8F255A581200E217F9 /* ParamParser.swift */, C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, C33FDB49255A580C00E217F9 /* WeakTimer.swift */, - C33FDB3F255A580C00E217F9 /* String+SSK.swift */, C33FDBC2255A581700E217F9 /* SSKAsserts.h */, C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */, - C33FDB14255A580800E217F9 /* OWSMath.h */, C33FDADC255A580400E217F9 /* NSObject+Casting.h */, C33FDAAA255A580000E217F9 /* NSObject+Casting.m */, C33FDBFE255A581C00E217F9 /* NSSet+Functional.h */, C33FDAC1255A580100E217F9 /* NSSet+Functional.m */, - C33FDB12255A580800E217F9 /* NSString+SSK.h */, - C33FDB45255A580C00E217F9 /* NSString+SSK.m */, C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */, C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */, C33FDBF8255A581C00E217F9 /* NSArray+OWS.h */, @@ -3732,18 +3731,13 @@ C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */, C38EF2E7255B6DBA007E1867 /* OWSScrubbingLogFormatter.h */, C38EF2F6255B6DBC007E1867 /* OWSScrubbingLogFormatter.m */, - C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */, - C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */, C38EF301255B6DBD007E1867 /* OWSFormat.h */, C38EF305255B6DBE007E1867 /* OWSFormat.m */, - C38EF281255B6D84007E1867 /* OWSAudioSession.swift */, C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */, C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */, - C38EF2EF255B6DBB007E1867 /* Weak.swift */, C38EF2FA255B6DBD007E1867 /* Bench.swift */, C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */, C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */, - C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */, ); path = Utilities; sourceTree = ""; @@ -3905,7 +3899,6 @@ files = ( C33FDD74255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.h in Headers */, C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */, - C33FDCCE255A582000E217F9 /* OWSMath.h in Headers */, C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */, C38EF311255B6DBF007E1867 /* OWSScrubbingLogFormatter.h in Headers */, B8C2B3442563782400551B4D /* ThreadUtil.h in Headers */, @@ -3915,10 +3908,8 @@ C38EF291255B6D86007E1867 /* SignalKeyingStorage.h in Headers */, C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */, C38EF2D8255B6DAF007E1867 /* OWSUserProfile.h in Headers */, - C33FDCCC255A582000E217F9 /* NSString+SSK.h in Headers */, C38EF313255B6DBF007E1867 /* OWSUnreadIndicator.h in Headers */, C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, - B8D797C3256B25A8007C59DF /* TSAttachmentPointer+Backups.h in Headers */, C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */, C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */, C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */, @@ -3935,7 +3926,6 @@ C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */, C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */, C38EF216255B6D3B007E1867 /* Theme.h in Headers */, - C38EF31B255B6DBF007E1867 /* OWSPreferences.h in Headers */, C33FDD0C255A582000E217F9 /* OWSHTTPSecurityPolicy.h in Headers */, C33FDC57255A582000E217F9 /* OWSContactsOutputStream.h in Headers */, C33FDCBD255A582000E217F9 /* OWSPrimaryStorage+SessionStore.h in Headers */, @@ -3945,7 +3935,6 @@ C38EF3F1255B6DF7007E1867 /* OWSSearchBar.h in Headers */, C33FDD75255A582000E217F9 /* OWSPrimaryStorage+Loki.h in Headers */, C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */, - C38EF294255B6D86007E1867 /* OWSSounds.h in Headers */, C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */, C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */, C33FDCA7255A582000E217F9 /* SSKMessageSenderJobRecord.h in Headers */, @@ -3961,9 +3950,7 @@ C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */, C33FDC4F255A582000E217F9 /* OWSChunkedOutputStream.h in Headers */, C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */, - C38EF325255B6DBF007E1867 /* OWSWindowManager.h in Headers */, C38EF404255B6DF7007E1867 /* ContactTableViewCell.h in Headers */, - C38EF24A255B6D67007E1867 /* UIView+OWS.h in Headers */, C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */, C38EF322255B6DBF007E1867 /* DebugLogger.h in Headers */, C38EF2D7255B6DAF007E1867 /* OWSProfileManager.h in Headers */, @@ -3972,17 +3959,13 @@ C33FDC61255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.h in Headers */, C38EF367255B6DCC007E1867 /* OWSTableViewController.h in Headers */, C38EF246255B6D67007E1867 /* UIFont+OWS.h in Headers */, - C37F53A7255B96E0002AEA92 /* OWSAudioPlayer.h in Headers */, C33FDD0D255A582000E217F9 /* PreKeyBundle+jsonDict.h in Headers */, C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */, C33FD9AF255A548A00E217F9 /* SignalUtilitiesKit.h in Headers */, C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */, C33FDD06255A582000E217F9 /* AppVersion.h in Headers */, C33FDD90255A582000E217F9 /* OWSUploadOperation.h in Headers */, - C33FDC73255A582000E217F9 /* OWSStorage+Subclass.h in Headers */, - C33FDCA4255A582000E217F9 /* OWSBackupFragment.h in Headers */, C33FDD27255A582000E217F9 /* TSPreKeyManager.h in Headers */, - C37F53E9255BA9CE002AEA92 /* Environment.h in Headers */, C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */, C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */, C33FDD01255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.h in Headers */, @@ -4010,13 +3993,16 @@ C32C5A36256DB856003C73A2 /* LKGroupUtilities.h in Headers */, C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */, C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */, + B8856DF8256F1633001CE70E /* NSString+SSK.h in Headers */, C3D9E4FD256778E30040E4F3 /* NSData+Image.h in Headers */, C300A63B2554B72200555489 /* NSDate+Timestamp.h in Headers */, C3D9E4E3256778720040E4F3 /* UIImage+OWS.h in Headers */, + B8856E1A256F1700001CE70E /* OWSMath.h in Headers */, C352A3772557864000338F3E /* NSTimer+Proxying.h in Headers */, C32C5B51256DC219003C73A2 /* NSNotificationCenter+OWS.h in Headers */, C3C2A67D255388CC00C340D1 /* SessionUtilitiesKit.h in Headers */, C32C6018256E07F9003C73A2 /* NSUserDefaults+OWS.h in Headers */, + B8856D8D256F1502001CE70E /* UIView+OWS.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4036,6 +4022,7 @@ C32C59C5256DB41F003C73A2 /* TSGroupModel.h in Headers */, C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */, C3D9E487256775D20040E4F3 /* TSAttachmentStream.h in Headers */, + B8856CB1256F0F47001CE70E /* OWSBackupFragment.h in Headers */, C3A3A122256E1A97004D228D /* OWSDisappearingMessagesFinder.h in Headers */, C32C5F4E256DFD58003C73A2 /* TSInvalidIdentityKeyReceivingErrorMessage.h in Headers */, C3A3A12B256E1AD5004D228D /* TSDatabaseSecondaryIndexes.h in Headers */, @@ -4050,14 +4037,18 @@ C3D9E486256775D20040E4F3 /* TSAttachmentPointer.h in Headers */, C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */, C3A3A0B3256E17F2004D228D /* SSKJobRecord.h in Headers */, + B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */, C32C5BE6256DC891003C73A2 /* OWSReadReceiptManager.h in Headers */, C32C5EC3256DE133003C73A2 /* OWSQuotedReplyModel.h in Headers */, C32C5BF8256DC8F6003C73A2 /* OWSDisappearingMessagesJob.h in Headers */, C32C5AAA256DBE8F003C73A2 /* TSIncomingMessage.h in Headers */, + B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */, C32C5B6B256DC357003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */, C32C5F23256DFCC0003C73A2 /* TSErrorMessage_privateConstructor.h in Headers */, C32C5BBA256DC7E3003C73A2 /* ProfileManagerProtocol.h in Headers */, C3A3A193256E20D4004D228D /* SignalRecipient.h in Headers */, + B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */, + B8856D3D256F11B2001CE70E /* Environment.h in Headers */, C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */, C32C5CAD256DD1DF003C73A2 /* TSAccountManager.h in Headers */, C3A3A0F5256E194C004D228D /* OWSRecipientIdentity.h in Headers */, @@ -4068,8 +4059,10 @@ C32C5BB0256DC73D003C73A2 /* OWSBlockingManager.h in Headers */, C3A3A15F256E1BB4004D228D /* ProtoUtils.h in Headers */, C3A3A145256E1B49004D228D /* OWSMediaGalleryFinder.h in Headers */, + B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */, C32C5C0A256DC9B4003C73A2 /* OWSIdentityManager.h in Headers */, C32C5F68256DFDAA003C73A2 /* TSInvalidIdentityKeyErrorMessage.h in Headers */, + B8856E9D256F1C3D001CE70E /* OWSSounds.h in Headers */, C32C5E64256DDFD6003C73A2 /* OWSStorage.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4932,20 +4925,15 @@ C38EF320255B6DBF007E1867 /* OWSScrubbingLogFormatter.m in Sources */, C38EF39B255B6DDA007E1867 /* ThreadViewModel.swift in Sources */, C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */, - C38EF330255B6DBF007E1867 /* OWSWindowManager.m in Sources */, C33FDD79255A582000E217F9 /* OWSHTTPSecurityPolicy.m in Sources */, C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */, C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */, C3D9E40C25676C100040E4F3 /* Storage+Conformances.swift in Sources */, C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */, C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */, - C38EF244255B6D67007E1867 /* UIDevice+featureSupport.swift in Sources */, C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */, C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */, - C38EF297255B6D86007E1867 /* OWSSounds.m in Sources */, - C33FDCF9255A582000E217F9 /* String+SSK.swift in Sources */, C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, - C38EF321255B6DBF007E1867 /* OWSAudioPlayer.m in Sources */, C33FDD0A255A582000E217F9 /* OWSPrimaryStorage+PreKeyStore.m in Sources */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, @@ -4979,11 +4967,9 @@ C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */, C38EF409255B6DF7007E1867 /* ContactTableViewCell.m in Sources */, C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */, - C38EF333255B6DBF007E1867 /* DeviceSleepManager.swift in Sources */, C33FDC52255A582000E217F9 /* RotateSignedKeyOperation.swift in Sources */, C38EF335255B6DBF007E1867 /* BlockListCache.swift in Sources */, C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */, - C38EF316255B6DBF007E1867 /* ProximityMonitoringManager.swift in Sources */, C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */, C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */, C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, @@ -4994,7 +4980,6 @@ C38EF218255B6D3B007E1867 /* Theme.m in Sources */, C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */, C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */, - C37F5403255BA9ED002AEA92 /* Environment.m in Sources */, C38EF2D4255B6DAF007E1867 /* OWSProfileManager.m in Sources */, C38EF248255B6D67007E1867 /* UIViewController+OWS.m in Sources */, C38EF272255B6D7A007E1867 /* OWSResaveCollectionDBMigration.m in Sources */, @@ -5008,10 +4993,8 @@ C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */, C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */, C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */, - C38EF24B255B6D67007E1867 /* UIView+OWS.m in Sources */, C38EF408255B6DF7007E1867 /* OWSSearchBar.m in Sources */, C38EF327255B6DBF007E1867 /* BlockListUIUtils.m in Sources */, - C33FDCFF255A582000E217F9 /* NSString+SSK.m in Sources */, C38EF310255B6DBF007E1867 /* DebugLogger.m in Sources */, C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */, C33FDC7B255A582000E217F9 /* NSSet+Functional.m in Sources */, @@ -5027,11 +5010,8 @@ C33FDC39255A581F00E217F9 /* OWSRecordTranscriptJob.m in Sources */, C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */, C33FDD1E255A582000E217F9 /* PreKeyRefreshOperation.swift in Sources */, - C38EF332255B6DBF007E1867 /* OWSPreferences.m in Sources */, C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */, C33FDD14255A582000E217F9 /* OWSUDManager.swift in Sources */, - C38EF28D255B6D86007E1867 /* OWSAudioSession.swift in Sources */, - C33FDCC1255A582000E217F9 /* OWSBackupFragment.m in Sources */, C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */, C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */, C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */, @@ -5041,6 +5021,7 @@ C38EF3BB255B6DE7007E1867 /* ImageEditorStrokeItem.swift in Sources */, C38EF3C0255B6DE7007E1867 /* ImageEditorCropViewController.swift in Sources */, C38EF401255B6DF7007E1867 /* VideoPlayerView.swift in Sources */, + B8856D60256F129B001CE70E /* OWSAlerts.swift in Sources */, C38EF3FE255B6DF7007E1867 /* OWSTextField.m in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */, @@ -5073,13 +5054,10 @@ C33FDC92255A582000E217F9 /* OWSGroupsOutputStream.m in Sources */, C38EF28E255B6D86007E1867 /* SignalKeyingStorage.m in Sources */, B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */, - C38EF406255B6DF7007E1867 /* OWSAlerts.swift in Sources */, C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */, C33FDDD8255A582000E217F9 /* OWSUploadOperation.m in Sources */, C33FDDC5255A582000E217F9 /* OWSError.m in Sources */, C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */, - B8D797B2256B25A1007C59DF /* TSAttachmentPointer+Backups.m in Sources */, - C38EF319255B6DBF007E1867 /* Weak.swift in Sources */, C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */, C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */, C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */, @@ -5123,6 +5101,8 @@ C352A36D2557858E00338F3E /* NSTimer+Proxying.m in Sources */, C32C5A2D256DB849003C73A2 /* LKGroupUtilities.m in Sources */, C3C2ABD22553C6C900C340D1 /* Data+SecureRandom.swift in Sources */, + B8856E09256F1676001CE70E /* UIDevice+featureSupport.swift in Sources */, + B8856DEF256F161F001CE70E /* NSString+SSK.m in Sources */, C32C5DC9256DD935003C73A2 /* ProxiedContentDownloader.swift in Sources */, C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */, C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */, @@ -5139,6 +5119,7 @@ C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */, C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */, C352A3A62557B60D00338F3E /* TSRequest.m in Sources */, + B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */, C3471ED42555386B00297E91 /* AESGCM.swift in Sources */, C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */, C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */, @@ -5146,9 +5127,11 @@ C32C5A24256DB7DB003C73A2 /* LKUserDefaults.swift in Sources */, C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */, C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */, + B8856D7B256F14F4001CE70E /* UIView+OWS.m in Sources */, C3D9E4F4256778AF0040E4F3 /* NSData+Image.m in Sources */, C32C5E0C256DDAFA003C73A2 /* NSRegularExpression+SSK.swift in Sources */, C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */, + B8856D23256F116B001CE70E /* Weak.swift in Sources */, C32C5A48256DB8F0003C73A2 /* BuildConfiguration.swift in Sources */, C300A60D2554B31900555489 /* Logging.swift in Sources */, C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */, @@ -5163,6 +5146,7 @@ files = ( C3A7229C2558E4310043A11F /* OpenGroupMessage+Conversion.swift in Sources */, C32C5DBE256DD743003C73A2 /* OpenGroupPoller.swift in Sources */, + B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */, C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */, C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */, C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */, @@ -5191,14 +5175,17 @@ C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */, C32C5F45256DFD2B003C73A2 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */, + B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */, C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */, C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */, C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */, C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */, C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */, + B8856D34256F1192001CE70E /* Environment.m in Sources */, C32C5AB1256DBE8F003C73A2 /* TSIncomingMessage.m in Sources */, C3A3A107256E1A5C004D228D /* OWSDisappearingMessagesFinder.m in Sources */, C32C59C3256DB41F003C73A2 /* TSGroupModel.m in Sources */, + B8856ECE256F1E58001CE70E /* OWSPreferences.m in Sources */, C3C2A7842553AAF300C340D1 /* SNProto.swift in Sources */, C32C5DC0256DD743003C73A2 /* Poller.swift in Sources */, C3C2A7682553A3D900C340D1 /* VisibleMessage+Contact.swift in Sources */, @@ -5220,8 +5207,10 @@ C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */, C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */, C3A3A099256E17B2004D228D /* SSKJobRecordFinder.swift in Sources */, + B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */, C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */, C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */, + B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */, C32C5F5F256DFD90003C73A2 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */, C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */, @@ -5237,6 +5226,7 @@ C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */, C32C5EB9256DE130003C73A2 /* OWSQuotedReplyModel+Conversion.swift in Sources */, C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */, + B8856E94256F1C37001CE70E /* OWSSounds.m in Sources */, C32C5BCC256DC830003C73A2 /* Storage+ClosedGroups.swift in Sources */, C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */, C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */, @@ -5248,9 +5238,11 @@ C3D9E3C025676AD70040E4F3 /* TSAttachment.m in Sources */, C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */, C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */, + B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */, C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */, C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */, C32C5C93256DD12D003C73A2 /* OWSUDManager.swift in Sources */, + B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */, C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */, C3A3A18A256E2092004D228D /* SignalRecipient.m in Sources */, C3C2A74425539EB700C340D1 /* Message.swift in Sources */, diff --git a/SignalUtilitiesKit/AppSetup.m b/SignalUtilitiesKit/AppSetup.m index 1266dd04a..b053609c5 100644 --- a/SignalUtilitiesKit/AppSetup.m +++ b/SignalUtilitiesKit/AppSetup.m @@ -15,7 +15,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index 21ed34b6f..bbad2c0f4 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -4,7 +4,7 @@ import PromiseKit extension MessageSender : SharedSenderKeysDelegate { @objc(send:withAttachments:inThread:usingTransaction:) - static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + public static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { if let message = message as? VisibleMessage { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { #if DEBUG @@ -29,11 +29,11 @@ extension MessageSender : SharedSenderKeysDelegate { } @objc(sendNonDurably:inThread:usingTransaction:) - static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + public static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) } - static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + public static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { message.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) return MessageSender.send(message, to: destination, using: transaction) diff --git a/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.h b/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.h deleted file mode 100644 index 7fab5a7d9..000000000 --- a/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.h +++ /dev/null @@ -1,19 +0,0 @@ -#import -#import -#import "OWSBackupFragment.h" - -#ifndef TSAttachmentPointer_Backups_h -#define TSAttachmentPointer_Backups_h - -@interface TSAttachmentPointer (Backups) - -// Non-nil for attachments which need "lazy backup restore." -- (nullable OWSBackupFragment *)lazyRestoreFragment; - -// Marks attachment as needing "lazy backup restore." -- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -@end - -#endif diff --git a/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.m b/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.m deleted file mode 100644 index 2e21f84df..000000000 --- a/SignalUtilitiesKit/Messaging/TSAttachmentPointer+Backups.m +++ /dev/null @@ -1,34 +0,0 @@ -#import "TSAttachmentPointer+Backups.h" - -@implementation TSAttachmentPointer (Backups) - -- (nullable OWSBackupFragment *)lazyRestoreFragment -{ - if (!self.lazyRestoreFragmentId) { - return nil; - } - OWSBackupFragment *_Nullable backupFragment = - [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId]; - OWSAssertDebug(backupFragment); - return backupFragment; -} - -- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(lazyRestoreFragment); - OWSAssertDebug(transaction); - - if (!lazyRestoreFragment.uniqueId) { - // If metadata hasn't been saved yet, save now. - [lazyRestoreFragment saveWithTransaction:transaction]; - - OWSAssertDebug(lazyRestoreFragment.uniqueId); - } - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSAttachmentPointer *attachment) { - [attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId]; - }]; -} - -@end diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 7516c76f9..43d281385 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -12,15 +12,11 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import -#import #import #import #import -#import -#import #import #import #import @@ -28,7 +24,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import @@ -42,7 +37,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import @@ -52,11 +46,9 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import #import -#import #import #import diff --git a/SignalUtilitiesKit/UI/OWSAlerts.swift b/SignalUtilitiesKit/OWSAlerts.swift similarity index 100% rename from SignalUtilitiesKit/UI/OWSAlerts.swift rename to SignalUtilitiesKit/OWSAlerts.swift diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m index 292ee2f05..dc696f818 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -13,7 +13,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/To Do/OWSUserProfile.m b/SignalUtilitiesKit/To Do/OWSUserProfile.m index 8d308ae8e..99f9368d1 100644 --- a/SignalUtilitiesKit/To Do/OWSUserProfile.m +++ b/SignalUtilitiesKit/To Do/OWSUserProfile.m @@ -8,7 +8,7 @@ #import #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/UI/MediaMessageView.swift b/SignalUtilitiesKit/UI/MediaMessageView.swift index e3db921e0..9f088e1f8 100644 --- a/SignalUtilitiesKit/UI/MediaMessageView.swift +++ b/SignalUtilitiesKit/UI/MediaMessageView.swift @@ -410,6 +410,10 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate { public func setAudioPlaybackState(_ value: AudioPlaybackState) { playbackState = value } + + public func showInvalidAudioFileAlert() { + OWSAlerts.showErrorAlert(message: NSLocalizedString("INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE", comment: "Message for the alert indicating that an audio file is invalid.")) + } private func ensureButtonState() { if playbackState == .playing { diff --git a/SignalUtilitiesKit/UI/SelectRecipientViewController.m b/SignalUtilitiesKit/UI/SelectRecipientViewController.m index 74b4a7c61..cf18cc5c4 100644 --- a/SignalUtilitiesKit/UI/SelectRecipientViewController.m +++ b/SignalUtilitiesKit/UI/SelectRecipientViewController.m @@ -9,7 +9,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/UI/SelectThreadViewController.m b/SignalUtilitiesKit/UI/SelectThreadViewController.m index 415b0074c..a24eb6837 100644 --- a/SignalUtilitiesKit/UI/SelectThreadViewController.m +++ b/SignalUtilitiesKit/UI/SelectThreadViewController.m @@ -12,7 +12,7 @@ #import "UIFont+OWS.h" #import "UIView+OWS.h" #import -#import +#import #import #import #import diff --git a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index 2d36a09c3..250ddc199 100644 --- a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -8,7 +8,7 @@ #import "UIFont+OWS.h" #import "UIView+OWS.h" #import -#import +#import #import #import #import From d5dc33e6193ee61577e326f9c413deeb1b3dab0f Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 12:46:47 +1100 Subject: [PATCH 037/177] Debug --- .../ConversationView/ConversationViewController.m | 2 ++ .../Sending & Receiving/MessageReceiver+Handling.swift | 2 +- .../Sending & Receiving/MessageSender+Encryption.swift | 2 +- .../Sending & Receiving/MessageSender.swift | 10 +++++----- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index b4139b10e..9326faa60 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3812,6 +3812,8 @@ typedef enum : NSUInteger { [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [tsMessage saveWithTransaction:transaction]; + }]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [SNMessageSender send:message withAttachments:[NSArray new] inThread:thread usingTransaction:transaction]; [thread setDraft:@"" transaction:transaction]; }]; diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 8bd51b568..daad909c6 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -172,7 +172,7 @@ extension MessageReceiver { // Cancel any typing indicators cancelTypingIndicatorsIfNeeded(for: message.sender!) // Notify the user if needed - guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID), let thread = TSThread.fetch(uniqueId: threadID) else { return } + guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return } Storage.read { transaction in SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift index 3a07bd7ae..c583451e5 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift @@ -7,7 +7,7 @@ internal extension MessageSender { let storage = Configuration.shared.signalStorage let cipher = try SMKSecretSessionCipher(sessionResetImplementation: Configuration.shared.sessionRestorationImplementation, sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: Configuration.shared.identityKeyStore) - let certificate = Configuration.shared.storage.getSenderCertificate(for: publicKey) + let certificate = SMKSenderCertificate(senderDeviceId: 1, senderRecipientId: Configuration.shared.storage.getUserPublicKey()!) return try cipher.throwswrapped_encryptMessage(recipientPublicKey: publicKey, deviceID: 1, paddedPlaintext: (plaintext as NSData).paddedMessageBody(), senderCertificate: certificate, protocolContext: transaction, useFallbackSessionCipher: true) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index dabf06e6e..d16b9d997 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -68,7 +68,7 @@ public final class MessageSender : NSObject { storage.withAsync({ transaction in MessageSender.handleFailedMessageSend(message, with: error, using: transaction) }, completion: { }) - if case .contact(_) = destination { + if case .contact(_) = destination, message is VisibleMessage { NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) } } @@ -86,7 +86,7 @@ public final class MessageSender : NSObject { return promise } // Encrypt the serialized protobuf - if case .contact(_) = destination { + if case .contact(_) = destination, message is VisibleMessage { DispatchQueue.main.async { NotificationCenter.default.post(name: .encryptingMessage, object: NSNumber(value: message.sentTimestamp!)) } @@ -125,7 +125,7 @@ public final class MessageSender : NSObject { return promise } // Calculate proof of work - if case .contact(_) = destination { + if case .contact(_) = destination, message is VisibleMessage { DispatchQueue.main.async { NotificationCenter.default.post(name: .calculatingMessagePoW, object: NSNumber(value: message.sentTimestamp!)) } @@ -138,7 +138,7 @@ public final class MessageSender : NSObject { return promise } // Send the result - if case .contact(_) = destination { + if case .contact(_) = destination, message is VisibleMessage { DispatchQueue.main.async { NotificationCenter.default.post(name: .messageSending, object: NSNumber(value: message.sentTimestamp!)) } @@ -169,7 +169,7 @@ public final class MessageSender : NSObject { storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) - if case .contact(_) = destination { + if case .contact(_) = destination, message is VisibleMessage { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) } if message is VisibleMessage { From c8e63019ab989a0ca701a907a0d4765ba742f6f9 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 12:56:08 +1100 Subject: [PATCH 038/177] Debug --- SessionMessagingKit/Database/Storage+Shared.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Database/Storage+Shared.swift b/SessionMessagingKit/Database/Storage+Shared.swift index 0f22ad986..1a81fccba 100644 --- a/SessionMessagingKit/Database/Storage+Shared.swift +++ b/SessionMessagingKit/Database/Storage+Shared.swift @@ -15,7 +15,7 @@ extension Storage { } public func getUserPublicKey() -> String? { - return OWSIdentityManager.shared().identityKeyPair()?.publicKey.toHexString() + return OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey } public func getUserKeyPair() -> ECKeyPair? { From 4942da1d23aab2e6e22d540f67ebf63f32b61e50 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 13:23:35 +1100 Subject: [PATCH 039/177] Send read receipts again --- .../Cells/OWSQuotedMessageView.m | 7 +- .../Control Messages/ReadReceipt.swift | 4 +- SessionMessagingKit/Messages/Message.swift | 2 +- .../Messages/Signal/TSIncomingMessage.m | 1 - .../Blocking/OWSBlockingManager.m | 70 +------------------ .../Link Previews/OWSLinkPreview.swift | 2 +- .../Quotes/OWSQuotedReplyModel.m | 2 - .../Read Tracking/OWSOutgoingReceiptManager.m | 59 ++++------------ .../Read Tracking/OWSReadReceiptManager.m | 28 +------- .../Typing Indicators/TypingIndicators.swift | 5 +- .../{Utilities => To Do}/SignalRecipient.h | 0 .../{Utilities => To Do}/SignalRecipient.m | 0 .../Utilities/OWSAudioPlayer.m | 2 - SessionMessagingKit/Utilities/OWSSounds.m | 3 +- Signal.xcodeproj/project.pbxproj | 4 +- 15 files changed, 26 insertions(+), 163 deletions(-) rename SessionMessagingKit/{Utilities => To Do}/SignalRecipient.h (100%) rename SessionMessagingKit/{Utilities => To Do}/SignalRecipient.m (100%) diff --git a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m index ae44305ed..6b35ee2ca 100644 --- a/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m @@ -543,12 +543,7 @@ const CGFloat kRemotelySourcedContentRowSpacing = 4; NSString *_Nullable localNumber = [TSAccountManager localNumber]; NSString *quotedAuthorText; if ([localNumber isEqualToString:self.quotedMessage.authorId]) { - - if (self.isOutgoing) { - quotedAuthorText = NSLocalizedString(@"You", @""); - } else { - quotedAuthorText = NSLocalizedString(@"You", @""); - } + quotedAuthorText = NSLocalizedString(@"You", @""); } else { __block NSString *quotedAuthor = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.quotedMessage.authorId] ?: self.quotedMessage.authorId; diff --git a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift index fc475c023..0c5d5ecf5 100644 --- a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift +++ b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift @@ -2,9 +2,11 @@ import SessionUtilitiesKit @objc(SNReadReceipt) public final class ReadReceipt : ControlMessage { - public var timestamps: [UInt64]? + @objc public var timestamps: [UInt64]? // MARK: Initialization + public override init() { super.init() } + internal init(timestamps: [UInt64]) { super.init() self.timestamps = timestamps diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index abfd2887a..0f04c20db 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -3,7 +3,7 @@ @objc(SNMessage) public class Message : NSObject, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public var id: String? - public var threadID: String? + @objc public var threadID: String? public var sentTimestamp: UInt64? public var receivedTimestamp: UInt64? public var recipient: String? diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m index 69e3a0f3a..6be45f3a8 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m @@ -141,7 +141,6 @@ NS_ASSUME_NONNULL_BEGIN return; } - NSTimeInterval secondsAgoRead = ((NSTimeInterval)[NSDate millisecondTimestamp] - (NSTimeInterval)readTimestamp) / 1000; _read = YES; [self saveWithTransaction:transaction]; diff --git a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m index 7ed42eb79..2ef11e634 100644 --- a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m +++ b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m @@ -253,7 +253,7 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if (sendSyncMessage) { - [self sendBlockListSyncMessageWithPhoneNumbers:blockedPhoneNumbers groupIds:blockedGroupIds]; + } else { // If this update came from an incoming block list sync message, // update the "synced blocked list" state immediately, @@ -299,70 +299,9 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan _blockedGroupMap = [NSMutableDictionary new]; } - [self syncBlockListIfNecessary]; [self observeNotifications]; } -- (void)syncBlockList -{ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self sendBlockListSyncMessageWithPhoneNumbers:self.blockedPhoneNumbers groupIds:self.blockedGroupIds]; - }); -} - -// This method should only be called from within a synchronized block. -- (void)syncBlockListIfNecessary -{ - // If we haven't yet successfully synced the current "block list" changes, - // try again to sync now. - NSArray *syncedBlockedPhoneNumbers = - [self.dbConnection objectForKey:kOWSBlockingManager_SyncedBlockedPhoneNumbersKey - inCollection:kOWSBlockingManager_BlockListCollection]; - NSSet *syncedBlockedPhoneNumberSet = - [[NSSet alloc] initWithArray:(syncedBlockedPhoneNumbers ?: [NSArray new])]; - - NSArray *syncedBlockedGroupIds = - [self.dbConnection objectForKey:kOWSBlockingManager_SyncedBlockedGroupIdsKey - inCollection:kOWSBlockingManager_BlockListCollection]; - NSSet *syncedBlockedGroupIdSet = [[NSSet alloc] initWithArray:(syncedBlockedGroupIds ?: [NSArray new])]; - - NSArray *localBlockedGroupIds = self.blockedGroupIds; - NSSet *localBlockedGroupIdSet = [[NSSet alloc] initWithArray:localBlockedGroupIds]; - - if ([self.blockedPhoneNumberSet isEqualToSet:syncedBlockedPhoneNumberSet] && - [localBlockedGroupIdSet isEqualToSet:syncedBlockedGroupIdSet]) { - return; - } - - [self sendBlockListSyncMessageWithPhoneNumbers:self.blockedPhoneNumbers groupIds:localBlockedGroupIds]; -} - -- (void)sendBlockListSyncMessageWithPhoneNumbers:(NSArray *)blockedPhoneNumbers - groupIds:(NSArray *)blockedGroupIds -{ - // TODO TODO TODO - - /* - OWSAssertDebug(blockedPhoneNumbers); - OWSAssertDebug(blockedGroupIds); - - OWSBlockedPhoneNumbersMessage *message = - [[OWSBlockedPhoneNumbersMessage alloc] initWithPhoneNumbers:blockedPhoneNumbers groupIds:blockedGroupIds]; - - [self.messageSender sendMessage:message - success:^{ - OWSLogInfo(@"Successfully sent blocked phone numbers sync message"); - - // DURABLE CLEANUP - we could replace the custom durability logic in this class - // with a durable JobQueue. - [self saveSyncedBlockListWithPhoneNumbers:blockedPhoneNumbers groupIds:blockedGroupIds]; - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send blocked phone numbers sync message with error: %@", error); - }]; - */ -} - /// Records the last block list which we successfully synced. - (void)saveSyncedBlockListWithPhoneNumbers:(NSArray *)blockedPhoneNumbers groupIds:(NSArray *)blockedGroupIds @@ -380,12 +319,7 @@ NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingMan - (void)applicationDidBecomeActive:(NSNotification *)notification { - [AppReadiness runNowOrWhenAppDidBecomeReady:^{ - @synchronized(self) - { - [self syncBlockListIfNecessary]; - } - }]; + } @end diff --git a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview.swift b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview.swift index f134d9971..f3e1f697a 100644 --- a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview.swift +++ b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview.swift @@ -224,7 +224,7 @@ public class OWSLinkPreview: MTLModel { let filePath = OWSFileSystem.temporaryFilePath(withFileExtension: fileExtension) do { try imageData.write(to: NSURL.fileURL(withPath: filePath), options: .atomicWrite) - } catch let error as NSError { + } catch { return nil } diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m index 2505ae6ee..59dada4d7 100644 --- a/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m +++ b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel.m @@ -126,8 +126,6 @@ NS_ASSUME_NONNULL_BEGIN return nil; } - TSThread *thread = [message threadWithTransaction:transaction]; - uint64_t timestamp = message.timestamp; NSString *_Nullable authorId = ^{ diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m index 0bb42314a..1dde261bb 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m @@ -103,7 +103,6 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa } NSMutableArray *sendPromises = [NSMutableArray array]; - [sendPromises addObjectsFromArray:[self sendReceiptsForReceiptType:OWSReceiptType_Delivery]]; [sendPromises addObjectsFromArray:[self sendReceiptsForReceiptType:OWSReceiptType_Read]]; if (sendPromises.count < 1) { @@ -149,8 +148,8 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa NSMutableArray *sendPromises = [NSMutableArray array]; for (NSString *recipientId in queuedReceiptMap) { - NSSet *timestamps = queuedReceiptMap[recipientId]; - if (timestamps.count < 1) { + NSSet *timestampsAsSet = queuedReceiptMap[recipientId]; + if (timestampsAsSet.count < 1) { continue; } @@ -160,51 +159,19 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa continue; } - // TODO TODO TODO - - /* - OWSReceiptsForSenderMessage *message; - NSString *receiptName; - switch (receiptType) { - case OWSReceiptType_Delivery: - message = - [OWSReceiptsForSenderMessage deliveryReceiptsForSenderMessageWithThread:thread - messageTimestamps:timestamps.allObjects]; - receiptName = @"Delivery"; - break; - case OWSReceiptType_Read: - message = [OWSReceiptsForSenderMessage readReceiptsForSenderMessageWithThread:thread - messageTimestamps:timestamps.allObjects]; - receiptName = @"Read"; - break; + SNReadReceipt *readReceipt = [SNReadReceipt new]; + NSMutableArray *timestamps = [NSMutableArray new]; + for (NSNumber *timestamp in timestampsAsSet) { + [timestamps addObject:timestamp]; } - - AnyPromise *sendPromise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - [self.messageSender sendMessage:message - success:^{ - OWSLogInfo( - @"Successfully sent %lu %@ receipts to sender.", (unsigned long)timestamps.count, receiptName); - - // DURABLE CLEANUP - we could replace the custom durability logic in this class - // with a durable JobQueue. - [self dequeueReceiptsWithRecipientId:recipientId timestamps:timestamps receiptType:receiptType]; - - // The value doesn't matter, we just need any non-NSError value. - resolve(@(1)); - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send %@ receipts to sender with error: %@", receiptName, error); - - if (error.domain == OWSSignalServiceKitErrorDomain - && error.code == OWSErrorCodeNoSuchSignalRecipient) { - [self dequeueReceiptsWithRecipientId:recipientId timestamps:timestamps receiptType:receiptType]; - } - - resolve(error); - }]; + readReceipt.timestamps = timestamps; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + AnyPromise *promise = [SNMessageSender sendNonDurably:readReceipt inThread:thread usingTransaction:transaction] + .thenOn(self.serialQueue, ^(id object) { + [self dequeueReceiptsWithRecipientId:recipientId timestamps:timestampsAsSet receiptType:@"Read"]; + }); + [sendPromises addObject:promise]; }]; - [sendPromises addObject:sendPromise]; - */ } return [sendPromises copy]; diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m index 67006c39d..cb7c6be47 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m @@ -234,46 +234,20 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)messageWasReadLocally:(TSIncomingMessage *)message { - // TODO TODO TODO - - /* dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(self) { - NSString *threadUniqueId = message.uniqueThreadId; - OWSAssertDebug(threadUniqueId.length > 0); - NSString *messageAuthorId = message.authorId; - OWSAssertDebug(messageAuthorId.length > 0); - OWSLinkedDeviceReadReceipt *newReadReceipt = - [[OWSLinkedDeviceReadReceipt alloc] initWithSenderId:messageAuthorId - messageIdTimestamp:message.timestamp - readTimestamp:[NSDate ows_millisecondTimeStamp]]; - - OWSLinkedDeviceReadReceipt *_Nullable oldReadReceipt = self.toLinkedDevicesReadReceiptMap[threadUniqueId]; - if (oldReadReceipt && oldReadReceipt.messageIdTimestamp > newReadReceipt.messageIdTimestamp) { - // If there's an existing "linked device" read receipt for the same thread with - // a newer timestamp, discard this "linked device" read receipt. - OWSLogVerbose(@"Ignoring redundant read receipt for linked devices."); - } else { - OWSLogVerbose(@"Enqueuing read receipt for linked devices."); - self.toLinkedDevicesReadReceiptMap[threadUniqueId] = newReadReceipt; - } - - if (![LKSessionMetaProtocol shouldSendReceiptInThread:message.thread]) { - return; - } + if (!message.thread.isGroupThread) { return; } // Don't send read receipts in group threads if ([self areReadReceiptsEnabled]) { - OWSLogVerbose(@"Enqueuing read receipt for sender."); [self.outgoingReceiptManager enqueueReadReceiptForEnvelope:messageAuthorId timestamp:message.timestamp]; } [self scheduleProcessing]; } }); - */ } #pragma mark - Read Receipts From Recipient diff --git a/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift index 2ac63c633..5894c3b33 100644 --- a/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift +++ b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift @@ -272,11 +272,8 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { let typingIndicator = TypingIndicator() typingIndicator.kind = action - typingIndicator.threadID = thread.uniqueId! - let destination = Message.Destination.from(thread) - let job = MessageSendJob(message: typingIndicator, destination: destination) Storage.write { transaction in - SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + MessageSender.send(typingIndicator, in: thread, using: transaction) } } } diff --git a/SessionMessagingKit/Utilities/SignalRecipient.h b/SessionMessagingKit/To Do/SignalRecipient.h similarity index 100% rename from SessionMessagingKit/Utilities/SignalRecipient.h rename to SessionMessagingKit/To Do/SignalRecipient.h diff --git a/SessionMessagingKit/Utilities/SignalRecipient.m b/SessionMessagingKit/To Do/SignalRecipient.m similarity index 100% rename from SessionMessagingKit/Utilities/SignalRecipient.m rename to SessionMessagingKit/To Do/SignalRecipient.m diff --git a/SessionMessagingKit/Utilities/OWSAudioPlayer.m b/SessionMessagingKit/Utilities/OWSAudioPlayer.m index 740da5f6a..2656a5b1e 100644 --- a/SessionMessagingKit/Utilities/OWSAudioPlayer.m +++ b/SessionMessagingKit/Utilities/OWSAudioPlayer.m @@ -111,8 +111,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)playWithAudioActivity:(OWSAudioActivity *)audioActivity { - BOOL success = [self.audioSession startAudioActivity:audioActivity]; - [self.audioPlayerPoller invalidate]; self.delegate.audioPlaybackState = AudioPlaybackState_Playing; diff --git a/SessionMessagingKit/Utilities/OWSSounds.m b/SessionMessagingKit/Utilities/OWSSounds.m index 95b7edd20..4415402db 100644 --- a/SessionMessagingKit/Utilities/OWSSounds.m +++ b/SessionMessagingKit/Utilities/OWSSounds.m @@ -37,7 +37,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob _soundURL = url; SystemSoundID newSoundID; - OSStatus status = AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &newSoundID); _soundID = newSoundID; return self; @@ -45,7 +44,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob - (void)dealloc { - OSStatus status = AudioServicesDisposeSystemSoundID(_soundID); + } @end diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 422377e07..ac88a5784 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -2822,6 +2822,8 @@ C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */, C32C5C92256DD12D003C73A2 /* OWSUDManager.swift */, C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, + C33FDAEC255A580500E217F9 /* SignalRecipient.h */, + C33FDBB7255A581600E217F9 /* SignalRecipient.m */, C33FDB94255A581300E217F9 /* TSAccountManager.h */, C33FDB88255A581200E217F9 /* TSAccountManager.m */, ); @@ -3338,8 +3340,6 @@ C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */, C33FDB91255A581200E217F9 /* ProtoUtils.h */, C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, - C33FDAEC255A580500E217F9 /* SignalRecipient.h */, - C33FDBB7255A581600E217F9 /* SignalRecipient.m */, C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, From c4e0b45b330c64af9b27df5a0691edbc36d824c7 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 13:30:30 +1100 Subject: [PATCH 040/177] Send expiration timer updates again --- .../OWSConversationSettingsViewController.m | 16 ++++------------ .../Control Messages/ExpirationTimerUpdate.swift | 7 +++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index ef205476a..3372ffa58 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -866,9 +866,7 @@ static CGRect oldframe; if (self.disappearingMessagesConfiguration.dictionaryValueDidChange) { [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.disappearingMessagesConfiguration saveWithTransaction:transaction]; - // MJK TODO - should be safe to remove this senderTimestamp - OWSDisappearingConfigurationUpdateInfoMessage *infoMessage = - [[OWSDisappearingConfigurationUpdateInfoMessage alloc] + OWSDisappearingConfigurationUpdateInfoMessage *infoMessage = [[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] thread:self.thread configuration:self.disappearingMessagesConfiguration @@ -876,15 +874,9 @@ static CGRect oldframe; createdInExistingGroup:NO]; [infoMessage saveWithTransaction:transaction]; - // TODO TODO TODO - - /* - OWSDisappearingMessagesConfigurationMessage *message = [[OWSDisappearingMessagesConfigurationMessage alloc] - initWithConfiguration:self.disappearingMessagesConfiguration - thread:self.thread]; - - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - */ + SNExpirationTimerUpdate *expirationTimerUpdate = [SNExpirationTimerUpdate new]; + expirationTimerUpdate.duration = self.disappearingMessagesConfiguration.durationSeconds; + [SNMessageSender send:expirationTimerUpdate withAttachments:@[] inThread:self.thread usingTransaction:transaction]; }]; } } diff --git a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift index 139e60430..3d365518c 100644 --- a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift @@ -5,6 +5,8 @@ public final class ExpirationTimerUpdate : ControlMessage { public var duration: UInt32? // MARK: Initialization + public override init() { super.init() } + internal init(duration: UInt32) { super.init() self.duration = duration @@ -53,4 +55,9 @@ public final class ExpirationTimerUpdate : ControlMessage { return nil } } + + // MARK: Convenience + @objc public func setDuration(_ duration: UInt32) { + + } } From 1ddb8ac50ec3dec103cdc31b13d64ee2653cab4b Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 14:01:24 +1100 Subject: [PATCH 041/177] Resolve more TODOs --- Session/Signal/AppNotifications.swift | 27 ++- .../ConversationViewController.m | 67 +----- .../OWSConversationSettingsViewController.m | 2 +- .../Read Tracking/OWSOutgoingReceiptManager.m | 2 +- .../Read Tracking/OWSReadReceiptManager.m | 38 --- .../MessageSender+Handling.swift | 60 +++-- SignalUtilitiesKit/OWSRecordTranscriptJob.m | 216 ------------------ SignalUtilitiesKit/UI/BlockListUIUtils.m | 4 +- .../UI/SharingThreadPickerViewController.m | 96 ++++---- 9 files changed, 101 insertions(+), 411 deletions(-) diff --git a/Session/Signal/AppNotifications.swift b/Session/Signal/AppNotifications.swift index 960dca597..4bf251056 100644 --- a/Session/Signal/AppNotifications.swift +++ b/Session/Signal/AppNotifications.swift @@ -434,18 +434,21 @@ class NotificationActionHandler { } return markAsRead(thread: thread).then { () -> Promise in - // TODO TODO TODO - -// let sendPromise = ThreadUtil.sendMessageNonDurably(text: replyText, -// thread: thread, -// quotedReplyModel: nil, -// messageSender: self.messageSender) - -// return sendPromise.recover { error in -// Logger.warn("Failed to send reply message from notification with error: \(error)") -// self.notificationPresenter.notifyForFailedSend(inThread: thread) -// } - return Promise.value(()) + let message = VisibleMessage() + message.sentTimestamp = NSDate.millisecondTimestamp() + message.text = replyText + let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread) + Storage.write { transaction in + tsMessage.save(with: transaction) + } + var promise: Promise! + Storage.writeSync { transaction in + promise = MessageSender.sendNonDurably(message, in: thread, using: transaction) + } + promise.catch { [weak self] error in + self?.notificationPresenter.notifyForFailedSend(inThread: thread) + } + return promise } } diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 9326faa60..f9849191e 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -1480,8 +1480,6 @@ typedef enum : NSUInteger { [message remove]; }]; [actionSheet addAction:deleteMessageAction]; - - // TODO TODO TODO // UIAlertAction *resendMessageAction = [UIAlertAction // actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") @@ -2992,68 +2990,7 @@ typedef enum : NSUInteger { - (void)updateGroupModelTo:(TSGroupModel *)newGroupModel successCompletion:(void (^_Nullable)(void))successCompletion { - __block TSGroupThread *groupThread; - __block TSOutgoingMessage *message; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - groupThread = [TSGroupThread getOrCreateThreadWithGroupModel:newGroupModel transaction:transaction]; - - NSString *updateGroupInfo = - [groupThread.groupModel getInfoStringAboutUpdateTo:newGroupModel]; - - groupThread.groupModel = newGroupModel; - [groupThread saveWithTransaction:transaction]; - - uint32_t expiresInSeconds = [groupThread disappearingMessagesDurationWithTransaction:transaction]; - message = [TSOutgoingMessage outgoingMessageInThread:groupThread - groupMetaMessage:TSGroupMetaMessageUpdate - expiresInSeconds:expiresInSeconds]; - [message updateWithCustomMessage:updateGroupInfo transaction:transaction]; - }]; - - [groupThread fireAvatarChangedNotification]; - - if (newGroupModel.groupImage) { - NSData *data = UIImagePNGRepresentation(newGroupModel.groupImage); - DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; - // DURABLE CLEANUP - currently one caller uses the completion handler to delete the tappable error message - // which causes this code to be called. Once we're more aggressive about durable sending retry, - // we could get rid of this "retryable tappable error message". - - // TODO TODO TODO - -// [self.messageSender sendTemporaryAttachment:dataSource -// contentType:OWSMimeTypeImagePng -// inMessage:message -// success:^{ -// OWSLogDebug(@"Successfully sent group update with avatar"); -// if (successCompletion) { -// successCompletion(); -// } -// } -// failure:^(NSError *error) { -// OWSLogError(@"Failed to send group avatar update with error: %@", error); -// }]; - } else { - // DURABLE CLEANUP - currently one caller uses the completion handler to delete the tappable error message - // which causes this code to be called. Once we're more aggressive about durable sending retry, - // we could get rid of this "retryable tappable error message". - - // TODO TODO TODO - -// [self.messageSender sendMessage:message -// success:^{ -// OWSLogDebug(@"Successfully sent group update"); -// if (successCompletion) { -// successCompletion(); -// } -// } -// failure:^(NSError *error) { -// OWSLogError(@"Failed to send group update with error: %@", error); -// }]; - } - - self.thread = groupThread; + } - (void)popKeyBoard @@ -3814,7 +3751,7 @@ typedef enum : NSUInteger { [tsMessage saveWithTransaction:transaction]; }]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [SNMessageSender send:message withAttachments:[NSArray new] inThread:thread usingTransaction:transaction]; + [SNMessageSender send:message inThread:thread usingTransaction:transaction]; [thread setDraft:@"" transaction:transaction]; }]; [self messageWasSent:tsMessage]; diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index 3372ffa58..9cf4d70c3 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -876,7 +876,7 @@ static CGRect oldframe; SNExpirationTimerUpdate *expirationTimerUpdate = [SNExpirationTimerUpdate new]; expirationTimerUpdate.duration = self.disappearingMessagesConfiguration.durationSeconds; - [SNMessageSender send:expirationTimerUpdate withAttachments:@[] inThread:self.thread usingTransaction:transaction]; + [SNMessageSender send:expirationTimerUpdate inThread:self.thread usingTransaction:transaction]; }]; } } diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m index 1dde261bb..c4209f073 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m @@ -168,7 +168,7 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { AnyPromise *promise = [SNMessageSender sendNonDurably:readReceipt inThread:thread usingTransaction:transaction] .thenOn(self.serialQueue, ^(id object) { - [self dequeueReceiptsWithRecipientId:recipientId timestamps:timestampsAsSet receiptType:@"Read"]; + [self dequeueReceiptsWithRecipientId:recipientId timestamps:timestampsAsSet receiptType:OWSReceiptType_Read]; }); [sendPromises addObject:promise]; }]; diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m index cb7c6be47..8c66234a7 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m @@ -176,45 +176,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)process { - // TODO TODO TODO - /* - @synchronized(self) - { - OWSLogVerbose(@"Processing read receipts."); - - NSArray *readReceiptsForLinkedDevices = - [self.toLinkedDevicesReadReceiptMap allValues]; - [self.toLinkedDevicesReadReceiptMap removeAllObjects]; - if (readReceiptsForLinkedDevices.count > 0) { - OWSReadReceiptsForLinkedDevicesMessage *message = - [[OWSReadReceiptsForLinkedDevicesMessage alloc] initWithReadReceipts:readReceiptsForLinkedDevices]; - - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; - } - - BOOL didWork = readReceiptsForLinkedDevices.count > 0; - - if (didWork) { - // Wait N seconds before processing read receipts again. - // This allows time for a batch to accumulate. - // - // We want a value high enough to allow us to effectively de-duplicate, - // read receipts without being so high that we risk not sending read - // receipts due to app exit. - const CGFloat kProcessingFrequencySeconds = 3.f; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kProcessingFrequencySeconds * NSEC_PER_SEC)), - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), - ^{ - [self process]; - }); - } else { - self.isProcessing = NO; - } - } - */ } #pragma mark - Mark as Read Locally diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index bbad2c0f4..37d746b9f 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -3,35 +3,55 @@ import PromiseKit extension MessageSender : SharedSenderKeysDelegate { - @objc(send:withAttachments:inThread:usingTransaction:) - public static func send(_ message: Message, with attachments: [SignalAttachment] = [], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { - if let message = message as? VisibleMessage { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { - #if DEBUG - preconditionFailure() - #endif - return - } - var streams: [TSAttachmentStream] = [] - attachments.forEach { - let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, - caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) - streams.append(stream) - stream.write($0.dataSource) - stream.save(with: transaction) - } - message.attachmentIDs = streams.map { $0.uniqueId! } + // MARK: - Sending Convenience + + private static func prep(_ attachments: [SignalAttachment], for message: Message, using transaction: YapDatabaseReadWriteTransaction) { + guard let message = message as? VisibleMessage else { return } + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { + #if DEBUG + preconditionFailure() + #endif + return } + var streams: [TSAttachmentStream] = [] + attachments.forEach { + let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, + caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) + streams.append(stream) + stream.write($0.dataSource) + stream.save(with: transaction) + } + message.attachmentIDs = streams.map { $0.uniqueId! } + } + + @objc(send:withAttachments:inThread:usingTransaction:) + public static func send(_ message: Message, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + prep(attachments, for: message, using: transaction) + send(message, in: thread, using: transaction) + } + + @objc(send:inThread:usingTransaction:) + public static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { message.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) let job = MessageSendJob(message: message, destination: destination) JobQueue.shared.add(job, using: transaction) } + @objc(sendNonDurably:withAttachments:inThread:usingTransaction:) + public static func objc_sendNonDurably(_ message: Message, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(sendNonDurably(message, with: attachments, in: thread, using: transaction)) + } + @objc(sendNonDurably:inThread:usingTransaction:) public static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) } + + public static func sendNonDurably(_ message: Message, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + prep(attachments, for: message, using: transaction) + return sendNonDurably(message, in: thread, using: transaction) + } public static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { message.threadID = thread.uniqueId! @@ -39,6 +59,10 @@ extension MessageSender : SharedSenderKeysDelegate { return MessageSender.send(message, to: destination, using: transaction) } + + + // MARK: - Closed Groups + public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { // Prepare var members = members diff --git a/SignalUtilitiesKit/OWSRecordTranscriptJob.m b/SignalUtilitiesKit/OWSRecordTranscriptJob.m index e98fe2cd8..e505e89d3 100644 --- a/SignalUtilitiesKit/OWSRecordTranscriptJob.m +++ b/SignalUtilitiesKit/OWSRecordTranscriptJob.m @@ -46,138 +46,7 @@ NS_ASSUME_NONNULL_BEGIN NSArray *attachmentStreams))attachmentHandler transaction:(YapDatabaseReadWriteTransaction *)transaction { - // TODO TODO TODO - /* - OWSAssertDebug(transcript); - OWSAssertDebug(transaction); - - if (transcript.isRecipientUpdate) { - // "Recipient updates" are processed completely separately in order - // to avoid resurrecting threads or messages. - [self processRecipientUpdateWithTranscript:transcript transaction:transaction]; - return; - } - - OWSLogInfo(@"Recording transcript in thread: %@ timestamp: %llu", transcript.thread.uniqueId, transcript.timestamp); - - if (transcript.isEndSessionMessage) { - OWSLogInfo(@"EndSession was sent to recipient: %@.", transcript.recipientId); - [self.primaryStorage deleteAllSessionsForContact:transcript.recipientId protocolContext:transaction]; - - // MJK TODO - we don't use this timestamp, safe to remove - [[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp - inThread:transcript.thread - messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction]; - - // Don't continue processing lest we print a bubble for the session reset. - return; - } - - TSOutgoingMessage *outgoingMessage = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:transcript.timestamp - inThread:transcript.thread - messageBody:transcript.body - attachmentIds:[NSMutableArray new] - expiresInSeconds:transcript.expirationDuration - expireStartedAt:transcript.expirationStartedAt - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:transcript.quotedMessage - contactShare:transcript.contact - linkPreview:transcript.linkPreview]; - - - if (transcript.thread.isGroupThread) { - TSGroupThread *thread = (TSGroupThread *)transcript.thread; - if (thread.isOpenGroup) { - [outgoingMessage setServerTimestampToReceivedTimestamp:serverTimestamp]; - } - } - - if (serverID != 0) { - outgoingMessage.openGroupServerMessageID = serverID; - } - - NSArray *attachmentPointers = - [TSAttachmentPointer attachmentPointersFromProtos:transcript.attachmentPointerProtos - albumMessage:outgoingMessage]; - for (TSAttachmentPointer *pointer in attachmentPointers) { - [pointer saveWithTransaction:transaction]; - [outgoingMessage.attachmentIds addObject:pointer.uniqueId]; - } - - TSQuotedMessage *_Nullable quotedMessage = transcript.quotedMessage; - if (quotedMessage && quotedMessage.thumbnailAttachmentPointerId) { - // We weren't able to derive a local thumbnail, so we'll fetch the referenced attachment. - TSAttachmentPointer *attachmentPointer = - [TSAttachmentPointer fetchObjectWithUniqueID:quotedMessage.thumbnailAttachmentPointerId - transaction:transaction]; - - if ([attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) { - OWSLogDebug(@"downloading attachments for transcript: %lu", (unsigned long)transcript.timestamp); - - [self.attachmentDownloads downloadAttachmentPointer:attachmentPointer - success:^(NSArray *attachmentStreams) { - OWSAssertDebug(attachmentStreams.count == 1); - TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [outgoingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream]; - [outgoingMessage saveWithTransaction:transaction]; - if (serverID != 0) { - [OWSPrimaryStorage.sharedManager setIDForMessageWithServerID:serverID to:outgoingMessage.uniqueId in:transaction]; - } - }]; - } - failure:^(NSError *error) { - OWSLogWarn(@"failed to fetch thumbnail for transcript: %lu with error: %@", - (unsigned long)transcript.timestamp, - error); - }]; - } - } - - [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:outgoingMessage.expiresInSeconds - thread:transcript.thread - createdByRemoteRecipientId:nil - createdInExistingGroup:NO - transaction:transaction]; - - if (transcript.isExpirationTimerUpdate) { - // early return to avoid saving an empty incoming message. - OWSAssertDebug(transcript.body.length == 0); - OWSAssertDebug(outgoingMessage.attachmentIds.count == 0); - - return; - } - - if (outgoingMessage.body.length < 1 && outgoingMessage.attachmentIds.count < 1 && !outgoingMessage.contactShare) { - OWSFailDebug(@"Ignoring message transcript for empty message."); - return; - } - - [outgoingMessage saveWithTransaction:transaction]; - [outgoingMessage updateWithWasSentFromLinkedDeviceWithUDRecipientIds:transcript.udRecipientIds - nonUdRecipientIds:transcript.nonUdRecipientIds - isSentUpdate:NO - transaction:transaction]; - [[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:outgoingMessage - expirationStartedAt:transcript.expirationStartedAt - transaction:transaction]; - [self.readReceiptManager applyEarlyReadReceiptsForOutgoingMessageFromLinkedDevice:outgoingMessage - transaction:transaction]; - - if (outgoingMessage.hasAttachments) { - [self.attachmentDownloads - downloadAttachmentsForMessage:outgoingMessage - transaction:transaction - success:attachmentHandler - failure:^(NSError *error) { - OWSLogError( - @"failed to fetch transcripts attachments for message: %@", outgoingMessage); - }]; - } - */ } #pragma mark - @@ -185,92 +54,7 @@ NS_ASSUME_NONNULL_BEGIN + (void)processRecipientUpdateWithTranscript:(OWSIncomingSentMessageTranscript *)transcript transaction:(YapDatabaseReadWriteTransaction *)transaction { - // TODO TODO TODO - /* - OWSAssertDebug(transcript); - OWSAssertDebug(transaction); - - if (!AreRecipientUpdatesEnabled()) { - OWSFailDebug(@"Ignoring 'recipient update' transcript; disabled."); - return; - } - - if (transcript.udRecipientIds.count < 1 && transcript.nonUdRecipientIds.count < 1) { - OWSFailDebug(@"Ignoring empty 'recipient update' transcript."); - return; - } - - uint64_t timestamp = transcript.timestamp; - if (timestamp < 1) { - OWSFailDebug(@"'recipient update' transcript has invalid timestamp."); - return; - } - - if (!transcript.thread.isGroupThread) { - OWSFailDebug(@"'recipient update' has missing or invalid thread."); - return; - } - TSGroupThread *groupThread = (TSGroupThread *)transcript.thread; - NSData *groupId = groupThread.groupModel.groupId; - if (groupId.length < 1) { - OWSFailDebug(@"'recipient update' transcript has invalid groupId."); - return; - } - - NSArray *messages - = (NSArray *)[TSInteraction interactionsWithTimestamp:timestamp - ofClass:[TSOutgoingMessage class] - withTransaction:transaction]; - if (messages.count < 1) { - // This message may have disappeared. - OWSLogError(@"No matching message with timestamp: %llu.", timestamp); - return; - } - - BOOL messageFound = NO; - for (TSOutgoingMessage *message in messages) { - if (!message.isFromLinkedDevice) { - // isFromLinkedDevice isn't always set for very old linked messages, but: - // - // a) We should never receive a "sent update" for a very old message. - // b) It's safe to discard suspicious "sent updates." - continue; - } - TSThread *thread = [message threadWithTransaction:transaction]; - if (!thread.isGroupThread) { - continue; - } - TSGroupThread *groupThread = (TSGroupThread *)thread; - if (![groupThread.groupModel.groupId isEqual:groupId]) { - continue; - } - - if (!message.isFromLinkedDevice) { - OWSFailDebug(@"Ignoring 'recipient update' for message which was sent locally."); - continue; - } - - OWSLogInfo(@"Processing 'recipient update' transcript in thread: %@, timestamp: %llu, nonUdRecipientIds: %d, " - @"udRecipientIds: %d.", - thread.uniqueId, - timestamp, - (int)transcript.nonUdRecipientIds.count, - (int)transcript.udRecipientIds.count); - - [message updateWithWasSentFromLinkedDeviceWithUDRecipientIds:transcript.udRecipientIds - nonUdRecipientIds:transcript.nonUdRecipientIds - isSentUpdate:YES - transaction:transaction]; - - messageFound = YES; - } - - if (!messageFound) { - // This message may have disappeared. - OWSLogError(@"No matching message with timestamp: %llu.", timestamp); - } - */ } @end diff --git a/SignalUtilitiesKit/UI/BlockListUIUtils.m b/SignalUtilitiesKit/UI/BlockListUIUtils.m index c6c9ab310..9633eb1d0 100644 --- a/SignalUtilitiesKit/UI/BlockListUIUtils.m +++ b/SignalUtilitiesKit/UI/BlockListUIUtils.m @@ -231,9 +231,7 @@ typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action); // via params and instead have to create our own sneaky transaction here. [groupThread leaveGroupWithSneakyTransaction]; - // TODO TODO TODO - -// [ThreadUtil enqueueLeaveGroupMessageInThread:groupThread]; + // TODO: If we ever start using this again we should make sure to send a group leave message here NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName; diff --git a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index 250ddc199..add5095c8 100644 --- a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -7,10 +7,11 @@ #import "UIColor+OWS.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" +#import #import #import #import -#import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -215,35 +216,26 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); didApproveAttachments:(NSArray *_Nonnull)attachments messageText:(NSString *_Nullable)messageText { - [self - tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) { - OWSAssertIsOnMainThread(); + [self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) { + SNVisibleMessage *message = [SNVisibleMessage new]; + message.sentTimestamp = [NSDate millisecondTimestamp]; + message.text = messageText; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [tsMessage saveWithTransaction:transaction]; + }]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [SNMessageSender sendNonDurably:message withAttachments:attachments inThread:self.thread usingTransaction:transaction] + .then(^(id object) { + sendCompletion(nil, tsMessage); + }).catch(^(NSError *error) { + sendCompletion(error, tsMessage); + }); + }]; - __block TSOutgoingMessage *outgoingMessage = nil; - // DURABLE CLEANUP - SAE uses non-durable sending to make sure the app is running long enough to complete - // the sending operation. Alternatively, we could use a durable send, but do more to make sure the - // SAE runs as long as it needs. - // TODO ALBUMS - send album via SAE - - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - - // TODO TODO TODO - -// outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText -// mediaAttachments:attachments -// inThread:self.thread -// quotedReplyModel:nil -// transaction:transaction -// messageSender:self.messageSender -// completion:^(NSError *_Nullable error) { -// sendCompletion(error, outgoingMessage); -// }]; - }]; - - // This is necessary to show progress. - self.outgoingMessage = outgoingMessage; - } - fromViewController:attachmentApproval]; + // This is necessary to show progress + self.outgoingMessage = tsMessage; + } fromViewController:attachmentApproval]; } - (void)attachmentApprovalDidCancel:(AttachmentApprovalViewController *)attachmentApproval @@ -262,36 +254,26 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); - (void)messageApproval:(MessageApprovalViewController *)approvalViewController didApproveMessage:(NSString *)messageText { - OWSAssertDebug(messageText.length > 0); - [self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) { - OWSAssertIsOnMainThread(); - - __block TSOutgoingMessage *outgoingMessage = nil; - // DURABLE CLEANUP - SAE uses non-durable sending to make sure the app is running long enough to complete - // the sending operation. Alternatively, we could use a durable send, but do more to make sure the - // SAE runs as long as it needs. - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - - // TODO TODO TODO -// -// outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText -// inThread:self.thread -// quotedReplyModel:nil -// transaction:transaction -// messageSender:self.messageSender -// completion:^(NSError *_Nullable error) { -// if (error) { -// sendCompletion(error, outgoingMessage); -// } else { -// sendCompletion(nil, outgoingMessage); -// } -// }]; - // This is necessary to show progress. - self.outgoingMessage = outgoingMessage; + SNVisibleMessage *message = [SNVisibleMessage new]; + message.sentTimestamp = [NSDate millisecondTimestamp]; + message.text = messageText; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [tsMessage saveWithTransaction:transaction]; }]; - } - fromViewController:approvalViewController]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [SNMessageSender sendNonDurably:message inThread:self.thread usingTransaction:transaction] + .then(^(id object) { + sendCompletion(nil, tsMessage); + }).catch(^(NSError *error) { + sendCompletion(error, tsMessage); + }); + }]; + + // This is necessary to show progress + self.outgoingMessage = tsMessage; + } fromViewController:approvalViewController]; } - (void)messageApprovalDidCancel:(MessageApprovalViewController *)approvalViewController From ab56e12ff44239cdd32ddb79bafee7cf01d34bd1 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 14:12:55 +1100 Subject: [PATCH 042/177] Fix read receipts --- .../Sending & Receiving/Read Tracking/OWSReadReceiptManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m index 8c66234a7..d869af4cd 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m @@ -201,7 +201,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE { NSString *messageAuthorId = message.authorId; - if (!message.thread.isGroupThread) { return; } // Don't send read receipts in group threads + if (message.thread.isGroupThread) { return; } // Don't send read receipts in group threads if ([self areReadReceiptsEnabled]) { [self.outgoingReceiptManager enqueueReadReceiptForEnvelope:messageAuthorId timestamp:message.timestamp]; From 341782f255134053ec8f320f953298805be09603 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 15:16:35 +1100 Subject: [PATCH 043/177] Fix profile handling --- .../ConversationViewController.m | 2 +- .../OWSConversationSettingsViewController.m | 2 +- Session/Signal/OWSOrphanDataCleaner.m | 2 +- .../Database/Storage+Shared.swift | 8 ++++ .../Signal/TSIncomingMessage+Conversion.swift | 10 +++-- .../Signal/TSOutgoingMessage+Conversion.swift | 4 +- .../Meta/SessionMessagingKit.h | 1 + .../Blocking/OWSBlockingManager.h | 2 - .../OWSLinkPreview+Conversion.swift | 7 ++++ .../MessageReceiver+Handling.swift | 8 ++-- .../Sending & Receiving/MessageSender.swift | 9 +++++ SessionMessagingKit/Storage.swift | 2 + .../To Do/OWSUserProfile.h | 0 .../To Do/OWSUserProfile.m | 40 +++---------------- Signal.xcodeproj/project.pbxproj | 20 ++++++---- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 1 - 16 files changed, 61 insertions(+), 57 deletions(-) create mode 100644 SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift rename {SignalUtilitiesKit => SessionMessagingKit}/To Do/OWSUserProfile.h (100%) rename {SignalUtilitiesKit => SessionMessagingKit}/To Do/OWSUserProfile.m (92%) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index f9849191e..91f8cfd1d 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -46,7 +46,7 @@ #import #import #import -#import +#import #import #import #import diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index 9cf4d70c3..c04248bab 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -19,7 +19,7 @@ #import #import -#import +#import #import #import #import diff --git a/Session/Signal/OWSOrphanDataCleaner.m b/Session/Signal/OWSOrphanDataCleaner.m index 29490b5b0..b494abb91 100644 --- a/Session/Signal/OWSOrphanDataCleaner.m +++ b/Session/Signal/OWSOrphanDataCleaner.m @@ -6,7 +6,7 @@ #import "DateUtil.h" #import #import -#import +#import #import #import #import diff --git a/SessionMessagingKit/Database/Storage+Shared.swift b/SessionMessagingKit/Database/Storage+Shared.swift index 1a81fccba..e698b0c3d 100644 --- a/SessionMessagingKit/Database/Storage+Shared.swift +++ b/SessionMessagingKit/Database/Storage+Shared.swift @@ -25,4 +25,12 @@ extension Storage { public func getUserDisplayName() -> String? { return SSKEnvironment.shared.profileManager.localProfileName() } + + public func getUserProfileKey() -> Data? { + return SSKEnvironment.shared.profileManager.localProfileKey().keyData + } + + public func getUserProfilePictureURL() -> String? { + return SSKEnvironment.shared.profileManager.profilePictureURL() + } } diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift index 05762914d..0076d31f8 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift @@ -3,16 +3,20 @@ public extension TSIncomingMessage { static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread) -> TSIncomingMessage { let sender = visibleMessage.sender! + var expiration: UInt32 = 0 + Storage.read { transaction in + expiration = thread.disappearingMessagesDuration(with: transaction) + } let result = TSIncomingMessage( timestamp: visibleMessage.sentTimestamp!, in: thread, authorId: sender, sourceDeviceId: 1, messageBody: visibleMessage.text!, - attachmentIds: [], - expiresInSeconds: 0, + attachmentIds: visibleMessage.attachmentIDs, + expiresInSeconds: expiration, quotedMessage: TSQuotedMessage.from(visibleMessage.quote), - linkPreview: nil, + linkPreview: OWSLinkPreview.from(visibleMessage.linkPreview), serverTimestamp: nil, wasReceivedByUD: true ) diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift index 3f0ec8d85..0ab7a70b4 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift @@ -11,13 +11,13 @@ outgoingMessageWithTimestamp: visibleMessage.sentTimestamp!, in: thread, messageBody: visibleMessage.text, - attachmentIds: NSMutableArray(), + attachmentIds: NSMutableArray(array: visibleMessage.attachmentIDs), expiresInSeconds: expiration, expireStartedAt: 0, isVoiceMessage: false, groupMetaMessage: .unspecified, quotedMessage: TSQuotedMessage.from(visibleMessage.quote), - linkPreview: nil + linkPreview: OWSLinkPreview.from(visibleMessage.linkPreview) ) } } diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index 1a44bbacf..f53ee7cfb 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -27,6 +27,7 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; #import #import #import +#import #import #import #import diff --git a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h index 95ef4913a..a470f6e4e 100644 --- a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h +++ b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h @@ -44,8 +44,6 @@ extern NSString *const kOWSBlockingManager_BlockListCollection; - (BOOL)isGroupIdBlocked:(NSData *)groupId; - (BOOL)isThreadBlocked:(TSThread *)thread; -- (void)syncBlockList; - @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift new file mode 100644 index 000000000..5f4e4ee62 --- /dev/null +++ b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift @@ -0,0 +1,7 @@ + +extension OWSLinkPreview { + + public static func from(_ linkPreview: VisibleMessage.LinkPreview?) -> OWSLinkPreview? { + return nil // TODO: Implement + } +} diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index daad909c6..f2236ac8c 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -146,12 +146,14 @@ extension MessageReceiver { let attachmentIDs = storage.persist(attachments, using: transaction) message.attachmentIDs = attachmentIDs // Update profile if needed - if let profile = message.profile { + if let newProfile = message.profile { let profileManager = SSKEnvironment.shared.profileManager - if let displayName = profile.displayName { + let oldProfile = OWSUserProfile.fetch(uniqueId: message.sender!, transaction: transaction) + if let displayName = newProfile.displayName, displayName != oldProfile?.profileName { profileManager.updateProfileForContact(withID: message.sender!, displayName: displayName, with: transaction) } - if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength { + if let profileKey = newProfile.profileKey, let profilePictureURL = newProfile.profilePictureURL, profileKey.count == kAES256_KeyByteLength, + profileKey != oldProfile?.profileKey?.keyData { profileManager.setProfileKeyData(profileKey, forRecipientId: message.sender!, avatarURL: profilePictureURL) } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index d16b9d997..e6370812a 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -74,6 +74,15 @@ public final class MessageSender : NSObject { } // Validate the message guard message.isValid else { seal.reject(Error.invalidMessage); return promise } + // Attach the user's profile if needed + if let message = message as? VisibleMessage { + let displayName = storage.getUserDisplayName()! + if let profileKey = storage.getUserProfileKey(), let profilePictureURL = storage.getUserProfilePictureURL() { + message.profile = VisibleMessage.Profile(displayName: displayName, profileKey: profileKey, profilePictureURL: profilePictureURL) + } else { + message.profile = VisibleMessage.Profile(displayName: displayName) + } + } // Convert it to protobuf guard let proto = message.toProto() else { seal.reject(Error.protoConversionFailed); return promise } // Serialize the protobuf diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 0d55606e5..9855ba670 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -12,6 +12,8 @@ public protocol SessionMessagingKitStorageProtocol { func getUserPublicKey() -> String? func getUserKeyPair() -> ECKeyPair? func getUserDisplayName() -> String? + func getUserProfileKey() -> Data? + func getUserProfilePictureURL() -> String? // MARK: - Signal Protocol diff --git a/SignalUtilitiesKit/To Do/OWSUserProfile.h b/SessionMessagingKit/To Do/OWSUserProfile.h similarity index 100% rename from SignalUtilitiesKit/To Do/OWSUserProfile.h rename to SessionMessagingKit/To Do/OWSUserProfile.h diff --git a/SignalUtilitiesKit/To Do/OWSUserProfile.m b/SessionMessagingKit/To Do/OWSUserProfile.m similarity index 92% rename from SignalUtilitiesKit/To Do/OWSUserProfile.m rename to SessionMessagingKit/To Do/OWSUserProfile.m index 99f9368d1..7e18a8d3b 100644 --- a/SignalUtilitiesKit/To Do/OWSUserProfile.m +++ b/SessionMessagingKit/To Do/OWSUserProfile.m @@ -4,16 +4,13 @@ #import "OWSUserProfile.h" #import - - -#import -#import -#import -#import #import #import -#import #import +#import +#import +#import +#import #import #import @@ -73,8 +70,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; + (OWSUserProfile *)getOrBuildUserProfileForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSAssertDebug(recipientId.length > 0); - OWSUserProfile *userProfile = [OWSUserProfile fetchObjectWithUniqueID:recipientId transaction:transaction]; if (!userProfile) { @@ -87,8 +82,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; } } - OWSAssertDebug(userProfile); - return userProfile; } @@ -110,7 +103,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; return self; } - OWSAssertDebug(recipientId.length > 0); _recipientId = recipientId; return self; @@ -120,8 +112,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; - (TSAccountManager *)tsAccountManager { - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - return SSKEnvironment.shared.tsAccountManager; } @@ -223,7 +213,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; NSDictionary *afterSnapshot = [latestInstance.dictionaryValue copy]; if ([beforeSnapshot isEqual:afterSnapshot]) { - OWSLogVerbose(@"Ignoring redundant update in %s: %@", functionName, self.debugDescription); didChange = NO; } else { [latestInstance saveWithTransaction:transaction]; @@ -373,8 +362,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; transaction:(YapDatabaseReadWriteTransaction *)transaction completion:(nullable OWSUserProfileCompletion)completion { - OWSAssertDebug(profileKey); - [self applyChanges:^(OWSUserProfile *userProfile) { [userProfile setProfileKey:profileKey]; } @@ -387,29 +374,21 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; - (YapDatabaseConnection *)dbReadConnection { - OWSFailDebug(@"UserProfile should always use OWSProfileManager's database connection."); - return TSYapDatabaseObject.dbReadConnection; } + (YapDatabaseConnection *)dbReadConnection { - OWSFailDebug(@"UserProfile should always use OWSProfileManager's database connection."); - return TSYapDatabaseObject.dbReadConnection; } - (YapDatabaseConnection *)dbReadWriteConnection { - OWSFailDebug(@"UserProfile should always use OWSProfileManager's database connection."); - return TSYapDatabaseObject.dbReadWriteConnection; } + (YapDatabaseConnection *)dbReadWriteConnection { - OWSFailDebug(@"UserProfile should always use OWSProfileManager's database connection."); - return TSYapDatabaseObject.dbReadWriteConnection; } @@ -417,7 +396,7 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; - (NSString *)debugDescription { return [NSString stringWithFormat:@"%@ %p %@ %lu %@ %@ %@", - self.logTag, + @"OWSUserProfile", self, self.recipientId, (unsigned long)self.profileKey.keyData.length, @@ -463,8 +442,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; + (nullable NSError *)migrateToSharedData { - OWSLogInfo(@""); - return [OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath sharedDataFilePath:self.sharedDataProfileAvatarsDirPath]; } @@ -485,13 +462,8 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; + (void)resetProfileStorage { - OWSAssertIsOnMainThread(); - NSError *error; [[NSFileManager defaultManager] removeItemAtPath:[self profileAvatarsDirPath] error:&error]; - if (error) { - OWSLogError(@"Failed to delete database: %@", error.description); - } } + (NSSet *)allProfileAvatarFilePaths @@ -504,8 +476,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; enumerateCollectionObjectsWithTransaction:transaction usingBlock:^(id object, BOOL *stop) { if (![object isKindOfClass:[OWSUserProfile class]]) { - OWSFailDebug( - @"unexpected object in user profiles: %@", [object class]); return; } OWSUserProfile *userProfile = object; diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index ac88a5784..d1d0b9d24 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -242,6 +242,9 @@ B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; }; B8544E3323D50E4900299F14 /* AppearanceUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */; }; + B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8566C62256F55930045A0B9 /* OWSLinkPreview+Conversion.swift */; }; + B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; + B8566C7D256F62030045A0B9 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; @@ -612,9 +615,7 @@ C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */; }; C38EF2B4255B6D9C007E1867 /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */; }; C38EF2D4255B6DAF007E1867 /* OWSProfileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */; }; - C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; C38EF2D7255B6DAF007E1867 /* OWSProfileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C38EF2D8255B6DAF007E1867 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF30C255B6DBF007E1867 /* OWSScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E2255B6DB9007E1867 /* OWSScreenLock.swift */; }; C38EF30D255B6DBF007E1867 /* OWSUnreadIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */; }; C38EF30E255B6DBF007E1867 /* FullTextSearcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */; }; @@ -1348,6 +1349,7 @@ B85357C223A1BD1200AAF6CD /* SeedVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedVC.swift; sourceTree = ""; }; B8544E3023D16CA500299F14 /* DeviceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceUtilities.swift; sourceTree = ""; }; B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceUtilities.swift; sourceTree = ""; }; + B8566C62256F55930045A0B9 /* OWSLinkPreview+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OWSLinkPreview+Conversion.swift"; sourceTree = ""; }; B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = ""; }; B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; @@ -1725,9 +1727,9 @@ C38EF2BE255B6DA6007E1867 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSUnreadIndicatorInteraction.h; path = "SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.h"; sourceTree = SOURCE_ROOT; }; C38EF2C1255B6DA6007E1867 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSUnreadIndicatorInteraction.m; path = "SessionMessagingKit/Sending & Receiving/Read Tracking/TSUnreadIndicatorInteraction.m"; sourceTree = SOURCE_ROOT; }; C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSProfileManager.m; path = "SignalUtilitiesKit/To Do/OWSProfileManager.m"; sourceTree = SOURCE_ROOT; }; - C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SignalUtilitiesKit/To Do/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; + C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUserProfile.m; path = "SessionMessagingKit/To Do/OWSUserProfile.m"; sourceTree = SOURCE_ROOT; }; C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSProfileManager.h; path = "SignalUtilitiesKit/To Do/OWSProfileManager.h"; sourceTree = SOURCE_ROOT; }; - C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = "SignalUtilitiesKit/To Do/OWSUserProfile.h"; sourceTree = SOURCE_ROOT; }; + C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSUserProfile.h; path = "SessionMessagingKit/To Do/OWSUserProfile.h"; sourceTree = SOURCE_ROOT; }; C38EF2E2255B6DB9007E1867 /* OWSScreenLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSScreenLock.swift; path = SignalUtilitiesKit/OWSScreenLock.swift; sourceTree = SOURCE_ROOT; }; C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSUnreadIndicator.m; path = SignalUtilitiesKit/OWSUnreadIndicator.m; sourceTree = SOURCE_ROOT; }; C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FullTextSearcher.swift; path = SignalUtilitiesKit/FullTextSearcher.swift; sourceTree = SOURCE_ROOT; }; @@ -2820,6 +2822,8 @@ C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */, C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */, + C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */, + C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */, C32C5C92256DD12D003C73A2 /* OWSUDManager.swift */, C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, C33FDAEC255A580500E217F9 /* SignalRecipient.h */, @@ -2858,6 +2862,7 @@ isa = PBXGroup; children = ( C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */, + B8566C62256F55930045A0B9 /* OWSLinkPreview+Conversion.swift */, ); path = "Link Previews"; sourceTree = ""; @@ -3205,8 +3210,6 @@ C38EF3EB255B6DF6007E1867 /* ContactTableViewCell.m */, C38EF2D2255B6DAF007E1867 /* OWSProfileManager.h */, C38EF2CF255B6DAE007E1867 /* OWSProfileManager.m */, - C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */, - C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */, C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */, C33FDB58255A580E00E217F9 /* OWSPrimaryStorage+Loki.m */, ); @@ -3907,7 +3910,6 @@ C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */, C38EF291255B6D86007E1867 /* SignalKeyingStorage.h in Headers */, C33FDC89255A582000E217F9 /* OWSAttachmentDownloads.h in Headers */, - C38EF2D8255B6DAF007E1867 /* OWSUserProfile.h in Headers */, C38EF313255B6DBF007E1867 /* OWSUnreadIndicator.h in Headers */, C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, C33FDDA9255A582000E217F9 /* TSStorageKeys.h in Headers */, @@ -4051,6 +4053,7 @@ B8856D3D256F11B2001CE70E /* Environment.h in Headers */, C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */, C32C5CAD256DD1DF003C73A2 /* TSAccountManager.h in Headers */, + B8566C7D256F62030045A0B9 /* OWSUserProfile.h in Headers */, C3A3A0F5256E194C004D228D /* OWSRecipientIdentity.h in Headers */, C32C5AB4256DBE8F003C73A2 /* TSOutgoingMessage.h in Headers */, C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */, @@ -5014,7 +5017,6 @@ C33FDD14255A582000E217F9 /* OWSUDManager.swift in Sources */, C33FDDAE255A582000E217F9 /* DisplayNameUtilities2.swift in Sources */, C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */, - C38EF2D6255B6DAF007E1867 /* OWSUserProfile.m in Sources */, C38EF30E255B6DBF007E1867 /* FullTextSearcher.swift in Sources */, C33FDDD9255A582000E217F9 /* LokiSessionRestorationImplementation.swift in Sources */, C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */, @@ -5196,6 +5198,7 @@ C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */, C3A721382558BDFA0043A11F /* OpenGroupMessage.swift in Sources */, C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */, + B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */, C32C5B3F256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift in Sources */, C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */, C32C5D19256DD493003C73A2 /* OWSLinkPreview.swift in Sources */, @@ -5217,6 +5220,7 @@ C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */, C32C5C1B256DC9E0003C73A2 /* GeneralUtilities.swift in Sources */, C32C5A02256DB658003C73A2 /* MessageSender+Handling.swift in Sources */, + B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */, C32C5D2E256DD4EA003C73A2 /* TSUnreadIndicatorInteraction.m in Sources */, C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */, C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */, diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 43d281385..1d8cb1e42 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -35,7 +35,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import From 3eae001202fcb872271c266dd92976add993293d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 15:51:12 +1100 Subject: [PATCH 044/177] Fix disappearing messages --- Session/Components/PNOptionView.swift | 2 +- .../OWSConversationSettingsViewController.m | 2 +- .../ExpirationTimerUpdate.swift | 2 +- .../MessageReceiver+Handling.swift | 40 +++++++++---------- .../Sending & Receiving/MessageSender.swift | 13 ------ .../MessageSender+Handling.swift | 17 ++++++++ 6 files changed, 40 insertions(+), 36 deletions(-) diff --git a/Session/Components/PNOptionView.swift b/Session/Components/PNOptionView.swift index e0fdde313..e412c4acd 100644 --- a/Session/Components/PNOptionView.swift +++ b/Session/Components/PNOptionView.swift @@ -34,7 +34,7 @@ final class OptionView : UIView { // Set up shadow layer.shadowColor = UIColor.black.cgColor layer.shadowOffset = CGSize(width: 0, height: 0.8) - layer.shadowOpacity = isLightMode ? 0.4 : 1 + layer.shadowOpacity = isLightMode ? 0.16 : 1 layer.shadowRadius = isLightMode ? 4 : 6 // Set up title label let titleLabel = UILabel() diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index c04248bab..ac678182e 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -864,7 +864,7 @@ static CGRect oldframe; } if (self.disappearingMessagesConfiguration.dictionaryValueDidChange) { - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.disappearingMessagesConfiguration saveWithTransaction:transaction]; OWSDisappearingConfigurationUpdateInfoMessage *infoMessage = [[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] diff --git a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift index 3d365518c..e922a54d9 100644 --- a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift @@ -58,6 +58,6 @@ public final class ExpirationTimerUpdate : ControlMessage { // MARK: Convenience @objc public func setDuration(_ duration: UInt32) { - + self.duration = duration } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index f2236ac8c..5bfa544a3 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -93,44 +93,44 @@ extension MessageReceiver { public static func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction + var isGroup = false var threadOrNil: TSThread? - Storage.read { transaction in - if let groupPublicKey = groupPublicKey { - guard Storage.shared.isClosedGroup(groupPublicKey) else { return } - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) - } else { - threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) - } + if let groupPublicKey = groupPublicKey { + guard Storage.shared.isClosedGroup(groupPublicKey) else { return } + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) + isGroup = true + } else { + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) } guard let thread = threadOrNil else { return } let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: true, durationSeconds: duration) configuration.save(with: transaction) - let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) + let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) ?? senderPublicKey let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, - configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) + configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: isGroup) message.save(with: transaction) SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() } public static func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction + var isGroup = false var threadOrNil: TSThread? - Storage.read { transaction in - if let groupPublicKey = groupPublicKey { - guard Storage.shared.isClosedGroup(groupPublicKey) else { return } - let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) - threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) - } else { - threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) - } + if let groupPublicKey = groupPublicKey { + guard Storage.shared.isClosedGroup(groupPublicKey) else { return } + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) + isGroup = true + } else { + threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) } guard let thread = threadOrNil else { return } let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: false, durationSeconds: 24 * 60 * 60) configuration.save(with: transaction) - let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) + let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction) ?? senderPublicKey let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread, - configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false) + configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: isGroup) message.save(with: transaction) SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index e6370812a..0154aed22 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -235,17 +235,4 @@ public final class MessageSender : NSObject { // Return return promise } - - // MARK: Result Handling - public static func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } - tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 - tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 - tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) - } - - public static func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } - tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction) - } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index 37d746b9f..bc2af8cc8 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -58,6 +58,23 @@ extension MessageSender : SharedSenderKeysDelegate { let destination = Message.Destination.from(thread) return MessageSender.send(message, to: destination, using: transaction) } + + + + // MARK: - Success & Failure Handling + + public static func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 + tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 + tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) + OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction as! YapDatabaseReadWriteTransaction) + } + + public static func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction) + } From f6b78f9e997e39f2af57fc69f06cfbd456e3066d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 16:06:20 +1100 Subject: [PATCH 045/177] Adjust snode API parameters --- SessionSnodeKit/SnodeAPI.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index 5bc44f96a..9f10d55fe 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -14,11 +14,11 @@ public final class SnodeAPI : NSObject { public static var workQueue: DispatchQueue { Threading.workQueue } // Just to make things fit with legacy code // MARK: Settings - private static let maxRetryCount: UInt = 4 + private static let maxRetryCount: UInt = 8 private static let minimumSnodePoolCount = 64 private static let minimumSwarmSnodeCount = 2 private static let seedNodePool: Set = [ "https://storage.seed1.loki.network", "https://storage.seed3.loki.network", "https://public.loki.foundation" ] - private static let snodeFailureThreshold = 4 + private static let snodeFailureThreshold = 3 private static let targetSwarmSnodeCount = 2 /// - Note: Changing this on the fly is not recommended. From a88ce33ee0f1c3f1612459c1907168003b3bda23 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 26 Nov 2020 16:33:42 +1100 Subject: [PATCH 046/177] WIP --- SessionMessagingKit/Jobs/MessageSendJob.swift | 2 ++ .../Messages/Signal/TSOutgoingMessage+Conversion.swift | 2 +- .../Messages/Visible Messages/VisibleMessage.swift | 8 ++++++-- .../Sending & Receiving/MessageSender.swift | 8 +++++++- .../Sending & Receiving/MessageSender+Handling.swift | 1 + 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 5bb1b1f5d..61b3718ab 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -1,5 +1,7 @@ import SessionUtilitiesKit +// TODO: Cancel when a message is deleted + @objc(SNMessageSendJob) public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public let message: Message diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift index 0ab7a70b4..5cf891342 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift @@ -11,7 +11,7 @@ outgoingMessageWithTimestamp: visibleMessage.sentTimestamp!, in: thread, messageBody: visibleMessage.text, - attachmentIds: NSMutableArray(array: visibleMessage.attachmentIDs), + attachmentIds: NSMutableArray(), expiresInSeconds: expiration, expireStartedAt: 0, isVoiceMessage: false, diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 3cd5fab53..1bc671635 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -47,6 +47,10 @@ public final class VisibleMessage : Message { } public override func toProto() -> SNProtoContent? { + preconditionFailure("Use toProto(using:) instead.") + } + + public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { let proto = SNProtoContent.builder() let dataMessage: SNProtoDataMessage.SNProtoDataMessageBuilder if let profile = profile, let profileProto = profile.toProto() { @@ -55,13 +59,13 @@ public final class VisibleMessage : Message { dataMessage = SNProtoDataMessage.builder() } if let text = text { dataMessage.setBody(text) } - let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0) } + let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } if !attachments.allSatisfy({ $0.isUploaded }) { #if DEBUG preconditionFailure("Sending a message before all associated attachments have been uploaded.") #endif } - let attachmentProtos = attachments.compactMap { TSAttachmentStream.buildProto(forAttachmentId: $0.uniqueId!) } + let attachmentProtos = attachments.compactMap { $0.buildProto() } dataMessage.setAttachments(attachmentProtos) if let quote = quote, let quoteProto = quote.toProto() { dataMessage.setQuote(quoteProto) } if let linkPreview = linkPreview, let linkPreviewProto = linkPreview.toProto() { dataMessage.setPreview([ linkPreviewProto ]) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 0154aed22..03f1f83ec 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -84,7 +84,13 @@ public final class MessageSender : NSObject { } } // Convert it to protobuf - guard let proto = message.toProto() else { seal.reject(Error.protoConversionFailed); return promise } + let protoOrNil: SNProtoContent? + if let message = message as? VisibleMessage { + protoOrNil = message.toProto(using: transaction as! YapDatabaseReadWriteTransaction) // Needed because of how TSAttachmentStream works + } else { + protoOrNil = message.toProto() + } + guard let proto = protoOrNil else { seal.reject(Error.protoConversionFailed); return promise } // Serialize the protobuf let plaintext: Data do { diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index bc2af8cc8..af5009f69 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -22,6 +22,7 @@ extension MessageSender : SharedSenderKeysDelegate { stream.save(with: transaction) } message.attachmentIDs = streams.map { $0.uniqueId! } + tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) } @objc(send:withAttachments:inThread:usingTransaction:) From f04db2afb10ad74856cb8f11890252edbd117f85 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 26 Nov 2020 17:41:39 +1100 Subject: [PATCH 047/177] Add missing save(with:) --- .../Messaging/Sending & Receiving/MessageSender+Handling.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index af5009f69..a0b13b789 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -23,6 +23,7 @@ extension MessageSender : SharedSenderKeysDelegate { } message.attachmentIDs = streams.map { $0.uniqueId! } tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) + tsMessage.save(with: transaction) } @objc(send:withAttachments:inThread:usingTransaction:) From 77c1f721b91f49c2ffca9adcb45fc7e003c4eafb Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 09:07:24 +1100 Subject: [PATCH 048/177] Further debug attachment sending --- .../Database/Storage+Jobs.swift | 12 ++++++++ .../Jobs/AttachmentDownloadJob.swift | 2 +- .../Jobs/AttachmentUploadJob.swift | 28 ++++++++++++++++++- SessionMessagingKit/Jobs/JobDelegate.swift | 1 - SessionMessagingKit/Jobs/JobQueue.swift | 10 +++---- SessionMessagingKit/Jobs/MessageSendJob.swift | 6 ++-- .../Signal/TSIncomingMessage+Conversion.swift | 2 +- .../Messages/Signal/TSOutgoingMessage.m | 2 -- .../Sending & Receiving/MessageReceiver.swift | 6 +++- .../Read Tracking/OWSOutgoingReceiptManager.m | 2 ++ SessionMessagingKit/Storage.swift | 2 ++ SessionMessagingKit/Utilities/Threading.swift | 6 ++++ .../Utilities/YapDatabaseTransaction+OWS.m | 2 +- Signal.xcodeproj/project.pbxproj | 4 +++ 14 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 SessionMessagingKit/Utilities/Threading.swift diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index ac91708a7..bb1e00f3e 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -56,4 +56,16 @@ extension Storage { #endif return result.first } + + public func getMessageSendJob(for messageSendJobID: String) -> MessageSendJob? { + var result: MessageSendJob? + Storage.read { transaction in + result = transaction.object(forKey: messageSendJobID, inCollection: MessageSendJob.collection) as? MessageSendJob + } + return result + } + + public func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) { + getMessageSendJob(for: messageSendJobID)?.execute() + } } diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index bfc4939c1..706e2e353 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -21,7 +21,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject // MARK: Settings public class var collection: String { return "AttachmentDownloadJobCollection" } - public static let maxFailureCount: UInt = 20 + public static let maxFailureCount: UInt = 100 // MARK: Initialization public init(attachmentID: String, tsIncomingMessageID: String) { diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index c50c78b37..45c92a490 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -3,6 +3,8 @@ import SessionUtilitiesKit public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public let attachmentID: String public let threadID: String + public let message: Message + public let messageSendJobID: String public var delegate: JobDelegate? public var id: String? public var failureCount: UInt = 0 @@ -22,18 +24,24 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N public static let maxFailureCount: UInt = 20 // MARK: Initialization - public init(attachmentID: String, threadID: String) { + public init(attachmentID: String, threadID: String, message: Message, messageSendJobID: String) { self.attachmentID = attachmentID self.threadID = threadID + self.message = message + self.messageSendJobID = messageSendJobID } // MARK: Coding public init?(coder: NSCoder) { guard let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String?, let threadID = coder.decodeObject(forKey: "threadID") as! String?, + let message = coder.decodeObject(forKey: "message") as! Message?, + let messageSendJobID = coder.decodeObject(forKey: "messageSendJobID") as! String?, let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.attachmentID = attachmentID self.threadID = threadID + self.message = message + self.messageSendJobID = messageSendJobID self.id = id self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } @@ -41,6 +49,8 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N public func encode(with coder: NSCoder) { coder.encode(attachmentID, forKey: "attachmentID") coder.encode(threadID, forKey: "threadID") + coder.encode(message, forKey: "message") + coder.encode(messageSendJobID, forKey: "messageSendJobID") coder.encode(id, forKey: "id") coder.encode(failureCount, forKey: "failureCount") } @@ -69,14 +79,30 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N private func handleSuccess() { delegate?.handleJobSucceeded(self) + Configuration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID) } private func handlePermanentFailure(error: Swift.Error) { delegate?.handleJobFailedPermanently(self, with: error) + failAssociatedMessageSendJob(with: error) } private func handleFailure(error: Swift.Error) { delegate?.handleJobFailed(self, with: error) + if failureCount + 1 == AttachmentUploadJob.maxFailureCount { + failAssociatedMessageSendJob(with: error) + } + } + + private func failAssociatedMessageSendJob(with error: Swift.Error) { + let storage = Configuration.shared.storage + let messageSendJob = storage.getMessageSendJob(for: messageSendJobID) + storage.withAsync({ transaction in // Intentionally capture self + MessageSender.handleFailedMessageSend(self.message, with: error, using: transaction) + if let messageSendJob = messageSendJob { + storage.markJobAsFailed(messageSendJob, using: transaction) + } + }, completion: { }) } } diff --git a/SessionMessagingKit/Jobs/JobDelegate.swift b/SessionMessagingKit/Jobs/JobDelegate.swift index d4b27f5b8..b45a5bf28 100644 --- a/SessionMessagingKit/Jobs/JobDelegate.swift +++ b/SessionMessagingKit/Jobs/JobDelegate.swift @@ -5,5 +5,4 @@ public protocol JobDelegate { func handleJobSucceeded(_ job: Job) func handleJobFailed(_ job: Job, with error: Error) func handleJobFailedPermanently(_ job: Job, with error: Error) - func postpone(_ job: Job) } diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 839242d0b..1a7eb2e3f 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -1,5 +1,7 @@ import SessionUtilitiesKit +// TODO: Check that retrying works + @objc(SNJobQueue) public final class JobQueue : NSObject, JobDelegate { private var hasResumedPendingJobs = false // Just for debugging @@ -9,7 +11,7 @@ public final class JobQueue : NSObject, JobDelegate { @objc public func add(_ job: Job, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction addWithoutExecuting(job, using: transaction) - transaction.addCompletionQueue(DispatchQueue.global(qos: .userInitiated)) { + transaction.addCompletionQueue(Threading.jobQueue) { job.execute() } } @@ -56,7 +58,7 @@ public final class JobQueue : NSObject, JobDelegate { }) } else { let retryInterval = self.getRetryInterval(for: job) - Timer.weakScheduledTimer(withTimeInterval: retryInterval, target: self, selector: #selector(self.retry(_:)), userInfo: job, repeats: false) + Timer.scheduledTimer(timeInterval: retryInterval, target: self, selector: #selector(self.retry(_:)), userInfo: job, repeats: false) } }) } @@ -74,10 +76,6 @@ public final class JobQueue : NSObject, JobDelegate { }) }) } - - public func postpone(_ job: Job) { - Timer.weakScheduledTimer(withTimeInterval: 3, target: self, selector: #selector(self.retry(_:)), userInfo: job, repeats: false) - } private func getRetryInterval(for job: Job) -> TimeInterval { // Arbitrary backoff factor... diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 61b3718ab..169a9cb67 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -1,6 +1,6 @@ import SessionUtilitiesKit -// TODO: Cancel when a message is deleted +// TODO: Cancel when a message/conversation is deleted @objc(SNMessageSendJob) public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility @@ -71,13 +71,13 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi if storage.getAttachmentUploadJob(for: attachment.uniqueId!) != nil { // Wait for it to finish } else { - let job = AttachmentUploadJob(attachmentID: attachment.uniqueId!, threadID: message.threadID!) + let job = AttachmentUploadJob(attachmentID: attachment.uniqueId!, threadID: message.threadID!, message: message, messageSendJobID: id!) storage.withAsync({ transaction in JobQueue.shared.add(job, using: transaction) }, completion: { }) } } - if !attachmentsToUpload.isEmpty { delegate?.postpone(self); return } // Wait for all attachments to upload before continuing + if !attachmentsToUpload.isEmpty { return } // Wait for all attachments to upload before continuing } // FIXME: This doesn't yet handle the attachment side of link previews, quotes, etc. storage.withAsync({ transaction in // Intentionally capture self diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift index 0076d31f8..c28b77bf9 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift @@ -12,7 +12,7 @@ public extension TSIncomingMessage { in: thread, authorId: sender, sourceDeviceId: 1, - messageBody: visibleMessage.text!, + messageBody: visibleMessage.text, attachmentIds: visibleMessage.attachmentIDs, expiresInSeconds: expiration, quotedMessage: TSQuotedMessage.from(visibleMessage.quote), diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m index 7ba4eaa91..12e5c1e0f 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m @@ -1059,8 +1059,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt return [result copy]; } -- (uint)ttl { return 2 * 24 * 60 * 60 * 1000; } - @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index ced2e30ae..9d918ef45 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -84,7 +84,11 @@ internal enum MessageReceiver { message.receivedTimestamp = NSDate.millisecondTimestamp() message.groupPublicKey = groupPublicKey message.openGroupServerMessageID = messageServerID - guard message.isValid else { throw Error.invalidMessage } + var isValid = message.isValid + if message is VisibleMessage && !isValid && proto.dataMessage?.attachments.isEmpty == false { + isValid = true + } + guard isValid else { throw Error.invalidMessage } return (message, proto) } else { throw Error.unknownMessage diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m index c4209f073..261cd393d 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSOutgoingReceiptManager.m @@ -133,6 +133,8 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa } - (NSArray *)sendReceiptsForReceiptType:(OWSReceiptType)receiptType { + if (receiptType == OWSReceiptType_Delivery) { return @[]; } // Don't send delivery receipts + NSString *collection = [self collectionForReceiptType:receiptType]; NSMutableDictionary *> *queuedReceiptMap = [NSMutableDictionary new]; diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 9855ba670..926aebc11 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -32,6 +32,8 @@ public protocol SessionMessagingKitStorageProtocol { func markJobAsFailed(_ job: Job, using transaction: Any) func getAllPendingJobs(of type: Job.Type) -> [Job] func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? + func getMessageSendJob(for messageSendJobID: String) -> MessageSendJob? + func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) // MARK: - Authorization diff --git a/SessionMessagingKit/Utilities/Threading.swift b/SessionMessagingKit/Utilities/Threading.swift new file mode 100644 index 000000000..fb4a1dbba --- /dev/null +++ b/SessionMessagingKit/Utilities/Threading.swift @@ -0,0 +1,6 @@ +import Foundation + +internal enum Threading { + + internal static let jobQueue = DispatchQueue(label: "SessionMessagingKit.jobQueue", qos: .userInitiated) +} diff --git a/SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.m b/SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.m index dbfad0a86..0c9ea9cd0 100644 --- a/SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.m +++ b/SessionMessagingKit/Utilities/YapDatabaseTransaction+OWS.m @@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN return value; } - - (nullable NSDictionary *)dictionaryForKey : (NSString *)key inCollection : (NSString *)collection +- (nullable NSDictionary *)dictionaryForKey : (NSString *)key inCollection : (NSString *)collection { return [self objectForKey:key inCollection:collection ofExpectedType:[NSDictionary class]]; } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d1d0b9d24..dcec96784 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -913,6 +913,7 @@ C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; + C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; }; C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; }; C3F0A5EC255C970D007BE2A3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5EB255C970D007BE2A3 /* Configuration.swift */; }; D2179CFC16BB0B3A0006F3AB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */; }; @@ -2012,6 +2013,7 @@ C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = ""; }; + C3ECBF7A257056B700EA7FCE /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = ""; }; C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = ""; }; C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; C3F0A5EB255C970D007BE2A3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; @@ -3351,6 +3353,7 @@ C33FDACD255A580200E217F9 /* SSKJobRecord.m */, C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */, C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */, + C3ECBF7A257056B700EA7FCE /* Threading.swift */, C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */, C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */, @@ -5216,6 +5219,7 @@ B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */, C32C5F5F256DFD90003C73A2 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */, + C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */, C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */, C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */, C32C5C1B256DC9E0003C73A2 /* GeneralUtilities.swift in Sources */, From 2fa3a7edb79a47e7ea24176465a68392a4b3e589 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 09:27:20 +1100 Subject: [PATCH 049/177] Fix job retrying --- SessionMessagingKit/Jobs/AttachmentUploadJob.swift | 4 ++++ SessionMessagingKit/Jobs/JobQueue.swift | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index 45c92a490..c42e2ba8e 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -57,6 +57,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N // MARK: Running public func execute() { + SNLog("Attachment upload failure count: \(failureCount).") guard let stream = TSAttachmentStream.fetch(uniqueId: attachmentID) else { return handleFailure(error: Error.noAttachment) } @@ -78,16 +79,19 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N } private func handleSuccess() { + SNLog("Attachment uploaded successfully.") delegate?.handleJobSucceeded(self) Configuration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID) } private func handlePermanentFailure(error: Swift.Error) { + SNLog("Attachment upload failed permanently due to error: \(error).") delegate?.handleJobFailedPermanently(self, with: error) failAssociatedMessageSendJob(with: error) } private func handleFailure(error: Swift.Error) { + SNLog("Attachment upload failed due to error: \(error).") delegate?.handleJobFailed(self, with: error) if failureCount + 1 == AttachmentUploadJob.maxFailureCount { failAssociatedMessageSendJob(with: error) diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 1a7eb2e3f..e73e12530 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -32,7 +32,11 @@ public final class JobQueue : NSObject, JobDelegate { let allJobTypes: [Job.Type] = [ AttachmentDownloadJob.self, AttachmentUploadJob.self, MessageReceiveJob.self, MessageSendJob.self, NotifyPNServerJob.self ] allJobTypes.forEach { type in let allPendingJobs = Configuration.shared.storage.getAllPendingJobs(of: type) - allPendingJobs.sorted(by: { $0.id! < $1.id! }).forEach { $0.execute() } // Retry the oldest jobs first + allPendingJobs.sorted(by: { $0.id! < $1.id! }).forEach { job in // Retry the oldest jobs first + SNLog("Resuming pending job of type: \(type).") + job.delegate = self + job.execute() + } } } @@ -58,6 +62,7 @@ public final class JobQueue : NSObject, JobDelegate { }) } else { let retryInterval = self.getRetryInterval(for: job) + SNLog("Job failed; scheduling retry.") Timer.scheduledTimer(timeInterval: retryInterval, target: self, selector: #selector(self.retry(_:)), userInfo: job, repeats: false) } }) @@ -90,8 +95,9 @@ public final class JobQueue : NSObject, JobDelegate { return 0.1 * min(maxBackoff, pow(backoffFactor, Double(job.failureCount))) } - @objc private func retry(_ job: Any) { - guard let job = job as? Job else { return } + @objc private func retry(_ timer: Timer) { + SNLog("Retrying job.") + guard let job = timer.userInfo as? Job else { return } job.execute() } } From c59fe05f8e0cc1ef152ea0b694bb1e31a8eaebb1 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 10:08:46 +1100 Subject: [PATCH 050/177] Cancel message send job(s) if associated message/thread is deleted --- .../ConversationViewController.m | 11 ++++++- .../ConversationView/ConversationViewItem.m | 27 +++++++++++----- Session/Signal/MessageActions.swift | 32 ++++++++----------- Session/View Controllers/HomeVC.swift | 15 +++++---- .../Database/Storage+Jobs.swift | 26 ++++++++++++++- .../Database/Storage+Shared.swift | 2 +- SessionMessagingKit/Jobs/JobQueue.swift | 5 +-- SessionMessagingKit/Jobs/MessageSendJob.swift | 5 +-- SessionMessagingKit/Storage.swift | 1 + 9 files changed, 83 insertions(+), 41 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 91f8cfd1d..d6a51e945 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -65,6 +65,7 @@ #import #import #import +#import #import #import #import @@ -1477,7 +1478,7 @@ typedef enum : NSUInteger { UIAlertAction *deleteMessageAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_DELETE_TITLE", @"") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { - [message remove]; + [self remove:message]; }]; [actionSheet addAction:deleteMessageAction]; @@ -1497,6 +1498,14 @@ typedef enum : NSUInteger { [self presentAlert:actionSheet]; } +- (void)remove:(TSOutgoingMessage *)message +{ + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [message removeWithTransaction:transaction]; + [LKStorage.shared cancelPendingMessageSendJobIfNeededForMessage:message.timestamp using:transaction]; + }]; +} + - (void)tappedCorruptedMessage:(TSErrorMessage *)message { NSString *alertMessage = [NSString diff --git a/Session/Signal/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m index 6583ffce5..8ad9ff9d5 100644 --- a/Session/Signal/ConversationView/ConversationViewItem.m +++ b/Session/Signal/ConversationView/ConversationViewItem.m @@ -1084,26 +1084,37 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) - (void)deleteAction { - [self.interaction remove]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [self.interaction removeWithTransaction:transaction]; + if (self.interaction.interactionType == OWSInteractionType_OutgoingMessage) { + [LKStorage.shared cancelPendingMessageSendJobIfNeededForMessage:self.interaction.timestamp using:transaction]; + } + }]; if (self.isGroupThread) { - // Skip if the thread is an RSS feed TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread; // Only allow deletion on incoming and outgoing messages OWSInteractionType interationType = self.interaction.interactionType; if (interationType != OWSInteractionType_IncomingMessage && interationType != OWSInteractionType_OutgoingMessage) return; - // Make sure it's a public chat message + // Make sure it's an open group message TSMessage *message = (TSMessage *)self.interaction; if (!message.isOpenGroupMessage) return; - - SNOpenGroup *publicChat = [LKStorage.shared getOpenGroupForThreadID:groupThread.uniqueId]; - if (publicChat == nil) return; + + // Get the open group + SNOpenGroup *openGroup = [LKStorage.shared getOpenGroupForThreadID:groupThread.uniqueId]; + if (openGroup == nil) return; + + // If it's an incoming message the user must have moderator status + if (self.interaction.interactionType == OWSInteractionType_IncomingMessage) { + NSString *userPublicKey = [LKStorage.shared getUserPublicKey]; + if (![SNOpenGroupAPI isUserModerator:userPublicKey forChannel:openGroup.channel onServer:openGroup.server]) { return; } + } // Delete the message - BOOL isSentByUser = (interationType == OWSInteractionType_OutgoingMessage); - [[SNOpenGroupAPI deleteMessageWithID:message.openGroupServerMessageID forGroup:publicChat.channel onServer:publicChat.server isSentByUser:isSentByUser].catch(^(NSError *error) { + BOOL wasSentByUser = (interationType == OWSInteractionType_OutgoingMessage); + [[SNOpenGroupAPI deleteMessageWithID:message.openGroupServerMessageID forGroup:openGroup.channel onServer:openGroup.server isSentByUser:wasSentByUser].catch(^(NSError *error) { // Roll back [self.interaction save]; }) retainUntilComplete]; diff --git a/Session/Signal/MessageActions.swift b/Session/Signal/MessageActions.swift index 03bdcb109..d049b7c20 100644 --- a/Session/Signal/MessageActions.swift +++ b/Session/Signal/MessageActions.swift @@ -13,23 +13,21 @@ protocol MessageActionsDelegate: class { } struct MessageActionBuilder { + static func reply(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction { return MenuAction(image: #imageLiteral(resourceName: "ic_reply"), title: NSLocalizedString("MESSAGE_ACTION_REPLY", comment: "Action sheet button title"), subtitle: nil, - block: { [weak delegate] (_) in - delegate?.messageActionsReplyToItem(conversationViewItem) - - }) + block: { [weak delegate] _ in delegate?.messageActionsReplyToItem(conversationViewItem) } + ) } static func copyText(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction { return MenuAction(image: #imageLiteral(resourceName: "ic_copy"), title: NSLocalizedString("MESSAGE_ACTION_COPY_TEXT", comment: "Action sheet button title"), subtitle: nil, - block: { (_) in - conversationViewItem.copyTextAction() - }) + block: { _ in conversationViewItem.copyTextAction() } + ) } static func copyPublicKey(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction { @@ -44,9 +42,8 @@ struct MessageActionBuilder { return MenuAction(image: #imageLiteral(resourceName: "ic_info"), title: NSLocalizedString("MESSAGE_ACTION_DETAILS", comment: "Action sheet button title"), subtitle: nil, - block: { [weak delegate] (_) in - delegate?.messageActionsShowDetailsForItem(conversationViewItem) - }) + block: { [weak delegate] _ in delegate?.messageActionsShowDetailsForItem(conversationViewItem) } + ) } static func report(_ conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction { @@ -61,27 +58,24 @@ struct MessageActionBuilder { return MenuAction(image: #imageLiteral(resourceName: "ic_trash"), title: NSLocalizedString("MESSAGE_ACTION_DELETE_MESSAGE", comment: "Action sheet button title"), subtitle: nil, - block: { (_) in - conversationViewItem.deleteAction() - }) + block: { _ in conversationViewItem.deleteAction() } + ) } static func copyMedia(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction { return MenuAction(image: #imageLiteral(resourceName: "ic_copy"), title: NSLocalizedString("MESSAGE_ACTION_COPY_MEDIA", comment: "Action sheet button title"), subtitle: nil, - block: { (_) in - conversationViewItem.copyMediaAction() - }) + block: { _ in conversationViewItem.copyMediaAction() } + ) } static func saveMedia(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction { return MenuAction(image: #imageLiteral(resourceName: "ic_download"), title: NSLocalizedString("MESSAGE_ACTION_SAVE_MEDIA", comment: "Action sheet button title"), subtitle: nil, - block: { (_) in - conversationViewItem.saveMediaAction() - }) + block: { _ in conversationViewItem.saveMediaAction() } + ) } } diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index a11422071..940766973 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -365,27 +365,28 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { guard let thread = self.thread(at: indexPath.row) else { return [] } - let publicChat = Storage.shared.getOpenGroup(for: thread.uniqueId!) + let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!) let delete = UITableViewRowAction(style: .destructive, title: NSLocalizedString("TXT_DELETE_TITLE", comment: "")) { [weak self] _, _ in let alert = UIAlertController(title: NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE", comment: ""), message: NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE", comment: ""), preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("TXT_DELETE_TITLE", comment: ""), style: .destructive) { _ in - Storage.writeSync { transaction in - if let publicChat = publicChat { + Storage.write { transaction in + Storage.shared.cancelPendingMessageSendJobs(for: thread.uniqueId!, using: transaction) + if let openGroup = openGroup { var messageIDs: Set = [] thread.enumerateInteractions(with: transaction) { interaction, _ in messageIDs.insert(interaction.uniqueId!) } OWSPrimaryStorage.shared().updateMessageIDCollectionByPruningMessagesWithIDs(messageIDs, in: transaction) - transaction.removeObject(forKey: "\(publicChat.server).\(publicChat.channel)", inCollection: Storage.lastMessageServerIDCollection) - transaction.removeObject(forKey: "\(publicChat.server).\(publicChat.channel)", inCollection: Storage.lastDeletionServerIDCollection) - let _ = OpenGroupAPI.leave(publicChat.channel, on: publicChat.server) + transaction.removeObject(forKey: "\(openGroup.server).\(openGroup.channel)", inCollection: Storage.lastMessageServerIDCollection) + transaction.removeObject(forKey: "\(openGroup.server).\(openGroup.channel)", inCollection: Storage.lastDeletionServerIDCollection) + let _ = OpenGroupAPI.leave(openGroup.channel, on: openGroup.server) thread.removeAllThreadInteractions(with: transaction) thread.remove(with: transaction) } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys == true { let groupID = thread.groupModel.groupId let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) let _ = MessageSender.leave(groupPublicKey, using: transaction).ensure { - Storage.writeSync { transaction in + Storage.write { transaction in thread.removeAllThreadInteractions(with: transaction) thread.remove(with: transaction) } diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index bb1e00f3e..8b0bf3315 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -28,7 +28,23 @@ extension Storage { transaction.removeAllObjects(inCollection: type.collection) } - public func cancelPendingMessageSendJobs(for threadID: String, using transaction: YapDatabaseReadWriteTransaction) { + @objc(cancelPendingMessageSendJobIfNeededForMessage:using:) + public func cancelPendingMessageSendJobIfNeeded(for tsMessageTimestamp: UInt64, using transaction: YapDatabaseReadWriteTransaction) { + var attachmentUploadJobKeys: [String] = [] + transaction.enumerateRows(inCollection: AttachmentUploadJob.collection) { key, object, _, _ in + guard let job = object as? AttachmentUploadJob, job.message.sentTimestamp == tsMessageTimestamp else { return } + attachmentUploadJobKeys.append(key) + } + var messageSendJobKeys: [String] = [] + transaction.enumerateRows(inCollection: MessageSendJob.collection) { key, object, _, _ in + guard let job = object as? MessageSendJob, job.message.sentTimestamp == tsMessageTimestamp else { return } + messageSendJobKeys.append(key) + } + transaction.removeObjects(forKeys: attachmentUploadJobKeys, inCollection: AttachmentUploadJob.collection) + transaction.removeObjects(forKeys: messageSendJobKeys, inCollection: MessageSendJob.collection) + } + + @objc public func cancelPendingMessageSendJobs(for threadID: String, using transaction: YapDatabaseReadWriteTransaction) { var attachmentUploadJobKeys: [String] = [] transaction.enumerateRows(inCollection: AttachmentUploadJob.collection) { key, object, _, _ in guard let job = object as? AttachmentUploadJob, job.threadID == threadID else { return } @@ -68,4 +84,12 @@ extension Storage { public func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) { getMessageSendJob(for: messageSendJobID)?.execute() } + + public func isJobCanceled(_ job: Job) -> Bool { + var result = true + Storage.read { transaction in + result = !transaction.hasObject(forKey: job.id!, inCollection: type(of: job).collection) + } + return result + } } diff --git a/SessionMessagingKit/Database/Storage+Shared.swift b/SessionMessagingKit/Database/Storage+Shared.swift index e698b0c3d..426ffd500 100644 --- a/SessionMessagingKit/Database/Storage+Shared.swift +++ b/SessionMessagingKit/Database/Storage+Shared.swift @@ -14,7 +14,7 @@ extension Storage { Storage.write(with: { work($0) }, completion: completion) } - public func getUserPublicKey() -> String? { + @objc public func getUserPublicKey() -> String? { return OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey } diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index e73e12530..09bb07d61 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -51,6 +51,7 @@ public final class JobQueue : NSObject, JobDelegate { public func handleJobFailed(_ job: Job, with error: Error) { job.failureCount += 1 let storage = Configuration.shared.storage + guard !storage.isJobCanceled(job) else { return SNLog("\(type(of: job)) canceled.") } storage.withAsync({ transaction in storage.persist(job, using: transaction) }, completion: { // Intentionally capture self @@ -62,7 +63,7 @@ public final class JobQueue : NSObject, JobDelegate { }) } else { let retryInterval = self.getRetryInterval(for: job) - SNLog("Job failed; scheduling retry.") + SNLog("\(type(of: job)) failed; scheduling retry (failure count is \(job.failureCount)).") Timer.scheduledTimer(timeInterval: retryInterval, target: self, selector: #selector(self.retry(_:)), userInfo: job, repeats: false) } }) @@ -96,8 +97,8 @@ public final class JobQueue : NSObject, JobDelegate { } @objc private func retry(_ timer: Timer) { - SNLog("Retrying job.") guard let job = timer.userInfo as? Job else { return } + SNLog("Retrying \(type(of: job)).") job.execute() } } diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 169a9cb67..893142ec1 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -1,7 +1,5 @@ import SessionUtilitiesKit -// TODO: Cancel when a message/conversation is deleted - @objc(SNMessageSendJob) public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public let message: Message @@ -63,6 +61,9 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // MARK: Running public func execute() { + if Double.random(in: 0..<1) > 0.01 { + return handleFailure(error: MessageSender.Error.noThread) + } let storage = Configuration.shared.storage if let message = message as? VisibleMessage { let attachments = message.attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0) } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 926aebc11..0f752fe00 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -34,6 +34,7 @@ public protocol SessionMessagingKitStorageProtocol { func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? func getMessageSendJob(for messageSendJobID: String) -> MessageSendJob? func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) + func isJobCanceled(_ job: Job) -> Bool // MARK: - Authorization From d01f43147af6dd4a596b30d0b64f8b7730688ced Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 10:29:27 +1100 Subject: [PATCH 051/177] Debug --- SessionMessagingKit/Jobs/JobQueue.swift | 2 -- SessionMessagingKit/Jobs/MessageSendJob.swift | 8 +++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 09bb07d61..e80060aa8 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -1,7 +1,5 @@ import SessionUtilitiesKit -// TODO: Check that retrying works - @objc(SNJobQueue) public final class JobQueue : NSObject, JobDelegate { private var hasResumedPendingJobs = false // Just for debugging diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 893142ec1..73255910a 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -61,11 +61,9 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // MARK: Running public func execute() { - if Double.random(in: 0..<1) > 0.01 { - return handleFailure(error: MessageSender.Error.noThread) - } let storage = Configuration.shared.storage if let message = message as? VisibleMessage { + guard TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) != nil else { return } // The message has been deleted let attachments = message.attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0) } let attachmentsToUpload = attachments.filter { !$0.isUploaded } attachmentsToUpload.forEach { attachment in @@ -104,6 +102,10 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi } private func handleFailure(error: Error) { + SNLog("Failed to send \(type(of: message)).") + if let message = message as? VisibleMessage { + guard TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) != nil else { return } // The message has been deleted + } delegate?.handleJobFailed(self, with: error) } } From 4dda59b4463875dc04705b425ba62fbd3f4e93f2 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 10:43:14 +1100 Subject: [PATCH 052/177] Debug attachment receiving --- SessionMessagingKit/Jobs/AttachmentUploadJob.swift | 1 - .../Visible Messages/VisibleMessage+Attachment.swift | 2 +- .../Attachments/TSAttachmentPointer+Conversion.swift | 4 +++- SessionMessagingKit/Utilities/DotNetAPI.swift | 11 +++++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index c42e2ba8e..f0f2f37aa 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -57,7 +57,6 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N // MARK: Running public func execute() { - SNLog("Attachment upload failure count: \(failureCount).") guard let stream = TSAttachmentStream.fetch(uniqueId: attachmentID) else { return handleFailure(error: Error.noAttachment) } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Attachment.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Attachment.swift index 998875a35..f1454ff35 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Attachment.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Attachment.swift @@ -17,7 +17,7 @@ public extension VisibleMessage { public var isValid: Bool { // key and digest can be nil for open group attachments - fileName != nil && contentType != nil && kind != nil && size != nil && sizeInBytes != nil && url != nil + contentType != nil && kind != nil && size != nil && sizeInBytes != nil && url != nil } public enum Kind : String { diff --git a/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer+Conversion.swift index c4b595f90..41fa7aa8e 100644 --- a/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Attachments/TSAttachmentPointer+Conversion.swift @@ -7,7 +7,7 @@ extension TSAttachmentPointer { case .generic: kind = .default case .voiceMessage: kind = .voiceMessage } - return TSAttachmentPointer( + let result = TSAttachmentPointer( serverId: 0, key: attachment.key, digest: attachment.digest, @@ -18,5 +18,7 @@ extension TSAttachmentPointer { albumMessageId: nil, attachmentType: kind, mediaSize: attachment.size!) + result.downloadURL = attachment.url! + return result } } diff --git a/SessionMessagingKit/Utilities/DotNetAPI.swift b/SessionMessagingKit/Utilities/DotNetAPI.swift index 4631439bd..8199b5b81 100644 --- a/SessionMessagingKit/Utilities/DotNetAPI.swift +++ b/SessionMessagingKit/Utilities/DotNetAPI.swift @@ -16,6 +16,7 @@ public class DotNetAPI : NSObject { // MARK: Error public enum Error : LocalizedError { case generic + case invalidURL case parsingFailed case signingFailed case encryptionFailed @@ -29,6 +30,7 @@ public class DotNetAPI : NSObject { public var errorDescription: String? { switch self { case .generic: return "An error occurred." + case .invalidURL: return "Invalid URL." case .parsingFailed: return "Invalid file server response." case .signingFailed: return "Couldn't sign message." case .encryptionFailed: return "Couldn't encrypt file." @@ -105,14 +107,15 @@ public class DotNetAPI : NSObject { return AnyPromise.from(downloadAttachment(from: url)) } - public static func downloadAttachment(from url: String) -> Promise { - var host = "https://\(URL(string: url)!.host!)" + public static func downloadAttachment(from urlAsString: String) -> Promise { + guard let url = URL(string: urlAsString) else { return Promise(error: Error.invalidURL) } + var host = "https://\(url.host!)" let sanitizedURL: String if FileServerAPI.fileStorageBucketURL.contains(host) { - sanitizedURL = url.replacingOccurrences(of: FileServerAPI.fileStorageBucketURL, with: "\(FileServerAPI.server)/loki/v1") + sanitizedURL = urlAsString.replacingOccurrences(of: FileServerAPI.fileStorageBucketURL, with: "\(FileServerAPI.server)/loki/v1") host = FileServerAPI.server } else { - sanitizedURL = url.replacingOccurrences(of: host, with: "\(host)/loki/v1") + sanitizedURL = urlAsString.replacingOccurrences(of: host, with: "\(host)/loki/v1") } let request: NSMutableURLRequest do { From 2a57b8ab5b3b1189d1229b5f9c532f270274e4e7 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 11:08:48 +1100 Subject: [PATCH 053/177] Fix disappearing messages --- Session/Signal/OWSConversationSettingsViewController.m | 3 ++- SessionMessagingKit/Database/Storage+Messaging.swift | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index ac678182e..3a34330f7 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -875,7 +875,8 @@ static CGRect oldframe; [infoMessage saveWithTransaction:transaction]; SNExpirationTimerUpdate *expirationTimerUpdate = [SNExpirationTimerUpdate new]; - expirationTimerUpdate.duration = self.disappearingMessagesConfiguration.durationSeconds; + BOOL isEnabled = self.disappearingMessagesConfiguration.enabled; + expirationTimerUpdate.duration = isEnabled ? self.disappearingMessagesConfiguration.durationSeconds : 0; [SNMessageSender send:expirationTimerUpdate inThread:self.thread usingTransaction:transaction]; }]; } diff --git a/SessionMessagingKit/Database/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift index 0d6df572d..96a265d7d 100644 --- a/SessionMessagingKit/Database/Storage+Messaging.swift +++ b/SessionMessagingKit/Database/Storage+Messaging.swift @@ -46,6 +46,8 @@ extension Storage { /// Also touches the associated message. public func setAttachmentState(to state: TSAttachmentPointerState, for pointer: TSAttachmentPointer, associatedWith tsIncomingMessageID: String, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction + // Workaround for some YapDatabase funkiness where pointer at this point can actually be a TSAttachmentStream + guard pointer.responds(to: #selector(setter: TSAttachmentPointer.state)) else { return } pointer.state = state pointer.save(with: transaction) guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { return } From 896ca8f0bd1ed0dad97a5738ae1b7ebe5e63c890 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 12:45:20 +1100 Subject: [PATCH 054/177] Fix profile picture updating --- SignalUtilitiesKit/To Do/OWSProfileManager.m | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m index dc696f818..79934c779 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -1101,16 +1101,7 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); } else if (!image) { OWSLogError(@"avatar image for %@ could not be loaded.", userProfile.recipientId); } else { - [self updateProfileAvatarCache:image filename:fileName]; - } - - // If we're updating the profile that corresponds to our local number, - // update the local profile as well. - if ([self.tsAccountManager.localNumber isEqualToString:userProfile.recipientId]) { - OWSUserProfile *localUserProfile = self.localUserProfile; - OWSAssertDebug(localUserProfile); - - [localUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil]; + [latestUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil]; [self updateProfileAvatarCache:image filename:fileName]; } From e3304a40f91776c1b3bd376c8ac630cca45b8490 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 13:52:20 +1100 Subject: [PATCH 055/177] Fix attachment quoting --- .../VisibleMessage+Quote.swift | 37 +++++++++++++++++-- .../Visible Messages/VisibleMessage.swift | 6 ++- .../OWSQuotedReplyModel+Conversion.swift | 1 + .../Quotes/TSQuotedMessage+Conversion.swift | 8 +++- .../MessageSender+Handling.swift | 10 ++++- 5 files changed, 55 insertions(+), 7 deletions(-) diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index 74bc57d37..43f51c63b 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -7,43 +7,52 @@ public extension VisibleMessage { public var timestamp: UInt64? public var publicKey: String? public var text: String? + public var attachmentID: String? - public var isValid: Bool { timestamp != nil && publicKey != nil && text != nil } + public var isValid: Bool { timestamp != nil && publicKey != nil } public override init() { super.init() } - internal init(timestamp: UInt64, publicKey: String, text: String) { + internal init(timestamp: UInt64, publicKey: String, text: String, attachmentID: String?) { self.timestamp = timestamp self.publicKey = publicKey self.text = text + self.attachmentID = attachmentID } public required init?(coder: NSCoder) { if let timestamp = coder.decodeObject(forKey: "timestamp") as! UInt64? { self.timestamp = timestamp } if let publicKey = coder.decodeObject(forKey: "authorId") as! String? { self.publicKey = publicKey } if let text = coder.decodeObject(forKey: "body") as! String? { self.text = text } + if let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String? { self.attachmentID = attachmentID } } public func encode(with coder: NSCoder) { coder.encode(timestamp, forKey: "timestamp") coder.encode(publicKey, forKey: "authorId") coder.encode(text, forKey: "body") + coder.encode(attachmentID, forKey: "attachmentID") } public static func fromProto(_ proto: SNProtoDataMessageQuote) -> Quote? { let timestamp = proto.id let publicKey = proto.author guard let text = proto.text else { return nil } - return Quote(timestamp: timestamp, publicKey: publicKey, text: text) + return Quote(timestamp: timestamp, publicKey: publicKey, text: text, attachmentID: nil) // TODO: attachmentID } public func toProto() -> SNProtoDataMessageQuote? { + preconditionFailure("Use toProto(using:) instead.") + } + + public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoDataMessageQuote? { guard let timestamp = timestamp, let publicKey = publicKey, let text = text else { SNLog("Couldn't construct quote proto from: \(self).") return nil } let quoteProto = SNProtoDataMessageQuote.builder(id: timestamp, author: publicKey) quoteProto.setText(text) + addAttachmentsIfNeeded(to: quoteProto, using: transaction) do { return try quoteProto.build() } catch { @@ -51,5 +60,27 @@ public extension VisibleMessage { return nil } } + + private func addAttachmentsIfNeeded(to quoteProto: SNProtoDataMessageQuote.SNProtoDataMessageQuoteBuilder, using transaction: YapDatabaseReadWriteTransaction) { + guard let attachmentID = attachmentID else { return } + guard let stream = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction), stream.isUploaded else { + #if DEBUG + preconditionFailure("Sending a message before all associated attachments have been uploaded.") + #endif + return + } + let quotedAttachmentProto = SNProtoDataMessageQuoteQuotedAttachment.builder() + quotedAttachmentProto.setContentType(stream.contentType) + if let fileName = stream.sourceFilename { quotedAttachmentProto.setFileName(fileName) } + guard let attachmentProto = stream.buildProto() else { + return SNLog("Ignoring invalid attachment for quoted message.") + } + quotedAttachmentProto.setThumbnail(attachmentProto) + do { + try quoteProto.addAttachments(quotedAttachmentProto.build()) + } catch { + SNLog("Couldn't construct quoted attachment proto from: \(self).") + } + } } } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 1bc671635..3c85f1da1 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -59,6 +59,10 @@ public final class VisibleMessage : Message { dataMessage = SNProtoDataMessage.builder() } if let text = text { dataMessage.setBody(text) } + var attachmentIDs = self.attachmentIDs + if let quotedAttachmentID = quote?.attachmentID, let index = attachmentIDs.firstIndex(of: quotedAttachmentID) { + attachmentIDs.remove(at: index) + } let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } if !attachments.allSatisfy({ $0.isUploaded }) { #if DEBUG @@ -67,7 +71,7 @@ public final class VisibleMessage : Message { } let attachmentProtos = attachments.compactMap { $0.buildProto() } dataMessage.setAttachments(attachmentProtos) - if let quote = quote, let quoteProto = quote.toProto() { dataMessage.setQuote(quoteProto) } + if let quote = quote, let quoteProto = quote.toProto(using: transaction) { dataMessage.setQuote(quoteProto) } if let linkPreview = linkPreview, let linkPreviewProto = linkPreview.toProto() { dataMessage.setPreview([ linkPreviewProto ]) } // TODO: Contact do { diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift index 3c932b16b..5a1ef63cd 100644 --- a/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Quotes/OWSQuotedReplyModel+Conversion.swift @@ -8,6 +8,7 @@ extension VisibleMessage.Quote { result.timestamp = quote.timestamp result.publicKey = quote.authorId result.text = quote.body + result.attachmentID = quote.attachmentStream?.uniqueId return result } } diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift index 1d018b5a4..3b36356fe 100644 --- a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift @@ -4,11 +4,15 @@ extension TSQuotedMessage { @objc(from:) public static func from(_ quote: VisibleMessage.Quote?) -> TSQuotedMessage? { guard let quote = quote else { return nil } + var attachments: [TSAttachment] = [] + if let attachmentID = quote.attachmentID, let attachment = TSAttachment.fetch(uniqueId: attachmentID) { + attachments.append(attachment) + } return TSQuotedMessage( timestamp: quote.timestamp!, authorId: quote.publicKey!, - body: quote.text, bodySource: .local, - receivedQuotedAttachmentInfos: [] + body: quote.text, + quotedAttachmentsForSending: attachments ) } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index a0b13b789..9bb8752c8 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -20,9 +20,16 @@ extension MessageSender : SharedSenderKeysDelegate { streams.append(stream) stream.write($0.dataSource) stream.save(with: transaction) + tsMessage.attachmentIds.add(stream.uniqueId!) + } + if let quotedMessageThumbnails = tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) { + streams += quotedMessageThumbnails + } + if let linkPreviewAttachmentID = tsMessage.linkPreview?.imageAttachmentId, + let stream = TSAttachment.fetch(uniqueId: linkPreviewAttachmentID, transaction: transaction) as? TSAttachmentStream { + streams.append(stream) } message.attachmentIDs = streams.map { $0.uniqueId! } - tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) tsMessage.save(with: transaction) } @@ -34,6 +41,7 @@ extension MessageSender : SharedSenderKeysDelegate { @objc(send:inThread:usingTransaction:) public static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + if message is VisibleMessage { prep([], for: message, using: transaction) } // To handle quotes & link previews message.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) let job = MessageSendJob(message: message, destination: destination) From addc859c84d4f37beeb8b06e032a1e95d3a19553 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 15:13:42 +1100 Subject: [PATCH 056/177] Fix duplicate messages & debug --- .../Signal/MediaGalleryViewController.swift | 1 - .../Database/Storage+Messaging.swift | 21 +++++++++++++++++++ SessionMessagingKit/Jobs/MessageSendJob.swift | 1 - .../VisibleMessage+Quote.swift | 4 ++-- .../Visible Messages/VisibleMessage.swift | 8 +++++++ .../MessageReceiver+Handling.swift | 21 +++++++++++++------ .../Sending & Receiving/MessageReceiver.swift | 7 ++++++- SessionMessagingKit/Storage.swift | 2 ++ .../MessageSender+Handling.swift | 6 ++---- 9 files changed, 56 insertions(+), 15 deletions(-) diff --git a/Session/Signal/MediaGalleryViewController.swift b/Session/Signal/MediaGalleryViewController.swift index ccc9c253e..a8153b0c9 100644 --- a/Session/Signal/MediaGalleryViewController.swift +++ b/Session/Signal/MediaGalleryViewController.swift @@ -377,7 +377,6 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel } guard let initialDetailItem = galleryItem else { - owsFailDebug("unexpectedly failed to build initialDetailItem.") return } diff --git a/SessionMessagingKit/Database/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift index 96a265d7d..7afb97b55 100644 --- a/SessionMessagingKit/Database/Storage+Messaging.swift +++ b/SessionMessagingKit/Database/Storage+Messaging.swift @@ -61,5 +61,26 @@ extension Storage { guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { return } tsIncomingMessage.touch(with: transaction) } + + private static let receivedMessageTimestampsCollection = "ReceivedMessageTimestampsCollection" + + public func getReceivedMessageTimestamps(using transaction: Any) -> [UInt64] { + var result: [UInt64] = [] + let transaction = transaction as! YapDatabaseReadWriteTransaction + transaction.enumerateRows(inCollection: Storage.receivedMessageTimestampsCollection) { _, object, _, _ in + guard let timestamp = object as? UInt64 else { return } + result.append(timestamp) + } + return result + } + + public func addReceivedMessageTimestamp(_ timestamp: UInt64, using transaction: Any) { + var receivedMessageTimestamps = getReceivedMessageTimestamps(using: transaction) + // TODO: Do we need to sort the timestamps here? + if receivedMessageTimestamps.count > 1000 { receivedMessageTimestamps.remove(at: 0) } // Limit the size of the collection to 1000 + receivedMessageTimestamps.append(timestamp) + let transaction = transaction as! YapDatabaseReadWriteTransaction + transaction.setObject(receivedMessageTimestamps, forKey: "receivedMessageTimestamps", inCollection: Storage.receivedMessageTimestampsCollection) + } } diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 73255910a..504203638 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -78,7 +78,6 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi } if !attachmentsToUpload.isEmpty { return } // Wait for all attachments to upload before continuing } - // FIXME: This doesn't yet handle the attachment side of link previews, quotes, etc. storage.withAsync({ transaction in // Intentionally capture self MessageSender.send(self.message, to: self.destination, using: transaction).done(on: DispatchQueue.global(qos: .userInitiated)) { self.handleSuccess() diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index 43f51c63b..d19893194 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -46,12 +46,12 @@ public extension VisibleMessage { } public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoDataMessageQuote? { - guard let timestamp = timestamp, let publicKey = publicKey, let text = text else { + guard let timestamp = timestamp, let publicKey = publicKey else { SNLog("Couldn't construct quote proto from: \(self).") return nil } let quoteProto = SNProtoDataMessageQuote.builder(id: timestamp, author: publicKey) - quoteProto.setText(text) + if let text = text { quoteProto.setText(text) } addAttachmentsIfNeeded(to: quoteProto, using: transaction) do { return try quoteProto.build() diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 3c85f1da1..88f7b7825 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -25,12 +25,20 @@ public final class VisibleMessage : Message { super.init(coder: coder) if let text = coder.decodeObject(forKey: "body") as! String? { self.text = text } if let attachmentIDs = coder.decodeObject(forKey: "attachments") as! [String]? { self.attachmentIDs = attachmentIDs } + if let quote = coder.decodeObject(forKey: "quote") as! Quote? { self.quote = quote } + if let linkPreview = coder.decodeObject(forKey: "linkPreview") as! LinkPreview? { self.linkPreview = linkPreview } + // TODO: Contact + if let profile = coder.decodeObject(forKey: "profile") as! Profile? { self.profile = profile } } public override func encode(with coder: NSCoder) { super.encode(with: coder) coder.encode(text, forKey: "body") coder.encode(attachmentIDs, forKey: "attachments") + coder.encode(quote, forKey: "quote") + coder.encode(linkPreview, forKey: "linkPreview") + // TODO: Contact + coder.encode(profile, forKey: "profile") } // MARK: Proto Conversion diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 5bfa544a3..b5631a540 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -160,14 +160,23 @@ extension MessageReceiver { // Persist the message guard let (threadID, tsIncomingMessageID) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } message.threadID = threadID + // Handle quoted attachment if needed + if message.quote != nil && proto.dataMessage?.quote != nil, let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { + let tsQuote = TSQuotedMessage(for: proto.dataMessage!, thread: thread, transaction: transaction) + if let thumbnailID = tsQuote?.thumbnailAttachmentStreamId() ?? tsQuote?.thumbnailAttachmentPointerId() { + message.quote?.attachmentID = thumbnailID + } + } // Start attachment downloads if needed storage.withAsync({ transaction in - attachmentIDs.forEach { attachmentID in - let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) - if CurrentAppContext().isMainAppAndActive { - JobQueue.shared.add(downloadJob, using: transaction) - } else { - JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) + DispatchQueue.main.async { + attachmentIDs.forEach { attachmentID in + let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) + if CurrentAppContext().isMainAppAndActive { // This has to be called from the main thread + JobQueue.shared.add(downloadJob, using: transaction) + } else { + JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) + } } } }, completion: { }) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 9d918ef45..a42a60bae 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -3,6 +3,7 @@ import SessionUtilitiesKit internal enum MessageReceiver { internal enum Error : LocalizedError { + case duplicateMessage case invalidMessage case unknownMessage case unknownEnvelopeType @@ -18,13 +19,14 @@ internal enum MessageReceiver { internal var isRetryable: Bool { switch self { - case .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false + case .duplicateMessage, .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false default: return true } } internal var errorDescription: String? { switch self { + case .duplicateMessage: return "Duplicate message." case .invalidMessage: return "Invalid message." case .unknownMessage: return "Unknown message type." case .unknownEnvelopeType: return "Unknown envelope type." @@ -45,6 +47,9 @@ internal enum MessageReceiver { let userPublicKey = Configuration.shared.storage.getUserPublicKey() // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) + let storage = Configuration.shared.storage + guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) else { throw Error.duplicateMessage } + storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction) // Decrypt the contents let plaintext: Data let sender: String diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 0f752fe00..5b2974483 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -71,6 +71,8 @@ public protocol SessionMessagingKitStorageProtocol { // MARK: - Message Handling + func getReceivedMessageTimestamps(using transaction: Any) -> [UInt64] + func addReceivedMessageTimestamp(_ timestamp: UInt64, using transaction: Any) /// Returns the ID of the thread the message was stored under along with the ID of the `TSIncomingMessage` that was constructed. func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, String)? /// Returns the IDs of the saved attachments. diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index 9bb8752c8..f67ed9e3a 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -20,16 +20,14 @@ extension MessageSender : SharedSenderKeysDelegate { streams.append(stream) stream.write($0.dataSource) stream.save(with: transaction) - tsMessage.attachmentIds.add(stream.uniqueId!) - } - if let quotedMessageThumbnails = tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) { - streams += quotedMessageThumbnails } + tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) if let linkPreviewAttachmentID = tsMessage.linkPreview?.imageAttachmentId, let stream = TSAttachment.fetch(uniqueId: linkPreviewAttachmentID, transaction: transaction) as? TSAttachmentStream { streams.append(stream) } message.attachmentIDs = streams.map { $0.uniqueId! } + tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) tsMessage.save(with: transaction) } From 20faa8e914bda7c05c8ef161cdc8652469b1eeb2 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 16:22:15 +1100 Subject: [PATCH 057/177] Debug --- .../ConversationViewController.m | 2 +- .../Database/Storage+Messaging.swift | 19 +++++++++++++------ .../Signal/TSIncomingMessage+Conversion.swift | 4 ++-- .../VisibleMessage+Quote.swift | 6 +++--- .../MessageReceiver+Handling.swift | 16 ++++++++-------- .../Quotes/TSQuotedMessage+Conversion.swift | 1 + SessionMessagingKit/Storage.swift | 6 ++++-- .../MessageSender+Handling.swift | 10 ++++------ .../UI/SharingThreadPickerViewController.m | 2 +- 9 files changed, 37 insertions(+), 29 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index d6a51e945..07a03c0fc 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3760,7 +3760,7 @@ typedef enum : NSUInteger { [tsMessage saveWithTransaction:transaction]; }]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [SNMessageSender send:message inThread:thread usingTransaction:transaction]; + [SNMessageSender send:message withAttachments:@[] inThread:thread usingTransaction:transaction]; [thread setDraft:@"" transaction:transaction]; }]; [self messageWasSent:tsMessage]; diff --git a/SessionMessagingKit/Database/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift index 7afb97b55..5896a5fa8 100644 --- a/SessionMessagingKit/Database/Storage+Messaging.swift +++ b/SessionMessagingKit/Database/Storage+Messaging.swift @@ -16,8 +16,8 @@ extension Storage { return try! promise.wait() } - /// Returns the ID of the thread the message was stored under along with the ID of the `TSIncomingMessage` that was constructed. - public func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, String)? { + /// Returns the ID of the thread. + public func getOrCreateThread(for publicKey: String, groupPublicKey: String?, using transaction: Any) -> String? { let transaction = transaction as! YapDatabaseReadWriteTransaction var threadOrNil: TSThread? if let groupPublicKey = groupPublicKey { @@ -25,13 +25,20 @@ extension Storage { let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) } else { - threadOrNil = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction) + threadOrNil = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) } - guard let thread = threadOrNil else { return nil } - let message = TSIncomingMessage.from(message, associatedWith: thread) + return threadOrNil?.uniqueId + } + + /// Returns the ID of the `TSIncomingMessage` that was constructed. + public func persist(_ message: VisibleMessage, withQuotedMessage quotedMessage: TSQuotedMessage?, groupPublicKey: String?, using transaction: Any) -> String? { + let transaction = transaction as! YapDatabaseReadWriteTransaction + guard let threadID = getOrCreateThread(for: message.sender!, groupPublicKey: groupPublicKey, using: transaction), + let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return nil } + let message = TSIncomingMessage.from(message, withQuotedMessage: quotedMessage, associatedWith: thread) message.save(with: transaction) DispatchQueue.main.async { message.touch() } // FIXME: Hack for a thread updating issue - return (thread.uniqueId!, message.uniqueId!) + return message.uniqueId! } /// Returns the IDs of the saved attachments. diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift index c28b77bf9..e487ef726 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift @@ -1,7 +1,7 @@ public extension TSIncomingMessage { - static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread) -> TSIncomingMessage { + static func from(_ visibleMessage: VisibleMessage, withQuotedMessage quotedMessage: TSQuotedMessage?, associatedWith thread: TSThread) -> TSIncomingMessage { let sender = visibleMessage.sender! var expiration: UInt32 = 0 Storage.read { transaction in @@ -15,7 +15,7 @@ public extension TSIncomingMessage { messageBody: visibleMessage.text, attachmentIds: visibleMessage.attachmentIDs, expiresInSeconds: expiration, - quotedMessage: TSQuotedMessage.from(visibleMessage.quote), + quotedMessage: quotedMessage, linkPreview: OWSLinkPreview.from(visibleMessage.linkPreview), serverTimestamp: nil, wasReceivedByUD: true diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index d19893194..b096b7192 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -13,7 +13,7 @@ public extension VisibleMessage { public override init() { super.init() } - internal init(timestamp: UInt64, publicKey: String, text: String, attachmentID: String?) { + internal init(timestamp: UInt64, publicKey: String, text: String?, attachmentID: String?) { self.timestamp = timestamp self.publicKey = publicKey self.text = text @@ -37,8 +37,8 @@ public extension VisibleMessage { public static func fromProto(_ proto: SNProtoDataMessageQuote) -> Quote? { let timestamp = proto.id let publicKey = proto.author - guard let text = proto.text else { return nil } - return Quote(timestamp: timestamp, publicKey: publicKey, text: text, attachmentID: nil) // TODO: attachmentID + let text = proto.text + return Quote(timestamp: timestamp, publicKey: publicKey, text: text, attachmentID: nil) } public func toProto() -> SNProtoDataMessageQuote? { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index b5631a540..98031f360 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -157,16 +157,16 @@ extension MessageReceiver { profileManager.setProfileKeyData(profileKey, forRecipientId: message.sender!, avatarURL: profilePictureURL) } } - // Persist the message - guard let (threadID, tsIncomingMessageID) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } - message.threadID = threadID - // Handle quoted attachment if needed + // Get or create thread + guard let threadID = storage.getOrCreateThread(for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + // Parse quote if needed + var tsQuotedMessage: TSQuotedMessage? = nil if message.quote != nil && proto.dataMessage?.quote != nil, let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { - let tsQuote = TSQuotedMessage(for: proto.dataMessage!, thread: thread, transaction: transaction) - if let thumbnailID = tsQuote?.thumbnailAttachmentStreamId() ?? tsQuote?.thumbnailAttachmentPointerId() { - message.quote?.attachmentID = thumbnailID - } + tsQuotedMessage = TSQuotedMessage(for: proto.dataMessage!, thread: thread, transaction: transaction) } + // Persist the message + guard let tsIncomingMessageID = storage.persist(message, withQuotedMessage: tsQuotedMessage, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + message.threadID = threadID // Start attachment downloads if needed storage.withAsync({ transaction in DispatchQueue.main.async { diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift index 3b36356fe..3bb505360 100644 --- a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift @@ -1,6 +1,7 @@ extension TSQuotedMessage { + /// To be used for outgoing messages only. @objc(from:) public static func from(_ quote: VisibleMessage.Quote?) -> TSQuotedMessage? { guard let quote = quote else { return nil } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 5b2974483..3f551397f 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -73,8 +73,10 @@ public protocol SessionMessagingKitStorageProtocol { func getReceivedMessageTimestamps(using transaction: Any) -> [UInt64] func addReceivedMessageTimestamp(_ timestamp: UInt64, using transaction: Any) - /// Returns the ID of the thread the message was stored under along with the ID of the `TSIncomingMessage` that was constructed. - func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, String)? + /// Returns the ID of the thread. + func getOrCreateThread(for publicKey: String, groupPublicKey: String?, using transaction: Any) -> String? + /// Returns the ID of the `TSIncomingMessage` that was constructed. + func persist(_ message: VisibleMessage, withQuotedMessage quotedMessage: TSQuotedMessage?, groupPublicKey: String?, using transaction: Any) -> String? /// Returns the IDs of the saved attachments. func persist(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] /// Also touches the associated message. diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index f67ed9e3a..a31d4f138 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -5,8 +5,7 @@ extension MessageSender : SharedSenderKeysDelegate { // MARK: - Sending Convenience - private static func prep(_ attachments: [SignalAttachment], for message: Message, using transaction: YapDatabaseReadWriteTransaction) { - guard let message = message as? VisibleMessage else { return } + private static func prep(_ attachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { #if DEBUG preconditionFailure() @@ -32,14 +31,13 @@ extension MessageSender : SharedSenderKeysDelegate { } @objc(send:withAttachments:inThread:usingTransaction:) - public static func send(_ message: Message, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + public static func send(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { prep(attachments, for: message, using: transaction) send(message, in: thread, using: transaction) } @objc(send:inThread:usingTransaction:) public static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { - if message is VisibleMessage { prep([], for: message, using: transaction) } // To handle quotes & link previews message.threadID = thread.uniqueId! let destination = Message.Destination.from(thread) let job = MessageSendJob(message: message, destination: destination) @@ -47,7 +45,7 @@ extension MessageSender : SharedSenderKeysDelegate { } @objc(sendNonDurably:withAttachments:inThread:usingTransaction:) - public static func objc_sendNonDurably(_ message: Message, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + public static func objc_sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { return AnyPromise.from(sendNonDurably(message, with: attachments, in: thread, using: transaction)) } @@ -56,7 +54,7 @@ extension MessageSender : SharedSenderKeysDelegate { return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) } - public static func sendNonDurably(_ message: Message, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + public static func sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { prep(attachments, for: message, using: transaction) return sendNonDurably(message, in: thread, using: transaction) } diff --git a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index add5095c8..0789020a7 100644 --- a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -263,7 +263,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); [tsMessage saveWithTransaction:transaction]; }]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [SNMessageSender sendNonDurably:message inThread:self.thread usingTransaction:transaction] + [SNMessageSender sendNonDurably:message withAttachments:@[] inThread:self.thread usingTransaction:transaction] .then(^(id object) { sendCompletion(nil, tsMessage); }).catch(^(NSError *error) { From f7bfa5c4d77b498895bed85749305afe49af9dfa Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 27 Nov 2020 17:13:37 +1100 Subject: [PATCH 058/177] WIP --- .../MessageReceiver+Handling.swift | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 98031f360..0d9c21327 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -143,7 +143,7 @@ extension MessageReceiver { guard let attachment = VisibleMessage.Attachment.fromProto(proto) else { return nil } return attachment.isValid ? attachment : nil } - let attachmentIDs = storage.persist(attachments, using: transaction) + var attachmentIDs = storage.persist(attachments, using: transaction) message.attachmentIDs = attachmentIDs // Update profile if needed if let newProfile = message.profile { @@ -163,20 +163,21 @@ extension MessageReceiver { var tsQuotedMessage: TSQuotedMessage? = nil if message.quote != nil && proto.dataMessage?.quote != nil, let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { tsQuotedMessage = TSQuotedMessage(for: proto.dataMessage!, thread: thread, transaction: transaction) + if let id = tsQuotedMessage?.thumbnailAttachmentStreamId() ?? tsQuotedMessage?.thumbnailAttachmentPointerId() { + attachmentIDs.append(id) + } } // Persist the message guard let tsIncomingMessageID = storage.persist(message, withQuotedMessage: tsQuotedMessage, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } message.threadID = threadID // Start attachment downloads if needed storage.withAsync({ transaction in - DispatchQueue.main.async { - attachmentIDs.forEach { attachmentID in - let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) - if CurrentAppContext().isMainAppAndActive { // This has to be called from the main thread - JobQueue.shared.add(downloadJob, using: transaction) - } else { - JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) - } + attachmentIDs.forEach { attachmentID in + let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) + if CurrentAppContext().isMainAppAndActive { // This has to be called from the main thread + JobQueue.shared.add(downloadJob, using: transaction) + } else { + JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) } } }, completion: { }) From d39e155e1c8477e923cbc6d348b8e1773f9f6842 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Sat, 28 Nov 2020 11:48:08 +1100 Subject: [PATCH 059/177] Make link previews work again --- .../ConversationViewController.m | 35 +++++++++++-------- .../Database/Storage+Messaging.swift | 4 +-- .../Signal/TSIncomingMessage+Conversion.swift | 4 +-- .../VisibleMessage+LinkPreview.swift | 18 ++++++++-- .../Visible Messages/VisibleMessage.swift | 15 ++++++-- .../OWSLinkPreview+Conversion.swift | 17 ++++++++- .../MessageReceiver+Handling.swift | 11 +++++- SessionMessagingKit/Storage.swift | 2 +- .../MessageSender+Handling.swift | 7 ++-- 9 files changed, 84 insertions(+), 29 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 07a03c0fc..00e61a9ef 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3753,22 +3753,29 @@ typedef enum : NSUInteger { message.sentTimestamp = [NSDate millisecondTimestamp]; message.text = text; message.quote = [SNQuote from:self.inputToolbar.quotedReply]; - TSThread *thread = self.thread; - TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; - [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; + OWSLinkPreviewDraft *linkPreviewDraft = self.inputToolbar.linkPreviewDraft; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [tsMessage saveWithTransaction:transaction]; + message.linkPreview = [SNLinkPreview from:linkPreviewDraft using:transaction]; + } completion:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + TSThread *thread = self.thread; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; + [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [tsMessage saveWithTransaction:transaction]; + }]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [SNMessageSender send:message withAttachments:@[] inThread:thread usingTransaction:transaction]; + [thread setDraft:@"" transaction:transaction]; + }]; + [self messageWasSent:tsMessage]; + [self.inputToolbar clearTextMessageAnimated:YES]; + [self resetMentions]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[weakSelf inputToolbar] toggleDefaultKeyboard]; + }); + }); }]; - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [SNMessageSender send:message withAttachments:@[] inThread:thread usingTransaction:transaction]; - [thread setDraft:@"" transaction:transaction]; - }]; - [self messageWasSent:tsMessage]; - [self.inputToolbar clearTextMessageAnimated:YES]; - [self resetMentions]; - dispatch_async(dispatch_get_main_queue(), ^{ - [[weakSelf inputToolbar] toggleDefaultKeyboard]; - }); } - (void)voiceMemoGestureDidStart diff --git a/SessionMessagingKit/Database/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift index 5896a5fa8..9783b72e1 100644 --- a/SessionMessagingKit/Database/Storage+Messaging.swift +++ b/SessionMessagingKit/Database/Storage+Messaging.swift @@ -31,11 +31,11 @@ extension Storage { } /// Returns the ID of the `TSIncomingMessage` that was constructed. - public func persist(_ message: VisibleMessage, withQuotedMessage quotedMessage: TSQuotedMessage?, groupPublicKey: String?, using transaction: Any) -> String? { + public func persist(_ message: VisibleMessage, quotedMessage: TSQuotedMessage?, linkPreview: OWSLinkPreview?, groupPublicKey: String?, using transaction: Any) -> String? { let transaction = transaction as! YapDatabaseReadWriteTransaction guard let threadID = getOrCreateThread(for: message.sender!, groupPublicKey: groupPublicKey, using: transaction), let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return nil } - let message = TSIncomingMessage.from(message, withQuotedMessage: quotedMessage, associatedWith: thread) + let message = TSIncomingMessage.from(message, quotedMessage: quotedMessage, linkPreview: linkPreview, associatedWith: thread) message.save(with: transaction) DispatchQueue.main.async { message.touch() } // FIXME: Hack for a thread updating issue return message.uniqueId! diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift index e487ef726..c97419fcb 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift @@ -1,7 +1,7 @@ public extension TSIncomingMessage { - static func from(_ visibleMessage: VisibleMessage, withQuotedMessage quotedMessage: TSQuotedMessage?, associatedWith thread: TSThread) -> TSIncomingMessage { + static func from(_ visibleMessage: VisibleMessage, quotedMessage: TSQuotedMessage?, linkPreview: OWSLinkPreview?, associatedWith thread: TSThread) -> TSIncomingMessage { let sender = visibleMessage.sender! var expiration: UInt32 = 0 Storage.read { transaction in @@ -16,7 +16,7 @@ public extension TSIncomingMessage { attachmentIds: visibleMessage.attachmentIDs, expiresInSeconds: expiration, quotedMessage: quotedMessage, - linkPreview: OWSLinkPreview.from(visibleMessage.linkPreview), + linkPreview: linkPreview, serverTimestamp: nil, wasReceivedByUD: true ) diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift index 44fc13273..587c5380f 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift @@ -6,37 +6,49 @@ public extension VisibleMessage { class LinkPreview : NSObject, NSCoding { public var title: String? public var url: String? + public var attachmentID: String? - public var isValid: Bool { title != nil && url != nil } + public var isValid: Bool { title != nil && url != nil && attachmentID != nil } - internal init(title: String?, url: String) { + internal init(title: String?, url: String, attachmentID: String?) { self.title = title self.url = url + self.attachmentID = attachmentID } public required init?(coder: NSCoder) { if let title = coder.decodeObject(forKey: "title") as! String? { self.title = title } if let url = coder.decodeObject(forKey: "urlString") as! String? { self.url = url } + if let attachmentID = coder.decodeObject(forKey: "attachmentID") as! String? { self.attachmentID = attachmentID } } public func encode(with coder: NSCoder) { coder.encode(title, forKey: "title") coder.encode(url, forKey: "urlString") + coder.encode(attachmentID, forKey: "attachmentID") } public static func fromProto(_ proto: SNProtoDataMessagePreview) -> LinkPreview? { let title = proto.title let url = proto.url - return LinkPreview(title: title, url: url) + return LinkPreview(title: title, url: url, attachmentID: nil) } public func toProto() -> SNProtoDataMessagePreview? { + preconditionFailure("Use toProto(using:) instead.") + } + + public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoDataMessagePreview? { guard let url = url else { SNLog("Couldn't construct link preview proto from: \(self).") return nil } let linkPreviewProto = SNProtoDataMessagePreview.builder(url: url) if let title = title { linkPreviewProto.setTitle(title) } + if let attachmentID = attachmentID, let stream = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction), + let attachmentProto = stream.buildProto() { + linkPreviewProto.setImage(attachmentProto) + } do { return try linkPreviewProto.build() } catch { diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 88f7b7825..6b05102df 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -60,17 +60,27 @@ public final class VisibleMessage : Message { public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { let proto = SNProtoContent.builder() + var attachmentIDs = self.attachmentIDs let dataMessage: SNProtoDataMessage.SNProtoDataMessageBuilder + // Profile if let profile = profile, let profileProto = profile.toProto() { dataMessage = profileProto.asBuilder() } else { dataMessage = SNProtoDataMessage.builder() } + // Text if let text = text { dataMessage.setBody(text) } - var attachmentIDs = self.attachmentIDs + // Quote if let quotedAttachmentID = quote?.attachmentID, let index = attachmentIDs.firstIndex(of: quotedAttachmentID) { attachmentIDs.remove(at: index) } + if let quote = quote, let quoteProto = quote.toProto(using: transaction) { dataMessage.setQuote(quoteProto) } + // Link preview + if let linkPreviewAttachmentID = linkPreview?.attachmentID, let index = attachmentIDs.firstIndex(of: linkPreviewAttachmentID) { + attachmentIDs.remove(at: index) + } + if let linkPreview = linkPreview, let linkPreviewProto = linkPreview.toProto(using: transaction) { dataMessage.setPreview([ linkPreviewProto ]) } + // Attachments let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } if !attachments.allSatisfy({ $0.isUploaded }) { #if DEBUG @@ -79,9 +89,8 @@ public final class VisibleMessage : Message { } let attachmentProtos = attachments.compactMap { $0.buildProto() } dataMessage.setAttachments(attachmentProtos) - if let quote = quote, let quoteProto = quote.toProto(using: transaction) { dataMessage.setQuote(quoteProto) } - if let linkPreview = linkPreview, let linkPreviewProto = linkPreview.toProto() { dataMessage.setPreview([ linkPreviewProto ]) } // TODO: Contact + // Build do { proto.setDataMessage(try dataMessage.build()) return try proto.build() diff --git a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift index 5f4e4ee62..72e49d2e3 100644 --- a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift @@ -2,6 +2,21 @@ extension OWSLinkPreview { public static func from(_ linkPreview: VisibleMessage.LinkPreview?) -> OWSLinkPreview? { - return nil // TODO: Implement + guard let linkPreview = linkPreview else { return nil } + return OWSLinkPreview(urlString: linkPreview.url!, title: linkPreview.title, imageAttachmentId: linkPreview.attachmentID) + } +} + +extension VisibleMessage.LinkPreview { + + @objc(from:using:) + public static func from(_ linkPreview: OWSLinkPreviewDraft?, using transaction: YapDatabaseReadWriteTransaction) -> VisibleMessage.LinkPreview? { + guard let linkPreview = linkPreview else { return nil } + do { + let linkPreview = try OWSLinkPreview.buildValidatedLinkPreview(fromInfo: linkPreview, transaction: transaction) + return VisibleMessage.LinkPreview(title: linkPreview.title, url: linkPreview.urlString!, attachmentID: linkPreview.imageAttachmentId) + } catch { + return nil + } } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 0d9c21327..2ffa63e37 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -167,8 +167,17 @@ extension MessageReceiver { attachmentIDs.append(id) } } + // Parse link preview if needed + var owsLinkPreview: OWSLinkPreview? + if message.linkPreview != nil && proto.dataMessage?.preview.isEmpty == false { + owsLinkPreview = try? OWSLinkPreview.buildValidatedLinkPreview(dataMessage: proto.dataMessage!, body: message.text, transaction: transaction) + if let id = owsLinkPreview?.imageAttachmentId { + attachmentIDs.append(id) + } + } // Persist the message - guard let tsIncomingMessageID = storage.persist(message, withQuotedMessage: tsQuotedMessage, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + guard let tsIncomingMessageID = storage.persist(message, quotedMessage: tsQuotedMessage, linkPreview: owsLinkPreview, + groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } message.threadID = threadID // Start attachment downloads if needed storage.withAsync({ transaction in diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 3f551397f..1637cc74a 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -76,7 +76,7 @@ public protocol SessionMessagingKitStorageProtocol { /// Returns the ID of the thread. func getOrCreateThread(for publicKey: String, groupPublicKey: String?, using transaction: Any) -> String? /// Returns the ID of the `TSIncomingMessage` that was constructed. - func persist(_ message: VisibleMessage, withQuotedMessage quotedMessage: TSQuotedMessage?, groupPublicKey: String?, using transaction: Any) -> String? + func persist(_ message: VisibleMessage, quotedMessage: TSQuotedMessage?, linkPreview: OWSLinkPreview?, groupPublicKey: String?, using transaction: Any) -> String? /// Returns the IDs of the saved attachments. func persist(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] /// Also touches the associated message. diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index a31d4f138..fb3faed8c 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -21,12 +21,15 @@ extension MessageSender : SharedSenderKeysDelegate { stream.save(with: transaction) } tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) - if let linkPreviewAttachmentID = tsMessage.linkPreview?.imageAttachmentId, - let stream = TSAttachment.fetch(uniqueId: linkPreviewAttachmentID, transaction: transaction) as? TSAttachmentStream { + var linkPreviewAttachmentID: String? + if let id = tsMessage.linkPreview?.imageAttachmentId, + let stream = TSAttachment.fetch(uniqueId: id, transaction: transaction) as? TSAttachmentStream { + linkPreviewAttachmentID = id streams.append(stream) } message.attachmentIDs = streams.map { $0.uniqueId! } tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) + if let id = linkPreviewAttachmentID { tsMessage.attachmentIds.remove(id) } tsMessage.save(with: transaction) } From c5a7d39518c7c4f17ae23b585f9b09bab6c4f307 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Sat, 28 Nov 2020 13:57:03 +1100 Subject: [PATCH 060/177] Clean --- .../Sending & Receiving/MessageReceiver+Handling.swift | 9 +++++---- .../Quotes/TSQuotedMessage+Conversion.swift | 1 - .../Sending & Receiving/MessageSender+Handling.swift | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 2ffa63e37..a1fb885c0 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -143,8 +143,9 @@ extension MessageReceiver { guard let attachment = VisibleMessage.Attachment.fromProto(proto) else { return nil } return attachment.isValid ? attachment : nil } - var attachmentIDs = storage.persist(attachments, using: transaction) + let attachmentIDs = storage.persist(attachments, using: transaction) message.attachmentIDs = attachmentIDs + var attachmentsToDownload = attachmentIDs // Update profile if needed if let newProfile = message.profile { let profileManager = SSKEnvironment.shared.profileManager @@ -164,7 +165,7 @@ extension MessageReceiver { if message.quote != nil && proto.dataMessage?.quote != nil, let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { tsQuotedMessage = TSQuotedMessage(for: proto.dataMessage!, thread: thread, transaction: transaction) if let id = tsQuotedMessage?.thumbnailAttachmentStreamId() ?? tsQuotedMessage?.thumbnailAttachmentPointerId() { - attachmentIDs.append(id) + attachmentsToDownload.append(id) } } // Parse link preview if needed @@ -172,7 +173,7 @@ extension MessageReceiver { if message.linkPreview != nil && proto.dataMessage?.preview.isEmpty == false { owsLinkPreview = try? OWSLinkPreview.buildValidatedLinkPreview(dataMessage: proto.dataMessage!, body: message.text, transaction: transaction) if let id = owsLinkPreview?.imageAttachmentId { - attachmentIDs.append(id) + attachmentsToDownload.append(id) } } // Persist the message @@ -181,7 +182,7 @@ extension MessageReceiver { message.threadID = threadID // Start attachment downloads if needed storage.withAsync({ transaction in - attachmentIDs.forEach { attachmentID in + attachmentsToDownload.forEach { attachmentID in let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) if CurrentAppContext().isMainAppAndActive { // This has to be called from the main thread JobQueue.shared.add(downloadJob, using: transaction) diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift index 3bb505360..377317376 100644 --- a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift @@ -2,7 +2,6 @@ extension TSQuotedMessage { /// To be used for outgoing messages only. - @objc(from:) public static func from(_ quote: VisibleMessage.Quote?) -> TSQuotedMessage? { guard let quote = quote else { return nil } var attachments: [TSAttachment] = [] diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index fb3faed8c..681730caf 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -12,6 +12,8 @@ extension MessageSender : SharedSenderKeysDelegate { #endif return } + // Anything added to message.attachmentIDs will be uploaded by an UploadAttachmentJob. Any attachment IDs added to tsMessage will + // make it render as an attachment (not what we want in the case of a link preview or quoted attachment). var streams: [TSAttachmentStream] = [] attachments.forEach { let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, From 1ca336651879b1a33fcffb631fe4f60a593dddcc Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 09:28:32 +1100 Subject: [PATCH 061/177] Fix MessageSendJob deserialization --- SessionMessagingKit/Jobs/MessageSendJob.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 504203638..e3937f2e7 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -31,11 +31,11 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi guard rawDestination.removeSuffix(")") else { return nil } let publicKey = rawDestination destination = .contact(publicKey: publicKey) - } else if rawDestination.removePrefix("closedGroup") { + } else if rawDestination.removePrefix("closedGroup(") { guard rawDestination.removeSuffix(")") else { return nil } let groupPublicKey = rawDestination destination = .closedGroup(groupPublicKey: groupPublicKey) - } else if rawDestination.removePrefix("openGroup") { + } else if rawDestination.removePrefix("openGroup(") { guard rawDestination.removeSuffix(")") else { return nil } let components = rawDestination.split(separator: ",").map { String($0).trimmingCharacters(in: .whitespacesAndNewlines) } guard components.count == 2, let channel = UInt64(components[0]) else { return nil } From b0712522eb621737b52745e093e43a8aabb9f985 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 09:30:21 +1100 Subject: [PATCH 062/177] Compress images a bit more --- Session/Signal/GifPickerViewController.swift | 2 +- Session/Signal/PhotoCapture.swift | 2 +- Session/Signal/PhotoLibrary.swift | 2 +- SessionShareExtension/ShareViewController.swift | 2 +- .../Attachment Approval/AttachmentApprovalViewController.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Session/Signal/GifPickerViewController.swift b/Session/Signal/GifPickerViewController.swift index f5c4711f5..350ecf378 100644 --- a/Session/Signal/GifPickerViewController.swift +++ b/Session/Signal/GifPickerViewController.swift @@ -388,7 +388,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect owsFailDebug("couldn't load asset.") return } - let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: rendition.utiType, imageQuality: .original) + let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: rendition.utiType, imageQuality: .medium) strongSelf.dismiss(animated: true) { // Delegate presents view controllers, so it's important that *this* controller be dismissed before that occurs. diff --git a/Session/Signal/PhotoCapture.swift b/Session/Signal/PhotoCapture.swift index 385f4b63c..f445273e7 100644 --- a/Session/Signal/PhotoCapture.swift +++ b/Session/Signal/PhotoCapture.swift @@ -396,7 +396,7 @@ extension PhotoCapture: CaptureOutputDelegate { let dataSource = DataSourceValue.dataSource(with: photoData, utiType: kUTTypeJPEG as String) - let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: kUTTypeJPEG as String, imageQuality: .original) + let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: kUTTypeJPEG as String, imageQuality: .medium) delegate?.photoCapture(self, didFinishProcessingAttachment: attachment) } diff --git a/Session/Signal/PhotoLibrary.swift b/Session/Signal/PhotoLibrary.swift index c2a93136e..b5e011da2 100644 --- a/Session/Signal/PhotoLibrary.swift +++ b/Session/Signal/PhotoLibrary.swift @@ -207,7 +207,7 @@ class PhotoCollectionContents { switch asset.mediaType { case .image: return requestImageDataSource(for: asset).map { (dataSource: DataSource, dataUTI: String) in - return SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI, imageQuality: .original) + return SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI, imageQuality: .medium) } case .video: return requestVideoDataSource(for: asset).map { (dataSource: DataSource, dataUTI: String) in diff --git a/SessionShareExtension/ShareViewController.swift b/SessionShareExtension/ShareViewController.swift index 556df6bc7..eb1e0059c 100644 --- a/SessionShareExtension/ShareViewController.swift +++ b/SessionShareExtension/ShareViewController.swift @@ -935,7 +935,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed return promise } - let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: specificUTIType, imageQuality: .original) + let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: specificUTIType, imageQuality: .medium) if loadedItem.isConvertibleToContactShare { Logger.info("isConvertibleToContactShare") attachment.isConvertibleToContactShare = true diff --git a/SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalViewController.swift b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalViewController.swift index 7c06c23f3..66d0dc51e 100644 --- a/SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalViewController.swift +++ b/SignalUtilitiesKit/UI/Attachment Approval/AttachmentApprovalViewController.swift @@ -623,7 +623,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC } dataSource.sourceFilename = filename - let dstAttachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI, imageQuality: .original) + let dstAttachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI, imageQuality: .medium) if let attachmentError = dstAttachment.error { owsFailDebug("Could not prepare attachment for output: \(attachmentError).") return attachmentItem.attachment From ad66d717750e42bd691e7239cf098bc21be92a0a Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 09:40:36 +1100 Subject: [PATCH 063/177] Fix group thread layout bug --- SignalUtilitiesKit/UI/ConversationStyle.swift | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/SignalUtilitiesKit/UI/ConversationStyle.swift b/SignalUtilitiesKit/UI/ConversationStyle.swift index a24d00639..f64786c2b 100644 --- a/SignalUtilitiesKit/UI/ConversationStyle.swift +++ b/SignalUtilitiesKit/UI/ConversationStyle.swift @@ -91,13 +91,8 @@ public class ConversationStyle: NSObject { @objc public func updateProperties() { if thread.isGroupThread() { - if thread is TSGroupThread { - gutterLeading = 16 - gutterTrailing = 16 - } else { - gutterLeading = 12 + 35 + 12 // 12 + Values.smallProfilePictureSize + 12 - gutterTrailing = 16 - } + gutterLeading = 12 + Values.smallProfilePictureSize + 12 + gutterTrailing = 16 } else { gutterLeading = 16 gutterTrailing = 16 From b621bdc69a573f52fb26083826fe89e288f3424f Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 11:00:28 +1100 Subject: [PATCH 064/177] Partially fix open groups --- .../Database/Storage+Jobs.swift | 2 +- .../Database/Storage+Messaging.swift | 12 ++++++---- .../Database/Storage+OpenGroups.swift | 12 ++++++++++ .../Jobs/MessageReceiveJob.swift | 24 ++++++++++++------- .../Signal/TSIncomingMessage+Conversion.swift | 8 ++++--- .../MessageReceiver+Handling.swift | 10 ++++---- .../Sending & Receiving/MessageReceiver.swift | 24 ++++++++++++------- .../Sending & Receiving/MessageSender.swift | 7 ++++++ .../Pollers/OpenGroupPoller.swift | 4 ++-- SessionMessagingKit/Storage.swift | 5 ++-- 10 files changed, 75 insertions(+), 33 deletions(-) diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index 8b0bf3315..8e9b5ab95 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -16,7 +16,7 @@ extension Storage { public func getAllPendingJobs(of type: Job.Type) -> [Job] { var result: [Job] = [] Storage.read { transaction in - transaction.enumerateRows(inCollection: type.collection) { _, object, _, _ in + transaction.enumerateRows(inCollection: type.collection) { key, object, _, x in guard let job = object as? Job else { return } result.append(job) } diff --git a/SessionMessagingKit/Database/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift index 9783b72e1..e725a0c4a 100644 --- a/SessionMessagingKit/Database/Storage+Messaging.swift +++ b/SessionMessagingKit/Database/Storage+Messaging.swift @@ -17,10 +17,14 @@ extension Storage { } /// Returns the ID of the thread. - public func getOrCreateThread(for publicKey: String, groupPublicKey: String?, using transaction: Any) -> String? { + public func getOrCreateThread(for publicKey: String, groupPublicKey: String?, openGroupID: String?, using transaction: Any) -> String? { let transaction = transaction as! YapDatabaseReadWriteTransaction var threadOrNil: TSThread? - if let groupPublicKey = groupPublicKey { + if let openGroupID = openGroupID { + if let threadID = Storage.shared.getThreadID(for: openGroupID), let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction) { + threadOrNil = thread + } + } else if let groupPublicKey = groupPublicKey { guard Storage.shared.isClosedGroup(groupPublicKey) else { return nil } let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) @@ -31,9 +35,9 @@ extension Storage { } /// Returns the ID of the `TSIncomingMessage` that was constructed. - public func persist(_ message: VisibleMessage, quotedMessage: TSQuotedMessage?, linkPreview: OWSLinkPreview?, groupPublicKey: String?, using transaction: Any) -> String? { + public func persist(_ message: VisibleMessage, quotedMessage: TSQuotedMessage?, linkPreview: OWSLinkPreview?, groupPublicKey: String?, openGroupID: String?, using transaction: Any) -> String? { let transaction = transaction as! YapDatabaseReadWriteTransaction - guard let threadID = getOrCreateThread(for: message.sender!, groupPublicKey: groupPublicKey, using: transaction), + guard let threadID = getOrCreateThread(for: message.sender!, groupPublicKey: groupPublicKey, openGroupID: openGroupID, using: transaction), let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return nil } let message = TSIncomingMessage.from(message, quotedMessage: quotedMessage, linkPreview: linkPreview, associatedWith: thread) message.save(with: transaction) diff --git a/SessionMessagingKit/Database/Storage+OpenGroups.swift b/SessionMessagingKit/Database/Storage+OpenGroups.swift index 8fc9ebc94..ed3fcd90a 100644 --- a/SessionMessagingKit/Database/Storage+OpenGroups.swift +++ b/SessionMessagingKit/Database/Storage+OpenGroups.swift @@ -24,6 +24,18 @@ extension Storage { } return result } + + public func getThreadID(for openGroupID: String) -> String? { + var result: String? + Storage.read { transaction in + transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection, using: { threadID, object, stop in + guard let openGroup = object as? OpenGroup, "\(openGroup.server).\(openGroup.channel)" == openGroupID else { return } + result = threadID + stop.pointee = true + }) + } + return result + } @objc(setOpenGroup:forThreadWithID:using:) public func setOpenGroup(_ openGroup: OpenGroup, for threadID: String, using transaction: Any) { diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index b66a039f8..8638cb539 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -2,7 +2,8 @@ import SessionUtilitiesKit public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public let data: Data - public let messageServerID: UInt64? + public let openGroupMessageServerID: UInt64? + public let openGroupID: String? public var delegate: JobDelegate? public var id: String? public var failureCount: UInt = 0 @@ -12,9 +13,14 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC public static let maxFailureCount: UInt = 10 // MARK: Initialization - public init(data: Data, messageServerID: UInt64? = nil) { + public init(data: Data, openGroupMessageServerID: UInt64? = nil, openGroupID: String? = nil) { self.data = data - self.messageServerID = messageServerID + self.openGroupMessageServerID = openGroupMessageServerID + self.openGroupID = openGroupID + #if DEBUG + if openGroupMessageServerID != nil { assert(openGroupID != nil) } + if openGroupID != nil { assert(openGroupMessageServerID != nil) } + #endif } // MARK: Coding @@ -22,14 +28,16 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC guard let data = coder.decodeObject(forKey: "data") as! Data?, let id = coder.decodeObject(forKey: "id") as! String? else { return nil } self.data = data - self.messageServerID = coder.decodeObject(forKey: "messageServerUD") as! UInt64? + self.openGroupMessageServerID = coder.decodeObject(forKey: "openGroupMessageServerID") as! UInt64? + self.openGroupID = coder.decodeObject(forKey: "openGroupID") as! String? self.id = id self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } public func encode(with coder: NSCoder) { coder.encode(data, forKey: "data") - coder.encode(messageServerID, forKey: "messageServerID") + coder.encode(openGroupMessageServerID, forKey: "openGroupMessageServerID") + coder.encode(openGroupID, forKey: "openGroupID") coder.encode(id, forKey: "id") coder.encode(failureCount, forKey: "failureCount") } @@ -38,11 +46,11 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC public func execute() { Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self do { - let (message, proto) = try MessageReceiver.parse(self.data, messageServerID: self.messageServerID, using: transaction) - try MessageReceiver.handle(message, associatedWithProto: proto, using: transaction) + let (message, proto) = try MessageReceiver.parse(self.data, openGroupMessageServerID: self.openGroupMessageServerID, using: transaction) + try MessageReceiver.handle(message, associatedWithProto: proto, openGroupID: self.openGroupID, using: transaction) self.handleSuccess() } catch { - SNLog("Couldn't parse message due to error: \(error).") + SNLog("Couldn't receive message due to error: \(error).") if let error = error as? MessageReceiver.Error, !error.isRetryable { self.handlePermanentFailure(error: error) } else { diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift index c97419fcb..d48bc62ae 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift @@ -7,6 +7,8 @@ public extension TSIncomingMessage { Storage.read { transaction in expiration = thread.disappearingMessagesDuration(with: transaction) } + let openGroupServerMessageID = visibleMessage.openGroupServerMessageID ?? 0 + let isOpenGroupMessage = (openGroupServerMessageID != 0) let result = TSIncomingMessage( timestamp: visibleMessage.sentTimestamp!, in: thread, @@ -14,14 +16,14 @@ public extension TSIncomingMessage { sourceDeviceId: 1, messageBody: visibleMessage.text, attachmentIds: visibleMessage.attachmentIDs, - expiresInSeconds: expiration, + expiresInSeconds: !isOpenGroupMessage ? expiration : 0, // Ensure we don't ever expire open group messages quotedMessage: quotedMessage, linkPreview: linkPreview, serverTimestamp: nil, wasReceivedByUD: true ) - result.openGroupServerMessageID = visibleMessage.openGroupServerMessageID ?? 0 - result.isOpenGroupMessage = result.openGroupServerMessageID != 0 + result.openGroupServerMessageID = openGroupServerMessageID + result.isOpenGroupMessage = isOpenGroupMessage return result } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index a1fb885c0..0b3b2d8cd 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -7,13 +7,13 @@ extension MessageReceiver { return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey) } - internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { + internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) - case let message as VisibleMessage: try handleVisibleMessage(message, associatedWithProto: proto, using: transaction) + case let message as VisibleMessage: try handleVisibleMessage(message, associatedWithProto: proto, openGroupID: openGroupID, using: transaction) default: fatalError() } } @@ -135,7 +135,7 @@ extension MessageReceiver { SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() } - private static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, using transaction: Any) throws { + private static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws { let storage = Configuration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction // Parse & persist attachments @@ -159,7 +159,7 @@ extension MessageReceiver { } } // Get or create thread - guard let threadID = storage.getOrCreateThread(for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + guard let threadID = storage.getOrCreateThread(for: message.sender!, groupPublicKey: message.groupPublicKey, openGroupID: openGroupID, using: transaction) else { throw Error.noThread } // Parse quote if needed var tsQuotedMessage: TSQuotedMessage? = nil if message.quote != nil && proto.dataMessage?.quote != nil, let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { @@ -178,7 +178,7 @@ extension MessageReceiver { } // Persist the message guard let tsIncomingMessageID = storage.persist(message, quotedMessage: tsQuotedMessage, linkPreview: owsLinkPreview, - groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread } + groupPublicKey: message.groupPublicKey, openGroupID: openGroupID, using: transaction) else { throw Error.noThread } message.threadID = threadID // Start attachment downloads if needed storage.withAsync({ transaction in diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index a42a60bae..3cd16bf29 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -43,8 +43,9 @@ internal enum MessageReceiver { } } - internal static func parse(_ data: Data, messageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { + internal static func parse(_ data: Data, openGroupMessageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { let userPublicKey = Configuration.shared.storage.getUserPublicKey() + let isOpenGroupMessage = (openGroupMessageServerID != 0) // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) let storage = Configuration.shared.storage @@ -54,12 +55,16 @@ internal enum MessageReceiver { let plaintext: Data let sender: String var groupPublicKey: String? = nil - switch envelope.type { - case .unidentifiedSender: (plaintext, sender) = try decryptWithSignalProtocol(envelope: envelope, using: transaction) - case .closedGroupCiphertext: - (plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) - groupPublicKey = envelope.source - default: throw Error.unknownEnvelopeType + if isOpenGroupMessage { + (plaintext, sender) = (envelope.content!, envelope.source!) + } else { + switch envelope.type { + case .unidentifiedSender: (plaintext, sender) = try decryptWithSignalProtocol(envelope: envelope, using: transaction) + case .closedGroupCiphertext: + (plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) + groupPublicKey = envelope.source + default: throw Error.unknownEnvelopeType + } } // Don't process the envelope any further if the sender is blocked guard !isBlocked(sender) else { throw Error.senderBlocked } @@ -83,12 +88,15 @@ internal enum MessageReceiver { return nil }() if let message = message { + if isOpenGroupMessage { + guard message is VisibleMessage else { throw Error.invalidMessage } + } message.sender = sender message.recipient = userPublicKey message.sentTimestamp = envelope.timestamp message.receivedTimestamp = NSDate.millisecondTimestamp() message.groupPublicKey = groupPublicKey - message.openGroupServerMessageID = messageServerID + message.openGroupServerMessageID = openGroupMessageServerID var isValid = message.isValid if message is VisibleMessage && !isValid && proto.dataMessage?.attachments.isEmpty == false { isValid = true diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 03f1f83ec..caad66df1 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -203,6 +203,7 @@ public final class MessageSender : NSObject { let (promise, seal) = Promise.pending() let storage = Configuration.shared.storage message.sentTimestamp = NSDate.millisecondTimestamp() + message.sender = storage.getUserPublicKey() switch destination { case .contact(_): preconditionFailure() case .closedGroup(_): preconditionFailure() @@ -215,6 +216,12 @@ public final class MessageSender : NSObject { }, completion: { }) } // Validate the message + if !(message is VisibleMessage) { + #if DEBUG + preconditionFailure() + #endif + seal.reject(Error.invalidMessage); return promise + } guard message.isValid else { seal.reject(Error.invalidMessage); return promise } // Convert the message to an open group message let (channel, server) = { () -> (UInt64, String) in diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 5dccd17da..bb2994013 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -142,7 +142,7 @@ public final class OpenGroupPoller : NSObject { syncMessageBuilder.setSent(syncMessageSent) content.setSyncMessage(try! syncMessageBuilder.build()) } - let envelope = SNProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp) + let envelope = SNProtoEnvelope.builder(type: .unidentifiedSender, timestamp: message.timestamp) envelope.setSource(senderPublicKey) envelope.setSourceDevice(1) envelope.setContent(try! content.build().serializedData()) @@ -150,7 +150,7 @@ public final class OpenGroupPoller : NSObject { Storage.write { transaction in transaction.setObject(senderDisplayName, forKey: senderPublicKey, inCollection: openGroup.id) let messageServerID = message.serverID - let job = MessageReceiveJob(data: try! envelope.buildSerializedData(), messageServerID: messageServerID) + let job = MessageReceiveJob(data: try! envelope.buildSerializedData(), openGroupMessageServerID: messageServerID, openGroupID: openGroup.id) Storage.write { transaction in SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 1637cc74a..650f2acf7 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -45,6 +45,7 @@ public protocol SessionMessagingKitStorageProtocol { // MARK: - Open Groups func getOpenGroup(for threadID: String) -> OpenGroup? + func getThreadID(for openGroupID: String) -> String? // MARK: - Open Group Public Keys @@ -74,9 +75,9 @@ public protocol SessionMessagingKitStorageProtocol { func getReceivedMessageTimestamps(using transaction: Any) -> [UInt64] func addReceivedMessageTimestamp(_ timestamp: UInt64, using transaction: Any) /// Returns the ID of the thread. - func getOrCreateThread(for publicKey: String, groupPublicKey: String?, using transaction: Any) -> String? + func getOrCreateThread(for publicKey: String, groupPublicKey: String?, openGroupID: String?, using transaction: Any) -> String? /// Returns the ID of the `TSIncomingMessage` that was constructed. - func persist(_ message: VisibleMessage, quotedMessage: TSQuotedMessage?, linkPreview: OWSLinkPreview?, groupPublicKey: String?, using transaction: Any) -> String? + func persist(_ message: VisibleMessage, quotedMessage: TSQuotedMessage?, linkPreview: OWSLinkPreview?, groupPublicKey: String?, openGroupID: String?, using transaction: Any) -> String? /// Returns the IDs of the saved attachments. func persist(_ attachments: [VisibleMessage.Attachment], using transaction: Any) -> [String] /// Also touches the associated message. From 8564c650a524cc76ce9a6594ce367f977e5aa8b5 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 12:00:26 +1100 Subject: [PATCH 065/177] Parse open group attachments --- .../OpenGroupMessage+Conversion.swift | 73 ++++++++++++++----- .../Open Groups/OpenGroupMessage.swift | 12 ++- .../Sending & Receiving/MessageSender.swift | 2 +- .../Pollers/OpenGroupPoller.swift | 2 +- 4 files changed, 66 insertions(+), 23 deletions(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift index be4515ce2..060be6bc9 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift @@ -1,35 +1,74 @@ internal extension OpenGroupMessage { - static func from(_ message: VisibleMessage, for server: String) -> OpenGroupMessage? { - guard message.isValid else { preconditionFailure() } // Should be valid at this point + static func from(_ message: VisibleMessage, for server: String, using transaction: YapDatabaseReadWriteTransaction) -> OpenGroupMessage? { let storage = Configuration.shared.storage - let displayName = storage.getUserDisplayName() ?? "Anonymous" guard let userPublicKey = storage.getUserPublicKey() else { return nil } + // Validation + guard message.isValid else { return nil } // Should be valid at this point + // Quote let quote: OpenGroupMessage.Quote? = { if let quote = message.quote { guard quote.isValid else { return nil } - return OpenGroupMessage.Quote(quotedMessageTimestamp: quote.timestamp!, quoteePublicKey: quote.publicKey!, quotedMessageBody: quote.text!, quotedMessageServerID: nil) // TODO: Server ID + let quotedMessageServerID = TSIncomingMessage.find(withAuthorId: quote.publicKey!, timestamp: quote.timestamp!, transaction: transaction)?.openGroupServerMessageID + return OpenGroupMessage.Quote(quotedMessageTimestamp: quote.timestamp!, quoteePublicKey: quote.publicKey!, quotedMessageBody: quote.text, quotedMessageServerID: quotedMessageServerID) } else { return nil } }() - let body = message.text! + // Message + let displayName = storage.getUserDisplayName() ?? "Anonymous" + let body = message.text ?? String(message.sentTimestamp!) // The back-end doesn't accept messages without a body so we use this as a workaround let result = OpenGroupMessage(serverID: nil, senderPublicKey: userPublicKey, displayName: displayName, profilePicture: nil, body: body, type: OpenGroupAPI.openGroupMessageType, timestamp: message.sentTimestamp!, quote: quote, attachments: [], signature: nil, serverTimestamp: 0) - if let linkPreview: OpenGroupMessage.Attachment = { - if let linkPreview = message.linkPreview { - guard linkPreview.isValid else { return nil } - // TODO: Implement - return OpenGroupMessage.Attachment(kind: .linkPreview, server: server, serverID: 0, contentType: "", size: 0, fileName: "", - flags: 0, width: 0, height: 0, caption: "", url: "", linkPreviewURL: "", linkPreviewTitle: "") - } else { - return nil - } - }() { - result.attachments.append(linkPreview) + // Link preview + if let linkPreview = message.linkPreview { + guard linkPreview.isValid, let attachmentID = linkPreview.attachmentID, + let attachment = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction) else { return nil } + let fileName = attachment.sourceFilename ?? UUID().uuidString + let width = attachment.shouldHaveImageSize() ? attachment.imageSize().width : 0 + let height = attachment.shouldHaveImageSize() ? attachment.imageSize().height : 0 + let openGroupLinkPreview = OpenGroupMessage.Attachment( + kind: .linkPreview, + server: server, + serverID: 0, + contentType: attachment.contentType, + size: UInt(attachment.byteCount), + fileName: fileName, + flags: 0, + width: UInt(width), + height: UInt(height), + caption: attachment.caption, + url: attachment.downloadURL, + linkPreviewURL: linkPreview.url, + linkPreviewTitle: linkPreview.title + ) + result.attachments.append(openGroupLinkPreview) } - // TODO: Attachments + // Attachments + let attachments: [OpenGroupMessage.Attachment] = message.attachmentIDs.compactMap { attachmentID in + guard let attachment = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction) else { return nil } // Should never occur + let fileName = attachment.sourceFilename ?? UUID().uuidString + let width = attachment.shouldHaveImageSize() ? attachment.imageSize().width : 0 + let height = attachment.shouldHaveImageSize() ? attachment.imageSize().height : 0 + return OpenGroupMessage.Attachment( + kind: .attachment, + server: server, + serverID: 0, + contentType: attachment.contentType, + size: UInt(attachment.byteCount), + fileName: fileName, + flags: 0, + width: UInt(width), + height: UInt(height), + caption: attachment.caption, + url: attachment.downloadURL, + linkPreviewURL: nil, + linkPreviewTitle: nil + ) + } + result.attachments += attachments + // Return return result } } diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift index b562f4a58..7b26d50c0 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift @@ -34,7 +34,7 @@ public final class OpenGroupMessage : NSObject { public struct Quote { public let quotedMessageTimestamp: UInt64 public let quoteePublicKey: String - public let quotedMessageBody: String + public let quotedMessageBody: String? public let quotedMessageServerID: UInt64? } @@ -96,7 +96,7 @@ public final class OpenGroupMessage : NSObject { quotedMessageTimestamp: UInt64, quoteePublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64, serverTimestamp: UInt64) { let quote: Quote? - if quotedMessageTimestamp != 0, let quoteeHexEncodedPublicKey = quoteePublicKey, let quotedMessageBody = quotedMessageBody { + if quotedMessageTimestamp != 0, let quoteeHexEncodedPublicKey = quoteePublicKey { let quotedMessageServerID = (quotedMessageServerID != 0) ? quotedMessageServerID : nil quote = Quote(quotedMessageTimestamp: quotedMessageTimestamp, quoteePublicKey: quoteeHexEncodedPublicKey, quotedMessageBody: quotedMessageBody, quotedMessageServerID: quotedMessageServerID) } else { @@ -137,7 +137,8 @@ public final class OpenGroupMessage : NSObject { internal func toJSON() -> JSON { var value: JSON = [ "timestamp" : timestamp ] if let quote = quote { - value["quote"] = [ "id" : quote.quotedMessageTimestamp, "author" : quote.quoteePublicKey, "text" : quote.quotedMessageBody ] + value["quote"] = [ "id" : quote.quotedMessageTimestamp, "author" : quote.quoteePublicKey ] + if let quotedMessageBody = quote.quotedMessageBody { value["text"] = quotedMessageBody } } if let signature = signature { value["sig"] = signature.data.toHexString() @@ -183,7 +184,10 @@ public final class OpenGroupMessage : NSObject { private func getValidationData(for signatureVersion: UInt64) -> Data? { var string = "\(body.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines))\(timestamp)" if let quote = quote { - string += "\(quote.quotedMessageTimestamp)\(quote.quoteePublicKey)\(quote.quotedMessageBody.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines))" + string += "\(quote.quotedMessageTimestamp)\(quote.quoteePublicKey)" + if let quotedMessageBody = quote.quotedMessageBody { + string += "\(quotedMessageBody.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines))" + } if let quotedMessageServerID = quote.quotedMessageServerID { string += "\(quotedMessageServerID)" } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index caad66df1..f331a87c5 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -231,7 +231,7 @@ public final class MessageSender : NSObject { } }() guard let message = message as? VisibleMessage, - let openGroupMessage = OpenGroupMessage.from(message, for: server) else { seal.reject(Error.invalidMessage); return promise } + let openGroupMessage = OpenGroupMessage.from(message, for: server, using: transaction as! YapDatabaseReadWriteTransaction) else { seal.reject(Error.invalidMessage); return promise } // Send the result OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = openGroupMessage.serverID diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index bb2994013..de35a3821 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -119,7 +119,7 @@ public final class OpenGroupPoller : NSObject { dataMessage.setGroup(try! groupContext.build()) if let quote = message.quote { let signalQuote = SNProtoDataMessageQuote.builder(id: quote.quotedMessageTimestamp, author: quote.quoteePublicKey) - signalQuote.setText(quote.quotedMessageBody) + if let quotedMessageBody = quote.quotedMessageBody { signalQuote.setText(quotedMessageBody) } dataMessage.setQuote(try! signalQuote.build()) } let body = (message.body == message.timestamp.description) ? "" : message.body // Workaround for the fact that the back-end doesn't accept messages without a body From 02454b6cc90d4504c0601e9bcf6e7aa5cee15647 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 12:11:06 +1100 Subject: [PATCH 066/177] Point to forked YapDatabase repo --- Podfile | 14 +++++++------- Podfile.lock | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Podfile b/Podfile index d3d2d1b36..bb59575b1 100644 --- a/Podfile +++ b/Podfile @@ -15,7 +15,7 @@ target 'Session' do pod 'Sodium', :inhibit_warnings => true pod 'SSZipArchive', :inhibit_warnings => true pod 'Starscream', git: 'https://github.com/signalapp/Starscream.git', branch: 'signal-release', :inhibit_warnings => true - pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true pod 'YYImage', git: 'https://github.com/signalapp/YYImage', :inhibit_warnings => true pod 'ZXingObjC', :inhibit_warnings => true end @@ -28,7 +28,7 @@ target 'SessionShareExtension' do pod 'PromiseKit', :inhibit_warnings => true pod 'PureLayout', '~> 3.1.4', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true - pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end target 'SessionPushNotificationExtension' do @@ -39,7 +39,7 @@ target 'SessionPushNotificationExtension' do pod 'PromiseKit', :inhibit_warnings => true pod 'PureLayout', '~> 3.1.4', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true - pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end target 'SignalUtilitiesKit' do @@ -57,7 +57,7 @@ target 'SignalUtilitiesKit' do pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'Starscream', git: 'https://github.com/signalapp/Starscream.git', branch: 'signal-release', :inhibit_warnings => true pod 'SwiftProtobuf', '~> 1.5.0', :inhibit_warnings => true - pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true pod 'YYImage', git: 'https://github.com/signalapp/YYImage', :inhibit_warnings => true end @@ -77,7 +77,7 @@ target 'SessionMessagingKit' do pod 'SAMKeychain', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'SwiftProtobuf', '~> 1.5.0', :inhibit_warnings => true - pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end target 'SessionProtocolKit' do @@ -96,7 +96,7 @@ target 'SessionSnodeKit' do pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'PromiseKit', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true - pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end target 'SessionUtilitiesKit' do @@ -108,7 +108,7 @@ target 'SessionUtilitiesKit' do pod 'PureLayout', '~> 3.1.4', :inhibit_warnings => true pod 'SAMKeychain', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true - pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release', :inhibit_warnings => true + pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end post_install do |installer| diff --git a/Podfile.lock b/Podfile.lock index b348a5ae6..ffaae8fc0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -144,7 +144,7 @@ DEPENDENCIES: - SSZipArchive - Starscream (from `https://github.com/signalapp/Starscream.git`, branch `signal-release`) - SwiftProtobuf (~> 1.5.0) - - YapDatabase/SQLCipher (from `https://github.com/signalapp/YapDatabase.git`, branch `signal-release`) + - YapDatabase/SQLCipher (from `https://github.com/loki-project/session-ios-yap-database.git`, branch `signal-release`) - YYImage (from `https://github.com/signalapp/YYImage`) - ZXingObjC @@ -181,7 +181,7 @@ EXTERNAL SOURCES: :git: https://github.com/signalapp/Starscream.git YapDatabase: :branch: signal-release - :git: https://github.com/signalapp/YapDatabase.git + :git: https://github.com/loki-project/session-ios-yap-database.git YYImage: :git: https://github.com/signalapp/YYImage @@ -200,7 +200,7 @@ CHECKOUT OPTIONS: :git: https://github.com/signalapp/Starscream.git YapDatabase: :commit: e43ab163b2dcb4c817339c819b07dac545f05fea - :git: https://github.com/signalapp/YapDatabase.git + :git: https://github.com/loki-project/session-ios-yap-database.git YYImage: :commit: d91910e6f313a255febbf69795198e74259bd51c :git: https://github.com/signalapp/YYImage @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: f65f7b4344906f219fb7e1e4ca93b4ed1ac3132a +PODFILE CHECKSUM: 4ebb6a2d7cbbdd42f72f7e7669db8aff6e26cf7c COCOAPODS: 1.10.0.rc.1 From d33fcb075667b4ce06149ef912ae1ecb3d9e9bca Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 13:01:43 +1100 Subject: [PATCH 067/177] Re-install pods --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index ffaae8fc0..fed017f6c 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -199,7 +199,7 @@ CHECKOUT OPTIONS: :commit: b09ea163c3cb305152c65b299cb024610f52e735 :git: https://github.com/signalapp/Starscream.git YapDatabase: - :commit: e43ab163b2dcb4c817339c819b07dac545f05fea + :commit: 5806f6b6e0b34124ee09283a9eca9ce7e6eaf14e :git: https://github.com/loki-project/session-ios-yap-database.git YYImage: :commit: d91910e6f313a255febbf69795198e74259bd51c From 993c673aadc1a5cd2a8824da9b83a9c79f23eced Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 13:18:26 +1100 Subject: [PATCH 068/177] Clean --- .../Sending & Receiving/MessageSender.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index f331a87c5..8b0299fab 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -216,11 +216,12 @@ public final class MessageSender : NSObject { }, completion: { }) } // Validate the message - if !(message is VisibleMessage) { + guard let message = message as? VisibleMessage else { #if DEBUG preconditionFailure() #endif - seal.reject(Error.invalidMessage); return promise + seal.reject(Error.invalidMessage) + return promise } guard message.isValid else { seal.reject(Error.invalidMessage); return promise } // Convert the message to an open group message @@ -230,8 +231,7 @@ public final class MessageSender : NSObject { default: preconditionFailure() } }() - guard let message = message as? VisibleMessage, - let openGroupMessage = OpenGroupMessage.from(message, for: server, using: transaction as! YapDatabaseReadWriteTransaction) else { seal.reject(Error.invalidMessage); return promise } + guard let openGroupMessage = OpenGroupMessage.from(message, for: server, using: transaction as! YapDatabaseReadWriteTransaction) else { seal.reject(Error.invalidMessage); return promise } // Send the result OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = openGroupMessage.serverID From ef76d738215a8912df190eed578a643444c8df53 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 14:20:36 +1100 Subject: [PATCH 069/177] Fix typo --- SessionMessagingKit/Sending & Receiving/MessageReceiver.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 3cd16bf29..d24b42839 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -45,7 +45,7 @@ internal enum MessageReceiver { internal static func parse(_ data: Data, openGroupMessageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { let userPublicKey = Configuration.shared.storage.getUserPublicKey() - let isOpenGroupMessage = (openGroupMessageServerID != 0) + let isOpenGroupMessage = (openGroupMessageServerID != nil) // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) let storage = Configuration.shared.storage From 6f6810d01009d7e0caee5d4612b171112763ebe9 Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:21:56 +1100 Subject: [PATCH 070/177] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 26c681144..f2935c4a0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -13,7 +13,7 @@ A clear and concise description of what the bug is. **To reproduce** -Steps to reproduce the behavior: +Steps to reproduce the behavior. **Screenshots or logs** From 3adbe99a96f1da8f664d6bbb244089361ef64bce Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:23:02 +1100 Subject: [PATCH 071/177] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 166d2068b..f2f5ca160 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -26,9 +26,9 @@ Describe here the issue that you are experiencing. - list the steps - that reproduce the bug -**Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour) +**Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour). -**Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour) +**Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour). ### Screenshots @@ -41,27 +41,3 @@ Describe here the issue that you are experiencing. **iOS version**: X.Y.Z **Session version:** X.Y.Z - -### Link to debug log - - - From 776c34d7962199089cc74fc0e18d0fe9b1d656ca Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:24:35 +1100 Subject: [PATCH 072/177] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5019d80d5..9a7bbfb5b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,6 @@ - -### First time contributor checklist - -- [ ] I have read the [README](https://github.com/WhisperSystems/Signal-iOS/blob/master/README.md) and [CONTRIBUTING](https://github.com/WhisperSystems/Signal-iOS/blob/master/CONTRIBUTING.md) documents -- [ ] I have signed the [Contributor Licence Agreement](https://whispersystems.org/cla/) ### Contributor checklist -- [ ] I'm following the [code, UI and style conventions](https://github.com/WhisperSystems/Signal-iOS/blob/master/CONTRIBUTING.md#code-conventions) - [ ] My commits are rebased on the latest master branch - [ ] My commits are in nice logical chunks - [ ] My contribution is fully baked and is ready to be merged as is From 95531f39c9afd82139532853c3d4495c0f0d7552 Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:28:01 +1100 Subject: [PATCH 073/177] Update BUILDING.md --- BUILDING.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 94116d759..ef671330d 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -31,12 +31,12 @@ You can then add the Session repo to sync with upstream changes: git remote add upstream https://github.com/loki-project/session-ios ``` -## 2. Dependencies +## 2. Pods To build and configure the libraries Session uses, just run: ``` -make dependencies +pod install ``` ## 3. Xcode @@ -49,16 +49,12 @@ open Signal.xcworkspace In the TARGETS area of the General tab, change the Team dropdown to your own. You will need to do that for all the listed targets, for ex. -Signal, SignalShareExtension, and SignalMessaging. You will need an Apple -Developer account for this. +Session, SessionShareExtension, and SessionPushNotificationExtension. You +will need an Apple Developer account for this. On the Capabilities tab, turn off Push Notifications and Data Protection, while keeping Background Modes on. The App Groups capability will need to -remain on in order to access the shared data storage. The App ID needs to -match the SignalApplicationGroup string set in TSConstants.h. - -If you wish to test the Documents API, the iCloud capability will need to -be on with the iCloud Documents option selected. +remain on in order to access the shared data storage. Build and Run and you are ready to go! From 3603811e45adf527925214ee9c4ba66d23ce601c Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:28:34 +1100 Subject: [PATCH 074/177] Delete CONTRIBUTING.md --- CONTRIBUTING.md | 62 ------------------------------------------------- 1 file changed, 62 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 0ef92478f..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,62 +0,0 @@ -# Contributing to Session iOS - -Thank you for supporting Session and looking for ways to help. Please note that some conventions here might be a bit different than what you are used to, even if you have contributed to other open source projects before. Reading this document will help you save time and work effectively with the developers and other contributors. - -## Where do I start? - -The bulk of the Session code can be found under Signal/src/Loki and SignalServiceKit/src/Loki. - - -## Development ideology - -Truths which we believe to be self-evident: - -1. **The answer is not more options.** If you feel compelled to add a preference that's exposed to the user, it's very possible you've made a wrong turn somewhere. -1. **The user doesn't know what a key is.** We need to minimize the points at which a user is exposed to this sort of terminology as extremely as possible. -1. **There are no power users.** The idea that some users "understand" concepts better than others has proven to be, for the most part, false. If anything, "power users" are more dangerous than the rest, and we should avoid exposing dangerous functionality to them. -1. **If it's "like PGP," it's wrong.** PGP is our guide for what not to do. -1. **It's an asynchronous world.** Be wary of anything that is anti-asynchronous: ACKs, protocol confirmations, or any protocol-level "advisory" message. -1. **There is no such thing as time.** Protocol ideas that require synchronized clocks are doomed to failure. - - -## Issues - -Please search both open and closed issues to make sure your bug report is not a duplicate. - -### Open issues - -#### If it's open, it's tracked -The developers read every issue, but high-priority bugs or features can take precedence over others. Session is an open source project, and everyone is encouraged to play an active role in diagnosing and fixing open issues. - -### Closed issues - -#### "My issue was closed without giving a reason!" -Although we do our best, writing detailed explanations for every issue can be time consuming, and the topic also might have been covered previously in other related issues. - - -## Pull requests - -### Smaller is better -Big changes are significantly less likely to be accepted. Large features often require protocol modifications and necessitate a staged rollout process that is coordinated across millions of users on multiple platforms (Android, iOS, and Desktop). - -Try not to take on too much at once. As a first-time contributor, we recommend starting with small and simple PRs in order to become familiar with the codebase. Most of the work should go into discovering which three lines need to change rather than writing the code. - -### Submit finished and well-tested pull requests -Please do not submit pull requests that are still a work in progress. Pull requests should be thoroughly tested and ready to merge before they are submitted. - -### Merging can sometimes take a while -If your pull request follows all of the advice above but still has not been merged, this usually means that the developers haven't had time to review it yet. We understand that this might feel frustrating, and we apologize. - - -## How can I contribute? -There are several other ways to get involved: -* Help new users learn about Session. - * Redirect support questions to support@loki.network. -* Improve documentation in the [wiki](https://github.com/loki-project/session-protocol-docs/wiki). -* Find and mark duplicate issues. -* Try to reproduce issues and help with troubleshooting. -* Discover solutions to open issues and post any relevant findings. -* Test other people's pull requests. -* Share Session with your friends and family. - -Session is made for you. Thank you for your feedback and support. From 809a93c5f1a68483a33d9d246d806f7146ddbdbe Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:28:43 +1100 Subject: [PATCH 075/177] Delete MAINTAINING.md --- MAINTAINING.md | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 MAINTAINING.md diff --git a/MAINTAINING.md b/MAINTAINING.md deleted file mode 100644 index 496d4740f..000000000 --- a/MAINTAINING.md +++ /dev/null @@ -1,14 +0,0 @@ -Apart from the general `BUILDING.md` there are certain things that have -to be done by Session maintainers. - -For transparency and bus factor, they are outlined here. - -## Dependencies - -Keeping Cocoapods based dependencies is easy enough. - -`pod update` - -Similarly, Carthage dependencies can be updated like so: - -`carthage update` From 01b7a0e12b9e6b7610a6ce0f12650cf55134d0c7 Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:35:47 +1100 Subject: [PATCH 076/177] Update BUILDING.md --- BUILDING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/BUILDING.md b/BUILDING.md index ef671330d..079245ff7 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -60,6 +60,13 @@ Build and Run and you are ready to go! ## Known issues +### PureLayout + +The CocoaPods PureLayout post install hook doesn't always get applied correctly +upon running `pod install`. See https://github.com/CocoaPods/CocoaPods/issues/10087 +for more information. + +### Push Notifications Features related to push notifications are known to be not working for third-party contributors since Apple's Push Notification service pushes will only work with the Session production code signing From 0f327092d24a965e31de2bda99c97d39712d23b7 Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:43:49 +1100 Subject: [PATCH 077/177] Update BUILDING.md --- BUILDING.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 079245ff7..859385764 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -61,9 +61,8 @@ Build and Run and you are ready to go! ## Known issues ### PureLayout - -The CocoaPods PureLayout post install hook doesn't always get applied correctly -upon running `pod install`. See https://github.com/CocoaPods/CocoaPods/issues/10087 +The PureLayout post install hook doesn't get applied correctly upon running +`pod install` if you're on Xcode 12. See https://github.com/CocoaPods/CocoaPods/issues/10087 for more information. ### Push Notifications From 3cf87d40ab34cad07f525fcf49701e28891aa273 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 15:06:05 +1100 Subject: [PATCH 078/177] Fix note to self --- .../Sending & Receiving/MessageSender.swift | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 8b0299fab..4049eab15 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -57,23 +57,33 @@ public final class MessageSender : NSObject { if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() } - message.sender = storage.getUserPublicKey() + let userPublicKey = storage.getUserPublicKey() + message.sender = userPublicKey switch destination { case .contact(let publicKey): message.recipient = publicKey case .closedGroup(let groupPublicKey): message.recipient = groupPublicKey case .openGroup(_, _): preconditionFailure() } + let isSelfSend = (message.recipient == userPublicKey) // Set the failure handler (for precondition failure handling) let _ = promise.catch(on: DispatchQueue.main) { error in storage.withAsync({ transaction in MessageSender.handleFailedMessageSend(message, with: error, using: transaction) }, completion: { }) - if case .contact(_) = destination, message is VisibleMessage { + if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) } } // Validate the message guard message.isValid else { seal.reject(Error.invalidMessage); return promise } + // Stop here if this is a self-send + guard !isSelfSend else { + storage.withAsync({ transaction in + MessageSender.handleSuccessfulMessageSend(message, using: transaction) + }, completion: { }) + seal.fulfill(()) + return promise + } // Attach the user's profile if needed if let message = message as? VisibleMessage { let displayName = storage.getUserDisplayName()! @@ -101,7 +111,7 @@ public final class MessageSender : NSObject { return promise } // Encrypt the serialized protobuf - if case .contact(_) = destination, message is VisibleMessage { + if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { DispatchQueue.main.async { NotificationCenter.default.post(name: .encryptingMessage, object: NSNumber(value: message.sentTimestamp!)) } @@ -140,7 +150,7 @@ public final class MessageSender : NSObject { return promise } // Calculate proof of work - if case .contact(_) = destination, message is VisibleMessage { + if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { DispatchQueue.main.async { NotificationCenter.default.post(name: .calculatingMessagePoW, object: NSNumber(value: message.sentTimestamp!)) } @@ -153,7 +163,7 @@ public final class MessageSender : NSObject { return promise } // Send the result - if case .contact(_) = destination, message is VisibleMessage { + if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { DispatchQueue.main.async { NotificationCenter.default.post(name: .messageSending, object: NSNumber(value: message.sentTimestamp!)) } @@ -184,7 +194,7 @@ public final class MessageSender : NSObject { storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, using: transaction) }, completion: { }) - if case .contact(_) = destination, message is VisibleMessage { + if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) } if message is VisibleMessage { From 21810a0c4c30d47e475f379a7fd33914c6a70724 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 15:20:03 +1100 Subject: [PATCH 079/177] Fix closed group message status handling --- .../Sending & Receiving/MessageSender.swift | 6 +++--- .../Sending & Receiving/MessageSender+Handling.swift | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 4049eab15..4c3bf0eb2 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -79,7 +79,7 @@ public final class MessageSender : NSObject { // Stop here if this is a self-send guard !isSelfSend else { storage.withAsync({ transaction in - MessageSender.handleSuccessfulMessageSend(message, using: transaction) + MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) }, completion: { }) seal.fulfill(()) return promise @@ -192,7 +192,7 @@ public final class MessageSender : NSObject { // Handle completion let _ = promise.done(on: DispatchQueue.main) { storage.withAsync({ transaction in - MessageSender.handleSuccessfulMessageSend(message, using: transaction) + MessageSender.handleSuccessfulMessageSend(message, to: destination,X using: transaction) }, completion: { }) if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) @@ -252,7 +252,7 @@ public final class MessageSender : NSObject { // Handle completion let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { storage.withAsync({ transaction in - MessageSender.handleSuccessfulMessageSend(message, using: transaction) + MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) }, completion: { }) } // Return diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift index 681730caf..670a924a4 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift @@ -74,11 +74,18 @@ extension MessageSender : SharedSenderKeysDelegate { // MARK: - Success & Failure Handling - public static func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { + public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, using transaction: Any) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 - tsMessage.update(withSentRecipient: message.recipient!, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) + var recipients = [ message.recipient! ] + if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point + let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction as! YapDatabaseReadTransaction), thread.usesSharedSenderKeys { + recipients = thread.groupModel.groupMemberIds + } + recipients.forEach { recipient in + tsMessage.update(withSentRecipient: recipient, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) + } OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction as! YapDatabaseReadWriteTransaction) } From 2d8933901d84229700297f9787ef164bd0631856 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 15:44:07 +1100 Subject: [PATCH 080/177] Fix open group display name handling --- SessionMessagingKit/Database/Storage+OpenGroups.swift | 4 ++-- SessionMessagingKit/Open Groups/OpenGroupAPI.swift | 2 +- .../Sending & Receiving/MessageReceiver+Handling.swift | 7 +++++++ .../Sending & Receiving/MessageSender.swift | 2 +- SessionMessagingKit/Storage.swift | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Database/Storage+OpenGroups.swift b/SessionMessagingKit/Database/Storage+OpenGroups.swift index ed3fcd90a..a6b87a1b1 100644 --- a/SessionMessagingKit/Database/Storage+OpenGroups.swift +++ b/SessionMessagingKit/Database/Storage+OpenGroups.swift @@ -198,8 +198,8 @@ extension Storage { return result } - public func setOpenGroupDisplayName(to displayName: String, for publicKey: String, on channel: UInt64, server: String, using transaction: Any) { - let collection = "\(server).\(channel)" // FIXME: This should be a proper collection + public func setOpenGroupDisplayName(to displayName: String, for publicKey: String, inOpenGroupWithID openGroupID: String, using transaction: Any) { + let collection = openGroupID (transaction as! YapDatabaseReadWriteTransaction).setObject(displayName, forKey: publicKey, inCollection: collection) } diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 7c75c7672..004920a41 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -262,7 +262,7 @@ public final class OpenGroupAPI : DotNetAPI { let endIndex = hexEncodedPublicKey.endIndex let cutoffIndex = hexEncodedPublicKey.index(endIndex, offsetBy: -8) let displayName = "\(rawDisplayName) (...\(hexEncodedPublicKey[cutoffIndex.. UInt64? - func setOpenGroupDisplayName(to displayName: String, for publicKey: String, on channel: UInt64, server: String, using transaction: Any) + func setOpenGroupDisplayName(to displayName: String, for publicKey: String, inOpenGroupWithID openGroupID: String, using transaction: Any) func setLastProfilePictureUploadDate(_ date: Date) // Stored in user defaults so no transaction is needed // MARK: - Message Handling From d01e732515b49d8a5e207e67a76f83e7d22877df Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 30 Nov 2020 16:10:58 +1100 Subject: [PATCH 081/177] Debug open group messaging --- SessionMessagingKit/Jobs/MessageSendJob.swift | 2 +- SessionMessagingKit/Open Groups/OpenGroupAPI.swift | 4 ++-- SessionMessagingKit/Open Groups/OpenGroupMessage.swift | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index e3937f2e7..d6e297b66 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -53,7 +53,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi switch destination { case .contact(let publicKey): coder.encode("contact(\(publicKey))", forKey: "destination") case .closedGroup(let groupPublicKey): coder.encode("closedGroup(\(groupPublicKey))", forKey: "destination") - case .openGroup(let channel, let server): coder.encode("openGroup(\(channel), \(server))") + case .openGroup(let channel, let server): coder.encode("openGroup(\(channel), \(server))", forKey: "destination") } coder.encode(id, forKey: "id") coder.encode(failureCount, forKey: "failureCount") diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 004920a41..65a175abc 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -86,8 +86,8 @@ public final class OpenGroupAPI : DotNetAPI { } } let quote: OpenGroupMessage.Quote? - if let quoteAsJSON = value["quote"] as? JSON, let quotedMessageTimestamp = quoteAsJSON["id"] as? UInt64, let quoteePublicKey = quoteAsJSON["author"] as? String, - let quotedMessageBody = quoteAsJSON["text"] as? String { + if let quoteAsJSON = value["quote"] as? JSON, let quotedMessageTimestamp = quoteAsJSON["id"] as? UInt64, let quoteePublicKey = quoteAsJSON["author"] as? String { + let quotedMessageBody = quoteAsJSON["text"] as? String let quotedMessageServerID = message["reply_to"] as? UInt64 quote = OpenGroupMessage.Quote(quotedMessageTimestamp: quotedMessageTimestamp, quoteePublicKey: quoteePublicKey, quotedMessageBody: quotedMessageBody, quotedMessageServerID: quotedMessageServerID) diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift index 7b26d50c0..cbcf22496 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift @@ -137,8 +137,9 @@ public final class OpenGroupMessage : NSObject { internal func toJSON() -> JSON { var value: JSON = [ "timestamp" : timestamp ] if let quote = quote { - value["quote"] = [ "id" : quote.quotedMessageTimestamp, "author" : quote.quoteePublicKey ] - if let quotedMessageBody = quote.quotedMessageBody { value["text"] = quotedMessageBody } + var quoteAsJSON: JSON = [ "id" : quote.quotedMessageTimestamp, "author" : quote.quoteePublicKey ] + if let quotedMessageBody = quote.quotedMessageBody { quoteAsJSON["text"] = quotedMessageBody } + value["quote"] = quoteAsJSON } if let signature = signature { value["sig"] = signature.data.toHexString() From add2c467e453d0f0e0d6c8d54f911299d9c6422c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 08:35:13 +1100 Subject: [PATCH 082/177] Restructure --- .../MessageReceiver+Handling.swift | 4 +- .../MessageSender+ClosedGroups.swift | 98 +------------------ .../Sending & Receiving/MessageSender.swift | 52 ++++++++++ Signal.xcodeproj/project.pbxproj | 12 ++- .../MessageSender+Convenience.swift | 40 ++++++++ 5 files changed, 102 insertions(+), 104 deletions(-) rename SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift => SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift (72%) create mode 100644 SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 155154500..1647ff4c7 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -202,9 +202,7 @@ extension MessageReceiver { cancelTypingIndicatorsIfNeeded(for: message.sender!) // Notify the user if needed guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return } - Storage.read { transaction in - SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction) - } + SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction) } private static func handleClosedGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift similarity index 72% rename from SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift rename to SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift index 670a924a4..4ef0698fb 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift @@ -1,103 +1,7 @@ -import SessionProtocolKit import PromiseKit extension MessageSender : SharedSenderKeysDelegate { - // MARK: - Sending Convenience - - private static func prep(_ attachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { - #if DEBUG - preconditionFailure() - #endif - return - } - // Anything added to message.attachmentIDs will be uploaded by an UploadAttachmentJob. Any attachment IDs added to tsMessage will - // make it render as an attachment (not what we want in the case of a link preview or quoted attachment). - var streams: [TSAttachmentStream] = [] - attachments.forEach { - let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, - caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) - streams.append(stream) - stream.write($0.dataSource) - stream.save(with: transaction) - } - tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) - var linkPreviewAttachmentID: String? - if let id = tsMessage.linkPreview?.imageAttachmentId, - let stream = TSAttachment.fetch(uniqueId: id, transaction: transaction) as? TSAttachmentStream { - linkPreviewAttachmentID = id - streams.append(stream) - } - message.attachmentIDs = streams.map { $0.uniqueId! } - tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) - if let id = linkPreviewAttachmentID { tsMessage.attachmentIds.remove(id) } - tsMessage.save(with: transaction) - } - - @objc(send:withAttachments:inThread:usingTransaction:) - public static func send(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { - prep(attachments, for: message, using: transaction) - send(message, in: thread, using: transaction) - } - - @objc(send:inThread:usingTransaction:) - public static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { - message.threadID = thread.uniqueId! - let destination = Message.Destination.from(thread) - let job = MessageSendJob(message: message, destination: destination) - JobQueue.shared.add(job, using: transaction) - } - - @objc(sendNonDurably:withAttachments:inThread:usingTransaction:) - public static func objc_sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { - return AnyPromise.from(sendNonDurably(message, with: attachments, in: thread, using: transaction)) - } - - @objc(sendNonDurably:inThread:usingTransaction:) - public static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { - return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) - } - - public static func sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { - prep(attachments, for: message, using: transaction) - return sendNonDurably(message, in: thread, using: transaction) - } - - public static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { - message.threadID = thread.uniqueId! - let destination = Message.Destination.from(thread) - return MessageSender.send(message, to: destination, using: transaction) - } - - - - // MARK: - Success & Failure Handling - - public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, using transaction: Any) { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } - tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 - tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 - var recipients = [ message.recipient! ] - if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point - let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction as! YapDatabaseReadTransaction), thread.usesSharedSenderKeys { - recipients = thread.groupModel.groupMemberIds - } - recipients.forEach { recipient in - tsMessage.update(withSentRecipient: recipient, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) - } - OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction as! YapDatabaseReadWriteTransaction) - } - - public static func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) { - guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } - tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction) - } - - - - // MARK: - Closed Groups - public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { // Prepare var members = members @@ -289,7 +193,7 @@ extension MessageSender : SharedSenderKeysDelegate { newMembers.remove(userPublicKey) return update(groupPublicKey, with: newMembers, name: group.groupName!, transaction: transaction) } - + public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) { // FIXME: This should be static SNLog("Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).") let transaction = transaction as! YapDatabaseReadWriteTransaction diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index bd5635132..f1952c505 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -42,6 +42,37 @@ public final class MessageSender : NSObject { public static let shared = MessageSender() // FIXME: Remove once requestSenderKey is static + // MARK: Preparation + private static func prep(_ attachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { + #if DEBUG + preconditionFailure() + #endif + return + } + // Anything added to message.attachmentIDs will be uploaded by an UploadAttachmentJob. Any attachment IDs added to tsMessage will + // make it render as an attachment (not what we want in the case of a link preview or quoted attachment). + var streams: [TSAttachmentStream] = [] + attachments.forEach { + let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, + caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) + streams.append(stream) + stream.write($0.dataSource) + stream.save(with: transaction) + } + tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) + var linkPreviewAttachmentID: String? + if let id = tsMessage.linkPreview?.imageAttachmentId, + let stream = TSAttachment.fetch(uniqueId: id, transaction: transaction) as? TSAttachmentStream { + linkPreviewAttachmentID = id + streams.append(stream) + } + message.attachmentIDs = streams.map { $0.uniqueId! } + tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) + if let id = linkPreviewAttachmentID { tsMessage.attachmentIds.remove(id) } + tsMessage.save(with: transaction) + } + // MARK: Convenience public static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise { switch destination { @@ -258,4 +289,25 @@ public final class MessageSender : NSObject { // Return return promise } + + // MARK: Success & Failure Handling + public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 + tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0 + var recipients = [ message.recipient! ] + if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point + let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction as! YapDatabaseReadTransaction), thread.usesSharedSenderKeys { + recipients = thread.groupModel.groupMemberIds + } + recipients.forEach { recipient in + tsMessage.update(withSentRecipient: recipient, wasSentByUD: true, transaction: transaction as! YapDatabaseReadWriteTransaction) + } + OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction as! YapDatabaseReadWriteTransaction) + } + + public static func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } + tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction) + } } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index dcec96784..41dd955a6 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -317,7 +317,7 @@ C32C59C5256DB41F003C73A2 /* TSGroupModel.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB0A255A580700E217F9 /* TSGroupModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; C32C59C6256DB41F003C73A2 /* TSGroupThread.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA79255A57FB00E217F9 /* TSGroupThread.h */; settings = {ATTRIBUTES = (Public, ); }; }; C32C59C7256DB41F003C73A2 /* TSThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB8255A581600E217F9 /* TSThread.m */; }; - C32C5A02256DB658003C73A2 /* MessageSender+Handling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1EF256621180092EF10 /* MessageSender+Handling.swift */; }; + C32C5A02256DB658003C73A2 /* MessageSender+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1EF256621180092EF10 /* MessageSender+Convenience.swift */; }; C32C5A13256DB7A5003C73A2 /* PushNotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */; }; C32C5A24256DB7DB003C73A2 /* LKUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* LKUserDefaults.swift */; }; C32C5A2D256DB849003C73A2 /* LKGroupUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */; }; @@ -579,6 +579,7 @@ C37F54BA255BB2D8002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54CB255BB53F002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54DC255BB84A002AEA92 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; }; + C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38D5E8C2575011E00B6A65C /* MessageSender+ClosedGroups.swift */; }; C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C38EF00E255B61DC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C38EF216255B6D3B007E1867 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF212255B6D3A007E1867 /* Theme.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1388,7 +1389,7 @@ B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = ""; }; B8D8F19225661BF80092EF10 /* Storage+Messaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Messaging.swift"; sourceTree = ""; }; B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OnionRequests.swift"; sourceTree = ""; }; - B8D8F1EF256621180092EF10 /* MessageSender+Handling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "MessageSender+Handling.swift"; path = "../../SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Handling.swift"; sourceTree = ""; }; + B8D8F1EF256621180092EF10 /* MessageSender+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "MessageSender+Convenience.swift"; path = "../../SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift"; sourceTree = ""; }; B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = ""; }; B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = ""; }; B9EB5ABC1884C002007CBB57 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; @@ -1684,6 +1685,7 @@ C379DCFD25673DBC0002D4EB /* TSAttachmentPointer+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSAttachmentPointer+Conversion.swift"; sourceTree = ""; }; C37F53E8255BA9BB002AEA92 /* Environment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = ""; }; C37F5402255BA9ED002AEA92 /* Environment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = ""; }; + C38D5E8C2575011E00B6A65C /* MessageSender+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+ClosedGroups.swift"; sourceTree = ""; }; C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SNProtoEnvelope+Conversion.swift"; sourceTree = ""; }; C38EF212255B6D3A007E1867 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Theme.h; path = SignalUtilitiesKit/UI/Theme.h; sourceTree = SOURCE_ROOT; }; C38EF214255B6D3A007E1867 /* Theme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Theme.m; path = SignalUtilitiesKit/UI/Theme.m; sourceTree = SOURCE_ROOT; }; @@ -2671,8 +2673,9 @@ C32C5995256DAF85003C73A2 /* Typing Indicators */, C3471FA32555439E00297E91 /* Notification+MessageSender.swift */, C300A5F12554B09800555489 /* MessageSender.swift */, + C38D5E8C2575011E00B6A65C /* MessageSender+ClosedGroups.swift */, + B8D8F1EF256621180092EF10 /* MessageSender+Convenience.swift */, C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */, - B8D8F1EF256621180092EF10 /* MessageSender+Handling.swift */, C300A5FB2554B0A000555489 /* MessageReceiver.swift */, C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */, C32C5A87256DBCF9003C73A2 /* MessageReceiver+Handling.swift */, @@ -5223,7 +5226,7 @@ C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */, C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */, C32C5C1B256DC9E0003C73A2 /* GeneralUtilities.swift in Sources */, - C32C5A02256DB658003C73A2 /* MessageSender+Handling.swift in Sources */, + C32C5A02256DB658003C73A2 /* MessageSender+Convenience.swift in Sources */, B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */, C32C5D2E256DD4EA003C73A2 /* TSUnreadIndicatorInteraction.m in Sources */, C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */, @@ -5239,6 +5242,7 @@ C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */, C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */, C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */, + C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */, C32C5B1C256DC19D003C73A2 /* TSQuotedMessage.m in Sources */, C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */, C352A30925574D8500338F3E /* Message+Destination.swift in Sources */, diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift new file mode 100644 index 000000000..ec516191d --- /dev/null +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift @@ -0,0 +1,40 @@ +import SessionProtocolKit +import PromiseKit + +extension MessageSender { + + @objc(send:withAttachments:inThread:usingTransaction:) + public static func send(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + prep(attachments, for: message, using: transaction) + send(message, in: thread, using: transaction) + } + + @objc(send:inThread:usingTransaction:) + public static func send(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + message.threadID = thread.uniqueId! + let destination = Message.Destination.from(thread) + let job = MessageSendJob(message: message, destination: destination) + JobQueue.shared.add(job, using: transaction) + } + + @objc(sendNonDurably:withAttachments:inThread:usingTransaction:) + public static func objc_sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(sendNonDurably(message, with: attachments, in: thread, using: transaction)) + } + + @objc(sendNonDurably:inThread:usingTransaction:) + public static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) + } + + public static func sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + prep(attachments, for: message, using: transaction) + return sendNonDurably(message, in: thread, using: transaction) + } + + public static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + message.threadID = thread.uniqueId! + let destination = Message.Destination.from(thread) + return MessageSender.send(message, to: destination, using: transaction) + } +} From f2572e4c91324d14d6fd56e5749efc3e90c177ac Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 09:03:13 +1100 Subject: [PATCH 083/177] Fix album message ID handling --- Session/Signal/MediaGalleryViewController.swift | 4 ---- SessionMessagingKit/Database/Storage+Messaging.swift | 4 ++++ SessionMessagingKit/Sending & Receiving/MessageSender.swift | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Session/Signal/MediaGalleryViewController.swift b/Session/Signal/MediaGalleryViewController.swift index a8153b0c9..89925344d 100644 --- a/Session/Signal/MediaGalleryViewController.swift +++ b/Session/Signal/MediaGalleryViewController.swift @@ -801,14 +801,10 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel func buildGalleryItem(attachment: TSAttachment, transaction: YapDatabaseReadTransaction) -> MediaGalleryItem? { guard let attachmentStream = attachment as? TSAttachmentStream else { - // Avoid crash in debug mode - // owsFailDebug("gallery doesn't yet support showing undownloaded attachments") return nil } guard let message = attachmentStream.fetchAlbumMessage(with: transaction) else { - // Avoid crash in debug mode - // owsFailDebug("message was unexpectedly nil") return nil } diff --git a/SessionMessagingKit/Database/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift index e725a0c4a..dae3b1265 100644 --- a/SessionMessagingKit/Database/Storage+Messaging.swift +++ b/SessionMessagingKit/Database/Storage+Messaging.swift @@ -41,6 +41,10 @@ extension Storage { let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return nil } let message = TSIncomingMessage.from(message, quotedMessage: quotedMessage, linkPreview: linkPreview, associatedWith: thread) message.save(with: transaction) + message.attachments(with: transaction).forEach { attachment in + attachment.albumMessageId = message.uniqueId! + attachment.save(with: transaction) + } DispatchQueue.main.async { message.touch() } // FIXME: Hack for a thread updating issue return message.uniqueId! } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index f1952c505..6c028235b 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -43,7 +43,7 @@ public final class MessageSender : NSObject { public static let shared = MessageSender() // FIXME: Remove once requestSenderKey is static // MARK: Preparation - private static func prep(_ attachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { + public static func prep(_ attachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { #if DEBUG preconditionFailure() From b49e50ff198fbe4026752dcee36897eae1f3f696 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 09:43:49 +1100 Subject: [PATCH 084/177] Clean up OpenGroupPoller --- .../Pollers/OpenGroupPoller.swift | 130 +++++++++--------- 1 file changed, 63 insertions(+), 67 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index de35a3821..f47d66490 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -6,7 +6,6 @@ public final class OpenGroupPoller : NSObject { private var pollForNewMessagesTimer: Timer? = nil private var pollForDeletedMessagesTimer: Timer? = nil private var pollForModeratorsTimer: Timer? = nil - private var pollForDisplayNamesTimer: Timer? = nil private var hasStarted = false private var isPolling = false @@ -14,8 +13,7 @@ public final class OpenGroupPoller : NSObject { private let pollForNewMessagesInterval: TimeInterval = 4 private let pollForDeletedMessagesInterval: TimeInterval = 60 private let pollForModeratorsInterval: TimeInterval = 10 * 60 - private let pollForDisplayNamesInterval: TimeInterval = 60 - + // MARK: Lifecycle @objc(initForOpenGroup:) public init(for openGroup: OpenGroup) { @@ -30,12 +28,10 @@ public final class OpenGroupPoller : NSObject { strongSelf.pollForNewMessagesTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForNewMessagesInterval, repeats: true) { _ in self?.pollForNewMessages() } strongSelf.pollForDeletedMessagesTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForDeletedMessagesInterval, repeats: true) { _ in self?.pollForDeletedMessages() } strongSelf.pollForModeratorsTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForModeratorsInterval, repeats: true) { _ in self?.pollForModerators() } - strongSelf.pollForDisplayNamesTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForDisplayNamesInterval, repeats: true) { _ in self?.pollForDisplayNames() } // Perform initial updates strongSelf.pollForNewMessages() strongSelf.pollForDeletedMessages() strongSelf.pollForModerators() - strongSelf.pollForDisplayNames() strongSelf.hasStarted = true } } @@ -44,7 +40,6 @@ public final class OpenGroupPoller : NSObject { pollForNewMessagesTimer?.invalidate() pollForDeletedMessagesTimer?.invalidate() pollForModeratorsTimer?.invalidate() - pollForDisplayNamesTimer?.invalidate() hasStarted = false } @@ -70,71 +65,77 @@ public final class OpenGroupPoller : NSObject { let cutoffIndex = senderPublicKey.index(endIndex, offsetBy: -8) return "\(rawDisplayName) (...\(senderPublicKey[cutoffIndex.. Date: Tue, 1 Dec 2020 11:40:37 +1100 Subject: [PATCH 085/177] Fix message duplication bug --- Session/Signal/AddToBlockListViewController.m | 1 - Session/Signal/ConversationView/ConversationViewModel.m | 1 - SessionMessagingKit/Database/Storage+Jobs.swift | 4 +++- SessionMessagingKit/Jobs/JobQueue.swift | 1 + .../Sending & Receiving/Pollers/OpenGroupPoller.swift | 3 ++- SessionUtilitiesKit/ProxiedContentDownloader.swift | 8 ++++---- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Session/Signal/AddToBlockListViewController.m b/Session/Signal/AddToBlockListViewController.m index 8d3315238..74c5cd8db 100644 --- a/Session/Signal/AddToBlockListViewController.m +++ b/Session/Signal/AddToBlockListViewController.m @@ -63,7 +63,6 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertDebug(signalAccount); - ContactsViewHelper *helper = self.contactsViewHelper; return ![SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]; } diff --git a/Session/Signal/ConversationView/ConversationViewModel.m b/Session/Signal/ConversationView/ConversationViewModel.m index cf50fcf4d..3b9557422 100644 --- a/Session/Signal/ConversationView/ConversationViewModel.m +++ b/Session/Signal/ConversationView/ConversationViewModel.m @@ -1073,7 +1073,6 @@ static const int kYapDatabaseRangeMaxLength = 25000; }; NSMutableSet *interactionIds = [NSMutableSet new]; - BOOL canLoadMoreItems = self.messageMapping.canLoadMore; [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { NSMutableArray *interactions = [NSMutableArray new]; diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index 8e9b5ab95..e07321f08 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -82,7 +82,9 @@ extension Storage { } public func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) { - getMessageSendJob(for: messageSendJobID)?.execute() + guard let job = getMessageSendJob(for: messageSendJobID) else { return } + job.delegate = JobQueue.shared + job.execute() } public func isJobCanceled(_ job: Job) -> Bool { diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index e80060aa8..81a8f1859 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -97,6 +97,7 @@ public final class JobQueue : NSObject, JobDelegate { @objc private func retry(_ timer: Timer) { guard let job = timer.userInfo as? Job else { return } SNLog("Retrying \(type(of: job)).") + job.delegate = self job.execute() } } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index f47d66490..c08d71072 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -48,7 +48,8 @@ public final class OpenGroupPoller : NSObject { public func objc_pollForNewMessages() -> AnyPromise { AnyPromise.from(pollForNewMessages()) } - + + @discardableResult public func pollForNewMessages() -> Promise { guard !self.isPolling else { return Promise.value(()) } self.isPolling = true diff --git a/SessionUtilitiesKit/ProxiedContentDownloader.swift b/SessionUtilitiesKit/ProxiedContentDownloader.swift index f01286dd6..644bf49b6 100644 --- a/SessionUtilitiesKit/ProxiedContentDownloader.swift +++ b/SessionUtilitiesKit/ProxiedContentDownloader.swift @@ -299,7 +299,7 @@ public class ProxiedContentAssetRequest: NSObject { try assetData.write(to: NSURL.fileURL(withPath: filePath), options: .atomicWrite) let asset = ProxiedContentAsset(assetDescription: assetDescription, filePath: filePath) return asset - } catch let error as NSError { + } catch { return nil } } @@ -366,7 +366,7 @@ public class ProxiedContentAsset: NSObject { do { let fileManager = FileManager.default try fileManager.removeItem(atPath: filePathCopy) - } catch let error as NSError { + } catch { } } @@ -801,7 +801,7 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio segmentRequestDidFail(assetRequest: assetRequest, assetSegment: assetSegment) return } - if let error = error { + if error != nil { segmentRequestDidFail(assetRequest: assetRequest, assetSegment: assetSegment) return } @@ -848,7 +848,7 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio // Don't back up ProxiedContent downloads. OWSFileSystem.protectFileOrFolder(atPath: dirPath) - } catch let error as NSError { + } catch { downloadFolderPath = tempDirPath } } From a87bad6603ad893b3c5de6828483377292cd8a5a Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 13:39:27 +1100 Subject: [PATCH 086/177] Fix open group link previews --- SessionMessagingKit/Open Groups/OpenGroupAPI.swift | 4 ++-- .../Open Groups/OpenGroupMessage+Conversion.swift | 14 +++++++++++--- .../Open Groups/OpenGroupMessage.swift | 12 ++++-------- .../Pollers/OpenGroupPoller.swift | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 65a175abc..84e4e9fcf 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -86,8 +86,8 @@ public final class OpenGroupAPI : DotNetAPI { } } let quote: OpenGroupMessage.Quote? - if let quoteAsJSON = value["quote"] as? JSON, let quotedMessageTimestamp = quoteAsJSON["id"] as? UInt64, let quoteePublicKey = quoteAsJSON["author"] as? String { - let quotedMessageBody = quoteAsJSON["text"] as? String + if let quoteAsJSON = value["quote"] as? JSON, let quotedMessageTimestamp = quoteAsJSON["id"] as? UInt64, let quoteePublicKey = quoteAsJSON["author"] as? String, + let quotedMessageBody = quoteAsJSON["text"] as? String { let quotedMessageServerID = message["reply_to"] as? UInt64 quote = OpenGroupMessage.Quote(quotedMessageTimestamp: quotedMessageTimestamp, quoteePublicKey: quoteePublicKey, quotedMessageBody: quotedMessageBody, quotedMessageServerID: quotedMessageServerID) diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift index 060be6bc9..ac0d95138 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift @@ -4,6 +4,7 @@ internal extension OpenGroupMessage { static func from(_ message: VisibleMessage, for server: String, using transaction: YapDatabaseReadWriteTransaction) -> OpenGroupMessage? { let storage = Configuration.shared.storage guard let userPublicKey = storage.getUserPublicKey() else { return nil } + var attachmentIDs = message.attachmentIDs // Validation guard message.isValid else { return nil } // Should be valid at this point // Quote @@ -11,7 +12,11 @@ internal extension OpenGroupMessage { if let quote = message.quote { guard quote.isValid else { return nil } let quotedMessageServerID = TSIncomingMessage.find(withAuthorId: quote.publicKey!, timestamp: quote.timestamp!, transaction: transaction)?.openGroupServerMessageID - return OpenGroupMessage.Quote(quotedMessageTimestamp: quote.timestamp!, quoteePublicKey: quote.publicKey!, quotedMessageBody: quote.text, quotedMessageServerID: quotedMessageServerID) + let quotedMessageBody = quote.text ?? String(quote.timestamp!) // The back-end doesn't accept messages without a body so we use this as a workaround + if let quotedAttachmentID = quote.attachmentID, let index = attachmentIDs.firstIndex(of: quotedAttachmentID) { + attachmentIDs.remove(at: index) + } + return OpenGroupMessage.Quote(quotedMessageTimestamp: quote.timestamp!, quoteePublicKey: quote.publicKey!, quotedMessageBody: quotedMessageBody, quotedMessageServerID: quotedMessageServerID) } else { return nil } @@ -25,13 +30,16 @@ internal extension OpenGroupMessage { if let linkPreview = message.linkPreview { guard linkPreview.isValid, let attachmentID = linkPreview.attachmentID, let attachment = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction) else { return nil } + if let index = attachmentIDs.firstIndex(of: attachmentID) { + attachmentIDs.remove(at: index) + } let fileName = attachment.sourceFilename ?? UUID().uuidString let width = attachment.shouldHaveImageSize() ? attachment.imageSize().width : 0 let height = attachment.shouldHaveImageSize() ? attachment.imageSize().height : 0 let openGroupLinkPreview = OpenGroupMessage.Attachment( kind: .linkPreview, server: server, - serverID: 0, + serverID: attachment.serverId, contentType: attachment.contentType, size: UInt(attachment.byteCount), fileName: fileName, @@ -46,7 +54,7 @@ internal extension OpenGroupMessage { result.attachments.append(openGroupLinkPreview) } // Attachments - let attachments: [OpenGroupMessage.Attachment] = message.attachmentIDs.compactMap { attachmentID in + let attachments: [OpenGroupMessage.Attachment] = attachmentIDs.compactMap { attachmentID in guard let attachment = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction) else { return nil } // Should never occur let fileName = attachment.sourceFilename ?? UUID().uuidString let width = attachment.shouldHaveImageSize() ? attachment.imageSize().width : 0 diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift index cbcf22496..1427787a7 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift @@ -34,7 +34,7 @@ public final class OpenGroupMessage : NSObject { public struct Quote { public let quotedMessageTimestamp: UInt64 public let quoteePublicKey: String - public let quotedMessageBody: String? + public let quotedMessageBody: String public let quotedMessageServerID: UInt64? } @@ -93,7 +93,7 @@ public final class OpenGroupMessage : NSObject { } @objc public convenience init(senderPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64, - quotedMessageTimestamp: UInt64, quoteePublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, + quotedMessageTimestamp: UInt64, quoteePublicKey: String?, quotedMessageBody: String, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64, serverTimestamp: UInt64) { let quote: Quote? if quotedMessageTimestamp != 0, let quoteeHexEncodedPublicKey = quoteePublicKey { @@ -137,8 +137,7 @@ public final class OpenGroupMessage : NSObject { internal func toJSON() -> JSON { var value: JSON = [ "timestamp" : timestamp ] if let quote = quote { - var quoteAsJSON: JSON = [ "id" : quote.quotedMessageTimestamp, "author" : quote.quoteePublicKey ] - if let quotedMessageBody = quote.quotedMessageBody { quoteAsJSON["text"] = quotedMessageBody } + let quoteAsJSON: JSON = [ "id" : quote.quotedMessageTimestamp, "author" : quote.quoteePublicKey, "text" : quote.quotedMessageBody ] value["quote"] = quoteAsJSON } if let signature = signature { @@ -185,10 +184,7 @@ public final class OpenGroupMessage : NSObject { private func getValidationData(for signatureVersion: UInt64) -> Data? { var string = "\(body.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines))\(timestamp)" if let quote = quote { - string += "\(quote.quotedMessageTimestamp)\(quote.quoteePublicKey)" - if let quotedMessageBody = quote.quotedMessageBody { - string += "\(quotedMessageBody.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines))" - } + string += "\(quote.quotedMessageTimestamp)\(quote.quoteePublicKey)\(quote.quotedMessageBody.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines))" if let quotedMessageServerID = quote.quotedMessageServerID { string += "\(quotedMessageServerID)" } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index c08d71072..1fbe8c974 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -108,7 +108,7 @@ public final class OpenGroupPoller : NSObject { // Quote if let quote = message.quote { let quoteProto = SNProtoDataMessageQuote.builder(id: quote.quotedMessageTimestamp, author: quote.quoteePublicKey) - if let quotedMessageBody = quote.quotedMessageBody { quoteProto.setText(quotedMessageBody) } + if quote.quotedMessageBody != String(quote.quotedMessageTimestamp) { quoteProto.setText(quote.quotedMessageBody) } dataMessageProto.setQuote(try! quoteProto.build()) } // Profile From c67f5f61a7b0feff791a36e572765ed6c5d653ff Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 14:02:55 +1100 Subject: [PATCH 087/177] Fix loader not disappearing --- SessionMessagingKit/Jobs/AttachmentUploadJob.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index f0f2f37aa..bc2285d23 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -81,6 +81,14 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N SNLog("Attachment uploaded successfully.") delegate?.handleJobSucceeded(self) Configuration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID) + Storage.shared.withAsync({ transaction in + var interaction: TSInteraction? + let transaction = transaction as! YapDatabaseReadWriteTransaction + TSDatabaseSecondaryIndexes.enumerateMessages(withTimestamp: self.message.sentTimestamp!, with: { _, key, _ in + interaction = TSInteraction.fetch(uniqueId: key, transaction: transaction) + }, using: transaction) + interaction?.touch(with: transaction) // To refresh the associated message cell and hide the loader + }, completion: { }) } private func handlePermanentFailure(error: Swift.Error) { From e8661cf4d74225253b4c5d58f4abf3283bff29a9 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 15:44:33 +1100 Subject: [PATCH 088/177] Debug --- .../OpenGroupMessage+Conversion.swift | 8 +++-- .../Sending & Receiving/MessageSender.swift | 32 +++++++++++-------- .../Pollers/OpenGroupPoller.swift | 4 +-- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift index ac0d95138..1c2eac258 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift @@ -11,7 +11,11 @@ internal extension OpenGroupMessage { let quote: OpenGroupMessage.Quote? = { if let quote = message.quote { guard quote.isValid else { return nil } - let quotedMessageServerID = TSIncomingMessage.find(withAuthorId: quote.publicKey!, timestamp: quote.timestamp!, transaction: transaction)?.openGroupServerMessageID + var quotedMessageServerID: UInt64? + TSDatabaseSecondaryIndexes.enumerateMessages(withTimestamp: quote.timestamp!, with: { _, key, _ in + guard let message = TSInteraction.fetch(uniqueId: key, transaction: transaction) as? TSMessage else { return } + quotedMessageServerID = message.openGroupServerMessageID + }, using: transaction) let quotedMessageBody = quote.text ?? String(quote.timestamp!) // The back-end doesn't accept messages without a body so we use this as a workaround if let quotedAttachmentID = quote.attachmentID, let index = attachmentIDs.firstIndex(of: quotedAttachmentID) { attachmentIDs.remove(at: index) @@ -62,7 +66,7 @@ internal extension OpenGroupMessage { return OpenGroupMessage.Attachment( kind: .attachment, server: server, - serverID: 0, + serverID: attachment.serverId, contentType: attachment.contentType, size: UInt(attachment.byteCount), fileName: fileName, diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 6c028235b..2813d5a69 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -43,31 +43,34 @@ public final class MessageSender : NSObject { public static let shared = MessageSender() // FIXME: Remove once requestSenderKey is static // MARK: Preparation - public static func prep(_ attachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { + public static func prep(_ signalAttachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { #if DEBUG preconditionFailure() - #endif + #else return + #endif } - // Anything added to message.attachmentIDs will be uploaded by an UploadAttachmentJob. Any attachment IDs added to tsMessage will - // make it render as an attachment (not what we want in the case of a link preview or quoted attachment). - var streams: [TSAttachmentStream] = [] - attachments.forEach { - let stream = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, + var attachments: [TSAttachmentStream] = [] + signalAttachments.forEach { + let attachment = TSAttachmentStream(contentType: $0.mimeType, byteCount: UInt32($0.dataLength), sourceFilename: $0.sourceFilename, caption: $0.captionText, albumMessageId: tsMessage.uniqueId!) - streams.append(stream) - stream.write($0.dataSource) - stream.save(with: transaction) + attachments.append(attachment) + attachment.write($0.dataSource) + attachment.save(with: transaction) } + // The line below locally generates a thumbnail for the quoted attachment. It just needs to happen at some point during the + // message sending process. tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) var linkPreviewAttachmentID: String? if let id = tsMessage.linkPreview?.imageAttachmentId, - let stream = TSAttachment.fetch(uniqueId: id, transaction: transaction) as? TSAttachmentStream { + let attachment = TSAttachment.fetch(uniqueId: id, transaction: transaction) as? TSAttachmentStream { linkPreviewAttachmentID = id - streams.append(stream) + attachments.append(attachment) } - message.attachmentIDs = streams.map { $0.uniqueId! } + // Anything added to message.attachmentIDs will be uploaded by an UploadAttachmentJob. Any attachment IDs added to tsMessage will + // make it render as an attachment (not what we want in the case of a link preview or quoted attachment). + message.attachmentIDs = attachments.map { $0.uniqueId! } tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) if let id = linkPreviewAttachmentID { tsMessage.attachmentIds.remove(id) } tsMessage.save(with: transaction) @@ -260,9 +263,10 @@ public final class MessageSender : NSObject { guard let message = message as? VisibleMessage else { #if DEBUG preconditionFailure() - #endif + #else seal.reject(Error.invalidMessage) return promise + #endif } guard message.isValid else { seal.reject(Error.invalidMessage); return promise } // Convert the message to an open group message diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 1fbe8c974..32f382e90 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -75,7 +75,7 @@ public final class OpenGroupPoller : NSObject { dataMessageProto.setBody(body) dataMessageProto.setTimestamp(message.timestamp) // Attachments - let attachments: [SNProtoAttachmentPointer] = message.attachments.compactMap { attachment in + let attachmentProtos: [SNProtoAttachmentPointer] = message.attachments.compactMap { attachment in guard attachment.kind == .attachment else { return nil } let attachmentProto = SNProtoAttachmentPointer.builder(id: attachment.serverID) attachmentProto.setContentType(attachment.contentType) @@ -88,7 +88,7 @@ public final class OpenGroupPoller : NSObject { attachmentProto.setUrl(attachment.url) return try! attachmentProto.build() } - dataMessageProto.setAttachments(attachments) + dataMessageProto.setAttachments(attachmentProtos) // Link preview if let linkPreview = message.attachments.first(where: { $0.kind == .linkPreview }) { let linkPreviewProto = SNProtoDataMessagePreview.builder(url: linkPreview.linkPreviewURL!) From 71df0b84f03077d7c39e08754b63108318ab07e3 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 16:25:31 +1100 Subject: [PATCH 089/177] Fix incorrect open group message timestamp --- .../Open Groups/OpenGroupMessage+Conversion.swift | 8 ++------ .../Sending & Receiving/MessageSender.swift | 4 +++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift index 1c2eac258..1c3b0d207 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift @@ -11,16 +11,12 @@ internal extension OpenGroupMessage { let quote: OpenGroupMessage.Quote? = { if let quote = message.quote { guard quote.isValid else { return nil } - var quotedMessageServerID: UInt64? - TSDatabaseSecondaryIndexes.enumerateMessages(withTimestamp: quote.timestamp!, with: { _, key, _ in - guard let message = TSInteraction.fetch(uniqueId: key, transaction: transaction) as? TSMessage else { return } - quotedMessageServerID = message.openGroupServerMessageID - }, using: transaction) let quotedMessageBody = quote.text ?? String(quote.timestamp!) // The back-end doesn't accept messages without a body so we use this as a workaround if let quotedAttachmentID = quote.attachmentID, let index = attachmentIDs.firstIndex(of: quotedAttachmentID) { attachmentIDs.remove(at: index) } - return OpenGroupMessage.Quote(quotedMessageTimestamp: quote.timestamp!, quoteePublicKey: quote.publicKey!, quotedMessageBody: quotedMessageBody, quotedMessageServerID: quotedMessageServerID) + // FIXME: For some reason the server always returns a 500 if quotedMessageServerID is set... + return OpenGroupMessage.Quote(quotedMessageTimestamp: quote.timestamp!, quoteePublicKey: quote.publicKey!, quotedMessageBody: quotedMessageBody, quotedMessageServerID: nil) } else { return nil } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 2813d5a69..4d20bc111 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -246,7 +246,9 @@ public final class MessageSender : NSObject { internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { let (promise, seal) = Promise.pending() let storage = Configuration.shared.storage - message.sentTimestamp = NSDate.millisecondTimestamp() + if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set + message.sentTimestamp = NSDate.millisecondTimestamp() + } message.sender = storage.getUserPublicKey() switch destination { case .contact(_): preconditionFailure() From ccc36c021be070b5e2e4a8c924091d746edc0560 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 17:00:50 +1100 Subject: [PATCH 090/177] Resolve some leftover TODOs --- .../ConversationViewController.m | 49 ++----------------- SessionMessagingKit/To Do/TSAccountManager.h | 1 - SessionMessagingKit/To Do/TSAccountManager.m | 31 ------------ 3 files changed, 5 insertions(+), 76 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 00e61a9ef..0c9327df3 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -1451,20 +1451,7 @@ typedef enum : NSUInteger { - (void)handleFailedDownloadTapForMessage:(TSMessage *)message { - OWSAssert(message); - - // TODO TODO TODO - -// [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { -// [self.attachmentDownloads downloadAttachmentsForMessage:message -// transaction:transaction -// success:^(NSArray *attachmentStreams) { -// OWSLogInfo(@"Successfully redownloaded attachment in thread: %@", message.thread); -// } -// failure:^(NSError *error) { -// OWSLogWarn(@"Failed to redownload message with error: %@", error); -// }]; -// }]; + // Do nothing } - (void)handleUnsentMessageTap:(TSOutgoingMessage *)message @@ -1481,7 +1468,9 @@ typedef enum : NSUInteger { [self remove:message]; }]; [actionSheet addAction:deleteMessageAction]; - + + // TODO TODO TODO + // UIAlertAction *resendMessageAction = [UIAlertAction // actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") // accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_again") @@ -1908,35 +1897,7 @@ typedef enum : NSUInteger { quotedReply:(OWSQuotedReplyModel *)quotedReply failedThumbnailDownloadAttachmentPointer:(TSAttachmentPointer *)attachmentPointer { - OWSAssertIsOnMainThread(); - OWSAssertDebug(viewItem); - OWSAssertDebug(attachmentPointer); - - TSMessage *message = (TSMessage *)viewItem.interaction; - if (![message isKindOfClass:[TSMessage class]]) { - OWSFailDebug(@"message had unexpected class: %@", message.class); - return; - } - - // TODO TODO TODO - -// [self.uiDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { -// [self.attachmentDownloads downloadAttachmentPointer:attachmentPointer -// success:^(NSArray *attachmentStreams) { -// OWSAssertDebug(attachmentStreams.count == 1); -// TSAttachmentStream *attachmentStream = attachmentStreams.firstObject; -// [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) { -// [message setQuotedMessageThumbnailAttachmentStream:attachmentStream]; -// [message saveWithTransaction:postSuccessTransaction]; -// }]; -// } -// failure:^(NSError *error) { -// OWSLogWarn(@"Failed to redownload thumbnail with error: %@", error); -// [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) { -// [message touchWithTransaction:postSuccessTransaction]; -// }]; -// }]; -// }]; + // Do nothing } - (void)didTapConversationItem:(id)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply diff --git a/SessionMessagingKit/To Do/TSAccountManager.h b/SessionMessagingKit/To Do/TSAccountManager.h index d660f5801..fae863d46 100644 --- a/SessionMessagingKit/To Do/TSAccountManager.h +++ b/SessionMessagingKit/To Do/TSAccountManager.h @@ -148,7 +148,6 @@ typedef NS_ENUM(NSUInteger, OWSRegistrationState) { // Re-registration is the process of re-registering _with the same phone number_. // Returns YES on success. -- (BOOL)resetForReregistration; - (nullable NSString *)reregisterationPhoneNumber; - (BOOL)isReregistering; diff --git a/SessionMessagingKit/To Do/TSAccountManager.m b/SessionMessagingKit/To Do/TSAccountManager.m index 43d697fa5..2ee6e4b8c 100644 --- a/SessionMessagingKit/To Do/TSAccountManager.m +++ b/SessionMessagingKit/To Do/TSAccountManager.m @@ -404,37 +404,6 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa [self postRegistrationStateDidChangeNotification]; } -#pragma mark - Re-registration - -- (BOOL)resetForReregistration -{ - @synchronized(self) { - NSString *_Nullable localNumber = self.localNumber; - if (!localNumber) { - return NO; - } - - _isRegistered = NO; - _cachedLocalNumber = nil; - _phoneNumberAwaitingVerification = nil; - _cachedIsDeregistered = nil; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction removeAllObjectsInCollection:TSAccountManager_UserAccountCollection]; - - // TODO TODO TODO -// [[OWSPrimaryStorage sharedManager] resetSessionStore:transaction]; - - [transaction setObject:localNumber - forKey:TSAccountManager_ReregisteringPhoneNumberKey - inCollection:TSAccountManager_UserAccountCollection]; - }]; - - [self postRegistrationStateDidChangeNotification]; - - return YES; - } -} - - (nullable NSString *)reregisterationPhoneNumber { NSString *_Nullable result = [self.dbConnection stringForKey:TSAccountManager_ReregisteringPhoneNumberKey From 000249b7441f791ab084393cab124f30b2dc08c4 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 17:40:18 +1100 Subject: [PATCH 091/177] Debug --- SessionMessagingKit/Configuration.swift | 21 ++++++++++++++++--- .../Utilities/OWSIdentityManager.m | 5 ++--- .../Signal/State/SessionStore.h | 2 ++ .../Database/OWSPrimaryStorage+SessionStore.h | 2 -- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index c4bf93445..cb86619b4 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -1,13 +1,28 @@ import SessionProtocolKit -public struct Configuration { +@objc(SNMessagingKitConfiguration) +public final class Configuration : NSObject { public let storage: SessionMessagingKitStorageProtocol - public let signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore + @objc public let signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore public let identityKeyStore: IdentityKeyStore public let sessionRestorationImplementation: SessionRestorationProtocol public let certificateValidator: SMKCertificateValidator - internal static var shared: Configuration! + @objc public static var shared: Configuration! + + fileprivate init( + storage: SessionMessagingKitStorageProtocol, + signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore, + identityKeyStore: IdentityKeyStore, + sessionRestorationImplementation: SessionRestorationProtocol, + certificateValidator: SMKCertificateValidator + ) { + self.storage = storage + self.signalStorage = signalStorage + self.identityKeyStore = identityKeyStore + self.sessionRestorationImplementation = sessionRestorationImplementation + self.certificateValidator = certificateValidator + } } public enum SNMessagingKit { // Just to make the external API nice diff --git a/SessionMessagingKit/Utilities/OWSIdentityManager.m b/SessionMessagingKit/Utilities/OWSIdentityManager.m index 3158122c3..e99e7c877 100644 --- a/SessionMessagingKit/Utilities/OWSIdentityManager.m +++ b/SessionMessagingKit/Utilities/OWSIdentityManager.m @@ -16,6 +16,7 @@ #import "TSContactThread.h" #import "TSErrorMessage.h" #import "TSGroupThread.h" +#import #import "YapDatabaseConnection+OWS.h" #import "YapDatabaseTransaction+OWS.h" #import @@ -222,9 +223,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa createdAt:[NSDate new] verificationState:verificationState] saveWithTransaction:transaction]; - // TODO TODO TODO - -// [self.primaryStorage archiveAllSessionsForContact:recipientId protocolContext:protocolContext]; + [SNMessagingKitConfiguration.shared.signalStorage archiveAllSessionsForContact:recipientId protocolContext:protocolContext]; [self fireIdentityStateChangeNotification]; diff --git a/SessionProtocolKit/Signal/State/SessionStore.h b/SessionProtocolKit/Signal/State/SessionStore.h index 513cdcb07..ce3a37eea 100644 --- a/SessionProtocolKit/Signal/State/SessionStore.h +++ b/SessionProtocolKit/Signal/State/SessionStore.h @@ -39,6 +39,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)deleteAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext; +- (void)archiveAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext; + @end NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h index 3f60b1a97..40b11fdfb 100644 --- a/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h +++ b/SignalUtilitiesKit/Database/OWSPrimaryStorage+SessionStore.h @@ -9,8 +9,6 @@ NS_ASSUME_NONNULL_BEGIN @interface OWSPrimaryStorage (SessionStore) -- (void)archiveAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext; - #pragma mark - Debug - (void)resetSessionStore:(YapDatabaseReadWriteTransaction *)transaction; From c8dfa377bdaeb84aa8fb376007bbcf0d8bfb1d3b Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 2 Dec 2020 09:51:26 +1100 Subject: [PATCH 092/177] Fix link preview migration issue --- Session/Signal/AppDelegate.m | 4 ++++ SessionMessagingKit/Messages/Signal/TSMessage.m | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 09bc074f7..705965b8f 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -166,6 +166,10 @@ static NSTimeInterval launchStartedAt; [LKAppModeManager configureWithDelegate:self]; + // OWSLinkPreview is now in SessionMessagingKit, so to still be able to deserialize link previews we + // need to tell NSKeyedUnarchiver about the change. + [NSKeyedUnarchiver setClass:OWSLinkPreview.class forClassName:@"SessionServiceKit.OWSLinkPreview"]; + BOOL isLoggingEnabled; #ifdef DEBUG // Specified at Product -> Scheme -> Edit Scheme -> Test -> Arguments -> Environment to avoid things like diff --git a/SessionMessagingKit/Messages/Signal/TSMessage.m b/SessionMessagingKit/Messages/Signal/TSMessage.m index dc9a1f0fe..a986a9f07 100644 --- a/SessionMessagingKit/Messages/Signal/TSMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSMessage.m @@ -79,7 +79,7 @@ const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; [self updateExpiresAt]; _quotedMessage = quotedMessage; _linkPreview = linkPreview; - _openGroupServerMessageID = -1; + _openGroupServerMessageID = 0; return self; } From 75b184c0b90f8f490a11219413136afe55800fc4 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 1 Dec 2020 19:45:42 +1100 Subject: [PATCH 093/177] Use new message receiving pipeline in PN extension --- Session/Signal/AppDelegate.m | 11 - .../MessageReceiver+Handling.swift | 31 +-- .../Sending & Receiving/MessageReceiver.swift | 10 +- ...ionPushNotificationExtension.entitlements} | 0 .../NotificationServiceExtension.swift | 226 ++++++------------ Signal.xcodeproj/project.pbxproj | 8 +- 6 files changed, 98 insertions(+), 188 deletions(-) rename SessionPushNotificationExtension/Meta/{LokiPushNotificationService.entitlements => SessionPushNotificationExtension.entitlements} (100%) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 09bc074f7..421579e60 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -511,17 +511,6 @@ static NSTimeInterval launchStartedAt; [Environment.shared.preferences setHasGeneratedThumbnails:YES]; }]; } - -#ifdef DEBUG - // A bug in orphan cleanup could be disastrous so let's only - // run it in DEBUG builds for a few releases. - // - // TODO: Release to production once we have analytics. - // TODO: Orphan cleanup is somewhat expensive - not least in doing a bunch - // TODO: of disk access. We might want to only run it "once per version" - // TODO: or something like that in production. - [OWSOrphanDataCleaner auditOnLaunchIfNecessary]; -#endif [self.readReceiptManager prepareCachedValues]; diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 1647ff4c7..85f3626b7 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -7,7 +7,7 @@ extension MessageReceiver { return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey) } - internal static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws { + public static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) @@ -135,7 +135,8 @@ extension MessageReceiver { SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() } - private static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws { + @discardableResult + public static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws -> String { let storage = Configuration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction // Parse & persist attachments @@ -188,21 +189,23 @@ extension MessageReceiver { groupPublicKey: message.groupPublicKey, openGroupID: openGroupID, using: transaction) else { throw Error.noThread } message.threadID = threadID // Start attachment downloads if needed - storage.withAsync({ transaction in - attachmentsToDownload.forEach { attachmentID in - let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) - if CurrentAppContext().isMainAppAndActive { // This has to be called from the main thread - JobQueue.shared.add(downloadJob, using: transaction) - } else { - JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) - } + attachmentsToDownload.forEach { attachmentID in + let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) + if CurrentAppContext().isMainAppAndActive { + JobQueue.shared.add(downloadJob, using: transaction) + } else { + JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) } - }, completion: { }) - // Cancel any typing indicators - cancelTypingIndicatorsIfNeeded(for: message.sender!) + } + // Cancel any typing indicators if needed + if CurrentAppContext().isMainAppAndActive { + cancelTypingIndicatorsIfNeeded(for: message.sender!) + } // Notify the user if needed - guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return } + guard CurrentAppContext().isMainAppAndActive, let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), + let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return tsIncomingMessageID } SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction) + return tsIncomingMessageID } private static func handleClosedGroupUpdate(_ message: ClosedGroupUpdate, using transaction: Any) { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index d24b42839..e31b34707 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -1,8 +1,8 @@ import SessionUtilitiesKit -internal enum MessageReceiver { +public enum MessageReceiver { - internal enum Error : LocalizedError { + public enum Error : LocalizedError { case duplicateMessage case invalidMessage case unknownMessage @@ -17,14 +17,14 @@ internal enum MessageReceiver { case noGroupPrivateKey case sharedSecretGenerationFailed - internal var isRetryable: Bool { + public var isRetryable: Bool { switch self { case .duplicateMessage, .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false default: return true } } - internal var errorDescription: String? { + public var errorDescription: String? { switch self { case .duplicateMessage: return "Duplicate message." case .invalidMessage: return "Invalid message." @@ -43,7 +43,7 @@ internal enum MessageReceiver { } } - internal static func parse(_ data: Data, openGroupMessageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { + public static func parse(_ data: Data, openGroupMessageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { let userPublicKey = Configuration.shared.storage.getUserPublicKey() let isOpenGroupMessage = (openGroupMessageServerID != nil) // Parse the envelope diff --git a/SessionPushNotificationExtension/Meta/LokiPushNotificationService.entitlements b/SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements similarity index 100% rename from SessionPushNotificationExtension/Meta/LokiPushNotificationService.entitlements rename to SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements diff --git a/SessionPushNotificationExtension/NotificationServiceExtension.swift b/SessionPushNotificationExtension/NotificationServiceExtension.swift index 509e7adb7..93a561056 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtension.swift +++ b/SessionPushNotificationExtension/NotificationServiceExtension.swift @@ -1,158 +1,75 @@ import UserNotifications +import SessionMessagingKit import SignalUtilitiesKit +// TODO: Group notifications + final class NotificationServiceExtension : UNNotificationServiceExtension { - static let isFromRemoteKey = "remote" - static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId" - private var didPerformSetup = false + private var areVersionMigrationsComplete = false + private var contentHandler: ((UNNotificationContent) -> Void)? + private var notificationContent: UNMutableNotificationContent? - var areVersionMigrationsComplete = false - var contentHandler: ((UNNotificationContent) -> Void)? - var notificationContent: UNMutableNotificationContent? + private static let isFromRemoteKey = "remote" + private static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId" override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler - notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent - + self.notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent + + // Abort if the main app is running var isMainAppActive = false if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") { isMainAppActive = sharedUserDefaults.bool(forKey: "isMainAppActive") } - // If the main app is running, skip the whole process - guard !isMainAppActive else { return self.completeWithFailure(content: notificationContent!) } - - // The code using DispatchQueue.main.async { self.setUpIfNecessary() { Modify the notification content } } will somehow cause a freeze when a second PN comes - - DispatchQueue.main.sync { self.setUpIfNecessary() {} } - + guard !isMainAppActive else { return self.handleFailure(for: notificationContent!) } + + // Perform main setup + DispatchQueue.main.sync { self.setUpIfNecessary() { } } + + // Handle the push notification AppReadiness.runNowOrWhenAppDidBecomeReady { - if let notificationContent = self.notificationContent { - // Modify the notification content here... - let base64EncodedData = notificationContent.userInfo["ENCRYPTED_DATA"] as! String - let data = Data(base64Encoded: base64EncodedData)! - if let envelope = try? MessageWrapper.unwrap(data: data), let data = try? envelope.serializedData() { - // TODO TODO TODO - - /* - decrypter.decryptEnvelope(envelope, - envelopeData: data, - successBlock: { result, transaction in - if let envelope = try? SNProtoEnvelope.parseData(result.envelopeData) { - messageManager.throws_processEnvelope(envelope, plaintextData: result.plaintextData, wasReceivedByUD: wasReceivedByUD, transaction: transaction, serverID: 0) - self.handleDecryptionResult(result: result, notificationContent: notificationContent, transaction: transaction) - } else { - self.completeWithFailure(content: notificationContent) - } - }, - failureBlock: { - self.completeWithFailure(content: notificationContent) - } - ) - */ - } else { - self.completeWithFailure(content: notificationContent) + let notificationContent = self.notificationContent! + guard let base64EncodedData = notificationContent.userInfo["ENCRYPTED_DATA"] as! String?, let data = Data(base64Encoded: base64EncodedData), + let envelope = try? MessageWrapper.unwrap(data: data), let envelopeAsData = try? envelope.serializedData() else { + return self.handleFailure(for: notificationContent) + } + Storage.write { transaction in // Intentionally capture self + do { + let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) + guard let visibleMessage = message as? VisibleMessage else { + return self.handleFailure(for: notificationContent) + } + let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, using: transaction) + guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { + return self.handleFailure(for: notificationContent) + } + let snippet = tsIncomingMessage.previewText(with: transaction).filterForDisplay + let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : tsIncomingMessage.thread.uniqueId!, NotificationServiceExtension.isFromRemoteKey : true ] + let senderPublicKey = message.sender! + let senderDisplayName = OWSProfileManager.shared().profileNameForRecipient(withID: senderPublicKey, avoidWriteTransaction: true) ?? senderPublicKey + notificationContent.userInfo = userInfo + notificationContent.badge = 1 + let notificationsPreference = Environment.shared.preferences!.notificationPreviewType() + switch notificationsPreference { + case .namePreview: + notificationContent.title = senderDisplayName + notificationContent.body = snippet! + case .nameNoPreview: + notificationContent.title = senderDisplayName + notificationContent.body = "New Message" + case .noNameNoPreview: + notificationContent.title = "Session" + notificationContent.body = "New Message" + default: break + } + self.handleSuccess(for: notificationContent) + } catch { + self.handleFailure(for: notificationContent) } } } } - - /* - func handleDecryptionResult(result: OWSMessageDecryptResult, notificationContent: UNMutableNotificationContent, transaction: YapDatabaseReadWriteTransaction) { - let contentProto = try? SNProtoContent.parseData(result.plaintextData!) - var thread: TSThread - var newNotificationBody = "" - let masterPublicKey = OWSPrimaryStorage.shared().getMasterHexEncodedPublicKey(for: result.source, in: transaction) ?? result.source - var displayName = OWSUserProfile.fetch(uniqueId: masterPublicKey, transaction: transaction)?.profileName ?? SSKEnvironment.shared.contactsManager.displayName(forPhoneIdentifier: masterPublicKey) - if let groupID = contentProto?.dataMessage?.group?.id { - thread = TSGroupThread.getOrCreateThread(withGroupId: groupID, groupType: .closedGroup, transaction: transaction) - var groupName = thread.name() - if groupName.count < 1 { - groupName = MessageStrings.newGroupDefaultTitle - } - let senderName = OWSUserProfile.fetch(uniqueId: masterPublicKey, transaction: transaction)?.profileName ?? SSKEnvironment.shared.contactsManager.displayName(forPhoneIdentifier: masterPublicKey) - displayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderName, groupName) - let group: SNProtoGroupContext = contentProto!.dataMessage!.group! - let oldGroupModel = (thread as! TSGroupThread).groupModel - let removedMembers = NSMutableSet(array: oldGroupModel.groupMemberIds) - let newGroupModel = TSGroupModel.init(title: group.name, - memberIds:group.members, - image: oldGroupModel.groupImage, - groupId: group.id, - groupType: oldGroupModel.groupType, - adminIds: group.admins) - removedMembers.minus(Set(newGroupModel.groupMemberIds)) - newGroupModel.removedMembers = removedMembers - switch contentProto?.dataMessage?.group?.type { - case .update: - newNotificationBody = oldGroupModel.getInfoStringAboutUpdate(to: newGroupModel, contactsManager: SSKEnvironment.shared.contactsManager) - break - case .quit: - let nameString = SSKEnvironment.shared.contactsManager.displayName(forPhoneIdentifier: masterPublicKey, transaction: transaction) - newNotificationBody = NSLocalizedString("GROUP_MEMBER_LEFT", comment: nameString) - break - default: - break - } - } else { - thread = TSContactThread.getOrCreateThread(withContactId: result.source, transaction: transaction) - } - let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : thread.uniqueId!, NotificationServiceExtension.isFromRemoteKey : true ] - notificationContent.title = displayName - notificationContent.userInfo = userInfo - notificationContent.badge = 1 - if let attachment = contentProto?.dataMessage?.attachments.last { - newNotificationBody = TSAttachment.emoji(forMimeType: attachment.contentType!) + "Attachment" - if let rawMessageBody = contentProto?.dataMessage?.body, rawMessageBody.count > 0 { - newNotificationBody += ": \(rawMessageBody)" - } - } - if newNotificationBody.count < 1 { - newNotificationBody = contentProto?.dataMessage?.body ?? "You've got a new message" - } - newNotificationBody = handleMentionIfNecessary(rawMessageBody: newNotificationBody, threadID: thread.uniqueId!, transaction: transaction) - - let notificationPreference = Environment.shared.preferences - if let notificationType = notificationPreference?.notificationPreviewType() { - switch notificationType { - case .nameNoPreview: - notificationContent.body = "New Message" - case .noNameNoPreview: - notificationContent.title = "" - notificationContent.body = "New Message" - default: - notificationContent.body = newNotificationBody - } - } else { - notificationContent.body = newNotificationBody - } - - if notificationContent.body.count < 1 { - self.completeWithFailure(content: notificationContent) - } else { - self.contentHandler!(notificationContent) - } - } - */ - - func handleMentionIfNecessary(rawMessageBody: String, threadID: String, transaction: YapDatabaseReadWriteTransaction) -> String { - var string = rawMessageBody - let regex = try! NSRegularExpression(pattern: "@[0-9a-fA-F]*", options: []) - var outerMatch = regex.firstMatch(in: string, options: .withoutAnchoringBounds, range: NSRange(location: 0, length: string.utf16.count)) - while let match = outerMatch { - let publicKey = String((string as NSString).substring(with: match.range).dropFirst()) // Drop the @ - let matchEnd: Int - let displayName: String? = OWSProfileManager.shared().profileNameForRecipient(withID: publicKey, transaction: transaction) - if let displayName = displayName { - string = (string as NSString).replacingCharacters(in: match.range, with: "@\(displayName)") - matchEnd = match.range.location + displayName.utf16.count - } else { - matchEnd = match.range.location + match.range.length - } - outerMatch = regex.firstMatch(in: string, options: .withoutAnchoringBounds, range: NSRange(location: matchEnd, length: string.utf16.count - matchEnd)) - } - return string - } func setUpIfNecessary(completion: @escaping () -> Void) { AssertIsOnMainThread() @@ -193,22 +110,19 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } ) - NotificationCenter.default.addObserver(self, - selector: #selector(storageIsReady), - name: .StorageIsReady, - object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(storageIsReady), name: .StorageIsReady, object: nil) } override func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. - if let contentHandler = contentHandler, let notificationContent = notificationContent { - contentHandler(notificationContent) - } - } - - func wasReceivedByUD(envelope: SNProtoEnvelope) -> Bool { - return (envelope.type == .unidentifiedSender && (!envelope.hasSource || envelope.source!.count < 1)) + let userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] + let notificationContent = self.notificationContent! + notificationContent.userInfo = userInfo + notificationContent.badge = 1 + notificationContent.title = "Session" + notificationContent.body = "New Message" + handleSuccess(for: notificationContent) } @objc @@ -242,14 +156,18 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } func completeSilenty() { - contentHandler?(.init()) + contentHandler!(.init()) } - - func completeWithFailure(content: UNMutableNotificationContent) { - content.body = "You've got a new message" + + func handleSuccess(for content: UNMutableNotificationContent) { + contentHandler!(content) + } + + func handleFailure(for content: UNMutableNotificationContent) { + content.body = "New Message" content.title = "Session" - let userInfo: [String:Any] = [NotificationServiceExtension.isFromRemoteKey : true] + let userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] content.userInfo = userInfo - contentHandler?(content) + contentHandler!(content) } } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 41dd955a6..ed70acbbb 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -1282,7 +1282,7 @@ 7BC01A3B241F40AB00BC7C55 /* SessionPushNotificationExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionPushNotificationExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = ""; }; 7BC01A3F241F40AB00BC7C55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7BDCFC0424206E7300641C39 /* LokiPushNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LokiPushNotificationService.entitlements; sourceTree = ""; }; + 7BDCFC0424206E7300641C39 /* SessionPushNotificationExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionPushNotificationExtension.entitlements; sourceTree = ""; }; 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = ""; }; 7DD180F770F8518B4E8796F2 /* Pods-SessionUtilitiesKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUtilitiesKit.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUtilitiesKit/Pods-SessionUtilitiesKit.app store release.xcconfig"; sourceTree = ""; }; 8981C8F64D94D3C52EB67A2C /* Pods-SignalTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.test.xcconfig"; sourceTree = ""; }; @@ -2687,7 +2687,7 @@ isa = PBXGroup; children = ( 7BC01A3F241F40AB00BC7C55 /* Info.plist */, - 7BDCFC0424206E7300641C39 /* LokiPushNotificationService.entitlements */, + 7BDCFC0424206E7300641C39 /* SessionPushNotificationExtension.entitlements */, ); path = Meta; sourceTree = ""; @@ -5748,7 +5748,7 @@ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = SessionPushNotificationExtension/Meta/LokiPushNotificationService.entitlements; + CODE_SIGN_ENTITLEMENTS = SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; @@ -5818,7 +5818,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = SessionPushNotificationExtension/Meta/LokiPushNotificationService.entitlements; + CODE_SIGN_ENTITLEMENTS = SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; From e21e703581e81a5f945064b4f13446ec1c3757fc Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 2 Dec 2020 10:01:34 +1100 Subject: [PATCH 094/177] Don't retry attachment downloads if the response was invalid --- SessionMessagingKit/Jobs/AttachmentDownloadJob.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 706e2e353..3b56df75e 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -64,6 +64,13 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) }, completion: { }) self.handlePermanentFailure(error: error) + } else if let error = error as? DotNetAPI.Error, case .parsingFailed = error { + // No need to retry if the response is invalid. Most likely this means we (incorrectly) + // got a "Cannot GET ..." error from the file server. + storage.withAsync({ transaction in + storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) + }, completion: { }) + self.handlePermanentFailure(error: error) } else { self.handleFailure(error: error) } From ec4b26e76aac37c377ee6b575cd0553ab4995daf Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 2 Dec 2020 15:36:04 +1100 Subject: [PATCH 095/177] Debug --- .../NotificationServiceExtension.swift | 2 + .../ShareViewController.swift | 2 + Signal.xcodeproj/project.pbxproj | 123 +++++++++++++----- .../Configuration.swift | 4 +- 4 files changed, 94 insertions(+), 37 deletions(-) rename {Session => SignalUtilitiesKit}/Configuration.swift (90%) diff --git a/SessionPushNotificationExtension/NotificationServiceExtension.swift b/SessionPushNotificationExtension/NotificationServiceExtension.swift index 93a561056..ad2e9f25e 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtension.swift +++ b/SessionPushNotificationExtension/NotificationServiceExtension.swift @@ -84,6 +84,8 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { // This should be the first thing we do. SetCurrentAppContext(NotificationServiceExtensionContext()) + SignalUtilitiesKit.Configuration.performMainSetup() + DebugLogger.shared().enableTTYLogging() if _isDebugAssertConfiguration() { DebugLogger.shared().enableFileLogging() diff --git a/SessionShareExtension/ShareViewController.swift b/SessionShareExtension/ShareViewController.swift index eb1e0059c..b7867c297 100644 --- a/SessionShareExtension/ShareViewController.swift +++ b/SessionShareExtension/ShareViewController.swift @@ -43,6 +43,8 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed let appContext = ShareAppExtensionContext(rootViewController: self) SetCurrentAppContext(appContext) + SignalUtilitiesKit.Configuration.performMainSetup() + AppModeManager.configure(delegate: self) DebugLogger.shared().enableTTYLogging() diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index ed70acbbb..433df4769 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -575,13 +575,10 @@ C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F5414255BAFA7002AEA92 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; - C37F54B9255BB2D4002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; - C37F54BA255BB2D8002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54CB255BB53F002AEA92 /* SessionProtocolKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A8622553B41A00C340D1 /* SessionProtocolKit.framework */; }; C37F54DC255BB84A002AEA92 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; }; C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38D5E8C2575011E00B6A65C /* MessageSender+ClosedGroups.swift */; }; C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; - C38EF00E255B61DC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; C38EF216255B6D3B007E1867 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF212255B6D3A007E1867 /* Theme.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF218255B6D3B007E1867 /* Theme.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF214255B6D3A007E1867 /* Theme.m */; }; C38EF228255B6D5D007E1867 /* AttachmentSharing.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF223255B6D5D007E1867 /* AttachmentSharing.m */; }; @@ -884,6 +881,10 @@ C3CA3AC8255CDB2900F4C6D4 /* spanish.txt in Resources */ = {isa = PBXBuildFile; fileRef = C3CA3AC7255CDB2900F4C6D4 /* spanish.txt */; }; C3CA3B2F255CF84E00F4C6D4 /* NullMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3CA3B2E255CF84E00F4C6D4 /* NullMessage.swift */; }; C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; }; + C3D90A1125773888002C9DF5 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C39DD28724F3318C008590FC /* Colors.xcassets */; }; + C3D90A5C25773A25002C9DF5 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; }; + C3D90A7A25773A93002C9DF5 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5EB255C970D007BE2A3 /* Configuration.swift */; }; + C3D90A8325774A68002C9DF5 /* OWSPrimaryStorageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */; }; C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */; }; C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; }; C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -916,7 +917,6 @@ C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; }; C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; }; - C3F0A5EC255C970D007BE2A3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5EB255C970D007BE2A3 /* Configuration.swift */; }; D2179CFC16BB0B3A0006F3AB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */; }; D2179CFE16BB0B480006F3AB /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFD16BB0B480006F3AB /* SystemConfiguration.framework */; }; D221A08E169C9E5E00537ABF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D221A08D169C9E5E00537ABF /* UIKit.framework */; }; @@ -991,6 +991,27 @@ remoteGlobalIDString = C3C2A8612553B41A00C340D1; remoteInfo = SessionProtocolKit; }; + C3D90A5425773A1A002C9DF5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D221A080169C9E5E00537ABF /* Project object */; + proxyType = 1; + remoteGlobalIDString = C331FF1A2558F9D300070591; + remoteInfo = SessionUIKit; + }; + C3D90A5825773A1A002C9DF5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D221A080169C9E5E00537ABF /* Project object */; + proxyType = 1; + remoteGlobalIDString = C33FD9AA255A548A00E217F9; + remoteInfo = SignalUtilitiesKit; + }; + C3D90A7025773A44002C9DF5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D221A080169C9E5E00537ABF /* Project object */; + proxyType = 1; + remoteGlobalIDString = C33FD9AA255A548A00E217F9; + remoteInfo = SignalUtilitiesKit; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -2060,8 +2081,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C37F54B9255BB2D4002AEA92 /* SessionProtocolKit.framework in Frameworks */, - C38EF00E255B61DC007E1867 /* SignalUtilitiesKit.framework in Frameworks */, + C3D90A5C25773A25002C9DF5 /* SessionUtilitiesKit.framework in Frameworks */, C3402FE52559036600EA6424 /* SessionUIKit.framework in Frameworks */, 3681EBBAC430992520DBD9AC /* Pods_SessionShareExtension.framework in Frameworks */, ); @@ -2071,7 +2091,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C37F54BA255BB2D8002AEA92 /* SessionProtocolKit.framework in Frameworks */, C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */, 8E10697B10CBC965F052A4CB /* Pods_SessionPushNotificationExtension.framework in Frameworks */, ); @@ -2952,6 +2971,7 @@ children = ( C33FD9B7255A54A300E217F9 /* Meta */, C3851CE3256250FA0061EEB0 /* To Do */, + C3F0A5EB255C970D007BE2A3 /* Configuration.swift */, C3CA3B11255CF17200F4C6D4 /* Utilities */, C3851CD225624B060061EEB0 /* UI */, C38BBA0D255E321C0041B9A3 /* Messaging */, @@ -3880,7 +3900,6 @@ isa = PBXGroup; children = ( C3F0A58F255C8E3D007BE2A3 /* Meta */, - C3F0A5EB255C970D007BE2A3 /* Configuration.swift */, B8CCF63B239757C10091D419 /* Components */, C32C5D49256DD522003C73A2 /* Database */, C32B405424A961E1001117B5 /* Dependencies */, @@ -4135,6 +4154,8 @@ buildRules = ( ); dependencies = ( + C3D90A5525773A1A002C9DF5 /* PBXTargetDependency */, + C3D90A5925773A1A002C9DF5 /* PBXTargetDependency */, ); name = SessionShareExtension; productName = SignalShareExtension; @@ -4153,6 +4174,7 @@ buildRules = ( ); dependencies = ( + C3D90A7125773A44002C9DF5 /* PBXTargetDependency */, ); name = SessionPushNotificationExtension; productName = LokiPushNotificationService; @@ -4457,6 +4479,7 @@ 347850331FD7494A007B8332 /* fontawesome-webfont.ttf in Resources */, 3478504C1FD7496D007B8332 /* Images.xcassets in Resources */, 347850311FD7494A007B8332 /* dripicons-v2.ttf in Resources */, + C3D90A1125773888002C9DF5 /* Colors.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4717,10 +4740,10 @@ "${BUILT_PRODUCTS_DIR}/ZXingObjC/ZXingObjC.framework", "${BUILT_PRODUCTS_DIR}/Curve25519Kit/Curve25519Kit.framework", "${PODS_ROOT}/GRKOpenSSLFramework/OpenSSL-iOS/bin/openssl.framework", - "${BUILT_PRODUCTS_DIR}/SignalCoreKit/SignalCoreKit.framework", - "${BUILT_PRODUCTS_DIR}/HKDFKit/HKDFKit.framework", "${BUILT_PRODUCTS_DIR}/SAMKeychain/SAMKeychain.framework", + "${BUILT_PRODUCTS_DIR}/SignalCoreKit/SignalCoreKit.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", + "${BUILT_PRODUCTS_DIR}/HKDFKit/HKDFKit.framework", "${BUILT_PRODUCTS_DIR}/libPhoneNumber-iOS/libPhoneNumber_iOS.framework", ); name = "[CP] Embed Pods Frameworks"; @@ -4743,10 +4766,10 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Curve25519Kit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalCoreKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HKDFKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SAMKeychain.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalCoreKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HKDFKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libPhoneNumber_iOS.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -4875,6 +4898,7 @@ 34480B361FD0929200BC14EF /* ShareAppExtensionContext.m in Sources */, 34641E1F2088DA6D00E2EDE5 /* SAEScreenLockViewController.m in Sources */, 3461284B1FD0B94000532771 /* SAELoadViewController.swift in Sources */, + C3D90A8325774A68002C9DF5 /* OWSPrimaryStorageProtocol.swift in Sources */, 347850571FD86544007B8332 /* SAEFailedViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4963,6 +4987,7 @@ C33FDC71255A582000E217F9 /* OWSFailedMessagesJob.m in Sources */, C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */, C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */, + C3D90A7A25773A93002C9DF5 /* Configuration.swift in Sources */, C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */, C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */, C33FDC64255A582000E217F9 /* NSObject+Casting.m in Sources */, @@ -5479,7 +5504,6 @@ 45F32C242057297A00A300D5 /* MessageDetailViewController.swift in Sources */, C396DAEF2518408B00FF6DC5 /* ParsingState.swift in Sources */, 3496955C219B605E00DCFE74 /* ImagePickerController.swift in Sources */, - C3F0A5EC255C970D007BE2A3 /* Configuration.swift in Sources */, 34D1F0841F8678AA0066283D /* ConversationInputToolbar.m in Sources */, 457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */, C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */, @@ -5567,6 +5591,21 @@ target = C3C2A8612553B41A00C340D1 /* SessionProtocolKit */; targetProxy = C3C2A8672553B41A00C340D1 /* PBXContainerItemProxy */; }; + C3D90A5525773A1A002C9DF5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C331FF1A2558F9D300070591 /* SessionUIKit */; + targetProxy = C3D90A5425773A1A002C9DF5 /* PBXContainerItemProxy */; + }; + C3D90A5925773A1A002C9DF5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C33FD9AA255A548A00E217F9 /* SignalUtilitiesKit */; + targetProxy = C3D90A5825773A1A002C9DF5 /* PBXContainerItemProxy */; + }; + C3D90A7125773A44002C9DF5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C33FD9AA255A548A00E217F9 /* SignalUtilitiesKit */; + targetProxy = C3D90A7025773A44002C9DF5 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -5606,6 +5645,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = F9BBF530D71905BA9007675F /* Pods-SessionShareExtension.debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -5623,7 +5663,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 139; + CURRENT_PROJECT_VERSION = 143; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5644,9 +5684,9 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.4; + MARKETING_VERSION = 1.6.5; MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension"; + PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -5662,6 +5702,7 @@ baseConfigurationReference = B27A64C349BBE85670300948 /* Pods-SessionShareExtension.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -5692,7 +5733,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 139; + CURRENT_PROJECT_VERSION = 143; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5718,9 +5759,9 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.4; + MARKETING_VERSION = 1.6.5; MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension"; + PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -5736,6 +5777,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = F121FB43E2A1C1CF7F2AFC23 /* Pods-SessionPushNotificationExtension.debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -5753,7 +5795,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 139; + CURRENT_PROJECT_VERSION = 143; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5772,7 +5814,7 @@ INFOPLIST_FILE = SessionPushNotificationExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.4; + MARKETING_VERSION = 1.6.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; @@ -5790,6 +5832,7 @@ baseConfigurationReference = 6AD66810558DCCC8D6FD14C6 /* Pods-SessionPushNotificationExtension.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -5823,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 139; + CURRENT_PROJECT_VERSION = 143; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5847,7 +5890,7 @@ INFOPLIST_FILE = SessionPushNotificationExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.4; + MARKETING_VERSION = 1.6.5; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; @@ -5903,10 +5946,11 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.SessionUIKit"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -5977,9 +6021,10 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -6037,10 +6082,11 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.SignalUtilitiesKit"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -6119,9 +6165,10 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -6171,10 +6218,11 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.SessionSnodeKit"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -6245,9 +6293,10 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -6306,10 +6355,11 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.SessionUtilitiesKit"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -6389,9 +6439,10 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -6441,10 +6492,11 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.SessionMessagingKit"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -6515,9 +6567,10 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -6571,7 +6624,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -6645,7 +6698,7 @@ SUPPORTS_MACCATALYST = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; diff --git a/Session/Configuration.swift b/SignalUtilitiesKit/Configuration.swift similarity index 90% rename from Session/Configuration.swift rename to SignalUtilitiesKit/Configuration.swift index 930229983..b8a6801df 100644 --- a/Session/Configuration.swift +++ b/SignalUtilitiesKit/Configuration.swift @@ -5,9 +5,9 @@ import SessionSnodeKit extension OWSPrimaryStorage : OWSPrimaryStorageProtocol { } @objc(SNConfiguration) -final class Configuration : NSObject { +public final class Configuration : NSObject { - @objc static func performMainSetup() { + @objc public static func performMainSetup() { SNMessagingKit.configure( storage: Storage.shared, signalStorage: OWSPrimaryStorage.shared(), From d6c115bc2a90591689cb4c6ab22b4cee76689ae2 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 2 Dec 2020 16:25:16 +1100 Subject: [PATCH 096/177] Fix module linking issue --- SessionMessagingKit/Configuration.swift | 8 ++-- .../File Server/FileServerAPI.swift | 2 +- .../Jobs/AttachmentDownloadJob.swift | 2 +- .../Jobs/AttachmentUploadJob.swift | 6 +-- SessionMessagingKit/Jobs/JobQueue.swift | 12 +++--- .../Jobs/MessageReceiveJob.swift | 2 +- SessionMessagingKit/Jobs/MessageSendJob.swift | 2 +- .../Unused/SessionRequest.swift | 4 +- .../Open Groups/OpenGroupAPI.swift | 18 ++++----- .../OpenGroupMessage+Conversion.swift | 2 +- .../Open Groups/OpenGroupMessage.swift | 2 +- .../MessageReceiver+Decryption.swift | 16 ++++---- .../MessageReceiver+Handling.swift | 2 +- .../Sending & Receiving/MessageReceiver.swift | 4 +- .../MessageSender+Encryption.swift | 10 ++--- .../Sending & Receiving/MessageSender.swift | 4 +- SessionMessagingKit/Utilities/DotNetAPI.swift | 6 +-- SessionProtocolKit/Configuration.swift | 8 ++-- .../Shared Sender Keys/SharedSenderKeys.swift | 16 ++++---- .../ShareViewController.swift | 4 +- SessionSnodeKit/Configuration.swift | 8 ++-- SessionSnodeKit/OnionRequestAPI.swift | 16 ++++---- SessionSnodeKit/SnodeAPI.swift | 40 +++++++++---------- SessionUtilitiesKit/Configuration.swift | 10 ++--- SessionUtilitiesKit/OWSMediaUtils.swift | 10 ++--- SessionUtilitiesKit/Storage.swift | 2 +- Signal.xcodeproj/project.pbxproj | 8 ++-- SignalUtilitiesKit/Configuration.swift | 6 +-- .../Migration/OWSDatabaseMigrationRunner.m | 2 +- 29 files changed, 116 insertions(+), 116 deletions(-) diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index cb86619b4..2e195fc19 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -1,14 +1,14 @@ import SessionProtocolKit -@objc(SNMessagingKitConfiguration) -public final class Configuration : NSObject { +@objc +public final class SNMessagingKitConfiguration : NSObject { public let storage: SessionMessagingKitStorageProtocol @objc public let signalStorage: SessionStore & PreKeyStore & SignedPreKeyStore public let identityKeyStore: IdentityKeyStore public let sessionRestorationImplementation: SessionRestorationProtocol public let certificateValidator: SMKCertificateValidator - @objc public static var shared: Configuration! + @objc public static var shared: SNMessagingKitConfiguration! fileprivate init( storage: SessionMessagingKitStorageProtocol, @@ -34,7 +34,7 @@ public enum SNMessagingKit { // Just to make the external API nice sessionRestorationImplementation: SessionRestorationProtocol, certificateValidator: SMKCertificateValidator ) { - Configuration.shared = Configuration( + SNMessagingKitConfiguration.shared = SNMessagingKitConfiguration( storage: storage, signalStorage: signalStorage, identityKeyStore: identityKeyStore, diff --git a/SessionMessagingKit/File Server/FileServerAPI.swift b/SessionMessagingKit/File Server/FileServerAPI.swift index 95ee986a7..b0b8d2a0e 100644 --- a/SessionMessagingKit/File Server/FileServerAPI.swift +++ b/SessionMessagingKit/File Server/FileServerAPI.swift @@ -49,7 +49,7 @@ public final class FileServerAPI : DotNetAPI { SNLog("Couldn't parse profile picture from: \(json).") throw Error.parsingFailed } - Configuration.shared.storage.setLastProfilePictureUploadDate(Date()) + SNMessagingKitConfiguration.shared.storage.setLastProfilePictureUploadDate(Date()) return downloadURL } } diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 3b56df75e..da76a7327 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -52,7 +52,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject guard let pointer = TSAttachmentPointer.fetch(uniqueId: attachmentID) else { return handleFailure(error: Error.noAttachment) } - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage storage.withAsync({ transaction in storage.setAttachmentState(to: .downloading, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) }, completion: { }) diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index bc2285d23..eaaf357a7 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -61,7 +61,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N return handleFailure(error: Error.noAttachment) } guard !stream.isUploaded else { return handleSuccess() } // Should never occur - let openGroup = Configuration.shared.storage.getOpenGroup(for: threadID) + let openGroup = SNMessagingKitConfiguration.shared.storage.getOpenGroup(for: threadID) let server = openGroup?.server ?? FileServerAPI.server // FIXME: A lot of what's currently happening in FileServerAPI should really be happening here FileServerAPI.uploadAttachment(stream, with: attachmentID, to: server).done(on: DispatchQueue.global(qos: .userInitiated)) { // Intentionally capture self @@ -80,7 +80,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N private func handleSuccess() { SNLog("Attachment uploaded successfully.") delegate?.handleJobSucceeded(self) - Configuration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID) + SNMessagingKitConfiguration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID) Storage.shared.withAsync({ transaction in var interaction: TSInteraction? let transaction = transaction as! YapDatabaseReadWriteTransaction @@ -106,7 +106,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N } private func failAssociatedMessageSendJob(with error: Swift.Error) { - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage let messageSendJob = storage.getMessageSendJob(for: messageSendJobID) storage.withAsync({ transaction in // Intentionally capture self MessageSender.handleFailedMessageSend(self.message, with: error, using: transaction) diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 81a8f1859..6b4b8903b 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -16,7 +16,7 @@ public final class JobQueue : NSObject, JobDelegate { @objc public func addWithoutExecuting(_ job: Job, using transaction: Any) { job.id = String(NSDate.millisecondTimestamp()) - Configuration.shared.storage.persist(job, using: transaction) + SNMessagingKitConfiguration.shared.storage.persist(job, using: transaction) job.delegate = self } @@ -29,7 +29,7 @@ public final class JobQueue : NSObject, JobDelegate { hasResumedPendingJobs = true let allJobTypes: [Job.Type] = [ AttachmentDownloadJob.self, AttachmentUploadJob.self, MessageReceiveJob.self, MessageSendJob.self, NotifyPNServerJob.self ] allJobTypes.forEach { type in - let allPendingJobs = Configuration.shared.storage.getAllPendingJobs(of: type) + let allPendingJobs = SNMessagingKitConfiguration.shared.storage.getAllPendingJobs(of: type) allPendingJobs.sorted(by: { $0.id! < $1.id! }).forEach { job in // Retry the oldest jobs first SNLog("Resuming pending job of type: \(type).") job.delegate = self @@ -39,8 +39,8 @@ public final class JobQueue : NSObject, JobDelegate { } public func handleJobSucceeded(_ job: Job) { - Configuration.shared.storage.withAsync({ transaction in - Configuration.shared.storage.markJobAsSucceeded(job, using: transaction) + SNMessagingKitConfiguration.shared.storage.withAsync({ transaction in + SNMessagingKitConfiguration.shared.storage.markJobAsSucceeded(job, using: transaction) }, completion: { // Do nothing }) @@ -48,7 +48,7 @@ public final class JobQueue : NSObject, JobDelegate { public func handleJobFailed(_ job: Job, with error: Error) { job.failureCount += 1 - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage guard !storage.isJobCanceled(job) else { return SNLog("\(type(of: job)) canceled.") } storage.withAsync({ transaction in storage.persist(job, using: transaction) @@ -69,7 +69,7 @@ public final class JobQueue : NSObject, JobDelegate { public func handleJobFailedPermanently(_ job: Job, with error: Error) { job.failureCount += 1 - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage storage.withAsync({ transaction in storage.persist(job, using: transaction) }, completion: { // Intentionally capture self diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 8638cb539..74192a582 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -44,7 +44,7 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC // MARK: Running public func execute() { - Configuration.shared.storage.withAsync({ transaction in // Intentionally capture self + SNMessagingKitConfiguration.shared.storage.withAsync({ transaction in // Intentionally capture self do { let (message, proto) = try MessageReceiver.parse(self.data, openGroupMessageServerID: self.openGroupMessageServerID, using: transaction) try MessageReceiver.handle(message, associatedWithProto: proto, openGroupID: self.openGroupID, using: transaction) diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index d6e297b66..33beadd79 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -61,7 +61,7 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // MARK: Running public func execute() { - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage if let message = message as? VisibleMessage { guard TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) != nil else { return } // The message has been deleted let attachments = message.attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0) } diff --git a/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift b/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift index 0d7c5d05f..e65fb237e 100644 --- a/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift +++ b/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift @@ -34,8 +34,8 @@ public final class SessionRequest : ControlMessage { public override class func fromProto(_ proto: SNProtoContent) -> SessionRequest? { guard proto.nullMessage != nil, let preKeyBundleProto = proto.prekeyBundleMessage else { return nil } var registrationID: UInt32 = 0 - Configuration.shared.storage.with { transaction in - registrationID = Configuration.shared.storage.getOrGenerateRegistrationID(using: transaction) + SNMessagingKitConfiguration.shared.storage.with { transaction in + registrationID = SNMessagingKitConfiguration.shared.storage.getOrGenerateRegistrationID(using: transaction) } guard let preKeyBundle = PreKeyBundle( registrationId: Int32(registrationID), diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 84e4e9fcf..3a509477a 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -20,15 +20,15 @@ public final class OpenGroupAPI : DotNetAPI { // MARK: Open Group Public Key Validation public static func getOpenGroupServerPublicKey(for server: String) -> Promise { - if let publicKey = Configuration.shared.storage.getOpenGroupPublicKey(for: server) { + if let publicKey = SNMessagingKitConfiguration.shared.storage.getOpenGroupPublicKey(for: server) { return Promise.value(publicKey) } else { return FileServerAPI.getPublicKey(for: server).then(on: DispatchQueue.global(qos: .default)) { publicKey -> Promise in let url = URL(string: server)! let request = TSRequest(url: url) return OnionRequestAPI.sendOnionRequest(request, to: server, using: publicKey, isJSONRequired: false).map(on: DispatchQueue.global(qos: .default)) { _ -> String in - Configuration.shared.storage.with { transaction in - Configuration.shared.storage.setOpenGroupPublicKey(for: server, to: publicKey, using: transaction) + SNMessagingKitConfiguration.shared.storage.with { transaction in + SNMessagingKitConfiguration.shared.storage.setOpenGroupPublicKey(for: server, to: publicKey, using: transaction) } return publicKey } @@ -43,7 +43,7 @@ public final class OpenGroupAPI : DotNetAPI { } public static func getMessages(for channel: UInt64, on server: String) -> Promise<[OpenGroupMessage]> { - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage var queryParameters = "include_annotations=1" if let lastMessageServerID = storage.getLastMessageServerID(for: channel, on: server) { queryParameters += "&since_id=\(lastMessageServerID)" @@ -141,7 +141,7 @@ public final class OpenGroupAPI : DotNetAPI { public static func sendMessage(_ message: OpenGroupMessage, to channel: UInt64, on server: String) -> Promise { SNLog("Sending message to open group channel with ID: \(channel) on server: \(server).") - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage guard let userKeyPair = storage.getUserKeyPair() else { return Promise(error: Error.generic) } guard let userDisplayName = storage.getUserDisplayName() else { return Promise(error: Error.generic) } let (promise, seal) = Promise.pending() @@ -181,7 +181,7 @@ public final class OpenGroupAPI : DotNetAPI { // MARK: Deletion public static func getDeletedMessageServerIDs(for channel: UInt64, on server: String) -> Promise<[UInt64]> { SNLog("Getting deleted messages for open group channel with ID: \(channel) on server: \(server).") - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage let queryParameters: String if let lastDeletionServerID = storage.getLastDeletionServerID(for: channel, on: server) { queryParameters = "since_id=\(lastDeletionServerID)" @@ -255,7 +255,7 @@ public final class OpenGroupAPI : DotNetAPI { SNLog("Couldn't parse display names for users: \(publicKeys) from: \(json).") throw Error.parsingFailed } - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage storage.with { transaction in data.forEach { data in guard let user = data["user"] as? JSON, let hexEncodedPublicKey = user["username"] as? String, let rawDisplayName = user["name"] as? String else { return } @@ -345,7 +345,7 @@ public final class OpenGroupAPI : DotNetAPI { SNLog("Couldn't parse info for open group channel with ID: \(channel) on server: \(server) from: \(json).") throw Error.parsingFailed } - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage storage.with { transaction in storage.setUserCount(to: memberCount, forOpenGroupWithID: "\(server).\(channel)", using: transaction) } @@ -473,7 +473,7 @@ internal extension Promise { return recover(on: DispatchQueue.global(qos: .userInitiated)) { error -> Promise in if case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, _) = error, statusCode == 401 || statusCode == 403 { SNLog("Auth token for: \(server) expired; dropping it.") - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage storage.with { transaction in storage.removeAuthToken(for: server, using: transaction) } diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift index 1c3b0d207..f7e9260d3 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage+Conversion.swift @@ -2,7 +2,7 @@ internal extension OpenGroupMessage { static func from(_ message: VisibleMessage, for server: String, using transaction: YapDatabaseReadWriteTransaction) -> OpenGroupMessage? { - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage guard let userPublicKey = storage.getUserPublicKey() else { return nil } var attachmentIDs = message.attachmentIDs // Validation diff --git a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift index 1427787a7..ab8feb3d2 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupMessage.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupMessage.swift @@ -117,7 +117,7 @@ public final class OpenGroupMessage : NSObject { SNLog("Failed to sign open group message.") return nil } - let userKeyPair = Configuration.shared.storage.getUserKeyPair()! + let userKeyPair = SNMessagingKitConfiguration.shared.storage.getUserKeyPair()! guard let signatureData = try? Ed25519.sign(data, with: userKeyPair) else { SNLog("Failed to sign open group message.") return nil diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift index df64a9062..b6d4fd744 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift @@ -5,12 +5,12 @@ import SessionUtilitiesKit internal extension MessageReceiver { static func decryptWithSignalProtocol(envelope: SNProtoEnvelope, using transaction: Any) throws -> (plaintext: Data, senderPublicKey: String) { - let storage = Configuration.shared.signalStorage - let certificateValidator = Configuration.shared.certificateValidator + let storage = SNMessagingKitConfiguration.shared.signalStorage + let certificateValidator = SNMessagingKitConfiguration.shared.certificateValidator guard let data = envelope.content else { throw Error.noData } - guard let userPublicKey = Configuration.shared.storage.getUserPublicKey() else { throw Error.noUserPublicKey } - let cipher = try SMKSecretSessionCipher(sessionResetImplementation: Configuration.shared.sessionRestorationImplementation, - sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: Configuration.shared.identityKeyStore) + guard let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { throw Error.noUserPublicKey } + let cipher = try SMKSecretSessionCipher(sessionResetImplementation: SNMessagingKitConfiguration.shared.sessionRestorationImplementation, + sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: SNMessagingKitConfiguration.shared.identityKeyStore) let result = try cipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator, cipherTextData: data, timestamp: envelope.timestamp, localRecipientId: userPublicKey, localDeviceId: 1, protocolContext: transaction) return (result.paddedPayload, result.senderRecipientId) @@ -18,13 +18,13 @@ internal extension MessageReceiver { static func decryptWithSharedSenderKeys(envelope: SNProtoEnvelope, using transaction: Any) throws -> (plaintext: Data, senderPublicKey: String) { // 1. ) Check preconditions - guard let groupPublicKey = envelope.source, Configuration.shared.storage.isClosedGroup(groupPublicKey) else { + guard let groupPublicKey = envelope.source, SNMessagingKitConfiguration.shared.storage.isClosedGroup(groupPublicKey) else { throw Error.invalidGroupPublicKey } guard let data = envelope.content else { throw Error.noData } - guard let hexEncodedGroupPrivateKey = Configuration.shared.storage.getClosedGroupPrivateKey(for: groupPublicKey) else { + guard let hexEncodedGroupPrivateKey = SNMessagingKitConfiguration.shared.storage.getClosedGroupPrivateKey(for: groupPublicKey) else { throw Error.noGroupPrivateKey } let groupPrivateKey = Data(hex: hexEncodedGroupPrivateKey) @@ -42,7 +42,7 @@ internal extension MessageReceiver { // 4. ) Parse the closed group ciphertext message let closedGroupCiphertextMessage = ClosedGroupCiphertextMessage(_throws_with: closedGroupCiphertextMessageAsData) let senderPublicKey = closedGroupCiphertextMessage.senderPublicKey.toHexString() - guard senderPublicKey != Configuration.shared.storage.getUserPublicKey() else { throw Error.selfSend } + guard senderPublicKey != SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { throw Error.selfSend } // 5. ) Use the info inside the closed group ciphertext message to decrypt the actual message content let plaintext = try SharedSenderKeys.decrypt(closedGroupCiphertextMessage.ivAndCiphertext, for: groupPublicKey, senderPublicKey: senderPublicKey, keyIndex: UInt(closedGroupCiphertextMessage.keyIndex), using: transaction) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 85f3626b7..2ef304d0e 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -137,7 +137,7 @@ extension MessageReceiver { @discardableResult public static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws -> String { - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction // Parse & persist attachments let attachments: [VisibleMessage.Attachment] = proto.dataMessage!.attachments.compactMap { proto in diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index e31b34707..780383c75 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -44,11 +44,11 @@ public enum MessageReceiver { } public static func parse(_ data: Data, openGroupMessageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) { - let userPublicKey = Configuration.shared.storage.getUserPublicKey() + let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() let isOpenGroupMessage = (openGroupMessageServerID != nil) // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) else { throw Error.duplicateMessage } storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction) // Decrypt the contents diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift index c583451e5..f3acba30d 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift @@ -4,17 +4,17 @@ import SessionUtilitiesKit internal extension MessageSender { static func encryptWithSignalProtocol(_ plaintext: Data, associatedWith message: Message, for publicKey: String, using transaction: Any) throws -> Data { - let storage = Configuration.shared.signalStorage - let cipher = try SMKSecretSessionCipher(sessionResetImplementation: Configuration.shared.sessionRestorationImplementation, - sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: Configuration.shared.identityKeyStore) - let certificate = SMKSenderCertificate(senderDeviceId: 1, senderRecipientId: Configuration.shared.storage.getUserPublicKey()!) + let storage = SNMessagingKitConfiguration.shared.signalStorage + let cipher = try SMKSecretSessionCipher(sessionResetImplementation: SNMessagingKitConfiguration.shared.sessionRestorationImplementation, + sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: SNMessagingKitConfiguration.shared.identityKeyStore) + let certificate = SMKSenderCertificate(senderDeviceId: 1, senderRecipientId: SNMessagingKitConfiguration.shared.storage.getUserPublicKey()!) return try cipher.throwswrapped_encryptMessage(recipientPublicKey: publicKey, deviceID: 1, paddedPlaintext: (plaintext as NSData).paddedMessageBody(), senderCertificate: certificate, protocolContext: transaction, useFallbackSessionCipher: true) } static func encryptWithSharedSenderKeys(_ plaintext: Data, for groupPublicKey: String, using transaction: Any) throws -> Data { // 1. ) Encrypt the data with the user's sender key - guard let userPublicKey = Configuration.shared.storage.getUserPublicKey() else { + guard let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { SNLog("Couldn't find user key pair.") throw Error.noUserPublicKey } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 4d20bc111..a2e95f574 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -87,7 +87,7 @@ public final class MessageSender : NSObject { // MARK: One-on-One Chats & Closed Groups internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { let (promise, seal) = Promise.pending() - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() } @@ -245,7 +245,7 @@ public final class MessageSender : NSObject { // MARK: Open Groups internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { let (promise, seal) = Promise.pending() - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() } diff --git a/SessionMessagingKit/Utilities/DotNetAPI.swift b/SessionMessagingKit/Utilities/DotNetAPI.swift index 8199b5b81..47b5c286c 100644 --- a/SessionMessagingKit/Utilities/DotNetAPI.swift +++ b/SessionMessagingKit/Utilities/DotNetAPI.swift @@ -46,7 +46,7 @@ public class DotNetAPI : NSObject { // MARK: Private API private static func requestNewAuthToken(for server: String) -> Promise { SNLog("Requesting auth token for server: \(server).") - guard let userKeyPair = Configuration.shared.storage.getUserKeyPair() else { return Promise(error: Error.generic) } + guard let userKeyPair = SNMessagingKitConfiguration.shared.storage.getUserKeyPair() else { return Promise(error: Error.generic) } let queryParameters = "pubKey=\(userKeyPair.publicKey.toHexString())" let url = URL(string: "\(server)/loki/v1/get_challenge?\(queryParameters)")! let request = TSRequest(url: url) @@ -77,7 +77,7 @@ public class DotNetAPI : NSObject { private static func submitAuthToken(_ token: String, for server: String) -> Promise { SNLog("Submitting auth token for server: \(server).") let url = URL(string: "\(server)/loki/v1/submit_challenge")! - guard let userPublicKey = Configuration.shared.storage.getUserPublicKey() else { return Promise(error: Error.generic) } + guard let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { return Promise(error: Error.generic) } let parameters = [ "pubKey" : userPublicKey, "token" : token ] let request = TSRequest(url: url, method: "POST", parameters: parameters) let serverPublicKeyPromise = (server == FileServerAPI.server) ? Promise.value(FileServerAPI.publicKey) @@ -89,7 +89,7 @@ public class DotNetAPI : NSObject { // MARK: Public API public static func getAuthToken(for server: String) -> Promise { - let storage = Configuration.shared.storage + let storage = SNMessagingKitConfiguration.shared.storage if let token = storage.getAuthToken(for: server) { return Promise.value(token) } else { diff --git a/SessionProtocolKit/Configuration.swift b/SessionProtocolKit/Configuration.swift index 9e1958654..0cd23d5ed 100644 --- a/SessionProtocolKit/Configuration.swift +++ b/SessionProtocolKit/Configuration.swift @@ -1,14 +1,14 @@ -public struct Configuration { +public struct SNProtocolKitConfiguration { public let storage: SessionProtocolKitStorageProtocol public let sharedSenderKeysDelegate: SharedSenderKeysDelegate - internal static var shared: Configuration! + internal static var shared: SNProtocolKitConfiguration! } -public enum SessionProtocolKit { // Just to make the external API nice +public enum SNProtocolKit { // Just to make the external API nice public static func configure(storage: SessionProtocolKitStorageProtocol, sharedSenderKeysDelegate: SharedSenderKeysDelegate) { - Configuration.shared = Configuration(storage: storage, sharedSenderKeysDelegate: sharedSenderKeysDelegate) + SNProtocolKitConfiguration.shared = SNProtocolKitConfiguration(storage: storage, sharedSenderKeysDelegate: sharedSenderKeysDelegate) } } diff --git a/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift b/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift index 653d24930..c22d34ba7 100644 --- a/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift +++ b/SessionProtocolKit/Shared Sender Keys/SharedSenderKeys.swift @@ -30,7 +30,7 @@ public enum SharedSenderKeys { public static func generateRatchet(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) -> ClosedGroupRatchet { let rootChainKey = Data.getSecureRandomData(ofSize: 32)!.toHexString() let ratchet = ClosedGroupRatchet(chainKey: rootChainKey, keyIndex: 0, messageKeys: []) - Configuration.shared.storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: ratchet, in: .current, using: transaction) + SNProtocolKitConfiguration.shared.storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: ratchet, in: .current, using: transaction) return ratchet } @@ -47,14 +47,14 @@ public enum SharedSenderKeys { #if DEBUG assert(!Thread.isMainThread) #endif - guard let ratchet = Configuration.shared.storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, from: .current) else { + guard let ratchet = SNProtocolKitConfiguration.shared.storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, from: .current) else { let error = RatchetingError.loadingFailed(groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey) SNLog("\(error.errorDescription!)") throw error } do { let result = try step(ratchet) - Configuration.shared.storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: result, in: .current, using: transaction) + SNProtocolKitConfiguration.shared.storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: result, in: .current, using: transaction) return result } catch { SNLog("Couldn't step ratchet due to error: \(error).") @@ -68,7 +68,7 @@ public enum SharedSenderKeys { assert(!Thread.isMainThread) #endif let collection: ClosedGroupRatchetCollectionType = (isRetry) ? .old : .current - guard let ratchet = Configuration.shared.storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, from: collection) else { + guard let ratchet = SNProtocolKitConfiguration.shared.storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, from: collection) else { let error = RatchetingError.loadingFailed(groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey) SNLog("\(error.errorDescription!)") throw error @@ -94,7 +94,7 @@ public enum SharedSenderKeys { } } let collection: ClosedGroupRatchetCollectionType = (isRetry) ? .old : .current - Configuration.shared.storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: result, in: collection, using: transaction) + SNProtocolKitConfiguration.shared.storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: result, in: collection, using: transaction) return result } } @@ -106,7 +106,7 @@ public enum SharedSenderKeys { ratchet = try stepRatchetOnce(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) } catch { if case RatchetingError.loadingFailed(_, _) = error { - Configuration.shared.sharedSenderKeysDelegate.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) + SNProtocolKitConfiguration.shared.sharedSenderKeysDelegate.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) } throw error } @@ -127,7 +127,7 @@ public enum SharedSenderKeys { return try decrypt(ivAndCiphertext, for: groupPublicKey, senderPublicKey: senderPublicKey, keyIndex: keyIndex, using: transaction, isRetry: true) } else { if case RatchetingError.loadingFailed(_, _) = error { - Configuration.shared.sharedSenderKeysDelegate.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) + SNProtocolKitConfiguration.shared.sharedSenderKeysDelegate.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) } throw error } @@ -157,7 +157,7 @@ public enum SharedSenderKeys { if !isRetry { return try decrypt(ivAndCiphertext, for: groupPublicKey, senderPublicKey: senderPublicKey, keyIndex: keyIndex, using: transaction, isRetry: true) } else { - Configuration.shared.sharedSenderKeysDelegate.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) + SNProtocolKitConfiguration.shared.sharedSenderKeysDelegate.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction) throw error ?? RatchetingError.generic } } diff --git a/SessionShareExtension/ShareViewController.swift b/SessionShareExtension/ShareViewController.swift index b7867c297..df273462d 100644 --- a/SessionShareExtension/ShareViewController.swift +++ b/SessionShareExtension/ShareViewController.swift @@ -43,8 +43,6 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed let appContext = ShareAppExtensionContext(rootViewController: self) SetCurrentAppContext(appContext) - SignalUtilitiesKit.Configuration.performMainSetup() - AppModeManager.configure(delegate: self) DebugLogger.shared().enableTTYLogging() @@ -251,6 +249,8 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed return } + SignalUtilitiesKit.Configuration.performMainSetup() + Logger.debug("") // TODO: Once "app ready" logic is moved into AppSetup, move this line there. diff --git a/SessionSnodeKit/Configuration.swift b/SessionSnodeKit/Configuration.swift index a56b6c908..b880ae6e1 100644 --- a/SessionSnodeKit/Configuration.swift +++ b/SessionSnodeKit/Configuration.swift @@ -1,13 +1,13 @@ -public struct Configuration { +public struct SNSnodeKitConfiguration { public let storage: SessionSnodeKitStorageProtocol - internal static var shared: Configuration! + internal static var shared: SNSnodeKitConfiguration! } -public enum SessionSnodeKit { // Just to make the external API nice +public enum SNSnodeKit { // Just to make the external API nice public static func configure(storage: SessionSnodeKitStorageProtocol) { - Configuration.shared = Configuration(storage: storage) + SNSnodeKitConfiguration.shared = SNSnodeKitConfiguration(storage: storage) } } diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index 7cf51eb7b..3a3b2e9bc 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -137,9 +137,9 @@ public enum OnionRequestAPI { } }.map2 { paths in OnionRequestAPI.paths = paths + reusablePaths - Configuration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.with { transaction in SNLog("Persisting onion request paths to database.") - Configuration.shared.storage.setOnionRequestPaths(to: paths, using: transaction) + SNSnodeKitConfiguration.shared.storage.setOnionRequestPaths(to: paths, using: transaction) } DispatchQueue.main.async { NotificationCenter.default.post(name: .pathsBuilt, object: nil) @@ -154,7 +154,7 @@ public enum OnionRequestAPI { guard pathSize >= 1 else { preconditionFailure("Can't build path of size zero.") } var paths = OnionRequestAPI.paths if paths.isEmpty { - paths = Configuration.shared.storage.getOnionRequestPaths() + paths = SNSnodeKitConfiguration.shared.storage.getOnionRequestPaths() OnionRequestAPI.paths = paths if !paths.isEmpty { guardSnodes.formUnion([ paths[0][0] ]) @@ -217,9 +217,9 @@ public enum OnionRequestAPI { oldPaths.remove(at: pathIndex) let newPaths = oldPaths + [ path ] paths = newPaths - Configuration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.with { transaction in SNLog("Persisting onion request paths to database.") - Configuration.shared.storage.setOnionRequestPaths(to: newPaths, using: transaction) + SNSnodeKitConfiguration.shared.storage.setOnionRequestPaths(to: newPaths, using: transaction) } } @@ -229,13 +229,13 @@ public enum OnionRequestAPI { guard let pathIndex = paths.firstIndex(of: path) else { return } paths.remove(at: pathIndex) OnionRequestAPI.paths = paths - Configuration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.with { transaction in if !paths.isEmpty { SNLog("Persisting onion request paths to database.") - Configuration.shared.storage.setOnionRequestPaths(to: paths, using: transaction) + SNSnodeKitConfiguration.shared.storage.setOnionRequestPaths(to: paths, using: transaction) } else { SNLog("Clearing onion request paths.") - Configuration.shared.storage.setOnionRequestPaths(to: [], using: transaction) + SNSnodeKitConfiguration.shared.storage.setOnionRequestPaths(to: [], using: transaction) } } } diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index 9f10d55fe..c40f4728c 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -61,7 +61,7 @@ public final class SnodeAPI : NSObject { internal static func getRandomSnode() -> Promise { if snodePool.count < minimumSnodePoolCount { - snodePool = Configuration.shared.storage.getSnodePool() + snodePool = SNSnodeKitConfiguration.shared.storage.getSnodePool() } if snodePool.count < minimumSnodePoolCount { let target = seedNodePool.randomElement()! @@ -97,9 +97,9 @@ public final class SnodeAPI : NSObject { } }.done2 { snode in seal.fulfill(snode) - Configuration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.with { transaction in SNLog("Persisting snode pool to database.") - Configuration.shared.storage.setSnodePool(to: SnodeAPI.snodePool, using: transaction) + SNSnodeKitConfiguration.shared.storage.setSnodePool(to: SnodeAPI.snodePool, using: transaction) } }.catch2 { error in SNLog("Failed to contact seed node at: \(target).") @@ -118,16 +118,16 @@ public final class SnodeAPI : NSObject { var snodePool = SnodeAPI.snodePool snodePool.remove(snode) SnodeAPI.snodePool = snodePool - Configuration.shared.storage.with { transaction in - Configuration.shared.storage.setSnodePool(to: snodePool, using: transaction) + SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.setSnodePool(to: snodePool, using: transaction) } } // MARK: Public API @objc public static func clearSnodePool() { snodePool.removeAll() - Configuration.shared.storage.with { transaction in - Configuration.shared.storage.setSnodePool(to: [], using: transaction) + SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.setSnodePool(to: [], using: transaction) } } @@ -136,8 +136,8 @@ public final class SnodeAPI : NSObject { if var swarm = swarm, let index = swarm.firstIndex(of: snode) { swarm.remove(at: index) SnodeAPI.swarmCache[publicKey] = swarm - Configuration.shared.storage.with { transaction in - Configuration.shared.storage.setSwarm(to: swarm, for: publicKey, using: transaction) + SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.setSwarm(to: swarm, for: publicKey, using: transaction) } } } @@ -149,12 +149,12 @@ public final class SnodeAPI : NSObject { public static func getSwarm(for publicKey: String, isForcedReload: Bool = false) -> Promise> { if swarmCache[publicKey] == nil { - swarmCache[publicKey] = Configuration.shared.storage.getSwarm(for: publicKey) + swarmCache[publicKey] = SNSnodeKitConfiguration.shared.storage.getSwarm(for: publicKey) } if let cachedSwarm = swarmCache[publicKey], cachedSwarm.count >= minimumSwarmSnodeCount && !isForcedReload { return Promise> { $0.fulfill(cachedSwarm) } } else { - SNLog("Getting swarm for: \((publicKey == Configuration.shared.storage.getUserPublicKey()) ? "self" : publicKey).") + SNLog("Getting swarm for: \((publicKey == SNSnodeKitConfiguration.shared.storage.getUserPublicKey()) ? "self" : publicKey).") let parameters: [String:Any] = [ "pubKey" : publicKey ] return getRandomSnode().then2 { snode in attempt(maxRetryCount: 4, recoveringOn: Threading.workQueue) { @@ -163,8 +163,8 @@ public final class SnodeAPI : NSObject { }.map2 { rawSnodes in let swarm = parseSnodes(from: rawSnodes) swarmCache[publicKey] = swarm - Configuration.shared.storage.with { transaction in - Configuration.shared.storage.setSwarm(to: swarm, for: publicKey, using: transaction) + SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.setSwarm(to: swarm, for: publicKey, using: transaction) } return swarm } @@ -172,7 +172,7 @@ public final class SnodeAPI : NSObject { } public static func getRawMessages(from snode: Snode, associatedWith publicKey: String) -> RawResponsePromise { - let storage = Configuration.shared.storage + let storage = SNSnodeKitConfiguration.shared.storage storage.with { transaction in storage.pruneLastMessageHashInfoIfExpired(for: snode, associatedWith: publicKey, using: transaction) } @@ -183,7 +183,7 @@ public final class SnodeAPI : NSObject { public static func getMessages(for publicKey: String) -> Promise> { let (promise, seal) = Promise>.pending() - let storage = Configuration.shared.storage + let storage = SNSnodeKitConfiguration.shared.storage Threading.workQueue.async { attempt(maxRetryCount: maxRetryCount, recoveringOn: Threading.workQueue) { getTargetSnodes(for: publicKey).mapValues2 { targetSnode in @@ -253,8 +253,8 @@ public final class SnodeAPI : NSObject { private static func updateLastMessageHashValueIfPossible(for snode: Snode, associatedWith publicKey: String, from rawMessages: [JSON]) { if let lastMessage = rawMessages.last, let lastHash = lastMessage["hash"] as? String, let expirationDate = lastMessage["expiration"] as? UInt64 { - Configuration.shared.storage.with { transaction in - Configuration.shared.storage.setLastMessageHashInfo(for: snode, associatedWith: publicKey, + SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.setLastMessageHashInfo(for: snode, associatedWith: publicKey, to: [ "hash" : lastHash, "expirationDate" : NSNumber(value: expirationDate) ], using: transaction) } } else if (!rawMessages.isEmpty) { @@ -263,7 +263,7 @@ public final class SnodeAPI : NSObject { } private static func removeDuplicates(from rawMessages: [JSON], associatedWith publicKey: String) -> [JSON] { - var receivedMessages = Configuration.shared.storage.getReceivedMessages(for: publicKey) + var receivedMessages = SNSnodeKitConfiguration.shared.storage.getReceivedMessages(for: publicKey) return rawMessages.filter { rawMessage in guard let hash = rawMessage["hash"] as? String else { SNLog("Missing hash value for message: \(rawMessage).") @@ -271,8 +271,8 @@ public final class SnodeAPI : NSObject { } let isDuplicate = receivedMessages.contains(hash) receivedMessages.insert(hash) - Configuration.shared.storage.with { transaction in - Configuration.shared.storage.setReceivedMessages(to: receivedMessages, for: publicKey, using: transaction) + SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.setReceivedMessages(to: receivedMessages, for: publicKey, using: transaction) } return !isDuplicate } diff --git a/SessionUtilitiesKit/Configuration.swift b/SessionUtilitiesKit/Configuration.swift index 22c85f3a3..ca72ad9df 100644 --- a/SessionUtilitiesKit/Configuration.swift +++ b/SessionUtilitiesKit/Configuration.swift @@ -1,10 +1,10 @@ -@objc(SNUtilitiesKitConfiguration) -public final class Configuration : NSObject { +@objc +public final class SNUtilitiesKitConfiguration : NSObject { @objc public let owsPrimaryStorage: OWSPrimaryStorageProtocol public let maxFileSize: UInt - @objc public static var shared: Configuration! + @objc public static var shared: SNUtilitiesKitConfiguration! fileprivate init(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) { self.owsPrimaryStorage = owsPrimaryStorage @@ -12,9 +12,9 @@ public final class Configuration : NSObject { } } -public enum SessionUtilitiesKit { // Just to make the external API nice +public enum SNUtilitiesKit { // Just to make the external API nice public static func configure(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) { - Configuration.shared = Configuration(owsPrimaryStorage: owsPrimaryStorage, maxFileSize: maxFileSize) + SNUtilitiesKitConfiguration.shared = SNUtilitiesKitConfiguration(owsPrimaryStorage: owsPrimaryStorage, maxFileSize: maxFileSize) } } diff --git a/SessionUtilitiesKit/OWSMediaUtils.swift b/SessionUtilitiesKit/OWSMediaUtils.swift index 59e064cee..fbab78183 100644 --- a/SessionUtilitiesKit/OWSMediaUtils.swift +++ b/SessionUtilitiesKit/OWSMediaUtils.swift @@ -111,15 +111,15 @@ public enum OWSMediaError: Error { * https://github.com/signalapp/Signal-Android/blob/master/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java */ @objc - public static var kMaxFileSizeAnimatedImage: UInt { Configuration.shared.maxFileSize } + public static var kMaxFileSizeAnimatedImage: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize } @objc - public static var kMaxFileSizeImage: UInt { Configuration.shared.maxFileSize } + public static var kMaxFileSizeImage: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize } @objc - public static var kMaxFileSizeVideo: UInt { Configuration.shared.maxFileSize } + public static var kMaxFileSizeVideo: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize } @objc - public static var kMaxFileSizeAudio: UInt { Configuration.shared.maxFileSize } + public static var kMaxFileSizeAudio: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize } @objc - public static var kMaxFileSizeGeneric: UInt { Configuration.shared.maxFileSize } + public static var kMaxFileSizeGeneric: UInt { SNUtilitiesKitConfiguration.shared.maxFileSize } @objc public static let kMaxVideoDimensions: CGFloat = 3 * 1024 diff --git a/SessionUtilitiesKit/Storage.swift b/SessionUtilitiesKit/Storage.swift index b294bafdf..a2e2dcbc5 100644 --- a/SessionUtilitiesKit/Storage.swift +++ b/SessionUtilitiesKit/Storage.swift @@ -10,7 +10,7 @@ import YapDatabase public final class Storage : NSObject { public static let serialQueue = DispatchQueue(label: "Storage.serialQueue", qos: .userInitiated) - private static var owsStorage: OWSPrimaryStorageProtocol { Configuration.shared.owsPrimaryStorage } + private static var owsStorage: OWSPrimaryStorageProtocol { SNUtilitiesKitConfiguration.shared.owsPrimaryStorage } @objc public static let shared = Storage() diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 433df4769..1fc8e2184 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4740,10 +4740,10 @@ "${BUILT_PRODUCTS_DIR}/ZXingObjC/ZXingObjC.framework", "${BUILT_PRODUCTS_DIR}/Curve25519Kit/Curve25519Kit.framework", "${PODS_ROOT}/GRKOpenSSLFramework/OpenSSL-iOS/bin/openssl.framework", - "${BUILT_PRODUCTS_DIR}/SAMKeychain/SAMKeychain.framework", "${BUILT_PRODUCTS_DIR}/SignalCoreKit/SignalCoreKit.framework", - "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/HKDFKit/HKDFKit.framework", + "${BUILT_PRODUCTS_DIR}/SAMKeychain/SAMKeychain.framework", + "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/libPhoneNumber-iOS/libPhoneNumber_iOS.framework", ); name = "[CP] Embed Pods Frameworks"; @@ -4766,10 +4766,10 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Curve25519Kit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SAMKeychain.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalCoreKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HKDFKit.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SAMKeychain.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libPhoneNumber_iOS.framework", ); runOnlyForDeploymentPostprocessing = 0; diff --git a/SignalUtilitiesKit/Configuration.swift b/SignalUtilitiesKit/Configuration.swift index b8a6801df..e45b98e87 100644 --- a/SignalUtilitiesKit/Configuration.swift +++ b/SignalUtilitiesKit/Configuration.swift @@ -15,8 +15,8 @@ public final class Configuration : NSObject { sessionRestorationImplementation: SessionRestorationImplementation(), certificateValidator: SMKCertificateDefaultValidator(trustRoot: OWSUDManagerImpl.trustRoot()) ) - SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: MessageSender.shared) - SessionSnodeKit.configure(storage: Storage.shared) - SessionUtilitiesKit.configure(owsPrimaryStorage: OWSPrimaryStorage.shared(), maxFileSize: UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier)) + SNProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: MessageSender.shared) + SNSnodeKit.configure(storage: Storage.shared) + SNUtilitiesKit.configure(owsPrimaryStorage: OWSPrimaryStorage.shared(), maxFileSize: UInt(Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier)) } } diff --git a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m index bdc905703..14a981e03 100644 --- a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m +++ b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m @@ -54,7 +54,7 @@ NS_ASSUME_NONNULL_BEGIN [knownMigrationIds addObject:migration.uniqueId]; } - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [OWSPrimaryStorage.sharedManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { NSArray *savedMigrationIds = [transaction allKeysInCollection:OWSDatabaseMigration.collection]; NSMutableSet *unknownMigrationIds = [NSMutableSet new]; From 7f8cc2f57ba08ad62352001b62aff95a44e987a5 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 2 Dec 2020 16:46:12 +1100 Subject: [PATCH 097/177] Fix PN extension setup --- .../NotificationServiceExtension.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SessionPushNotificationExtension/NotificationServiceExtension.swift b/SessionPushNotificationExtension/NotificationServiceExtension.swift index ad2e9f25e..eed427f2b 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtension.swift +++ b/SessionPushNotificationExtension/NotificationServiceExtension.swift @@ -84,8 +84,6 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { // This should be the first thing we do. SetCurrentAppContext(NotificationServiceExtensionContext()) - SignalUtilitiesKit.Configuration.performMainSetup() - DebugLogger.shared().enableTTYLogging() if _isDebugAssertConfiguration() { DebugLogger.shared().enableFileLogging() @@ -153,6 +151,8 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { // App isn't ready until storage is ready AND all version migrations are complete. guard OWSStorage.isStorageReady() && areVersionMigrationsComplete else { return } + SignalUtilitiesKit.Configuration.performMainSetup() + // Note that this does much more than set a flag; it will also run all deferred blocks. AppReadiness.setAppIsReady() } From f0cbdb8cda72d368f6646d52228602601f393812 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 10:12:29 +1100 Subject: [PATCH 098/177] Fix share extension --- .../MessageReceiver+Handling.swift | 10 +++-- .../Sending & Receiving/MessageSender.swift | 45 +++++++++---------- .../NotificationServiceExtension.swift | 6 +-- .../MessageSender+Convenience.swift | 19 +++++++- .../UI/SharingThreadPickerViewController.m | 15 +------ 5 files changed, 49 insertions(+), 46 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 2ef304d0e..31e093258 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -139,6 +139,10 @@ extension MessageReceiver { public static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws -> String { let storage = SNMessagingKitConfiguration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction + var isMainAppAndActive = false + if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") { + isMainAppAndActive = sharedUserDefaults.bool(forKey: "isMainAppActive") + } // Parse & persist attachments let attachments: [VisibleMessage.Attachment] = proto.dataMessage!.attachments.compactMap { proto in guard let attachment = VisibleMessage.Attachment.fromProto(proto) else { return nil } @@ -191,18 +195,18 @@ extension MessageReceiver { // Start attachment downloads if needed attachmentsToDownload.forEach { attachmentID in let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID) - if CurrentAppContext().isMainAppAndActive { + if isMainAppAndActive { JobQueue.shared.add(downloadJob, using: transaction) } else { JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction) } } // Cancel any typing indicators if needed - if CurrentAppContext().isMainAppAndActive { + if isMainAppAndActive { cancelTypingIndicatorsIfNeeded(for: message.sender!) } // Notify the user if needed - guard CurrentAppContext().isMainAppAndActive, let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), + guard isMainAppAndActive, let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return tsIncomingMessageID } SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction) return tsIncomingMessageID diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index a2e95f574..b1d2b18d4 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -114,8 +114,9 @@ public final class MessageSender : NSObject { guard !isSelfSend else { storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) - }, completion: { }) - seal.fulfill(()) + }, completion: { + seal.fulfill(()) + }) return promise } // Attach the user's profile if needed @@ -211,7 +212,18 @@ public final class MessageSender : NSObject { let _ = $0.done(on: DispatchQueue.global(qos: .userInitiated)) { _ in guard !isSuccess else { return } // Succeed as soon as the first promise succeeds isSuccess = true - seal.fulfill(()) + if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { + NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) + } + storage.withAsync({ transaction in + MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) + if message is VisibleMessage { + let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) + JobQueue.shared.add(notifyPNServerJob, using: transaction) + } + }, completion: { + seal.fulfill(()) + }) } $0.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in errorCount += 1 @@ -223,21 +235,6 @@ public final class MessageSender : NSObject { SNLog("Couldn't send message due to error: \(error).") seal.reject(error) } - // Handle completion - let _ = promise.done(on: DispatchQueue.main) { - storage.withAsync({ transaction in - MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) - }, completion: { }) - if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { - NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) - } - if message is VisibleMessage { - let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) - storage.withAsync({ transaction in - JobQueue.shared.add(notifyPNServerJob, using: transaction) - }, completion: { }) - } - } // Return return promise } @@ -282,15 +279,13 @@ public final class MessageSender : NSObject { // Send the result OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = openGroupMessage.serverID - seal.fulfill(()) - }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in - seal.reject(error) - } - // Handle completion - let _ = promise.done(on: DispatchQueue.global(qos: .userInitiated)) { storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) - }, completion: { }) + }, completion: { + seal.fulfill(()) + }) + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in + seal.reject(error) } // Return return promise diff --git a/SessionPushNotificationExtension/NotificationServiceExtension.swift b/SessionPushNotificationExtension/NotificationServiceExtension.swift index eed427f2b..335df69e1 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtension.swift +++ b/SessionPushNotificationExtension/NotificationServiceExtension.swift @@ -18,11 +18,11 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { self.notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent // Abort if the main app is running - var isMainAppActive = false + var isMainAppAndActive = false if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") { - isMainAppActive = sharedUserDefaults.bool(forKey: "isMainAppActive") + isMainAppAndActive = sharedUserDefaults.bool(forKey: "isMainAppActive") } - guard !isMainAppActive else { return self.handleFailure(for: notificationContent!) } + guard !isMainAppAndActive else { return self.handleFailure(for: notificationContent!) } // Perform main setup DispatchQueue.main.sync { self.setUpIfNecessary() { } } diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift index ec516191d..fb79c5f34 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift @@ -29,7 +29,24 @@ extension MessageSender { public static func sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { prep(attachments, for: message, using: transaction) - return sendNonDurably(message, in: thread, using: transaction) + let attachments = message.attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } + let attachmentsToUpload = attachments.filter { !$0.isUploaded } + let attachmentUploadPromises: [Promise] = attachmentsToUpload.map { stream in + let openGroup = SNMessagingKitConfiguration.shared.storage.getOpenGroup(for: thread.uniqueId!) + let server = openGroup?.server ?? FileServerAPI.server + // FIXME: This is largely a duplication of the code in AttachmentUploadJob + let maxRetryCount: UInt = (openGroup != nil) ? 24 : 8 + return attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global(qos: .userInitiated)) { + FileServerAPI.uploadAttachment(stream, with: stream.uniqueId!, to: server) + } + } + return when(resolved: attachmentUploadPromises).then(on: DispatchQueue.global(qos: .userInitiated)) { results -> Promise in + let errors = results.compactMap { result -> Swift.Error? in + if case .rejected(let error) = result { return error } else { return nil } + } + if let error = errors.first { return Promise(error: error) } + return sendNonDurably(message, in: thread, using: transaction) + } } public static func sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { diff --git a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index 0789020a7..a30c44d9c 100644 --- a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -26,7 +26,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); @property (nonatomic, readonly) OWSMessageSender *messageSender; @property (nonatomic) TSThread *thread; @property (nonatomic, readonly, weak) id shareViewDelegate; -@property (nonatomic, readonly) UIProgressView *progressView; @property (atomic, nullable) TSOutgoingMessage *outgoingMessage; @end @@ -66,7 +65,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); { [super loadView]; - _progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; self.title = NSLocalizedString(@"SHARE_EXTENSION_VIEW_TITLE", @"Title for the 'share extension' view."); } @@ -286,8 +284,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); - (void)tryToSendMessageWithBlock:(SendMessageBlock)sendMessageBlock fromViewController:(UIViewController *)fromViewController { - // Reset progress in case we're retrying - self.progressView.progress = 0; NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title"); UIAlertController *progressAlert = [UIAlertController alertControllerWithTitle:progressTitle @@ -301,14 +297,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); }]; [progressAlert addAction:progressCancelAction]; - - // We add a progress subview to an AlertController, which is a total hack. - // ...but it looks good, and given how short a progress view is and how - // little the alert controller changes, I'm not super worried about it. - [progressAlert.view addSubview:self.progressView]; - [self.progressView autoPinWidthToSuperviewWithMargin:24]; - [self.progressView autoAlignAxis:ALAxisHorizontal toSameAxisOfView:progressAlert.view withOffset:4]; - SendCompletionBlock sendCompletion = ^(NSError *_Nullable error, TSOutgoingMessage *message) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -476,7 +464,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); { OWSLogDebug(@"upload progress."); OWSAssertIsOnMainThread(); - OWSAssertDebug(self.progressView); if (!self.outgoingMessage) { OWSLogDebug(@"Ignoring upload progress until there is an outgoing message."); @@ -496,7 +483,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); if ([attachmentRecordId isEqual:attachmentID]) { if (!isnan(progress)) { - [self.progressView setProgress:progress animated:YES]; + // This is where we'd set progress if we could } else { OWSFailDebug(@"Invalid attachment progress."); } From 7a8dbe1bf98d258f8ba94a3bde4fb983fcd70372 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 10:39:53 +1100 Subject: [PATCH 099/177] Tighten up error handling a bit more --- .../Sending & Receiving/MessageSender.swift | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index b1d2b18d4..8710f57c8 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -88,10 +88,12 @@ public final class MessageSender : NSObject { internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { let (promise, seal) = Promise.pending() let storage = SNMessagingKitConfiguration.shared.storage + let transaction = transaction as! YapDatabaseReadWriteTransaction + let userPublicKey = storage.getUserPublicKey() + // Set the timestamp, sender and recipient if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() } - let userPublicKey = storage.getUserPublicKey() message.sender = userPublicKey switch destination { case .contact(let publicKey): message.recipient = publicKey @@ -99,17 +101,18 @@ public final class MessageSender : NSObject { case .openGroup(_, _): preconditionFailure() } let isSelfSend = (message.recipient == userPublicKey) - // Set the failure handler (for precondition failure handling) - let _ = promise.catch(on: DispatchQueue.main) { error in - storage.withAsync({ transaction in - MessageSender.handleFailedMessageSend(message, with: error, using: transaction) - }, completion: { }) + // Set the failure handler (need it here already for precondition failure handling) + func handleFailure(with error: Swift.Error, using transaction: YapDatabaseReadWriteTransaction) { + MessageSender.handleFailedMessageSend(message, with: error, using: transaction) if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) } + transaction.addCompletionQueue(DispatchQueue.main) { + seal.reject(error) + } } // Validate the message - guard message.isValid else { seal.reject(Error.invalidMessage); return promise } + guard message.isValid else { handleFailure(with: Error.invalidMessage, using: transaction); return promise } // Stop here if this is a self-send guard !isSelfSend else { storage.withAsync({ transaction in @@ -131,18 +134,18 @@ public final class MessageSender : NSObject { // Convert it to protobuf let protoOrNil: SNProtoContent? if let message = message as? VisibleMessage { - protoOrNil = message.toProto(using: transaction as! YapDatabaseReadWriteTransaction) // Needed because of how TSAttachmentStream works + protoOrNil = message.toProto(using: transaction) // Needed because of how TSAttachmentStream works } else { protoOrNil = message.toProto() } - guard let proto = protoOrNil else { seal.reject(Error.protoConversionFailed); return promise } + guard let proto = protoOrNil else { handleFailure(with: Error.protoConversionFailed, using: transaction); return promise } // Serialize the protobuf let plaintext: Data do { plaintext = try proto.serializedData() } catch { SNLog("Couldn't serialize proto due to error: \(error).") - seal.reject(error) + handleFailure(with: error, using: transaction) return promise } // Encrypt the serialized protobuf @@ -160,7 +163,7 @@ public final class MessageSender : NSObject { } } catch { SNLog("Couldn't encrypt message for destination: \(destination) due to error: \(error).") - seal.reject(error) + handleFailure(with: error, using: transaction) return promise } // Wrap the result @@ -181,7 +184,7 @@ public final class MessageSender : NSObject { senderPublicKey: senderPublicKey, base64EncodedContent: ciphertext.base64EncodedString()) } catch { SNLog("Couldn't wrap message due to error: \(error).") - seal.reject(error) + handleFailure(with: error, using: transaction) return promise } // Calculate proof of work @@ -194,7 +197,7 @@ public final class MessageSender : NSObject { let base64EncodedData = wrappedMessage.base64EncodedString() guard let (timestamp, nonce) = ProofOfWork.calculate(ttl: type(of: message).ttl, publicKey: recipient, data: base64EncodedData) else { SNLog("Proof of work calculation failed.") - seal.reject(Error.proofOfWorkCalculationFailed) + handleFailure(with: Error.proofOfWorkCalculationFailed, using: transaction) return promise } // Send the result @@ -228,12 +231,16 @@ public final class MessageSender : NSObject { $0.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in errorCount += 1 guard errorCount == promiseCount else { return } // Only error out if all promises failed - seal.reject(error) + storage.withAsync({ transaction in + handleFailure(with: error, using: transaction as! YapDatabaseReadWriteTransaction) + }, completion: { }) } } }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in SNLog("Couldn't send message due to error: \(error).") - seal.reject(error) + storage.withAsync({ transaction in + handleFailure(with: error, using: transaction as! YapDatabaseReadWriteTransaction) + }, completion: { }) } // Return return promise @@ -243,6 +250,8 @@ public final class MessageSender : NSObject { internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise { let (promise, seal) = Promise.pending() let storage = SNMessagingKitConfiguration.shared.storage + let transaction = transaction as! YapDatabaseReadWriteTransaction + // Set the timestamp, sender and recipient if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() } @@ -252,22 +261,23 @@ public final class MessageSender : NSObject { case .closedGroup(_): preconditionFailure() case .openGroup(let channel, let server): message.recipient = "\(server).\(channel)" } - // Set the failure handler (for precondition failure handling) - let _ = promise.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in - storage.withAsync({ transaction in - MessageSender.handleFailedMessageSend(message, with: error, using: transaction) - }, completion: { }) + // Set the failure handler (need it here already for precondition failure handling) + func handleFailure(with error: Swift.Error, using transaction: YapDatabaseReadWriteTransaction) { + MessageSender.handleFailedMessageSend(message, with: error, using: transaction) + transaction.addCompletionQueue(DispatchQueue.main) { + seal.reject(error) + } } // Validate the message guard let message = message as? VisibleMessage else { #if DEBUG preconditionFailure() #else - seal.reject(Error.invalidMessage) + handleFailure(with: Error.invalidMessage, using: transaction) return promise #endif } - guard message.isValid else { seal.reject(Error.invalidMessage); return promise } + guard message.isValid else { handleFailure(with: Error.invalidMessage, using: transaction); return promise } // Convert the message to an open group message let (channel, server) = { () -> (UInt64, String) in switch destination { @@ -275,7 +285,7 @@ public final class MessageSender : NSObject { default: preconditionFailure() } }() - guard let openGroupMessage = OpenGroupMessage.from(message, for: server, using: transaction as! YapDatabaseReadWriteTransaction) else { seal.reject(Error.invalidMessage); return promise } + guard let openGroupMessage = OpenGroupMessage.from(message, for: server, using: transaction) else { handleFailure(with: Error.invalidMessage, using: transaction); return promise } // Send the result OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = openGroupMessage.serverID @@ -285,7 +295,9 @@ public final class MessageSender : NSObject { seal.fulfill(()) }) }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in - seal.reject(error) + storage.withAsync({ transaction in + handleFailure(with: error, using: transaction as! YapDatabaseReadWriteTransaction) + }, completion: { }) } // Return return promise From 00549a993fc34c122f7b8d0e2f77993ffa8051ae Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 10:53:30 +1100 Subject: [PATCH 100/177] Debug --- .../Sending & Receiving/MessageSender.swift | 17 +++++------------ SignalUtilitiesKit/OWSUDManager.swift | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 8710f57c8..f7a78ce61 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -107,9 +107,7 @@ public final class MessageSender : NSObject { if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) } - transaction.addCompletionQueue(DispatchQueue.main) { - seal.reject(error) - } + seal.reject(error) } // Validate the message guard message.isValid else { handleFailure(with: Error.invalidMessage, using: transaction); return promise } @@ -117,9 +115,8 @@ public final class MessageSender : NSObject { guard !isSelfSend else { storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) - }, completion: { seal.fulfill(()) - }) + }, completion: { }) return promise } // Attach the user's profile if needed @@ -224,9 +221,8 @@ public final class MessageSender : NSObject { let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) JobQueue.shared.add(notifyPNServerJob, using: transaction) } - }, completion: { seal.fulfill(()) - }) + }, completion: { }) } $0.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in errorCount += 1 @@ -264,9 +260,7 @@ public final class MessageSender : NSObject { // Set the failure handler (need it here already for precondition failure handling) func handleFailure(with error: Swift.Error, using transaction: YapDatabaseReadWriteTransaction) { MessageSender.handleFailedMessageSend(message, with: error, using: transaction) - transaction.addCompletionQueue(DispatchQueue.main) { - seal.reject(error) - } + seal.reject(error) } // Validate the message guard let message = message as? VisibleMessage else { @@ -291,9 +285,8 @@ public final class MessageSender : NSObject { message.openGroupServerMessageID = openGroupMessage.serverID storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) - }, completion: { seal.fulfill(()) - }) + }, completion: { }) }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in storage.withAsync({ transaction in handleFailure(with: error, using: transaction as! YapDatabaseReadWriteTransaction) diff --git a/SignalUtilitiesKit/OWSUDManager.swift b/SignalUtilitiesKit/OWSUDManager.swift index f9a5106b9..080ec0f32 100644 --- a/SignalUtilitiesKit/OWSUDManager.swift +++ b/SignalUtilitiesKit/OWSUDManager.swift @@ -355,7 +355,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { private func generateSenderCertificate() -> Promise<(certificateData: Data, certificate: SMKSenderCertificate)> { return Promise<(certificateData: Data, certificate: SMKSenderCertificate)> { seal in // Loki: Generate a sender certificate locally - let sender = OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey + guard let sender = OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey else { seal.reject(OWSUDError.assertionError(description: "")); return } let certificate = SMKSenderCertificate(senderDeviceId: 1, senderRecipientId: sender) let certificateAsData = try certificate.serialized() guard isValidCertificate(certificate) else { From 67b6162fb9ce438745ad20f01bcf22acfcf37559 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 13:50:59 +1100 Subject: [PATCH 101/177] Fix open group attachment sharing --- SessionMessagingKit/Sending & Receiving/MessageSender.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index f7a78ce61..cde012889 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -272,6 +272,10 @@ public final class MessageSender : NSObject { #endif } guard message.isValid else { handleFailure(with: Error.invalidMessage, using: transaction); return promise } + // The back-end doesn't accept messages without a body so we use this as a workaround + if message.text?.isEmpty != false { + message.text = String(message.sentTimestamp!) + } // Convert the message to an open group message let (channel, server) = { () -> (UInt64, String) in switch destination { From 2c28f6addb2149bbb10679491d90e7cdd9bd98bc Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 15:08:29 +1100 Subject: [PATCH 102/177] Clean --- .../Meta/Info.plist | 2 +- ...nNotificationServiceExtension.entitlements | 2 + .../NotificationServiceExtension.swift | 20 ++++---- .../NotificationServiceExtensionContext.swift | 0 SessionShareExtension/Meta/Info.plist | 2 +- Signal.xcodeproj/project.pbxproj | 48 +++++++++---------- ...sionNotificationServiceExtension.xcscheme} | 15 +++--- 7 files changed, 44 insertions(+), 45 deletions(-) rename {SessionPushNotificationExtension => SessionNotificationServiceExtension}/Meta/Info.plist (95%) rename SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements => SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements (88%) rename {SessionPushNotificationExtension => SessionNotificationServiceExtension}/NotificationServiceExtension.swift (91%) rename {SessionPushNotificationExtension => SessionNotificationServiceExtension}/NotificationServiceExtensionContext.swift (100%) rename Signal.xcodeproj/xcshareddata/xcschemes/{SessionPushNotificationExtension.xcscheme => SessionNotificationServiceExtension.xcscheme} (90%) diff --git a/SessionPushNotificationExtension/Meta/Info.plist b/SessionNotificationServiceExtension/Meta/Info.plist similarity index 95% rename from SessionPushNotificationExtension/Meta/Info.plist rename to SessionNotificationServiceExtension/Meta/Info.plist index 28d809d22..b3c8b67ea 100644 --- a/SessionPushNotificationExtension/Meta/Info.plist +++ b/SessionNotificationServiceExtension/Meta/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - SessionPushNotificationExtension + SessionNotificationServiceExtension CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements b/SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements similarity index 88% rename from SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements rename to SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements index f10895535..758088249 100644 --- a/SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements +++ b/SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements @@ -2,6 +2,8 @@ + aps-environment + development com.apple.security.application-groups group.com.loki-project.loki-messenger diff --git a/SessionPushNotificationExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift similarity index 91% rename from SessionPushNotificationExtension/NotificationServiceExtension.swift rename to SessionNotificationServiceExtension/NotificationServiceExtension.swift index 335df69e1..844b37895 100644 --- a/SessionPushNotificationExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -4,7 +4,7 @@ import SignalUtilitiesKit // TODO: Group notifications -final class NotificationServiceExtension : UNNotificationServiceExtension { +public final class NotificationServiceExtension : UNNotificationServiceExtension { private var didPerformSetup = false private var areVersionMigrationsComplete = false private var contentHandler: ((UNNotificationContent) -> Void)? @@ -13,7 +13,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { private static let isFromRemoteKey = "remote" private static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId" - override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + override public func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler self.notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent @@ -71,7 +71,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } } - func setUpIfNecessary(completion: @escaping () -> Void) { + private func setUpIfNecessary(completion: @escaping () -> Void) { AssertIsOnMainThread() // The NSE will often re-use the same process, so if we're @@ -113,7 +113,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { NotificationCenter.default.addObserver(self, selector: #selector(storageIsReady), name: .StorageIsReady, object: nil) } - override func serviceExtensionTimeWillExpire() { + override public func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. let userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] @@ -126,7 +126,7 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } @objc - func versionMigrationsDidComplete() { + private func versionMigrationsDidComplete() { AssertIsOnMainThread() areVersionMigrationsComplete = true @@ -135,14 +135,14 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { } @objc - func storageIsReady() { + private func storageIsReady() { AssertIsOnMainThread() checkIsAppReady() } @objc - func checkIsAppReady() { + private func checkIsAppReady() { AssertIsOnMainThread() // Only mark the app as ready once. @@ -157,15 +157,15 @@ final class NotificationServiceExtension : UNNotificationServiceExtension { AppReadiness.setAppIsReady() } - func completeSilenty() { + private func completeSilenty() { contentHandler!(.init()) } - func handleSuccess(for content: UNMutableNotificationContent) { + private func handleSuccess(for content: UNMutableNotificationContent) { contentHandler!(content) } - func handleFailure(for content: UNMutableNotificationContent) { + private func handleFailure(for content: UNMutableNotificationContent) { content.body = "New Message" content.title = "Session" let userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] diff --git a/SessionPushNotificationExtension/NotificationServiceExtensionContext.swift b/SessionNotificationServiceExtension/NotificationServiceExtensionContext.swift similarity index 100% rename from SessionPushNotificationExtension/NotificationServiceExtensionContext.swift rename to SessionNotificationServiceExtension/NotificationServiceExtensionContext.swift diff --git a/SessionShareExtension/Meta/Info.plist b/SessionShareExtension/Meta/Info.plist index de9b79680..dd54da13e 100644 --- a/SessionShareExtension/Meta/Info.plist +++ b/SessionShareExtension/Meta/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Signal + SessionShareExtension CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 1fc8e2184..bf82e05af 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -182,7 +182,6 @@ 4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */; }; 4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */; }; 4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB5F26820F7D060004D1B42 /* MessageActions.swift */; }; - 4CC1ECF9211A47CE00CC13BE /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; }; 4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC613352227A00400E21A3A /* ConversationSearch.swift */; }; 4CEB78C92178EBAB00F315D2 /* OWSSessionResetJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */; }; @@ -193,7 +192,7 @@ 76C87F19181EFCE600C4ACAB /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */; }; 76EB054018170B33006006FC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB03C318170B33006006FC /* AppDelegate.m */; }; 7BC01A3E241F40AB00BC7C55 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */; }; - 7BC01A42241F40AB00BC7C55 /* SessionPushNotificationExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionPushNotificationExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 7BC01A42241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; }; 7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; }; 8E10697B10CBC965F052A4CB /* Pods_SessionPushNotificationExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9E02BC2732E07195B5AFA75 /* Pods_SessionPushNotificationExtension.framework */; }; @@ -1021,7 +1020,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( - 7BC01A42241F40AB00BC7C55 /* SessionPushNotificationExtension.appex in Embed App Extensions */, + 7BC01A42241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex in Embed App Extensions */, 453518721FC635DD00210559 /* SessionShareExtension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; @@ -1281,7 +1280,6 @@ 4CA46F4B219CCC630038ABDE /* CaptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptionView.swift; sourceTree = ""; }; 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureViewController.swift; sourceTree = ""; }; 4CB5F26820F7D060004D1B42 /* MessageActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActions.swift; sourceTree = ""; }; - 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateNag.swift; sourceTree = ""; }; 4CC613352227A00400E21A3A /* ConversationSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearch.swift; sourceTree = ""; }; 4CEB78C72178EBAB00F315D2 /* OWSSessionResetJobRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OWSSessionResetJobRecord.h; sourceTree = ""; }; @@ -1300,10 +1298,10 @@ 76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 76EB03C218170B33006006FC /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 76EB03C318170B33006006FC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 7BC01A3B241F40AB00BC7C55 /* SessionPushNotificationExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionPushNotificationExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = ""; }; 7BC01A3F241F40AB00BC7C55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7BDCFC0424206E7300641C39 /* SessionPushNotificationExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionPushNotificationExtension.entitlements; sourceTree = ""; }; + 7BDCFC0424206E7300641C39 /* SessionNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionNotificationServiceExtension.entitlements; sourceTree = ""; }; 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = ""; }; 7DD180F770F8518B4E8796F2 /* Pods-SessionUtilitiesKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUtilitiesKit.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUtilitiesKit/Pods-SessionUtilitiesKit.app store release.xcconfig"; sourceTree = ""; }; 8981C8F64D94D3C52EB67A2C /* Pods-SignalTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.test.xcconfig"; sourceTree = ""; }; @@ -2160,7 +2158,6 @@ C37F54DC255BB84A002AEA92 /* SessionSnodeKit.framework in Frameworks */, C37F54CB255BB53F002AEA92 /* SessionProtocolKit.framework in Frameworks */, C37F5414255BAFA7002AEA92 /* SignalUtilitiesKit.framework in Frameworks */, - 4CC1ECF9211A47CE00CC13BE /* StoreKit.framework in Frameworks */, 455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */, 455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */, 45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */, @@ -2478,14 +2475,14 @@ path = Signal; sourceTree = ""; }; - 7BC01A3C241F40AB00BC7C55 /* SessionPushNotificationExtension */ = { + 7BC01A3C241F40AB00BC7C55 /* SessionNotificationServiceExtension */ = { isa = PBXGroup; children = ( C31C219B255BC92200EC2D66 /* Meta */, 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */, 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */, ); - path = SessionPushNotificationExtension; + path = SessionNotificationServiceExtension; sourceTree = ""; }; 9404664EC513585B05DF1350 /* Pods */ = { @@ -2706,7 +2703,7 @@ isa = PBXGroup; children = ( 7BC01A3F241F40AB00BC7C55 /* Info.plist */, - 7BDCFC0424206E7300641C39 /* SessionPushNotificationExtension.entitlements */, + 7BDCFC0424206E7300641C39 /* SessionNotificationServiceExtension.entitlements */, ); path = Meta; sourceTree = ""; @@ -3814,7 +3811,7 @@ children = ( D221A093169C9E5E00537ABF /* Session */, 453518691FC635DD00210559 /* SessionShareExtension */, - 7BC01A3C241F40AB00BC7C55 /* SessionPushNotificationExtension */, + 7BC01A3C241F40AB00BC7C55 /* SessionNotificationServiceExtension */, C33FD9AC255A548A00E217F9 /* SignalUtilitiesKit */, C331FF1C2558F9D300070591 /* SessionUIKit */, C3C2A6F125539DE700C340D1 /* SessionMessagingKit */, @@ -3832,7 +3829,7 @@ children = ( D221A089169C9E5E00537ABF /* Session.app */, 453518681FC635DD00210559 /* SessionShareExtension.appex */, - 7BC01A3B241F40AB00BC7C55 /* SessionPushNotificationExtension.appex */, + 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */, C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */, C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */, C3C2A6F025539DE700C340D1 /* SessionMessagingKit.framework */, @@ -3850,7 +3847,6 @@ B847570023D568EB00759540 /* SignalServiceKit.framework */, 3496955F21A2FC8100DCFE74 /* CloudKit.framework */, 4C9CA25C217E676900607C63 /* ZXingObjC.framework */, - 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */, 455A16DB1F1FEA0000F86704 /* Metal.framework */, 455A16DC1F1FEA0000F86704 /* MetalKit.framework */, 45847E861E4283C30080EAB3 /* Intents.framework */, @@ -4162,9 +4158,9 @@ productReference = 453518681FC635DD00210559 /* SessionShareExtension.appex */; productType = "com.apple.product-type.app-extension"; }; - 7BC01A3A241F40AB00BC7C55 /* SessionPushNotificationExtension */ = { + 7BC01A3A241F40AB00BC7C55 /* SessionNotificationServiceExtension */ = { isa = PBXNativeTarget; - buildConfigurationList = 7BC01A45241F40AB00BC7C55 /* Build configuration list for PBXNativeTarget "SessionPushNotificationExtension" */; + buildConfigurationList = 7BC01A45241F40AB00BC7C55 /* Build configuration list for PBXNativeTarget "SessionNotificationServiceExtension" */; buildPhases = ( 4B4609DACEC6E462A2394D2F /* [CP] Check Pods Manifest.lock */, 7BC01A37241F40AB00BC7C55 /* Sources */, @@ -4176,9 +4172,9 @@ dependencies = ( C3D90A7125773A44002C9DF5 /* PBXTargetDependency */, ); - name = SessionPushNotificationExtension; + name = SessionNotificationServiceExtension; productName = LokiPushNotificationService; - productReference = 7BC01A3B241F40AB00BC7C55 /* SessionPushNotificationExtension.appex */; + productReference = 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */; productType = "com.apple.product-type.app-extension"; }; C331FF1A2558F9D300070591 /* SessionUIKit */ = { @@ -4457,7 +4453,7 @@ targets = ( D221A088169C9E5E00537ABF /* Session */, 453518671FC635DD00210559 /* SessionShareExtension */, - 7BC01A3A241F40AB00BC7C55 /* SessionPushNotificationExtension */, + 7BC01A3A241F40AB00BC7C55 /* SessionNotificationServiceExtension */, C33FD9AA255A548A00E217F9 /* SignalUtilitiesKit */, C331FF1A2558F9D300070591 /* SessionUIKit */, C3C2A6EF25539DE700C340D1 /* SessionMessagingKit */, @@ -5558,7 +5554,7 @@ }; 7BC01A41241F40AB00BC7C55 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 7BC01A3A241F40AB00BC7C55 /* SessionPushNotificationExtension */; + target = 7BC01A3A241F40AB00BC7C55 /* SessionNotificationServiceExtension */; targetProxy = 7BC01A40241F40AB00BC7C55 /* PBXContainerItemProxy */; }; C331FF212558F9D300070591 /* PBXTargetDependency */ = { @@ -5790,7 +5786,7 @@ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements; + CODE_SIGN_ENTITLEMENTS = SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; @@ -5811,13 +5807,13 @@ ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = SessionPushNotificationExtension/Meta/Info.plist; + INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; MARKETING_VERSION = 1.6.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; + PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -5861,7 +5857,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = SessionPushNotificationExtension/Meta/SessionPushNotificationExtension.entitlements; + CODE_SIGN_ENTITLEMENTS = SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; @@ -5887,13 +5883,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - INFOPLIST_FILE = SessionPushNotificationExtension/Meta/Info.plist; + INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; MARKETING_VERSION = 1.6.5; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; + PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -7006,7 +7002,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "App Store Release"; }; - 7BC01A45241F40AB00BC7C55 /* Build configuration list for PBXNativeTarget "SessionPushNotificationExtension" */ = { + 7BC01A45241F40AB00BC7C55 /* Build configuration list for PBXNativeTarget "SessionNotificationServiceExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( 7BC01A43241F40AB00BC7C55 /* Debug */, diff --git a/Signal.xcodeproj/xcshareddata/xcschemes/SessionPushNotificationExtension.xcscheme b/Signal.xcodeproj/xcshareddata/xcschemes/SessionNotificationServiceExtension.xcscheme similarity index 90% rename from Signal.xcodeproj/xcshareddata/xcschemes/SessionPushNotificationExtension.xcscheme rename to Signal.xcodeproj/xcshareddata/xcschemes/SessionNotificationServiceExtension.xcscheme index f92a82fc5..2d7587516 100644 --- a/Signal.xcodeproj/xcshareddata/xcschemes/SessionPushNotificationExtension.xcscheme +++ b/Signal.xcodeproj/xcshareddata/xcschemes/SessionNotificationServiceExtension.xcscheme @@ -2,7 +2,7 @@ + version = "2.0"> @@ -16,8 +16,8 @@ @@ -50,13 +50,14 @@ selectedDebuggerIdentifier = "" selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn" launchStyle = "0" + askForAppToLaunch = "Yes" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" - allowLocationSimulation = "YES"> - + allowLocationSimulation = "YES" + launchAutomaticallySubstyle = "2"> + - + Date: Thu, 3 Dec 2020 15:23:41 +1100 Subject: [PATCH 103/177] Prune unused notification service extension pods --- Podfile | 7 +------ Podfile.lock | 2 +- Signal.xcodeproj/project.pbxproj | 18 +++++++++++------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Podfile b/Podfile index bb59575b1..59d3020d3 100644 --- a/Podfile +++ b/Podfile @@ -31,13 +31,8 @@ target 'SessionShareExtension' do pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end -target 'SessionPushNotificationExtension' do - pod 'AFNetworking', inhibit_warnings: true - pod 'CryptoSwift', :inhibit_warnings => true +target 'SessionNotificationServiceExtension' do pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true - pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master', :inhibit_warnings => true - pod 'PromiseKit', :inhibit_warnings => true - pod 'PureLayout', '~> 3.1.4', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end diff --git a/Podfile.lock b/Podfile.lock index fed017f6c..670322a3d 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 4ebb6a2d7cbbdd42f72f7e7669db8aff6e26cf7c +PODFILE CHECKSUM: 88588faaf6a7f21ee82f4ae806699ae94de6b45b COCOAPODS: 1.10.0.rc.1 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index bf82e05af..f2a67c454 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -188,6 +188,7 @@ 4CFE6B6C21F92BA700006701 /* LegacyNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */; }; 5DF9AB212C6DB1E8BE70EFF6 /* Pods_SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB523C549815DE935E98151E /* Pods_SessionMessagingKit.framework */; }; 70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; }; + 75A5E31037A6F0E5677F3B5C /* Pods_SessionNotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62ED73E38E0EC8506A9131AD /* Pods_SessionNotificationServiceExtension.framework */; }; 768A1A2B17FC9CD300E00ED8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 768A1A2A17FC9CD300E00ED8 /* libz.dylib */; }; 76C87F19181EFCE600C4ACAB /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */; }; 76EB054018170B33006006FC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB03C318170B33006006FC /* AppDelegate.m */; }; @@ -195,7 +196,6 @@ 7BC01A42241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; }; 7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; }; - 8E10697B10CBC965F052A4CB /* Pods_SessionPushNotificationExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9E02BC2732E07195B5AFA75 /* Pods_SessionPushNotificationExtension.framework */; }; 945AA2B82B621254F69FA9E8 /* Pods_SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9117261809D69B3D7C26B8F1 /* Pods_SessionUtilitiesKit.framework */; }; 9EE44C6B4D4A069B86112387 /* Pods_SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9559C3068280BA2383F547F7 /* Pods_SessionSnodeKit.framework */; }; A11CD70D17FA230600A2D1B1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A11CD70C17FA230600A2D1B1 /* QuartzCore.framework */; }; @@ -1288,6 +1288,7 @@ 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuActionsViewController.swift; sourceTree = ""; }; 53D547348A367C8A14D37FC0 /* Pods_SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5F3070F3395081DD0EB4F933 /* Pods-SignalUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalUtilitiesKit/Pods-SignalUtilitiesKit.debug.xcconfig"; sourceTree = ""; }; + 62ED73E38E0EC8506A9131AD /* Pods_SessionNotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SessionNotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 69349DE607F5BA6036C9AC60 /* Pods-SignalShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.debug.xcconfig"; sourceTree = ""; }; 6A26D6558DE69AF455E571C1 /* Pods-SessionMessagingKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionMessagingKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionMessagingKit/Pods-SessionMessagingKit.debug.xcconfig"; sourceTree = ""; }; 6AD66810558DCCC8D6FD14C6 /* Pods-SessionPushNotificationExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionPushNotificationExtension.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionPushNotificationExtension/Pods-SessionPushNotificationExtension.app store release.xcconfig"; sourceTree = ""; }; @@ -2041,6 +2042,7 @@ C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Shared.swift"; sourceTree = ""; }; C3F0A607255C98A6007BE2A3 /* Storage+SnodeAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+SnodeAPI.swift"; sourceTree = ""; }; C88965DE4F4EC4FC919BEC4E /* Pods-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.debug.xcconfig"; sourceTree = ""; }; + C98441E849C3CA7FE8220D33 /* Pods-SessionNotificationServiceExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionNotificationServiceExtension.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionNotificationServiceExtension/Pods-SessionNotificationServiceExtension.app store release.xcconfig"; sourceTree = ""; }; CB3724C70247A916D43271FE /* Pods_Session.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Session.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; D2179CFD16BB0B480006F3AB /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; @@ -2054,10 +2056,10 @@ D221A0E7169DFFC500537ABF /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = ../../../../../../System/Library/Frameworks/AVFoundation.framework; sourceTree = ""; }; D24B5BD4169F568C00681372 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = ../../../../../../System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; D2AEACDB16C426DA00C364C0 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; - D9E02BC2732E07195B5AFA75 /* Pods_SessionPushNotificationExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SessionPushNotificationExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DE2DD605305BC6EFAD731723 /* Pods-Signal.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Signal.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Signal/Pods-Signal.debug.xcconfig"; sourceTree = ""; }; DF728B4B438716EAF95CEC18 /* Pods-Signal.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Signal.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-Signal/Pods-Signal.app store release.xcconfig"; sourceTree = ""; }; E1A0AD8B16E13FDD0071E604 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + E631A7167783FA9D1FFBC453 /* Pods-SessionNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionNotificationServiceExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionNotificationServiceExtension/Pods-SessionNotificationServiceExtension.debug.xcconfig"; sourceTree = ""; }; E7E2FBF1546840C91B7E4879 /* Pods-SessionUtilities.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUtilities.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUtilities/Pods-SessionUtilities.debug.xcconfig"; sourceTree = ""; }; E85DB184824BA9DC302EC8B3 /* Pods-SignalTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.app store release.xcconfig"; sourceTree = ""; }; EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Permissions.h"; sourceTree = ""; }; @@ -2090,7 +2092,7 @@ buildActionMask = 2147483647; files = ( C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */, - 8E10697B10CBC965F052A4CB /* Pods_SessionPushNotificationExtension.framework in Frameworks */, + 75A5E31037A6F0E5677F3B5C /* Pods_SessionNotificationServiceExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2522,6 +2524,8 @@ 6AD66810558DCCC8D6FD14C6 /* Pods-SessionPushNotificationExtension.app store release.xcconfig */, F9BBF530D71905BA9007675F /* Pods-SessionShareExtension.debug.xcconfig */, B27A64C349BBE85670300948 /* Pods-SessionShareExtension.app store release.xcconfig */, + E631A7167783FA9D1FFBC453 /* Pods-SessionNotificationServiceExtension.debug.xcconfig */, + C98441E849C3CA7FE8220D33 /* Pods-SessionNotificationServiceExtension.app store release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -3886,8 +3890,8 @@ 71CFEDD2D3C54277731012DF /* Pods_SessionUIKit.framework */, 53D547348A367C8A14D37FC0 /* Pods_SignalUtilitiesKit.framework */, CB3724C70247A916D43271FE /* Pods_Session.framework */, - D9E02BC2732E07195B5AFA75 /* Pods_SessionPushNotificationExtension.framework */, 200605FD180CB8B89F566B41 /* Pods_SessionShareExtension.framework */, + 62ED73E38E0EC8506A9131AD /* Pods_SessionNotificationServiceExtension.framework */, ); name = Frameworks; sourceTree = ""; @@ -4704,7 +4708,7 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-SessionPushNotificationExtension-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-SessionNotificationServiceExtension-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -5771,7 +5775,7 @@ }; 7BC01A43241F40AB00BC7C55 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F121FB43E2A1C1CF7F2AFC23 /* Pods-SessionPushNotificationExtension.debug.xcconfig */; + baseConfigurationReference = E631A7167783FA9D1FFBC453 /* Pods-SessionNotificationServiceExtension.debug.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; @@ -5825,7 +5829,7 @@ }; 7BC01A44241F40AB00BC7C55 /* App Store Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6AD66810558DCCC8D6FD14C6 /* Pods-SessionPushNotificationExtension.app store release.xcconfig */; + baseConfigurationReference = C98441E849C3CA7FE8220D33 /* Pods-SessionNotificationServiceExtension.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = NO; From beeeddd7fcb3180746f5148333b0229f167c1001 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 16:15:53 +1100 Subject: [PATCH 104/177] Require app extension safe API for all frameworks used by PN extension --- Signal.xcodeproj/project.pbxproj | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index f2a67c454..e0665ac83 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5645,7 +5645,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = F9BBF530D71905BA9007675F /* Pods-SessionShareExtension.debug.xcconfig */; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -5702,7 +5701,6 @@ baseConfigurationReference = B27A64C349BBE85670300948 /* Pods-SessionShareExtension.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -5777,7 +5775,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = E631A7167783FA9D1FFBC453 /* Pods-SessionNotificationServiceExtension.debug.xcconfig */; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -5832,7 +5829,6 @@ baseConfigurationReference = C98441E849C3CA7FE8220D33 /* Pods-SessionNotificationServiceExtension.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6035,6 +6031,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 5F3070F3395081DD0EB4F933 /* Pods-SignalUtilitiesKit.debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6097,6 +6094,7 @@ baseConfigurationReference = 9C0469AC557930C01552CC83 /* Pods-SignalUtilitiesKit.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6179,6 +6177,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = A6344D429FFAC3B44E6A06FA /* Pods-SessionSnodeKit.debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6233,6 +6232,7 @@ baseConfigurationReference = C022DD8E076866C6241610BF /* Pods-SessionSnodeKit.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6307,6 +6307,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 264033E641846B67E0CB21B0 /* Pods-SessionUtilitiesKit.debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6370,6 +6371,7 @@ baseConfigurationReference = 7DD180F770F8518B4E8796F2 /* Pods-SessionUtilitiesKit.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6453,6 +6455,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 6A26D6558DE69AF455E571C1 /* Pods-SessionMessagingKit.debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6507,6 +6510,7 @@ baseConfigurationReference = FF9BA33D021B115B1F5B4E46 /* Pods-SessionMessagingKit.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6581,6 +6585,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = AEA8083C060FF9BAFF6E0C9F /* Pods-SessionProtocolKit.debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -6635,6 +6640,7 @@ baseConfigurationReference = 174BD0AE74771D02DAC2B7A9 /* Pods-SessionProtocolKit.app store release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; From 4f6d0b996a5f732efc8a4211279a1518ca735ac0 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 17:00:15 +1100 Subject: [PATCH 105/177] Fix production build error --- Session/Signal/AppDelegate.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 3bebc219e..6972c9232 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -650,7 +650,6 @@ static NSTimeInterval launchStartedAt; OWSLogWarn(@"We're in debug mode. Faking success for remote registration with a fake push identifier."); [self.pushRegistrationManager didReceiveVanillaPushToken:[[NSMutableData dataWithLength:32] copy]]; #else - OWSProdError([OWSAnalyticsEvents appDelegateErrorFailedToRegisterForRemoteNotifications]); [self.pushRegistrationManager didFailToReceiveVanillaPushTokenWithError:error]; #endif } From 76f92000b9ace0aec441fc816aa0b0b65b6f005e Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 17:09:47 +1100 Subject: [PATCH 106/177] Add missing pod --- Podfile | 1 + Podfile.lock | 2 +- .../Sending & Receiving/Notifications/PushNotificationAPI.swift | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Podfile b/Podfile index 59d3020d3..dc63545b6 100644 --- a/Podfile +++ b/Podfile @@ -32,6 +32,7 @@ target 'SessionShareExtension' do end target 'SessionNotificationServiceExtension' do + pod 'CryptoSwift', :inhibit_warnings => true pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true diff --git a/Podfile.lock b/Podfile.lock index 670322a3d..d81730612 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 88588faaf6a7f21ee82f4ae806699ae94de6b45b +PODFILE CHECKSUM: 78c69e4efd6f98e563a7da1481741827fb18e21e COCOAPODS: 1.10.0.rc.1 diff --git a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift index a7076ad8c..1a7b06bfc 100644 --- a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift +++ b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift @@ -5,7 +5,7 @@ import PromiseKit public final class PushNotificationAPI : NSObject { // MARK: Settings - public static let server = "https://live.apns.getsession.org" + public static let server = "https://dev.apns.getsession.org" public static let serverPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049" private static let maxRetryCount: UInt = 4 private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60 From bcd0d5ba94c8f2d037578e7a28549f4620b56da3 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 17:10:24 +1100 Subject: [PATCH 107/177] Revert accidentally committed code --- .../Sending & Receiving/Notifications/PushNotificationAPI.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift index 1a7b06bfc..a7076ad8c 100644 --- a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift +++ b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift @@ -5,7 +5,7 @@ import PromiseKit public final class PushNotificationAPI : NSObject { // MARK: Settings - public static let server = "https://dev.apns.getsession.org" + public static let server = "https://live.apns.getsession.org" public static let serverPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049" private static let maxRetryCount: UInt = 4 private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60 From 75f7a7973b4ce4bc199afa7856e734d744fd2a57 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 3 Dec 2020 17:26:29 +1100 Subject: [PATCH 108/177] Debug PN extension --- Podfile | 1 - Podfile.lock | 2 +- .../NotificationServiceExtension.swift | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Podfile b/Podfile index dc63545b6..59d3020d3 100644 --- a/Podfile +++ b/Podfile @@ -32,7 +32,6 @@ target 'SessionShareExtension' do end target 'SessionNotificationServiceExtension' do - pod 'CryptoSwift', :inhibit_warnings => true pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true diff --git a/Podfile.lock b/Podfile.lock index d81730612..e843a6e1c 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 78c69e4efd6f98e563a7da1481741827fb18e21e +PODFILE CHECKSUM: 7699c2a380fc803ef7f51157f1f75da756aa3b45 COCOAPODS: 1.10.0.rc.1 diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 844b37895..fbae95002 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -45,9 +45,9 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension return self.handleFailure(for: notificationContent) } let snippet = tsIncomingMessage.previewText(with: transaction).filterForDisplay - let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : tsIncomingMessage.thread.uniqueId!, NotificationServiceExtension.isFromRemoteKey : true ] + let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : tsIncomingMessage.thread(with: transaction).uniqueId!, NotificationServiceExtension.isFromRemoteKey : true ] let senderPublicKey = message.sender! - let senderDisplayName = OWSProfileManager.shared().profileNameForRecipient(withID: senderPublicKey, avoidWriteTransaction: true) ?? senderPublicKey + let senderDisplayName = OWSProfileManager.shared().profileNameForRecipient(withID: senderPublicKey, transaction: transaction) ?? senderPublicKey notificationContent.userInfo = userInfo notificationContent.badge = 1 let notificationsPreference = Environment.shared.preferences!.notificationPreviewType() From 5cf732709b9d100bb2e25239ec4a5cc58c78d90e Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 4 Dec 2020 09:16:40 +1100 Subject: [PATCH 109/177] Handle PN mentions --- .../Mentions/MentionsManager.swift | 2 +- .../NotificationServiceExtension.swift | 44 ++++++++++++++++--- SignalUtilitiesKit/To Do/OWSProfileManager.h | 2 + 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/Mentions/MentionsManager.swift b/SessionMessagingKit/Sending & Receiving/Mentions/MentionsManager.swift index 861b8522a..d2cf53a4f 100644 --- a/SessionMessagingKit/Sending & Receiving/Mentions/MentionsManager.swift +++ b/SessionMessagingKit/Sending & Receiving/Mentions/MentionsManager.swift @@ -11,7 +11,7 @@ public final class MentionsManager : NSObject { internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } // MARK: Settings - private static var userIDScanLimit: UInt = 4096 + private static var userIDScanLimit: UInt = 512 // MARK: Initialization private override init() { } diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index fbae95002..8f5d15da8 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -44,8 +44,10 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { return self.handleFailure(for: notificationContent) } - let snippet = tsIncomingMessage.previewText(with: transaction).filterForDisplay - let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : tsIncomingMessage.thread(with: transaction).uniqueId!, NotificationServiceExtension.isFromRemoteKey : true ] + let threadID = tsIncomingMessage.thread(with: transaction).uniqueId! + let snippet = tsIncomingMessage.previewText(with: transaction).filterForDisplay?.replacingMentions(for: threadID, using: transaction) + ?? "You've got a new message" + let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : threadID, NotificationServiceExtension.isFromRemoteKey : true ] let senderPublicKey = message.sender! let senderDisplayName = OWSProfileManager.shared().profileNameForRecipient(withID: senderPublicKey, transaction: transaction) ?? senderPublicKey notificationContent.userInfo = userInfo @@ -54,13 +56,13 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension switch notificationsPreference { case .namePreview: notificationContent.title = senderDisplayName - notificationContent.body = snippet! + notificationContent.body = snippet case .nameNoPreview: notificationContent.title = senderDisplayName - notificationContent.body = "New Message" + notificationContent.body = "You've got a new message" case .noNameNoPreview: notificationContent.title = "Session" - notificationContent.body = "New Message" + notificationContent.body = "You've got a new message" default: break } self.handleSuccess(for: notificationContent) @@ -121,7 +123,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension notificationContent.userInfo = userInfo notificationContent.badge = 1 notificationContent.title = "Session" - notificationContent.body = "New Message" + notificationContent.body = "You've got a new message" handleSuccess(for: notificationContent) } @@ -166,10 +168,38 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension } private func handleFailure(for content: UNMutableNotificationContent) { - content.body = "New Message" + content.body = "You've got a new message" content.title = "Session" let userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] content.userInfo = userInfo contentHandler!(content) } } + +private extension String { + + func replacingMentions(for threadID: String, using transaction: YapDatabaseReadWriteTransaction) -> String { + guard let userPublicKey = Storage.shared.getUserPublicKey() else { return self } + MentionsManager.populateUserPublicKeyCacheIfNeeded(for: threadID, in: transaction) + var result = self + let regex = try! NSRegularExpression(pattern: "@[0-9a-fA-F]*", options: []) + let knownPublicKeys = MentionsManager.userPublicKeyCache[threadID] ?? [] + var mentions: [(range: NSRange, publicKey: String)] = [] + var m0 = regex.firstMatch(in: result, options: .withoutAnchoringBounds, range: NSRange(location: 0, length: result.utf16.count)) + while let m1 = m0 { + let publicKey = String((result as NSString).substring(with: m1.range).dropFirst()) // Drop the @ + var matchEnd = m1.range.location + m1.range.length + if knownPublicKeys.contains(publicKey) { + let displayName = (publicKey == userPublicKey) ? OWSProfileManager.shared().getLocalUserProfile(with: transaction).profileName + : OWSUserProfile.fetch(uniqueId: publicKey, transaction: transaction)?.profileName + if let displayName = displayName { + result = (result as NSString).replacingCharacters(in: m1.range, with: "@\(displayName)") + mentions.append((range: NSRange(location: m1.range.location, length: displayName.utf16.count + 1), publicKey: publicKey)) // + 1 to include the @ + matchEnd = m1.range.location + displayName.utf16.count + } + } + m0 = regex.firstMatch(in: result, options: .withoutAnchoringBounds, range: NSRange(location: matchEnd, length: result.utf16.count - matchEnd)) + } + return result + } +} diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.h b/SignalUtilitiesKit/To Do/OWSProfileManager.h index 05e4dad1b..b8ecdc656 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.h +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.h @@ -41,6 +41,8 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; - (nullable NSData *)localProfileAvatarData; - (nullable NSString *)profilePictureURL; +- (OWSUserProfile *)getLocalUserProfileWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; + // This method is used to update the "local profile" state on the client // and the service. Client state is only updated if service state is // successfully updated. From 91a75a65b134097ec2a852ca05a6bb48bd08dbb4 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 4 Dec 2020 09:40:58 +1100 Subject: [PATCH 110/177] Handle group messages in PNs --- .../Utilities/FullTextSearchFinder.swift | 3 +-- .../NotificationServiceExtension.swift | 10 +++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Utilities/FullTextSearchFinder.swift b/SessionMessagingKit/Utilities/FullTextSearchFinder.swift index 83ff10ea8..556d40e71 100644 --- a/SessionMessagingKit/Utilities/FullTextSearchFinder.swift +++ b/SessionMessagingKit/Utilities/FullTextSearchFinder.swift @@ -177,8 +177,7 @@ public class FullTextSearchFinder: NSObject { } private static let recipientIndexer: SearchIndexer = SearchIndexer { (recipientId: String, transaction: YapDatabaseReadTransaction) in - let displayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: recipientId, avoidingWriteTransaction: true) ?? recipientId - + let displayName = OWSUserProfile.fetch(uniqueId: recipientId, transaction: transaction)?.profileName ?? recipientId return "\(recipientId) \(displayName)" } diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 8f5d15da8..71f1ddae9 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -45,11 +45,15 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension return self.handleFailure(for: notificationContent) } let threadID = tsIncomingMessage.thread(with: transaction).uniqueId! + let senderPublicKey = message.sender! + var senderDisplayName = OWSProfileManager.shared().profileNameForRecipient(withID: senderPublicKey, transaction: transaction) ?? senderPublicKey let snippet = tsIncomingMessage.previewText(with: transaction).filterForDisplay?.replacingMentions(for: threadID, using: transaction) ?? "You've got a new message" + if let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction), let group = thread as? TSGroupThread, + group.groupModel.groupType == .closedGroup { // Should always be true because we don't get PNs for open groups + senderDisplayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderDisplayName, group.groupModel.groupName ?? MessageStrings.newGroupDefaultTitle) + } let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : threadID, NotificationServiceExtension.isFromRemoteKey : true ] - let senderPublicKey = message.sender! - let senderDisplayName = OWSProfileManager.shared().profileNameForRecipient(withID: senderPublicKey, transaction: transaction) ?? senderPublicKey notificationContent.userInfo = userInfo notificationContent.badge = 1 let notificationsPreference = Environment.shared.preferences!.notificationPreviewType() @@ -191,7 +195,7 @@ private extension String { var matchEnd = m1.range.location + m1.range.length if knownPublicKeys.contains(publicKey) { let displayName = (publicKey == userPublicKey) ? OWSProfileManager.shared().getLocalUserProfile(with: transaction).profileName - : OWSUserProfile.fetch(uniqueId: publicKey, transaction: transaction)?.profileName + : (OWSProfileManager.shared().profileNameForRecipient(withID: publicKey, transaction: transaction) ?? publicKey) if let displayName = displayName { result = (result as NSString).replacingCharacters(in: m1.range, with: "@\(displayName)") mentions.append((range: NSRange(location: m1.range.location, length: displayName.utf16.count + 1), publicKey: publicKey)) // + 1 to include the @ From 2396f22edeccc27c83f427c8e6d8ab4f049d3e4d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 4 Dec 2020 10:00:06 +1100 Subject: [PATCH 111/177] Also notify for newly created groups --- .../Sending & Receiving/MessageSender.swift | 6 ++- .../NotificationServiceExtension.swift | 38 ++++++++++++------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index cde012889..b2f982fc3 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -217,7 +217,11 @@ public final class MessageSender : NSObject { } storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) - if message is VisibleMessage { + var shouldNotify = (message is VisibleMessage) + if let closedGroupUpdate = message as? ClosedGroupUpdate, case .new = closedGroupUpdate.kind { + shouldNotify = true + } + if shouldNotify { let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) JobQueue.shared.add(notifyPNServerJob, using: transaction) } diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 71f1ddae9..225957db8 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -37,23 +37,33 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension Storage.write { transaction in // Intentionally capture self do { let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) - guard let visibleMessage = message as? VisibleMessage else { - return self.handleFailure(for: notificationContent) - } - let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, using: transaction) - guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { - return self.handleFailure(for: notificationContent) - } - let threadID = tsIncomingMessage.thread(with: transaction).uniqueId! let senderPublicKey = message.sender! var senderDisplayName = OWSProfileManager.shared().profileNameForRecipient(withID: senderPublicKey, transaction: transaction) ?? senderPublicKey - let snippet = tsIncomingMessage.previewText(with: transaction).filterForDisplay?.replacingMentions(for: threadID, using: transaction) - ?? "You've got a new message" - if let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction), let group = thread as? TSGroupThread, - group.groupModel.groupType == .closedGroup { // Should always be true because we don't get PNs for open groups - senderDisplayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderDisplayName, group.groupModel.groupName ?? MessageStrings.newGroupDefaultTitle) + let snippet: String + var userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] + switch message { + case let visibleMessage as VisibleMessage: + let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, using: transaction) + guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { + return self.handleFailure(for: notificationContent) + } + let threadID = tsIncomingMessage.thread(with: transaction).uniqueId! + userInfo[NotificationServiceExtension.threadIdKey] = threadID + snippet = tsIncomingMessage.previewText(with: transaction).filterForDisplay?.replacingMentions(for: threadID, using: transaction) + ?? "You've got a new message" + if let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction), let group = thread as? TSGroupThread, + group.groupModel.groupType == .closedGroup { // Should always be true because we don't get PNs for open groups + senderDisplayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderDisplayName, group.groupModel.groupName ?? MessageStrings.newGroupDefaultTitle) + } + case let closedGroupUpdate as ClosedGroupUpdate: + // TODO: We could consider actually handling the update here. Not sure if there's enough time though, seeing as though + // in some cases we need to send messages (e.g. our sender key) to a number of other users. + switch closedGroupUpdate.kind { + case .new(_, let name, _, _, _, _): snippet = "\(senderDisplayName) added you to \(name)" + default: return self.handleFailure(for: notificationContent) + } + default: return self.handleFailure(for: notificationContent) } - let userInfo: [String:Any] = [ NotificationServiceExtension.threadIdKey : threadID, NotificationServiceExtension.isFromRemoteKey : true ] notificationContent.userInfo = userInfo notificationContent.badge = 1 let notificationsPreference = Environment.shared.preferences!.notificationPreviewType() From a3b1a81ab30d7f5ef9486a662cece130c07481b9 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 4 Dec 2020 10:22:01 +1100 Subject: [PATCH 112/177] Lower attachment download job max failure count --- SessionMessagingKit/Jobs/AttachmentDownloadJob.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index da76a7327..00e228b69 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -21,7 +21,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject // MARK: Settings public class var collection: String { return "AttachmentDownloadJobCollection" } - public static let maxFailureCount: UInt = 100 + public static let maxFailureCount: UInt = 20 // MARK: Initialization public init(attachmentID: String, tsIncomingMessageID: String) { From ec1d79ca63a9327d61194db48035b9c669eef9f5 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 4 Dec 2020 11:05:19 +1100 Subject: [PATCH 113/177] Fix message duplication bug --- SessionMessagingKit/Database/Storage+Messaging.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SessionMessagingKit/Database/Storage+Messaging.swift b/SessionMessagingKit/Database/Storage+Messaging.swift index dae3b1265..13c092553 100644 --- a/SessionMessagingKit/Database/Storage+Messaging.swift +++ b/SessionMessagingKit/Database/Storage+Messaging.swift @@ -83,8 +83,8 @@ extension Storage { var result: [UInt64] = [] let transaction = transaction as! YapDatabaseReadWriteTransaction transaction.enumerateRows(inCollection: Storage.receivedMessageTimestampsCollection) { _, object, _, _ in - guard let timestamp = object as? UInt64 else { return } - result.append(timestamp) + guard let timestamps = object as? [UInt64] else { return } + result = timestamps } return result } From 226ef41d5853eda6bbd8e3ab9bf8dd6da79572f2 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 4 Dec 2020 11:07:20 +1100 Subject: [PATCH 114/177] Update version number --- Signal.xcodeproj/project.pbxproj | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index e0665ac83..2ef6ba5de 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5662,7 +5662,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 143; + CURRENT_PROJECT_VERSION = 144; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5683,7 +5683,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.5; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5731,7 +5731,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 143; + CURRENT_PROJECT_VERSION = 144; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5757,7 +5757,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.5; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5792,7 +5792,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 143; + CURRENT_PROJECT_VERSION = 144; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5811,7 +5811,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.5; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5862,7 +5862,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 143; + CURRENT_PROJECT_VERSION = 144; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5886,7 +5886,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.5; + MARKETING_VERSION = 1.7.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6881,7 +6881,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 143; + CURRENT_PROJECT_VERSION = 144; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6917,7 +6917,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.6.5; + MARKETING_VERSION = 1.7.0; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6949,7 +6949,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 143; + CURRENT_PROJECT_VERSION = 144; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6985,7 +6985,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.6.5; + MARKETING_VERSION = 1.7.0; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From 557a851dced2d7a60399438bc77165d5658f8e42 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 4 Dec 2020 17:10:00 +1100 Subject: [PATCH 115/177] Enforce assumptions --- SessionSnodeKit/OnionRequestAPI.swift | 14 ++++++- SessionSnodeKit/SnodeAPI.swift | 59 ++++++++++++++++----------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index 3a3b2e9bc..4a08a0999 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -4,8 +4,11 @@ import SessionUtilitiesKit /// See the "Onion Requests" section of [The Session Whitepaper](https://arxiv.org/pdf/2002.04609.pdf) for more information. public enum OnionRequestAPI { + /// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions. private static var pathFailureCount: [Path:UInt] = [:] + /// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions. private static var snodeFailureCount: [Snode:UInt] = [:] + /// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions. public static var guardSnodes: Set = [] public static var paths: [Path] = [] // Not a set to ensure we consistently show the same path to the user @@ -196,10 +199,16 @@ public enum OnionRequestAPI { } private static func dropGuardSnode(_ snode: Snode) { + #if DEBUG + dispatchPrecondition(condition: .onQueue(Threading.workQueue)) + #endif guardSnodes = guardSnodes.filter { $0 != snode } } private static func drop(_ snode: Snode) throws { + #if DEBUG + dispatchPrecondition(condition: .onQueue(Threading.workQueue)) + #endif // We repair the path here because we can do it sync. In the case where we drop a whole // path we leave the re-building up to getPath(excluding:) because re-building the path // in that case is async. @@ -224,6 +233,9 @@ public enum OnionRequestAPI { } private static func drop(_ path: Path) { + #if DEBUG + dispatchPrecondition(condition: .onQueue(Threading.workQueue)) + #endif OnionRequestAPI.pathFailureCount[path] = 0 var paths = OnionRequestAPI.paths guard let pathIndex = paths.firstIndex(of: path) else { return } @@ -392,7 +404,7 @@ public enum OnionRequestAPI { seal.reject(error) } } - promise.catch2 { error in // Must be invoked on LokiAPI.workQueue + promise.catch2 { error in // Must be invoked on Threading.workQueue guard case HTTP.Error.httpRequestFailed(let statusCode, let json) = error else { return } let path = paths.first { $0.contains(guardSnode) } func handleUnspecificError() { diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index c40f4728c..05c43399b 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -77,33 +77,35 @@ public final class SnodeAPI : NSObject { ] SNLog("Populating snode pool using: \(target).") let (promise, seal) = Promise.pending() - attempt(maxRetryCount: 4, recoveringOn: Threading.workQueue) { - HTTP.execute(.post, url, parameters: parameters, useSSLURLSession: true).map2 { json -> Snode in - guard let intermediate = json["result"] as? JSON, let rawSnodes = intermediate["service_node_states"] as? [JSON] else { throw Error.randomSnodePoolUpdatingFailed } - snodePool = Set(rawSnodes.compactMap { rawSnode in - guard let address = rawSnode["public_ip"] as? String, let port = rawSnode["storage_port"] as? Int, - let ed25519PublicKey = rawSnode["pubkey_ed25519"] as? String, let x25519PublicKey = rawSnode["pubkey_x25519"] as? String, address != "0.0.0.0" else { - SNLog("Failed to parse target from: \(rawSnode).") - return nil + Threading.workQueue.async { + attempt(maxRetryCount: 4, recoveringOn: Threading.workQueue) { + HTTP.execute(.post, url, parameters: parameters, useSSLURLSession: true).map2 { json -> Snode in + guard let intermediate = json["result"] as? JSON, let rawSnodes = intermediate["service_node_states"] as? [JSON] else { throw Error.randomSnodePoolUpdatingFailed } + snodePool = Set(rawSnodes.compactMap { rawSnode in + guard let address = rawSnode["public_ip"] as? String, let port = rawSnode["storage_port"] as? Int, + let ed25519PublicKey = rawSnode["pubkey_ed25519"] as? String, let x25519PublicKey = rawSnode["pubkey_x25519"] as? String, address != "0.0.0.0" else { + SNLog("Failed to parse target from: \(rawSnode).") + return nil + } + return Snode(address: "https://\(address)", port: UInt16(port), publicKeySet: Snode.KeySet(ed25519Key: ed25519PublicKey, x25519Key: x25519PublicKey)) + }) + // randomElement() uses the system's default random generator, which is cryptographically secure + if !snodePool.isEmpty { + return snodePool.randomElement()! + } else { + throw Error.randomSnodePoolUpdatingFailed } - return Snode(address: "https://\(address)", port: UInt16(port), publicKeySet: Snode.KeySet(ed25519Key: ed25519PublicKey, x25519Key: x25519PublicKey)) - }) - // randomElement() uses the system's default random generator, which is cryptographically secure - if !snodePool.isEmpty { - return snodePool.randomElement()! - } else { - throw Error.randomSnodePoolUpdatingFailed } + }.done2 { snode in + seal.fulfill(snode) + SNSnodeKitConfiguration.shared.storage.with { transaction in + SNLog("Persisting snode pool to database.") + SNSnodeKitConfiguration.shared.storage.setSnodePool(to: SnodeAPI.snodePool, using: transaction) + } + }.catch2 { error in + SNLog("Failed to contact seed node at: \(target).") + seal.reject(error) } - }.done2 { snode in - seal.fulfill(snode) - SNSnodeKitConfiguration.shared.storage.with { transaction in - SNLog("Persisting snode pool to database.") - SNSnodeKitConfiguration.shared.storage.setSnodePool(to: SnodeAPI.snodePool, using: transaction) - } - }.catch2 { error in - SNLog("Failed to contact seed node at: \(target).") - seal.reject(error) } return promise } else { @@ -115,6 +117,9 @@ public final class SnodeAPI : NSObject { } internal static func dropSnodeFromSnodePool(_ snode: Snode) { + #if DEBUG + dispatchPrecondition(condition: .onQueue(Threading.workQueue)) + #endif var snodePool = SnodeAPI.snodePool snodePool.remove(snode) SnodeAPI.snodePool = snodePool @@ -132,6 +137,9 @@ public final class SnodeAPI : NSObject { } public static func dropSnodeFromSwarmIfNeeded(_ snode: Snode, publicKey: String) { + #if DEBUG + dispatchPrecondition(condition: .onQueue(Threading.workQueue)) + #endif let swarm = SnodeAPI.swarmCache[publicKey] if var swarm = swarm, let index = swarm.firstIndex(of: snode) { swarm.remove(at: index) @@ -282,6 +290,9 @@ public final class SnodeAPI : NSObject { /// - Note: Should only be invoked from `Threading.workQueue` to avoid race conditions. @discardableResult internal static func handleError(withStatusCode statusCode: UInt, json: JSON?, forSnode snode: Snode, associatedWith publicKey: String? = nil) -> Error? { + #if DEBUG + dispatchPrecondition(condition: .onQueue(Threading.workQueue)) + #endif func handleBadSnode() { let oldFailureCount = SnodeAPI.snodeFailureCount[snode] ?? 0 let newFailureCount = oldFailureCount + 1 From 905b829de279508f012437071daab5a0a27652ce Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 09:29:46 +1100 Subject: [PATCH 116/177] Refresh snode pool at least once a day --- .../{GeneralUtilities.swift => General.swift} | 0 SessionSnodeKit/SnodeAPI.swift | 8 +++++++- SessionSnodeKit/Storage+SnodeAPI.swift | 13 ++++++++++++ SessionSnodeKit/Storage.swift | 2 ++ ...+Utilities.swift => String+Trimming.swift} | 0 SessionUtilitiesKit/General.swift | 3 +++ Signal.xcodeproj/project.pbxproj | 20 +++++++++++-------- 7 files changed, 37 insertions(+), 9 deletions(-) rename SessionMessagingKit/Utilities/{GeneralUtilities.swift => General.swift} (100%) rename SessionSnodeKit/Utilities/{String+Utilities.swift => String+Trimming.swift} (100%) create mode 100644 SessionUtilitiesKit/General.swift diff --git a/SessionMessagingKit/Utilities/GeneralUtilities.swift b/SessionMessagingKit/Utilities/General.swift similarity index 100% rename from SessionMessagingKit/Utilities/GeneralUtilities.swift rename to SessionMessagingKit/Utilities/General.swift diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index 05c43399b..c957da688 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -63,7 +63,13 @@ public final class SnodeAPI : NSObject { if snodePool.count < minimumSnodePoolCount { snodePool = SNSnodeKitConfiguration.shared.storage.getSnodePool() } - if snodePool.count < minimumSnodePoolCount { + let now = Date() + let isSnodePoolExpired = given(Storage.shared.getLastSnodePoolRefreshDate()) { now.timeIntervalSince($0) > 24 * 60 * 60 } ?? true + let isRefreshNeeded = (snodePool.count < minimumSnodePoolCount) || isSnodePoolExpired + if isRefreshNeeded { + Storage.write { transaction in + Storage.shared.setLastSnodePoolRefreshDate(to: now, using: transaction) + } let target = seedNodePool.randomElement()! let url = "\(target)/json_rpc" let parameters: JSON = [ diff --git a/SessionSnodeKit/Storage+SnodeAPI.swift b/SessionSnodeKit/Storage+SnodeAPI.swift index 85cc28d29..c7378fd76 100644 --- a/SessionSnodeKit/Storage+SnodeAPI.swift +++ b/SessionSnodeKit/Storage+SnodeAPI.swift @@ -5,6 +5,7 @@ extension Storage { // MARK: - Snode Pool private static let snodePoolCollection = "LokiSnodePoolCollection" + private static let lastSnodePoolRefreshDateCollection = "LokiLastSnodePoolRefreshDateCollection" public func getSnodePool() -> Set { var result: Set = [] @@ -27,6 +28,18 @@ extension Storage { public func clearSnodePool(in transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.snodePoolCollection) } + + public func getLastSnodePoolRefreshDate() -> Date? { + var result: Date? + Storage.read { transaction in + result = transaction.object(forKey: "lastSnodePoolRefreshDate", inCollection: Storage.lastSnodePoolRefreshDateCollection) as? Date + } + return result + } + + public func setLastSnodePoolRefreshDate(to date: Date, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(date, forKey: "lastSnodePoolRefreshDate", inCollection: Storage.lastSnodePoolRefreshDateCollection) + } diff --git a/SessionSnodeKit/Storage.swift b/SessionSnodeKit/Storage.swift index 8d3836173..edf4334d5 100644 --- a/SessionSnodeKit/Storage.swift +++ b/SessionSnodeKit/Storage.swift @@ -9,6 +9,8 @@ public protocol SessionSnodeKitStorageProtocol { func setOnionRequestPaths(to paths: [OnionRequestAPI.Path], using transaction: Any) func getSnodePool() -> Set func setSnodePool(to snodePool: Set, using transaction: Any) + func getLastSnodePoolRefreshDate() -> Date? + func setLastSnodePoolRefreshDate(to date: Date, using transaction: Any) func getSwarm(for publicKey: String) -> Set func setSwarm(to swarm: Set, for publicKey: String, using transaction: Any) func getLastMessageHash(for snode: Snode, associatedWith publicKey: String) -> String? diff --git a/SessionSnodeKit/Utilities/String+Utilities.swift b/SessionSnodeKit/Utilities/String+Trimming.swift similarity index 100% rename from SessionSnodeKit/Utilities/String+Utilities.swift rename to SessionSnodeKit/Utilities/String+Trimming.swift diff --git a/SessionUtilitiesKit/General.swift b/SessionUtilitiesKit/General.swift new file mode 100644 index 000000000..d70410bdb --- /dev/null +++ b/SessionUtilitiesKit/General.swift @@ -0,0 +1,3 @@ + +/// Returns `f(x!)` if `x != nil`, or `nil` otherwise. +public func given(_ x: T?, _ f: (T) throws -> U) rethrows -> U? { return try x.map(f) } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 2ef6ba5de..ca1f5e552 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -280,6 +280,7 @@ B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; }; B8B26C8F234D629C004ED98C /* MentionCandidateSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */; }; B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BB82A4238F627000BA5194 /* HomeVC.swift */; }; + B8BC00C0257D90E30032E807 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BC00BF257D90E30032E807 /* General.swift */; }; B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C2B2C72563685C00551B4D /* CircleView.swift */; }; B8C2B332256376F000551B4D /* ThreadUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B8C2B331256376F000551B4D /* ThreadUtil.m */; }; B8C2B3442563782400551B4D /* ThreadUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = B8C2B33B2563770800551B4D /* ThreadUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -360,7 +361,7 @@ C32C5BF8256DC8F6003C73A2 /* OWSDisappearingMessagesJob.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA80255A57FC00E217F9 /* OWSDisappearingMessagesJob.h */; settings = {ATTRIBUTES = (Public, ); }; }; C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA9255A581500E217F9 /* OWSIdentityManager.m */; }; C32C5C0A256DC9B4003C73A2 /* OWSIdentityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C32C5C1B256DC9E0003C73A2 /* GeneralUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */; }; + C32C5C1B256DC9E0003C73A2 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBC1255A581700E217F9 /* General.swift */; }; C32C5C24256DCB30003C73A2 /* NotificationsProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB75255A581000E217F9 /* AppReadiness.m */; }; C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB01255A580700E217F9 /* AppReadiness.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -784,7 +785,7 @@ C3C2A5C7255385EE00C340D1 /* SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BE255385EE00C340D1 /* SnodeAPI.swift */; }; C3C2A5DB2553860B00C340D1 /* Promise+Hashing.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5CF2553860700C340D1 /* Promise+Hashing.swift */; }; C3C2A5DC2553860B00C340D1 /* Promise+Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D02553860800C340D1 /* Promise+Threading.swift */; }; - C3C2A5DE2553860B00C340D1 /* String+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D22553860900C340D1 /* String+Utilities.swift */; }; + C3C2A5DE2553860B00C340D1 /* String+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D22553860900C340D1 /* String+Trimming.swift */; }; C3C2A5E02553860B00C340D1 /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D42553860A00C340D1 /* Threading.swift */; }; C3C2A5E42553860B00C340D1 /* Data+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D82553860B00C340D1 /* Data+Utilities.swift */; }; C3C2A67D255388CC00C340D1 /* SessionUtilitiesKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C3C2A67B255388CC00C340D1 /* SessionUtilitiesKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1395,6 +1396,7 @@ B8BB82B423947F2D00BA5194 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; B8BB82B82394911B00BA5194 /* Separator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Separator.swift; sourceTree = ""; }; B8BB82BD2394D4CE00BA5194 /* Fonts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; + B8BC00BF257D90E30032E807 /* General.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = General.swift; sourceTree = ""; }; B8C2B2C72563685C00551B4D /* CircleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleView.swift; sourceTree = ""; }; B8C2B331256376F000551B4D /* ThreadUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ThreadUtil.m; sourceTree = ""; }; B8C2B33B2563770800551B4D /* ThreadUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadUtil.h; sourceTree = ""; }; @@ -1636,7 +1638,7 @@ C33FDBBB255A581600E217F9 /* OWSPrimaryStorage+Loki.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSPrimaryStorage+Loki.h"; sourceTree = ""; }; C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKKeychainStorage.swift; sourceTree = ""; }; C33FDBBF255A581700E217F9 /* OWSHTTPSecurityPolicy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSHTTPSecurityPolicy.m; sourceTree = ""; }; - C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralUtilities.swift; sourceTree = ""; }; + C33FDBC1255A581700E217F9 /* General.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = General.swift; sourceTree = ""; }; C33FDBC2255A581700E217F9 /* SSKAsserts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKAsserts.h; sourceTree = ""; }; C33FDBC9255A581700E217F9 /* CreatePreKeysOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreatePreKeysOperation.swift; sourceTree = ""; }; C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKGroupUtilities.h; sourceTree = ""; }; @@ -1927,7 +1929,7 @@ C3C2A5CF2553860700C340D1 /* Promise+Hashing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Hashing.swift"; sourceTree = ""; }; C3C2A5D02553860800C340D1 /* Promise+Threading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Threading.swift"; sourceTree = ""; }; C3C2A5D12553860800C340D1 /* Array+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Description.swift"; sourceTree = ""; }; - C3C2A5D22553860900C340D1 /* String+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Utilities.swift"; sourceTree = ""; }; + C3C2A5D22553860900C340D1 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = ""; }; C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Delaying.swift"; sourceTree = ""; }; C3C2A5D42553860A00C340D1 /* Threading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = ""; }; C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Description.swift"; sourceTree = ""; }; @@ -3344,7 +3346,7 @@ C37F5402255BA9ED002AEA92 /* Environment.m */, C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */, C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, - C33FDBC1255A581700E217F9 /* GeneralUtilities.swift */, + C33FDBC1255A581700E217F9 /* General.swift */, C3A71D0A2558989C0043A11F /* MessageWrapper.swift */, C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */, C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */, @@ -3420,7 +3422,7 @@ C3C2A5D82553860B00C340D1 /* Data+Utilities.swift */, C3C2A5CF2553860700C340D1 /* Promise+Hashing.swift */, C3C2A5D02553860800C340D1 /* Promise+Threading.swift */, - C3C2A5D22553860900C340D1 /* String+Utilities.swift */, + C3C2A5D22553860900C340D1 /* String+Trimming.swift */, C3C2A5D42553860A00C340D1 /* Threading.swift */, ); path = Utilities; @@ -3444,6 +3446,7 @@ C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */, C3A71D662558A0170043A11F /* DiffieHellman.swift */, C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */, + B8BC00BF257D90E30032E807 /* General.swift */, C3C2A5BC255385EE00C340D1 /* HTTP.swift */, C3C2A5D92553860B00C340D1 /* JSON.swift */, C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */, @@ -5112,7 +5115,7 @@ C32C5CBE256DD282003C73A2 /* Storage+OnionRequests.swift in Sources */, C3C2A5DC2553860B00C340D1 /* Promise+Threading.swift in Sources */, C3C2A5C4255385EE00C340D1 /* OnionRequestAPI+Encryption.swift in Sources */, - C3C2A5DE2553860B00C340D1 /* String+Utilities.swift in Sources */, + C3C2A5DE2553860B00C340D1 /* String+Trimming.swift in Sources */, C3C2A5DB2553860B00C340D1 /* Promise+Hashing.swift in Sources */, C3C2A5E42553860B00C340D1 /* Data+Utilities.swift in Sources */, C3C2A5C2255385EE00C340D1 /* Configuration.swift in Sources */, @@ -5157,6 +5160,7 @@ C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */, C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */, C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */, + B8BC00C0257D90E30032E807 /* General.swift in Sources */, C32C5A24256DB7DB003C73A2 /* LKUserDefaults.swift in Sources */, C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */, C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */, @@ -5250,7 +5254,7 @@ C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */, C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */, C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */, - C32C5C1B256DC9E0003C73A2 /* GeneralUtilities.swift in Sources */, + C32C5C1B256DC9E0003C73A2 /* General.swift in Sources */, C32C5A02256DB658003C73A2 /* MessageSender+Convenience.swift in Sources */, B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */, C32C5D2E256DD4EA003C73A2 /* TSUnreadIndicatorInteraction.m in Sources */, From fa757e414bf49af9066fbe7a5353411c8673a13b Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 09:30:29 +1100 Subject: [PATCH 117/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index ca1f5e552..9c646f622 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 144; + CURRENT_PROJECT_VERSION = 145; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 144; + CURRENT_PROJECT_VERSION = 145; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 144; + CURRENT_PROJECT_VERSION = 145; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 144; + CURRENT_PROJECT_VERSION = 145; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 144; + CURRENT_PROJECT_VERSION = 145; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 144; + CURRENT_PROJECT_VERSION = 145; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 21ec0510164b06035207ef969c4e9081861d6e21 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 10:04:38 +1100 Subject: [PATCH 118/177] Fix PN sending from share extension --- .../Jobs/NotifyPNServerJob.swift | 13 ++++++++++--- .../Sending & Receiving/MessageSender.swift | 17 +++++++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift index c26ed550c..2c506dc43 100644 --- a/SessionMessagingKit/Jobs/NotifyPNServerJob.swift +++ b/SessionMessagingKit/Jobs/NotifyPNServerJob.swift @@ -34,18 +34,25 @@ public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSC // MARK: Running public func execute() { + let _: Promise = execute() + } + + public func execute() -> Promise { let server = PushNotificationAPI.server let parameters = [ "data" : message.data.description, "send_to" : message.recipient ] let url = URL(string: "\(server)/notify")! let request = TSRequest(url: url, method: "POST", parameters: parameters) request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] - attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.global()) { + let promise = attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.global()) { OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: PushNotificationAPI.serverPublicKey).map { _ in } - }.done(on: DispatchQueue.global()) { // Intentionally capture self + } + let _ = promise.done(on: DispatchQueue.global()) { // Intentionally capture self self.handleSuccess() - }.catch(on: DispatchQueue.global()) { error in + } + promise.catch(on: DispatchQueue.global()) { error in self.handleFailure(error: error) } + return promise } private func handleSuccess() { diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index b2f982fc3..063075333 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -90,6 +90,10 @@ public final class MessageSender : NSObject { let storage = SNMessagingKitConfiguration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction let userPublicKey = storage.getUserPublicKey() + var isMainAppAndActive = false + if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") { + isMainAppAndActive = sharedUserDefaults.bool(forKey: "isMainAppActive") + } // Set the timestamp, sender and recipient if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set message.sentTimestamp = NSDate.millisecondTimestamp() @@ -223,9 +227,18 @@ public final class MessageSender : NSObject { } if shouldNotify { let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage) - JobQueue.shared.add(notifyPNServerJob, using: transaction) + if isMainAppAndActive { + JobQueue.shared.add(notifyPNServerJob, using: transaction) + seal.fulfill(()) + } else { + notifyPNServerJob.execute().done(on: DispatchQueue.global(qos: .userInitiated)) { + seal.fulfill(()) + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { _ in + seal.fulfill(()) // Always fulfill because the notify PN server job isn't critical. + } + } + } - seal.fulfill(()) }, completion: { }) } $0.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in From 438bbccdfa7ca35da1c8f0ddc160a8c12bf97328 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 11:21:24 +1100 Subject: [PATCH 119/177] Fix background polling --- Session/Utilities/BackgroundPoller.swift | 40 ++++++++++++++++--- .../Jobs/MessageReceiveJob.swift | 20 ++++++++-- .../MessageReceiver+Handling.swift | 8 ++-- .../Pollers/ClosedGroupPoller.swift | 2 +- .../Pollers/OpenGroupPoller.swift | 25 ++++++++++-- .../Sending & Receiving/Pollers/Poller.swift | 2 +- .../NotificationServiceExtension.swift | 2 +- 7 files changed, 80 insertions(+), 19 deletions(-) diff --git a/Session/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift index 9ec7c4761..31fcabd66 100644 --- a/Session/Utilities/BackgroundPoller.swift +++ b/Session/Utilities/BackgroundPoller.swift @@ -1,23 +1,23 @@ import PromiseKit +import SessionSnodeKit @objc(LKBackgroundPoller) public final class BackgroundPoller : NSObject { private static var closedGroupPoller: ClosedGroupPoller! + private static var promises: [Promise] = [] private override init() { } @objc(pollWithCompletionHandler:) public static func poll(completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - var promises: [Promise] = [] - // TODO TODO TODO -// promises.append(AppEnvironment.shared.messageFetcherJob.run()) // FIXME: It'd be nicer to just use Poller directly - closedGroupPoller = ClosedGroupPoller() - promises.append(contentsOf: closedGroupPoller.pollOnce()) + promises = [] + promises.append(pollForMessages()) + promises.append(contentsOf: pollForClosedGroupMessages()) let openGroups: [String:OpenGroup] = Storage.shared.getAllUserOpenGroups() openGroups.values.forEach { openGroup in let poller = OpenGroupPoller(for: openGroup) poller.stop() - promises.append(poller.pollForNewMessages()) + promises.append(poller.pollForNewMessages(isBackgroundPoll: true)) } when(resolved: promises).done { _ in completionHandler(.newData) @@ -25,4 +25,32 @@ public final class BackgroundPoller : NSObject { completionHandler(.failed) } } + + private static func pollForMessages() -> Promise { + let userPublicKey = getUserHexEncodedPublicKey() + return getMessages(for: userPublicKey) + } + + private static func pollForClosedGroupMessages() -> [Promise] { + let publicKeys = Storage.shared.getUserClosedGroupPublicKeys() + return publicKeys.map { getMessages(for: $0) } + } + + private static func getMessages(for publicKey: String) -> Promise { + return SnodeAPI.getSwarm(for: publicKey).then2 { swarm -> Promise in + guard let snode = swarm.randomElement() else { throw SnodeAPI.Error.generic } + return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise in + let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey) + let promises = messages.compactMap { json -> Promise? in + // Use a best attempt approach here; we don't want to fail the entire process if one of the + // messages failed to parse. + guard let envelope = SNProtoEnvelope.from(json), + let data = try? envelope.serializedData() else { return nil } + let job = MessageReceiveJob(data: data, isBackgroundPoll: true) + return job.execute() + } + return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects + } + } + } } diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index 74192a582..b8895d12f 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -1,9 +1,11 @@ import SessionUtilitiesKit +import PromiseKit public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public let data: Data public let openGroupMessageServerID: UInt64? public let openGroupID: String? + public let isBackgroundPoll: Bool public var delegate: JobDelegate? public var id: String? public var failureCount: UInt = 0 @@ -13,10 +15,11 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC public static let maxFailureCount: UInt = 10 // MARK: Initialization - public init(data: Data, openGroupMessageServerID: UInt64? = nil, openGroupID: String? = nil) { + public init(data: Data, openGroupMessageServerID: UInt64? = nil, openGroupID: String? = nil, isBackgroundPoll: Bool) { self.data = data self.openGroupMessageServerID = openGroupMessageServerID self.openGroupID = openGroupID + self.isBackgroundPoll = isBackgroundPoll #if DEBUG if openGroupMessageServerID != nil { assert(openGroupID != nil) } if openGroupID != nil { assert(openGroupMessageServerID != nil) } @@ -26,10 +29,12 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC // MARK: Coding public init?(coder: NSCoder) { guard let data = coder.decodeObject(forKey: "data") as! Data?, - let id = coder.decodeObject(forKey: "id") as! String? else { return nil } + let id = coder.decodeObject(forKey: "id") as! String?, + let isBackgroundPoll = coder.decodeObject(forKey: "isBackgroundPoll") as! Bool? else { return nil } self.data = data self.openGroupMessageServerID = coder.decodeObject(forKey: "openGroupMessageServerID") as! UInt64? self.openGroupID = coder.decodeObject(forKey: "openGroupID") as! String? + self.isBackgroundPoll = isBackgroundPoll self.id = id self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0 } @@ -38,17 +43,24 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC coder.encode(data, forKey: "data") coder.encode(openGroupMessageServerID, forKey: "openGroupMessageServerID") coder.encode(openGroupID, forKey: "openGroupID") + coder.encode(isBackgroundPoll, forKey: "isBackgroundPoll") coder.encode(id, forKey: "id") coder.encode(failureCount, forKey: "failureCount") } // MARK: Running public func execute() { + let _: Promise = execute() + } + + public func execute() -> Promise { + let (promise, seal) = Promise.pending() SNMessagingKitConfiguration.shared.storage.withAsync({ transaction in // Intentionally capture self do { let (message, proto) = try MessageReceiver.parse(self.data, openGroupMessageServerID: self.openGroupMessageServerID, using: transaction) - try MessageReceiver.handle(message, associatedWithProto: proto, openGroupID: self.openGroupID, using: transaction) + try MessageReceiver.handle(message, associatedWithProto: proto, openGroupID: self.openGroupID, isBackgroundPoll: self.isBackgroundPoll, using: transaction) self.handleSuccess() + seal.fulfill(()) } catch { SNLog("Couldn't receive message due to error: \(error).") if let error = error as? MessageReceiver.Error, !error.isRetryable { @@ -56,8 +68,10 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC } else { self.handleFailure(error: error) } + seal.fulfill(()) // The promise is just used to keep track of when we're done } }, completion: { }) + return promise } private func handleSuccess() { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 31e093258..e72f002fc 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -7,13 +7,13 @@ extension MessageReceiver { return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey) } - public static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws { + public static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, openGroupID: String?, isBackgroundPoll: Bool, using transaction: Any) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) case let message as TypingIndicator: handleTypingIndicator(message, using: transaction) case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction) case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction) - case let message as VisibleMessage: try handleVisibleMessage(message, associatedWithProto: proto, openGroupID: openGroupID, using: transaction) + case let message as VisibleMessage: try handleVisibleMessage(message, associatedWithProto: proto, openGroupID: openGroupID, isBackgroundPoll: isBackgroundPoll, using: transaction) default: fatalError() } } @@ -136,7 +136,7 @@ extension MessageReceiver { } @discardableResult - public static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, openGroupID: String?, using transaction: Any) throws -> String { + public static func handleVisibleMessage(_ message: VisibleMessage, associatedWithProto proto: SNProtoContent, openGroupID: String?, isBackgroundPoll: Bool, using transaction: Any) throws -> String { let storage = SNMessagingKitConfiguration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction var isMainAppAndActive = false @@ -206,7 +206,7 @@ extension MessageReceiver { cancelTypingIndicatorsIfNeeded(for: message.sender!) } // Notify the user if needed - guard isMainAppAndActive, let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), + guard (isMainAppAndActive || isBackgroundPoll), let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction), let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return tsIncomingMessageID } SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction) return tsIncomingMessageID diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift index ca2ae693e..4b339dd7c 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift @@ -67,7 +67,7 @@ public final class ClosedGroupPoller : NSObject { guard let envelope = SNProtoEnvelope.from(json) else { return } do { let data = try envelope.serializedData() - let job = MessageReceiveJob(data: data) + let job = MessageReceiveJob(data: data, isBackgroundPoll: false) Storage.write { transaction in SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 32f382e90..995c1cc9c 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -51,11 +51,18 @@ public final class OpenGroupPoller : NSObject { @discardableResult public func pollForNewMessages() -> Promise { + return pollForNewMessages(isBackgroundPoll: false) + } + + @discardableResult + public func pollForNewMessages(isBackgroundPoll: Bool) -> Promise { guard !self.isPolling else { return Promise.value(()) } self.isPolling = true let openGroup = self.openGroup let userPublicKey = getUserHexEncodedPublicKey() - return OpenGroupAPI.getMessages(for: openGroup.channel, on: openGroup.server).done(on: DispatchQueue.global(qos: .default)) { messages in + let (promise, seal) = Promise.pending() + promise.retainUntilComplete() + OpenGroupAPI.getMessages(for: openGroup.channel, on: openGroup.server).done(on: DispatchQueue.global(qos: .default)) { messages in self.isPolling = false // Sorting the messages by timestamp before importing them fixes an issue where messages that quote older messages can't find those older messages messages.sorted { $0.serverTimestamp < $1.serverTimestamp }.forEach { message in @@ -153,11 +160,23 @@ public final class OpenGroupPoller : NSObject { Storage.write { transaction in Storage.shared.setOpenGroupDisplayName(to: senderDisplayName, for: senderPublicKey, inOpenGroupWithID: openGroup.id, using: transaction) let messageServerID = message.serverID - let job = MessageReceiveJob(data: try! envelope.buildSerializedData(), openGroupMessageServerID: messageServerID, openGroupID: openGroup.id) - SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + let job = MessageReceiveJob(data: try! envelope.buildSerializedData(), openGroupMessageServerID: messageServerID, openGroupID: openGroup.id, isBackgroundPoll: isBackgroundPoll) + if isBackgroundPoll { + job.execute().done(on: DispatchQueue.global(qos: .userInitiated)) { + seal.fulfill(()) + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { _ in + seal.fulfill(()) // The promise is just used to keep track of when we're done + } + } else { + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + seal.fulfill(()) + } } } + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { _ in + seal.fulfill(()) // The promise is just used to keep track of when we're done } + return promise } private func pollForDeletedMessages() { diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift index 082e3a7fc..f182c744e 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift @@ -97,7 +97,7 @@ public final class Poller : NSObject { guard let envelope = SNProtoEnvelope.from(json) else { return } do { let data = try envelope.serializedData() - let job = MessageReceiveJob(data: data) + let job = MessageReceiveJob(data: data, isBackgroundPoll: false) Storage.write { transaction in SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 225957db8..4306575e9 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -43,7 +43,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension var userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] switch message { case let visibleMessage as VisibleMessage: - let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, using: transaction) + let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, isBackgroundPoll: false, using: transaction) guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { return self.handleFailure(for: notificationContent) } From eafff041df4776d3c1d14e9a42a92d134a5b872d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 11:45:56 +1100 Subject: [PATCH 120/177] Debug open group background polling --- .../Pollers/OpenGroupPoller.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 995c1cc9c..429f9b127 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -9,6 +9,14 @@ public final class OpenGroupPoller : NSObject { private var hasStarted = false private var isPolling = false + private var isMainAppAndActive: Bool { + var isMainAppAndActive = false + if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") { + isMainAppAndActive = sharedUserDefaults.bool(forKey: "isMainAppActive") + } + return isMainAppAndActive + } + // MARK: Settings private let pollForNewMessagesInterval: TimeInterval = 4 private let pollForDeletedMessagesInterval: TimeInterval = 60 @@ -22,7 +30,8 @@ public final class OpenGroupPoller : NSObject { } @objc public func startIfNeeded() { - if hasStarted { return } + guard !hasStarted else { return } + guard isMainAppAndActive else { stop(); return } DispatchQueue.main.async { [weak self] in // Timers don't do well on background queues guard let strongSelf = self else { return } strongSelf.pollForNewMessagesTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForNewMessagesInterval, repeats: true) { _ in self?.pollForNewMessages() } @@ -51,6 +60,7 @@ public final class OpenGroupPoller : NSObject { @discardableResult public func pollForNewMessages() -> Promise { + guard isMainAppAndActive else { stop(); return Promise.value(()) } return pollForNewMessages(isBackgroundPoll: false) } From 61611db58efb1b0672eab64cea6c2a695f9bbf29 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 13:19:46 +1100 Subject: [PATCH 121/177] Show message sync when sending a message --- .../Signal/ConversationView/ConversationViewController.m | 7 ++++--- .../Link Previews/OWSLinkPreview+Conversion.swift | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 0c9327df3..e23512245 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3715,13 +3715,14 @@ typedef enum : NSUInteger { message.text = text; message.quote = [SNQuote from:self.inputToolbar.quotedReply]; OWSLinkPreviewDraft *linkPreviewDraft = self.inputToolbar.linkPreviewDraft; + TSThread *thread = self.thread; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; + [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { message.linkPreview = [SNLinkPreview from:linkPreviewDraft using:transaction]; } completion:^{ dispatch_async(dispatch_get_main_queue(), ^{ - TSThread *thread = self.thread; - TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; - [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; + tsMessage.linkPreview = [OWSLinkPreview from:message.linkPreview]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [tsMessage saveWithTransaction:transaction]; }]; diff --git a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift index 72e49d2e3..59f3f15f6 100644 --- a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift @@ -1,7 +1,7 @@ extension OWSLinkPreview { - public static func from(_ linkPreview: VisibleMessage.LinkPreview?) -> OWSLinkPreview? { + @objc public static func from(_ linkPreview: VisibleMessage.LinkPreview?) -> OWSLinkPreview? { guard let linkPreview = linkPreview else { return nil } return OWSLinkPreview(urlString: linkPreview.url!, title: linkPreview.title, imageAttachmentId: linkPreview.attachmentID) } From 3f5bc18f6b99c9aa32b4846ebdc1fb842c512230 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 15:11:49 +1100 Subject: [PATCH 122/177] Fix remaining TODOs --- .../ConversationViewController.m | 36 ++++++++------ .../Control Messages/ClosedGroupUpdate.swift | 20 +++++++- .../ExpirationTimerUpdate.swift | 9 ++++ .../Control Messages/ReadReceipt.swift | 9 ++++ .../Control Messages/TypingIndicator.swift | 18 ++++++- .../Signal/TSOutgoingMessage+Conversion.swift | 21 +++++++++ .../VisibleMessage+LinkPreview.swift | 11 +++++ .../VisibleMessage+Profile.swift | 11 +++++ .../VisibleMessage+Quote.swift | 15 +++++- .../Visible Messages/VisibleMessage.swift | 14 ++++++ .../OWSLinkPreview+Conversion.swift | 5 ++ .../Sending & Receiving/MessageSender.swift | 22 ++++++++- .../Quotes/TSQuotedMessage+Conversion.swift | 13 +++++ .../MessageSender+Convenience.swift | 11 ++++- .../UI/SharingThreadPickerViewController.m | 47 +++++++++---------- 15 files changed, 216 insertions(+), 46 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index e23512245..e0560412d 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -1454,9 +1454,9 @@ typedef enum : NSUInteger { // Do nothing } -- (void)handleUnsentMessageTap:(TSOutgoingMessage *)message +- (void)handleUnsentMessageTap:(TSOutgoingMessage *)tsMessage { - UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:message.mostRecentFailureText + UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:tsMessage.mostRecentFailureText message:nil preferredStyle:UIAlertControllerStyleActionSheet]; @@ -1465,23 +1465,29 @@ typedef enum : NSUInteger { UIAlertAction *deleteMessageAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_DELETE_TITLE", @"") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { - [self remove:message]; + [self remove:tsMessage]; }]; [actionSheet addAction:deleteMessageAction]; - // TODO TODO TODO + UIAlertAction *resendMessageAction = [UIAlertAction + actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") + accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_again") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + SNVisibleMessage *message = [SNVisibleMessage from:tsMessage]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + NSMutableArray *attachments = @[].mutableCopy; + for (NSString *attachmentID in tsMessage.attachmentIds) { + TSAttachmentStream *stream = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID transaction:transaction]; + if (![stream isKindOfClass:TSAttachmentStream.class]) { continue; } + [attachments addObject:stream]; + } + [SNMessageSender prep:attachments forMessage:message usingTransaction: transaction]; + [SNMessageSender send:message inThread:self.thread usingTransaction:transaction]; + }]; + }]; -// UIAlertAction *resendMessageAction = [UIAlertAction -// actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") -// accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_again") -// style:UIAlertActionStyleDefault -// handler:^(UIAlertAction *action) { -// [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { -// [self.messageSenderJobQueue addMessage:message transaction:transaction]; -// }]; -// }]; - -// [actionSheet addAction:resendMessageAction]; + [actionSheet addAction:resendMessageAction]; [self dismissKeyBoard]; [self presentAlert:actionSheet]; diff --git a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift index b0d343520..7b55c0c32 100644 --- a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift @@ -6,11 +6,20 @@ public final class ClosedGroupUpdate : ControlMessage { public var kind: Kind? // MARK: Kind - public enum Kind { + public enum Kind : CustomStringConvertible { case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) case info(groupPublicKey: Data, name: String, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) case senderKeyRequest(groupPublicKey: Data) case senderKey(groupPublicKey: Data, senderKey: ClosedGroupSenderKey) + + public var description: String { + switch self { + case .new: return "new" + case .info: return "info" + case .senderKeyRequest: return "senderKeyRequest" + case .senderKey: return "senderKey" + } + } } // MARK: Initialization @@ -154,6 +163,15 @@ public final class ClosedGroupUpdate : ControlMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + ClosedGroupUpdate( + kind: \(kind?.description ?? "null") + ) + """ + } } private extension ClosedGroupSenderKey { diff --git a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift index e922a54d9..7c2f221dc 100644 --- a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift @@ -56,6 +56,15 @@ public final class ExpirationTimerUpdate : ControlMessage { } } + // MARK: Description + public override var description: String { + """ + ExpirationTimerUpdate( + duration: \(duration?.description ?? "null") + ) + """ + } + // MARK: Convenience @objc public func setDuration(_ duration: UInt32) { self.duration = duration diff --git a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift index 0c5d5ecf5..5199d8980 100644 --- a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift +++ b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift @@ -54,4 +54,13 @@ public final class ReadReceipt : ControlMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + ReadReceipt( + timestamps: \(timestamps?.description ?? "null") + ) + """ + } } diff --git a/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift b/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift index a867d77b2..6d094cd62 100644 --- a/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift +++ b/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift @@ -7,7 +7,7 @@ public final class TypingIndicator : ControlMessage { public override class var ttl: UInt64 { 30 * 1000 } // MARK: Kind - public enum Kind : Int { + public enum Kind : Int, CustomStringConvertible { case started, stopped static func fromProto(_ proto: SNProtoTypingMessage.SNProtoTypingMessageAction) -> Kind { @@ -23,6 +23,13 @@ public final class TypingIndicator : ControlMessage { case .stopped: return .stopped } } + + public var description: String { + switch self { + case .started: return "started" + case .stopped: return "stopped" + } + } } // MARK: Validation @@ -72,4 +79,13 @@ public final class TypingIndicator : ControlMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + TypingIndicator( + kind: \(kind?.description ?? "null") + ) + """ + } } diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift index 5cf891342..c23e5e7ef 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift @@ -1,3 +1,4 @@ +import SessionUtilitiesKit @objc public extension TSOutgoingMessage { @@ -21,3 +22,23 @@ ) } } + +@objc public extension VisibleMessage { + + @objc(from:) + static func from(_ tsMessage: TSOutgoingMessage) -> VisibleMessage { + let result = VisibleMessage() + result.threadID = tsMessage.uniqueThreadId + result.sentTimestamp = tsMessage.timestamp + result.recipient = tsMessage.recipientIds().first + if let thread = tsMessage.thread as? TSGroupThread, thread.usesSharedSenderKeys { + let groupID = thread.groupModel.groupId + result.groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) + } + result.text = tsMessage.body + result.attachmentIDs = tsMessage.attachmentIds.compactMap { $0 as? String } + result.quote = VisibleMessage.Quote.from(tsMessage.quotedMessage) + result.linkPreview = VisibleMessage.LinkPreview.from(tsMessage.linkPreview) + return result + } +} diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift index 587c5380f..f1f4053af 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift @@ -56,5 +56,16 @@ public extension VisibleMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + LinkPreview( + title: \(title ?? "null") + url: \(url ?? "null") + attachmentID: \(attachmentID ?? "null") + ) + """ + } } } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift index 9ea0ff7e1..71bec53c3 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift @@ -57,5 +57,16 @@ public extension VisibleMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + Profile( + displayName: \(displayName ?? "null") + profileKey: \(profileKey?.description ?? "null") + profilePictureURL: \(profilePictureURL ?? "null") + ) + """ + } } } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index b096b7192..d2ad216e9 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -66,8 +66,9 @@ public extension VisibleMessage { guard let stream = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction), stream.isUploaded else { #if DEBUG preconditionFailure("Sending a message before all associated attachments have been uploaded.") - #endif + #else return + #endif } let quotedAttachmentProto = SNProtoDataMessageQuoteQuotedAttachment.builder() quotedAttachmentProto.setContentType(stream.contentType) @@ -82,5 +83,17 @@ public extension VisibleMessage { SNLog("Couldn't construct quoted attachment proto from: \(self).") } } + + // MARK: Description + public override var description: String { + """ + Quote( + timestamp: \(timestamp?.description ?? "null") + publicKey: \(publicKey ?? "null") + text: \(text ?? "null") + attachmentID: \(attachmentID ?? "null") + ) + """ + } } } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 6b05102df..a25735ce2 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -99,4 +99,18 @@ public final class VisibleMessage : Message { return nil } } + + // MARK: Description + public override var description: String { + """ + VisibleMessage( + text: \(text ?? "null") + attachmentIDs: \(attachmentIDs) + quote: \(quote?.description ?? "null") + linkPreview: \(linkPreview?.description ?? "null") + contact: \(contact?.description ?? "null") + profile: \(profile?.description ?? "null") + ) + """ + } } diff --git a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift index 59f3f15f6..5bb5c3c7f 100644 --- a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift @@ -9,6 +9,11 @@ extension OWSLinkPreview { extension VisibleMessage.LinkPreview { + public static func from(_ linkPreview: OWSLinkPreview?) -> VisibleMessage.LinkPreview? { + guard let linkPreview = linkPreview else { return nil } + return VisibleMessage.LinkPreview(title: linkPreview.title, url: linkPreview.urlString!, attachmentID: linkPreview.imageAttachmentId) + } + @objc(from:using:) public static func from(_ linkPreview: OWSLinkPreviewDraft?, using transaction: YapDatabaseReadWriteTransaction) -> VisibleMessage.LinkPreview? { guard let linkPreview = linkPreview else { return nil } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 063075333..2e43bb6c8 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -59,6 +59,19 @@ public final class MessageSender : NSObject { attachment.write($0.dataSource) attachment.save(with: transaction) } + prep(attachments, for: message, using: transaction) + } + + @objc(prep:forMessage:usingTransaction:) + public static func prep(_ attachmentStreams: [TSAttachmentStream], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { + #if DEBUG + preconditionFailure() + #else + return + #endif + } + var attachments = attachmentStreams // The line below locally generates a thumbnail for the quoted attachment. It just needs to happen at some point during the // message sending process. tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) @@ -71,6 +84,7 @@ public final class MessageSender : NSObject { // Anything added to message.attachmentIDs will be uploaded by an UploadAttachmentJob. Any attachment IDs added to tsMessage will // make it render as an attachment (not what we want in the case of a link preview or quoted attachment). message.attachmentIDs = attachments.map { $0.uniqueId! } + tsMessage.attachmentIds.removeAllObjects() tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) if let id = linkPreviewAttachmentID { tsMessage.attachmentIds.remove(id) } tsMessage.save(with: transaction) @@ -109,7 +123,9 @@ public final class MessageSender : NSObject { func handleFailure(with error: Swift.Error, using transaction: YapDatabaseReadWriteTransaction) { MessageSender.handleFailedMessageSend(message, with: error, using: transaction) if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { - NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) + DispatchQueue.main.async { + NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) + } } seal.reject(error) } @@ -217,7 +233,9 @@ public final class MessageSender : NSObject { guard !isSuccess else { return } // Succeed as soon as the first promise succeeds isSuccess = true if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { - NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) + DispatchQueue.main.async { + NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) + } } storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift index 377317376..9cdf974d1 100644 --- a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift @@ -16,3 +16,16 @@ extension TSQuotedMessage { ) } } + +extension VisibleMessage.Quote { + + public static func from(_ quote: TSQuotedMessage?) -> VisibleMessage.Quote? { + guard let quote = quote else { return nil } + let result = VisibleMessage.Quote() + result.timestamp = quote.timestamp + result.publicKey = quote.authorId + result.text = quote.body + result.attachmentID = quote.quotedAttachments.first?.attachmentId + return result + } +} diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift index fb79c5f34..bb7279306 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift @@ -22,6 +22,11 @@ extension MessageSender { return AnyPromise.from(sendNonDurably(message, with: attachments, in: thread, using: transaction)) } + @objc(sendNonDurably:withAttachmentIDs:inThread:usingTransaction:) + public static func objc_sendNonDurably(_ message: VisibleMessage, with attachmentIDs: [String], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(sendNonDurably(message, with: attachmentIDs, in: thread, using: transaction)) + } + @objc(sendNonDurably:inThread:usingTransaction:) public static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) @@ -29,7 +34,11 @@ extension MessageSender { public static func sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { prep(attachments, for: message, using: transaction) - let attachments = message.attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } + return sendNonDurably(message, with: message.attachmentIDs, in: thread, using: transaction) + } + + public static func sendNonDurably(_ message: VisibleMessage, with attachmentIDs: [String], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } let attachmentsToUpload = attachments.filter { !$0.isUploaded } let attachmentUploadPromises: [Promise] = attachmentsToUpload.map { stream in let openGroup = SNMessagingKitConfiguration.shared.storage.getOpenGroup(for: thread.uniqueId!) diff --git a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index a30c44d9c..ea8332eb6 100644 --- a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -414,10 +414,10 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); }); } -- (void)resendMessage:(TSOutgoingMessage *)message fromViewController:(UIViewController *)fromViewController +- (void)resendMessage:(TSOutgoingMessage *)tsMessage fromViewController:(UIViewController *)fromViewController { OWSAssertIsOnMainThread(); - OWSAssertDebug(message); + OWSAssertDebug(tsMessage); OWSAssertDebug(fromViewController); NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title"); @@ -434,29 +434,26 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); [fromViewController presentAlert:progressAlert - completion:^{ - - // TODO TODO TODO - -// [self.messageSender sendMessage:message -// success:^{ -// OWSLogInfo(@"Resending attachment succeeded."); -// dispatch_async(dispatch_get_main_queue(), ^{ -// [self.shareViewDelegate shareViewWasCompleted]; -// }); -// } -// failure:^(NSError *error) { -// dispatch_async(dispatch_get_main_queue(), ^{ -// [fromViewController -// dismissViewControllerAnimated:YES -// completion:^{ -// OWSLogInfo(@"Sending attachment failed with error: %@", error); -// [self showSendFailureAlertWithError:error -// message:message -// fromViewController:fromViewController]; -// }]; -// }); -// }]; + completion:^{ + SNVisibleMessage *message = [SNVisibleMessage from:tsMessage]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + NSMutableArray *attachments = @[].mutableCopy; + for (NSString *attachmentID in tsMessage.attachmentIds) { + TSAttachmentStream *stream = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID transaction:transaction]; + if (![stream isKindOfClass:TSAttachmentStream.class]) { continue; } + [attachments addObject:stream]; + } + [SNMessageSender prep:attachments forMessage:message usingTransaction: transaction]; + [SNMessageSender sendNonDurably:message withAttachmentIDs:tsMessage.attachmentIds inThread:self.thread usingTransaction:transaction] + .thenOn(dispatch_get_main_queue(), ^() { + [self.shareViewDelegate shareViewWasCompleted]; + }) + .catchOn(dispatch_get_main_queue(), ^(NSError *error) { + [fromViewController dismissViewControllerAnimated:YES completion:^{ + [self showSendFailureAlertWithError:error message:tsMessage fromViewController:fromViewController]; + }]; + }); + }]; }]; } From efe8f1c8bbd0d6b4c8ff3caacae05a4b7d315cbe Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 16:00:21 +1100 Subject: [PATCH 123/177] Clean --- .../Database/Storage+Shared.swift | 22 ++++++++++--------- .../Jobs/AttachmentDownloadJob.swift | 8 +++---- .../Jobs/AttachmentUploadJob.swift | 4 ++-- SessionMessagingKit/Jobs/JobQueue.swift | 10 ++++----- .../Jobs/MessageReceiveJob.swift | 2 +- SessionMessagingKit/Jobs/MessageSendJob.swift | 4 ++-- .../Unused/SessionRequest.swift | 2 +- .../Open Groups/OpenGroupAPI.swift | 15 +++++++------ .../MessageSender+ClosedGroups.swift | 4 +++- .../Sending & Receiving/MessageSender.swift | 12 +++++----- .../Pollers/ClosedGroupPoller.swift | 2 +- .../Pollers/OpenGroupPoller.swift | 6 ++--- .../Sending & Receiving/Pollers/Poller.swift | 2 +- .../Typing Indicators/TypingIndicators.swift | 4 ++-- SessionMessagingKit/Storage.swift | 8 +++++-- SessionMessagingKit/Utilities/DotNetAPI.swift | 2 +- SessionProtocolKit/Storage.swift | 2 +- SessionSnodeKit/OnionRequestAPI.swift | 6 ++--- SessionSnodeKit/SnodeAPI.swift | 20 ++++++++--------- SessionSnodeKit/Storage.swift | 5 ++++- 20 files changed, 76 insertions(+), 64 deletions(-) diff --git a/SessionMessagingKit/Database/Storage+Shared.swift b/SessionMessagingKit/Database/Storage+Shared.swift index 426ffd500..4ceec0b9a 100644 --- a/SessionMessagingKit/Database/Storage+Shared.swift +++ b/SessionMessagingKit/Database/Storage+Shared.swift @@ -1,17 +1,19 @@ - -// TODO: Since we now have YapDatabase as a dependency in all modules we can work with YapDatabaseTransactions directly -// rather than passing transactions around as Any everywhere. +import PromiseKit extension Storage { - // TODO: This is essentially a duplicate of Storage.writeSync - public func with(_ work: @escaping (Any) -> Void) { - Storage.writeSync { work($0) } + @discardableResult + public func write(with block: @escaping (Any) -> Void) -> Promise { + Storage.write(with: { block($0) }) } - - // TODO: This is essentially a duplicate of Storage.write - public func withAsync(_ work: @escaping (Any) -> Void, completion: @escaping () -> Void) { - Storage.write(with: { work($0) }, completion: completion) + + @discardableResult + public func write(with block: @escaping (Any) -> Void, completion: @escaping () -> Void) -> Promise { + Storage.write(with: { block($0) }, completion: completion) + } + + public func writeSync(with block: @escaping (Any) -> Void) { + Storage.writeSync { block($0) } } @objc public func getUserPublicKey() -> String? { diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 00e228b69..b8cadf59b 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -53,21 +53,21 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject return handleFailure(error: Error.noAttachment) } let storage = SNMessagingKitConfiguration.shared.storage - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.setAttachmentState(to: .downloading, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) }, completion: { }) let temporaryFilePath = URL(fileURLWithPath: OWSTemporaryDirectoryAccessibleAfterFirstAuth() + UUID().uuidString) let handleFailure: (Swift.Error) -> Void = { error in // Intentionally capture self OWSFileSystem.deleteFile(temporaryFilePath.absoluteString) if let error = error as? Error, case .noAttachment = error { - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) }, completion: { }) self.handlePermanentFailure(error: error) } else if let error = error as? DotNetAPI.Error, case .parsingFailed = error { // No need to retry if the response is invalid. Most likely this means we (incorrectly) // got a "Cannot GET ..." error from the file server. - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsIncomingMessageID, using: transaction) }, completion: { }) self.handlePermanentFailure(error: error) @@ -98,7 +98,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject return handleFailure(error) } OWSFileSystem.deleteFile(temporaryFilePath.absoluteString) - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.persist(stream, associatedWith: self.tsIncomingMessageID, using: transaction) }, completion: { }) }.catch(on: DispatchQueue.global()) { error in diff --git a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift index eaaf357a7..0c47d1705 100644 --- a/SessionMessagingKit/Jobs/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentUploadJob.swift @@ -81,7 +81,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N SNLog("Attachment uploaded successfully.") delegate?.handleJobSucceeded(self) SNMessagingKitConfiguration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID) - Storage.shared.withAsync({ transaction in + Storage.shared.write(with: { transaction in var interaction: TSInteraction? let transaction = transaction as! YapDatabaseReadWriteTransaction TSDatabaseSecondaryIndexes.enumerateMessages(withTimestamp: self.message.sentTimestamp!, with: { _, key, _ in @@ -108,7 +108,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N private func failAssociatedMessageSendJob(with error: Swift.Error) { let storage = SNMessagingKitConfiguration.shared.storage let messageSendJob = storage.getMessageSendJob(for: messageSendJobID) - storage.withAsync({ transaction in // Intentionally capture self + storage.write(with: { transaction in // Intentionally capture self MessageSender.handleFailedMessageSend(self.message, with: error, using: transaction) if let messageSendJob = messageSendJob { storage.markJobAsFailed(messageSendJob, using: transaction) diff --git a/SessionMessagingKit/Jobs/JobQueue.swift b/SessionMessagingKit/Jobs/JobQueue.swift index 6b4b8903b..0e1285245 100644 --- a/SessionMessagingKit/Jobs/JobQueue.swift +++ b/SessionMessagingKit/Jobs/JobQueue.swift @@ -39,7 +39,7 @@ public final class JobQueue : NSObject, JobDelegate { } public func handleJobSucceeded(_ job: Job) { - SNMessagingKitConfiguration.shared.storage.withAsync({ transaction in + SNMessagingKitConfiguration.shared.storage.write(with: { transaction in SNMessagingKitConfiguration.shared.storage.markJobAsSucceeded(job, using: transaction) }, completion: { // Do nothing @@ -50,11 +50,11 @@ public final class JobQueue : NSObject, JobDelegate { job.failureCount += 1 let storage = SNMessagingKitConfiguration.shared.storage guard !storage.isJobCanceled(job) else { return SNLog("\(type(of: job)) canceled.") } - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.persist(job, using: transaction) }, completion: { // Intentionally capture self if job.failureCount == type(of: job).maxFailureCount { - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.markJobAsFailed(job, using: transaction) }, completion: { // Do nothing @@ -70,10 +70,10 @@ public final class JobQueue : NSObject, JobDelegate { public func handleJobFailedPermanently(_ job: Job, with error: Error) { job.failureCount += 1 let storage = SNMessagingKitConfiguration.shared.storage - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.persist(job, using: transaction) }, completion: { // Intentionally capture self - storage.withAsync({ transaction in + storage.write(with: { transaction in storage.markJobAsFailed(job, using: transaction) }, completion: { // Do nothing diff --git a/SessionMessagingKit/Jobs/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/MessageReceiveJob.swift index b8895d12f..8e3782a2b 100644 --- a/SessionMessagingKit/Jobs/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/MessageReceiveJob.swift @@ -55,7 +55,7 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC public func execute() -> Promise { let (promise, seal) = Promise.pending() - SNMessagingKitConfiguration.shared.storage.withAsync({ transaction in // Intentionally capture self + SNMessagingKitConfiguration.shared.storage.write(with: { transaction in // Intentionally capture self do { let (message, proto) = try MessageReceiver.parse(self.data, openGroupMessageServerID: self.openGroupMessageServerID, using: transaction) try MessageReceiver.handle(message, associatedWithProto: proto, openGroupID: self.openGroupID, isBackgroundPoll: self.isBackgroundPoll, using: transaction) diff --git a/SessionMessagingKit/Jobs/MessageSendJob.swift b/SessionMessagingKit/Jobs/MessageSendJob.swift index 33beadd79..f04fde3d4 100644 --- a/SessionMessagingKit/Jobs/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/MessageSendJob.swift @@ -71,14 +71,14 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi // Wait for it to finish } else { let job = AttachmentUploadJob(attachmentID: attachment.uniqueId!, threadID: message.threadID!, message: message, messageSendJobID: id!) - storage.withAsync({ transaction in + storage.write(with: { transaction in JobQueue.shared.add(job, using: transaction) }, completion: { }) } } if !attachmentsToUpload.isEmpty { return } // Wait for all attachments to upload before continuing } - storage.withAsync({ transaction in // Intentionally capture self + storage.write(with: { transaction in // Intentionally capture self MessageSender.send(self.message, to: self.destination, using: transaction).done(on: DispatchQueue.global(qos: .userInitiated)) { self.handleSuccess() }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in diff --git a/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift b/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift index e65fb237e..1d57a891d 100644 --- a/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift +++ b/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift @@ -34,7 +34,7 @@ public final class SessionRequest : ControlMessage { public override class func fromProto(_ proto: SNProtoContent) -> SessionRequest? { guard proto.nullMessage != nil, let preKeyBundleProto = proto.prekeyBundleMessage else { return nil } var registrationID: UInt32 = 0 - SNMessagingKitConfiguration.shared.storage.with { transaction in + SNMessagingKitConfiguration.shared.storage.writeSync { transaction in registrationID = SNMessagingKitConfiguration.shared.storage.getOrGenerateRegistrationID(using: transaction) } guard let preKeyBundle = PreKeyBundle( diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 3a509477a..714cbdddc 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -27,7 +27,7 @@ public final class OpenGroupAPI : DotNetAPI { let url = URL(string: server)! let request = TSRequest(url: url) return OnionRequestAPI.sendOnionRequest(request, to: server, using: publicKey, isJSONRequired: false).map(on: DispatchQueue.global(qos: .default)) { _ -> String in - SNMessagingKitConfiguration.shared.storage.with { transaction in + SNMessagingKitConfiguration.shared.storage.writeSync { transaction in SNMessagingKitConfiguration.shared.storage.setOpenGroupPublicKey(for: server, to: publicKey, using: transaction) } return publicKey @@ -81,7 +81,7 @@ public final class OpenGroupAPI : DotNetAPI { } let lastMessageServerID = storage.getLastMessageServerID(for: channel, on: server) if serverID > (lastMessageServerID ?? 0) { - storage.with { transaction in + storage.writeSync { transaction in storage.setLastMessageServerID(for: channel, on: server, to: serverID, using: transaction) } } @@ -205,7 +205,7 @@ public final class OpenGroupAPI : DotNetAPI { } let lastDeletionServerID = storage.getLastDeletionServerID(for: channel, on: server) if serverID > (lastDeletionServerID ?? 0) { - storage.with { transaction in + storage.writeSync { transaction in storage.setLastDeletionServerID(for: channel, on: server, to: serverID, using: transaction) } } @@ -256,7 +256,7 @@ public final class OpenGroupAPI : DotNetAPI { throw Error.parsingFailed } let storage = SNMessagingKitConfiguration.shared.storage - storage.with { transaction in + storage.writeSync { transaction in data.forEach { data in guard let user = data["user"] as? JSON, let hexEncodedPublicKey = user["username"] as? String, let rawDisplayName = user["name"] as? String else { return } let endIndex = hexEncodedPublicKey.endIndex @@ -346,7 +346,7 @@ public final class OpenGroupAPI : DotNetAPI { throw Error.parsingFailed } let storage = SNMessagingKitConfiguration.shared.storage - storage.with { transaction in + storage.writeSync { transaction in storage.setUserCount(to: memberCount, forOpenGroupWithID: "\(server).\(channel)", using: transaction) } let openGroupInfo = OpenGroupInfo(displayName: displayName, profilePictureURL: profilePictureURL, memberCount: memberCount) @@ -360,7 +360,8 @@ public final class OpenGroupAPI : DotNetAPI { public static func updateProfileIfNeeded(for channel: UInt64, on server: String, from info: OpenGroupInfo) { let openGroupID = "\(server).\(channel)" - Storage.write { transaction in + SNMessagingKitConfiguration.shared.storage.write { transaction in + let transaction = transaction as! YapDatabaseReadWriteTransaction // Update user count Storage.shared.setUserCount(to: info.memberCount, forOpenGroupWithID: openGroupID, using: transaction) let thread = TSGroupThread.getOrCreateThread(withGroupId: openGroupID.data(using: .utf8)!, groupType: .openGroup, transaction: transaction) @@ -474,7 +475,7 @@ internal extension Promise { if case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, _) = error, statusCode == 401 || statusCode == 403 { SNLog("Auth token for: \(server) expired; dropping it.") let storage = SNMessagingKitConfiguration.shared.storage - storage.with { transaction in + storage.writeSync { transaction in storage.removeAuthToken(for: server, using: transaction) } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift index 4ef0698fb..ad4aca5da 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift @@ -89,7 +89,7 @@ extension MessageSender : SharedSenderKeysDelegate { } when(resolved: promises).done2 { _ in seal.fulfill(()) }.catch2 { seal.reject($0) } let _ = promise.done { - Storage.writeSync { transaction in + SNMessagingKitConfiguration.shared.storage.writeSync { transaction in let allOldRatchets = Storage.shared.getAllClosedGroupRatchets(for: groupPublicKey) for (senderPublicKey, oldRatchet) in allOldRatchets { let collection = ClosedGroupRatchetCollectionType.old @@ -106,6 +106,7 @@ extension MessageSender : SharedSenderKeysDelegate { } else { // Send closed group update messages to any new members using established channels for member in newMembers { + let transaction = transaction as! YapDatabaseReadWriteTransaction let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) let closedGroupUpdateKind = ClosedGroupUpdate.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, @@ -118,6 +119,7 @@ extension MessageSender : SharedSenderKeysDelegate { let userRatchet = SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) for member in members { + let transaction = transaction as! YapDatabaseReadWriteTransaction guard member != userPublicKey else { continue } let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 2e43bb6c8..612c06ff2 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -133,7 +133,7 @@ public final class MessageSender : NSObject { guard message.isValid else { handleFailure(with: Error.invalidMessage, using: transaction); return promise } // Stop here if this is a self-send guard !isSelfSend else { - storage.withAsync({ transaction in + storage.write(with: { transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) seal.fulfill(()) }, completion: { }) @@ -237,7 +237,7 @@ public final class MessageSender : NSObject { NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) } } - storage.withAsync({ transaction in + storage.write(with: { transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) var shouldNotify = (message is VisibleMessage) if let closedGroupUpdate = message as? ClosedGroupUpdate, case .new = closedGroupUpdate.kind { @@ -262,14 +262,14 @@ public final class MessageSender : NSObject { $0.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in errorCount += 1 guard errorCount == promiseCount else { return } // Only error out if all promises failed - storage.withAsync({ transaction in + storage.write(with: { transaction in handleFailure(with: error, using: transaction as! YapDatabaseReadWriteTransaction) }, completion: { }) } } }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in SNLog("Couldn't send message due to error: \(error).") - storage.withAsync({ transaction in + storage.write(with: { transaction in handleFailure(with: error, using: transaction as! YapDatabaseReadWriteTransaction) }, completion: { }) } @@ -322,12 +322,12 @@ public final class MessageSender : NSObject { // Send the result OpenGroupAPI.sendMessage(openGroupMessage, to: channel, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = openGroupMessage.serverID - storage.withAsync({ transaction in + storage.write(with: { transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) seal.fulfill(()) }, completion: { }) }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in - storage.withAsync({ transaction in + storage.write(with: { transaction in handleFailure(with: error, using: transaction as! YapDatabaseReadWriteTransaction) }, completion: { }) } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift index 4b339dd7c..0b9ee4a0f 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift @@ -68,7 +68,7 @@ public final class ClosedGroupPoller : NSObject { do { let data = try envelope.serializedData() let job = MessageReceiveJob(data: data, isBackgroundPoll: false) - Storage.write { transaction in + SNMessagingKitConfiguration.shared.storage.write { transaction in SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } } catch { diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 429f9b127..79486d488 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -167,7 +167,7 @@ public final class OpenGroupPoller : NSObject { envelope.setSourceDevice(1) envelope.setContent(try! content.build().serializedData()) envelope.setServerTimestamp(message.serverTimestamp) - Storage.write { transaction in + SNMessagingKitConfiguration.shared.storage.write { transaction in Storage.shared.setOpenGroupDisplayName(to: senderDisplayName, for: senderPublicKey, inOpenGroupWithID: openGroup.id, using: transaction) let messageServerID = message.serverID let job = MessageReceiveJob(data: try! envelope.buildSerializedData(), openGroupMessageServerID: messageServerID, openGroupID: openGroup.id, isBackgroundPoll: isBackgroundPoll) @@ -193,9 +193,9 @@ public final class OpenGroupPoller : NSObject { let openGroup = self.openGroup let _ = OpenGroupAPI.getDeletedMessageServerIDs(for: openGroup.channel, on: openGroup.server).done(on: DispatchQueue.global(qos: .default)) { deletedMessageServerIDs in let deletedMessageIDs = deletedMessageServerIDs.compactMap { Storage.shared.getIDForMessage(withServerID: UInt64($0)) } - Storage.writeSync { transaction in + SNMessagingKitConfiguration.shared.storage.writeSync { transaction in deletedMessageIDs.forEach { messageID in - TSMessage.fetch(uniqueId: String(messageID))?.remove(with: transaction) + TSMessage.fetch(uniqueId: String(messageID))?.remove(with: transaction as! YapDatabaseReadWriteTransaction) } } } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift index f182c744e..dc0a2610c 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift @@ -98,7 +98,7 @@ public final class Poller : NSObject { do { let data = try envelope.serializedData() let job = MessageReceiveJob(data: data, isBackgroundPoll: false) - Storage.write { transaction in + SNMessagingKitConfiguration.shared.storage.write { transaction in SessionMessagingKit.JobQueue.shared.add(job, using: transaction) } } catch { diff --git a/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift index 5894c3b33..8333f1763 100644 --- a/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift +++ b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift @@ -272,8 +272,8 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { let typingIndicator = TypingIndicator() typingIndicator.kind = action - Storage.write { transaction in - MessageSender.send(typingIndicator, in: thread, using: transaction) + SNMessagingKitConfiguration.shared.storage.write { transaction in + MessageSender.send(typingIndicator, in: thread, using: transaction as! YapDatabaseReadWriteTransaction) } } } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 1ebeac99c..0a0ad7b2d 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -1,11 +1,15 @@ import SessionProtocolKit +import PromiseKit public protocol SessionMessagingKitStorageProtocol { // MARK: - Shared - func with(_ work: @escaping (Any) -> Void) - func withAsync(_ work: @escaping (Any) -> Void, completion: @escaping () -> Void) + @discardableResult + func write(with block: @escaping (Any) -> Void) -> Promise + @discardableResult + func write(with block: @escaping (Any) -> Void, completion: @escaping () -> Void) -> Promise + func writeSync(with block: @escaping (Any) -> Void) // MARK: - General diff --git a/SessionMessagingKit/Utilities/DotNetAPI.swift b/SessionMessagingKit/Utilities/DotNetAPI.swift index 47b5c286c..e3f154071 100644 --- a/SessionMessagingKit/Utilities/DotNetAPI.swift +++ b/SessionMessagingKit/Utilities/DotNetAPI.swift @@ -94,7 +94,7 @@ public class DotNetAPI : NSObject { return Promise.value(token) } else { return requestNewAuthToken(for: server).then(on: DispatchQueue.global(qos: .userInitiated)) { submitAuthToken($0, for: server) }.map(on: DispatchQueue.global(qos: .userInitiated)) { token in - storage.with { transaction in + storage.writeSync { transaction in storage.setAuthToken(for: server, to: token, using: transaction) } return token diff --git a/SessionProtocolKit/Storage.swift b/SessionProtocolKit/Storage.swift index b61c5bdb1..1b13064ae 100644 --- a/SessionProtocolKit/Storage.swift +++ b/SessionProtocolKit/Storage.swift @@ -5,7 +5,7 @@ public enum ClosedGroupRatchetCollectionType { public protocol SessionProtocolKitStorageProtocol { - func with(_ work: @escaping (Any) -> Void) + func writeSync(with block: @escaping (Any) -> Void) func getUserKeyPair() -> ECKeyPair? func getClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, from collection: ClosedGroupRatchetCollectionType) -> ClosedGroupRatchet? diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index 4a08a0999..ddf93b0fd 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -140,7 +140,7 @@ public enum OnionRequestAPI { } }.map2 { paths in OnionRequestAPI.paths = paths + reusablePaths - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNLog("Persisting onion request paths to database.") SNSnodeKitConfiguration.shared.storage.setOnionRequestPaths(to: paths, using: transaction) } @@ -226,7 +226,7 @@ public enum OnionRequestAPI { oldPaths.remove(at: pathIndex) let newPaths = oldPaths + [ path ] paths = newPaths - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNLog("Persisting onion request paths to database.") SNSnodeKitConfiguration.shared.storage.setOnionRequestPaths(to: newPaths, using: transaction) } @@ -241,7 +241,7 @@ public enum OnionRequestAPI { guard let pathIndex = paths.firstIndex(of: path) else { return } paths.remove(at: pathIndex) OnionRequestAPI.paths = paths - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in if !paths.isEmpty { SNLog("Persisting onion request paths to database.") SNSnodeKitConfiguration.shared.storage.setOnionRequestPaths(to: paths, using: transaction) diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index c957da688..f4527975b 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -67,7 +67,7 @@ public final class SnodeAPI : NSObject { let isSnodePoolExpired = given(Storage.shared.getLastSnodePoolRefreshDate()) { now.timeIntervalSince($0) > 24 * 60 * 60 } ?? true let isRefreshNeeded = (snodePool.count < minimumSnodePoolCount) || isSnodePoolExpired if isRefreshNeeded { - Storage.write { transaction in + SNSnodeKitConfiguration.shared.storage.write { transaction in Storage.shared.setLastSnodePoolRefreshDate(to: now, using: transaction) } let target = seedNodePool.randomElement()! @@ -104,7 +104,7 @@ public final class SnodeAPI : NSObject { } }.done2 { snode in seal.fulfill(snode) - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNLog("Persisting snode pool to database.") SNSnodeKitConfiguration.shared.storage.setSnodePool(to: SnodeAPI.snodePool, using: transaction) } @@ -129,7 +129,7 @@ public final class SnodeAPI : NSObject { var snodePool = SnodeAPI.snodePool snodePool.remove(snode) SnodeAPI.snodePool = snodePool - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNSnodeKitConfiguration.shared.storage.setSnodePool(to: snodePool, using: transaction) } } @@ -137,7 +137,7 @@ public final class SnodeAPI : NSObject { // MARK: Public API @objc public static func clearSnodePool() { snodePool.removeAll() - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNSnodeKitConfiguration.shared.storage.setSnodePool(to: [], using: transaction) } } @@ -150,7 +150,7 @@ public final class SnodeAPI : NSObject { if var swarm = swarm, let index = swarm.firstIndex(of: snode) { swarm.remove(at: index) SnodeAPI.swarmCache[publicKey] = swarm - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNSnodeKitConfiguration.shared.storage.setSwarm(to: swarm, for: publicKey, using: transaction) } } @@ -177,7 +177,7 @@ public final class SnodeAPI : NSObject { }.map2 { rawSnodes in let swarm = parseSnodes(from: rawSnodes) swarmCache[publicKey] = swarm - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNSnodeKitConfiguration.shared.storage.setSwarm(to: swarm, for: publicKey, using: transaction) } return swarm @@ -187,7 +187,7 @@ public final class SnodeAPI : NSObject { public static func getRawMessages(from snode: Snode, associatedWith publicKey: String) -> RawResponsePromise { let storage = SNSnodeKitConfiguration.shared.storage - storage.with { transaction in + storage.writeSync { transaction in storage.pruneLastMessageHashInfoIfExpired(for: snode, associatedWith: publicKey, using: transaction) } let lastHash = storage.getLastMessageHash(for: snode, associatedWith: publicKey) ?? "" @@ -201,7 +201,7 @@ public final class SnodeAPI : NSObject { Threading.workQueue.async { attempt(maxRetryCount: maxRetryCount, recoveringOn: Threading.workQueue) { getTargetSnodes(for: publicKey).mapValues2 { targetSnode in - storage.with { transaction in + storage.writeSync { transaction in storage.pruneLastMessageHashInfoIfExpired(for: targetSnode, associatedWith: publicKey, using: transaction) } let lastHash = storage.getLastMessageHash(for: targetSnode, associatedWith: publicKey) ?? "" @@ -267,7 +267,7 @@ public final class SnodeAPI : NSObject { private static func updateLastMessageHashValueIfPossible(for snode: Snode, associatedWith publicKey: String, from rawMessages: [JSON]) { if let lastMessage = rawMessages.last, let lastHash = lastMessage["hash"] as? String, let expirationDate = lastMessage["expiration"] as? UInt64 { - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNSnodeKitConfiguration.shared.storage.setLastMessageHashInfo(for: snode, associatedWith: publicKey, to: [ "hash" : lastHash, "expirationDate" : NSNumber(value: expirationDate) ], using: transaction) } @@ -285,7 +285,7 @@ public final class SnodeAPI : NSObject { } let isDuplicate = receivedMessages.contains(hash) receivedMessages.insert(hash) - SNSnodeKitConfiguration.shared.storage.with { transaction in + SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNSnodeKitConfiguration.shared.storage.setReceivedMessages(to: receivedMessages, for: publicKey, using: transaction) } return !isDuplicate diff --git a/SessionSnodeKit/Storage.swift b/SessionSnodeKit/Storage.swift index edf4334d5..878585618 100644 --- a/SessionSnodeKit/Storage.swift +++ b/SessionSnodeKit/Storage.swift @@ -1,8 +1,11 @@ import SessionUtilitiesKit +import PromiseKit public protocol SessionSnodeKitStorageProtocol { - func with(_ work: @escaping (Any) -> Void) + @discardableResult + func write(with block: @escaping (Any) -> Void) -> Promise + func writeSync(with block: @escaping (Any) -> Void) func getUserPublicKey() -> String? func getOnionRequestPaths() -> [OnionRequestAPI.Path] From 5b240da61976ca33767cf8697720c3e7e11ffc78 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 16:27:29 +1100 Subject: [PATCH 124/177] Add Session ID change notice --- Session/Utilities/KeyPairUtilities.swift | 5 +++++ Session/View Controllers/NukeDataModal.swift | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Session/Utilities/KeyPairUtilities.swift b/Session/Utilities/KeyPairUtilities.swift index d5858ea38..8a0984808 100644 --- a/Session/Utilities/KeyPairUtilities.swift +++ b/Session/Utilities/KeyPairUtilities.swift @@ -20,4 +20,9 @@ enum KeyPairUtilities { dbConnection.setObject(ed25519KeyPair.publicKey.toHexString(), forKey: LKED25519PublicKey, inCollection: collection) dbConnection.setObject(x25519KeyPair, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: collection) } + + static func hasV2KeyPair() -> Bool { + let dbConnection = OWSIdentityManager.shared().dbConnection + return (dbConnection.object(forKey: LKED25519SecretKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) != nil) + } } diff --git a/Session/View Controllers/NukeDataModal.swift b/Session/View Controllers/NukeDataModal.swift index c1b18419e..e45779346 100644 --- a/Session/View Controllers/NukeDataModal.swift +++ b/Session/View Controllers/NukeDataModal.swift @@ -49,7 +49,19 @@ final class NukeDataModal : Modal { // MARK: Interaction @objc private func nuke() { - UserDefaults.removeAll() // Not done in the nuke data implementation as unlinking requires this to happen later - NotificationCenter.default.post(name: .dataNukeRequested, object: nil) + func proceed() { + UserDefaults.removeAll() // Not done in the nuke data implementation as unlinking requires this to happen later + NotificationCenter.default.post(name: .dataNukeRequested, object: nil) + } + if KeyPairUtilities.hasV2KeyPair() { + proceed() + } else { + presentingViewController?.dismiss(animated: true, completion: nil) + let message = "We've upgraded the way Session IDs are generated, so your Session ID will be different if you choose to restore your account." + let alert = UIAlertController(title: "Are You Sure?", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in proceed() }) + alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) + presentingViewController?.present(alert, animated: true, completion: nil) + } } } From ea848393247f0fe0b22ba563f199407f9bd781c8 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 16:32:01 +1100 Subject: [PATCH 125/177] Update copy --- Session/View Controllers/NukeDataModal.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Session/View Controllers/NukeDataModal.swift b/Session/View Controllers/NukeDataModal.swift index e45779346..2ae012e10 100644 --- a/Session/View Controllers/NukeDataModal.swift +++ b/Session/View Controllers/NukeDataModal.swift @@ -57,7 +57,7 @@ final class NukeDataModal : Modal { proceed() } else { presentingViewController?.dismiss(animated: true, completion: nil) - let message = "We've upgraded the way Session IDs are generated, so your Session ID will be different if you choose to restore your account." + let message = "We’ve upgraded the way Session IDs are generated, so you will be unable to restore your current Session ID." let alert = UIAlertController(title: "Are You Sure?", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in proceed() }) alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) From 1d9ad6c37fb2352e6190781affee17154859360b Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 08:49:34 +1100 Subject: [PATCH 126/177] Fix captions --- Session/Signal/ConversationView/ConversationViewController.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index e0560412d..be2b1fe3f 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3145,6 +3145,7 @@ typedef enum : NSUInteger { } } SNVisibleMessage *message = [SNVisibleMessage new]; + message.text = messageText; message.sentTimestamp = [NSDate millisecondTimestamp]; TSThread *thread = self.thread; TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; From 36415d4c94b455feed798554ebe3de496fdcf992 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 08:50:28 +1100 Subject: [PATCH 127/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 9c646f622..7a2e1c1aa 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 145; + CURRENT_PROJECT_VERSION = 146; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 145; + CURRENT_PROJECT_VERSION = 146; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 145; + CURRENT_PROJECT_VERSION = 146; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 145; + CURRENT_PROJECT_VERSION = 146; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 145; + CURRENT_PROJECT_VERSION = 146; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 145; + CURRENT_PROJECT_VERSION = 146; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 97325840e97dfe4a9ec23d171e8248be753fb939 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 10:33:53 +1100 Subject: [PATCH 128/177] Guard against invalid open group server URLs --- SessionMessagingKit/File Server/FileServerAPI.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/File Server/FileServerAPI.swift b/SessionMessagingKit/File Server/FileServerAPI.swift index b0b8d2a0e..3852ffeaa 100644 --- a/SessionMessagingKit/File Server/FileServerAPI.swift +++ b/SessionMessagingKit/File Server/FileServerAPI.swift @@ -56,7 +56,8 @@ public final class FileServerAPI : DotNetAPI { // MARK: Open Group Server Public Key public static func getPublicKey(for openGroupServer: String) -> Promise { - let url = URL(string: "\(server)/loki/v1/getOpenGroupKey/\(URL(string: openGroupServer)!.host!)")! + guard let host = URL(string: openGroupServer)?.host, + let url = URL(string: "\(server)/loki/v1/getOpenGroupKey/\(host)") else { return Promise(error: DotNetAPI.Error.invalidURL) } let request = TSRequest(url: url) let token = "loki" // Tokenless request; use a dummy token request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ] From 5e3e755c477ff3f746c6a9024bbdf91584c58c78 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 10:49:29 +1100 Subject: [PATCH 129/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7a2e1c1aa..5f0e8fc44 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 146; + CURRENT_PROJECT_VERSION = 147; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 146; + CURRENT_PROJECT_VERSION = 147; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 146; + CURRENT_PROJECT_VERSION = 147; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 146; + CURRENT_PROJECT_VERSION = 147; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 146; + CURRENT_PROJECT_VERSION = 147; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 146; + CURRENT_PROJECT_VERSION = 147; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From f504965dfa99b02c4e187c13ad16cbaaeef11ff3 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 13:17:02 +1100 Subject: [PATCH 130/177] Set group context Android needs this --- .../Control Messages/ClosedGroupUpdate.swift | 4 +++- .../Control Messages/ExpirationTimerUpdate.swift | 9 ++++++++- .../Messages/Control Messages/ReadReceipt.swift | 2 +- .../Messages/Control Messages/TypingIndicator.swift | 2 +- .../Control Messages/Unused/NullMessage.swift | 2 +- .../Control Messages/Unused/SessionRequest.swift | 2 +- SessionMessagingKit/Messages/Message.swift | 11 +++++++++-- .../Messages/Visible Messages/VisibleMessage.swift | 13 ++++++++----- .../Sending & Receiving/MessageSender.swift | 8 +------- 9 files changed, 33 insertions(+), 20 deletions(-) diff --git a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift index 7b55c0c32..2e2bc18f9 100644 --- a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift @@ -126,7 +126,7 @@ public final class ClosedGroupUpdate : ControlMessage { return ClosedGroupUpdate(kind: kind) } - public override func toProto() -> SNProtoContent? { + public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { guard let kind = kind else { SNLog("Couldn't construct closed group update proto from: \(self).") return nil @@ -156,6 +156,8 @@ public final class ClosedGroupUpdate : ControlMessage { let contentProto = SNProtoContent.builder() let dataMessageProto = SNProtoDataMessage.builder() dataMessageProto.setClosedGroupUpdate(try closedGroupUpdate.build()) + // Group context + try setGroupContextIfNeeded(on: dataMessageProto, using: transaction) contentProto.setDataMessage(try dataMessageProto.build()) return try contentProto.build() } catch { diff --git a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift index 7c2f221dc..473259c32 100644 --- a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift @@ -38,7 +38,7 @@ public final class ExpirationTimerUpdate : ControlMessage { return ExpirationTimerUpdate(duration: duration) } - public override func toProto() -> SNProtoContent? { + public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { guard let duration = duration else { SNLog("Couldn't construct expiration timer update proto from: \(self).") return nil @@ -46,6 +46,13 @@ public final class ExpirationTimerUpdate : ControlMessage { let dataMessageProto = SNProtoDataMessage.builder() dataMessageProto.setFlags(UInt32(SNProtoDataMessage.SNProtoDataMessageFlags.expirationTimerUpdate.rawValue)) dataMessageProto.setExpireTimer(duration) + // Group context + do { + try setGroupContextIfNeeded(on: dataMessageProto, using: transaction) + } catch { + SNLog("Couldn't construct expiration timer update proto from: \(self).") + return nil + } let contentProto = SNProtoContent.builder() do { contentProto.setDataMessage(try dataMessageProto.build()) diff --git a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift index 5199d8980..cdce7ae1e 100644 --- a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift +++ b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift @@ -38,7 +38,7 @@ public final class ReadReceipt : ControlMessage { return ReadReceipt(timestamps: timestamps) } - public override func toProto() -> SNProtoContent? { + public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { guard let timestamps = timestamps else { SNLog("Couldn't construct read receipt proto from: \(self).") return nil diff --git a/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift b/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift index 6d094cd62..e09de0d5d 100644 --- a/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift +++ b/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift @@ -64,7 +64,7 @@ public final class TypingIndicator : ControlMessage { return TypingIndicator(kind: kind) } - public override func toProto() -> SNProtoContent? { + public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { guard let timestamp = sentTimestamp, let kind = kind else { SNLog("Couldn't construct typing indicator proto from: \(self).") return nil diff --git a/SessionMessagingKit/Messages/Control Messages/Unused/NullMessage.swift b/SessionMessagingKit/Messages/Control Messages/Unused/NullMessage.swift index a66b93192..488956883 100644 --- a/SessionMessagingKit/Messages/Control Messages/Unused/NullMessage.swift +++ b/SessionMessagingKit/Messages/Control Messages/Unused/NullMessage.swift @@ -22,7 +22,7 @@ public final class NullMessage : ControlMessage { return NullMessage() } - public override func toProto() -> SNProtoContent? { + public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { let nullMessageProto = SNProtoNullMessage.builder() let paddingSize = UInt.random(in: 0..<512) // random(in:) uses the system's default random generator, which is cryptographically secure let padding = Data.getSecureRandomData(ofSize: paddingSize)! diff --git a/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift b/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift index 1d57a891d..52f6e0293 100644 --- a/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift +++ b/SessionMessagingKit/Messages/Control Messages/Unused/SessionRequest.swift @@ -50,7 +50,7 @@ public final class SessionRequest : ControlMessage { return SessionRequest(preKeyBundle: preKeyBundle) } - public override func toProto() -> SNProtoContent? { + public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { guard let preKeyBundle = preKeyBundle else { SNLog("Couldn't construct session request proto from: \(self).") return nil diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index 0f04c20db..985f9ba41 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -44,8 +44,15 @@ public class Message : NSObject, NSCoding { // NSObject/NSCoding conformance is preconditionFailure("fromProto(_:) is abstract and must be overridden.") } - public func toProto() -> SNProtoContent? { - preconditionFailure("toProto() is abstract and must be overridden.") + public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { + preconditionFailure("toProto(using:) is abstract and must be overridden.") + } + + public func setGroupContextIfNeeded(on dataMessage: SNProtoDataMessage.SNProtoDataMessageBuilder, using transaction: YapDatabaseReadTransaction) throws { + guard let thread = TSThread.fetch(uniqueId: threadID!, transaction: transaction) as? TSGroupThread, thread.usesSharedSenderKeys else { return } + // Android needs a group context or it'll interpret the message as a one-to-one message + let groupProto = SNProtoGroupContext.builder(id: thread.groupModel.groupId, type: .deliver) + dataMessage.setGroup(try groupProto.build()) } // MARK: General diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index a25735ce2..522bd5169 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -54,11 +54,7 @@ public final class VisibleMessage : Message { return result } - public override func toProto() -> SNProtoContent? { - preconditionFailure("Use toProto(using:) instead.") - } - - public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { + public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { let proto = SNProtoContent.builder() var attachmentIDs = self.attachmentIDs let dataMessage: SNProtoDataMessage.SNProtoDataMessageBuilder @@ -90,6 +86,13 @@ public final class VisibleMessage : Message { let attachmentProtos = attachments.compactMap { $0.buildProto() } dataMessage.setAttachments(attachmentProtos) // TODO: Contact + // Group context + do { + try setGroupContextIfNeeded(on: dataMessage, using: transaction) + } catch { + SNLog("Couldn't construct visible message proto from: \(self).") + return nil + } // Build do { proto.setDataMessage(try dataMessage.build()) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 612c06ff2..078b19c47 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -149,13 +149,7 @@ public final class MessageSender : NSObject { } } // Convert it to protobuf - let protoOrNil: SNProtoContent? - if let message = message as? VisibleMessage { - protoOrNil = message.toProto(using: transaction) // Needed because of how TSAttachmentStream works - } else { - protoOrNil = message.toProto() - } - guard let proto = protoOrNil else { handleFailure(with: Error.protoConversionFailed, using: transaction); return promise } + guard let proto = message.toProto(using: transaction) else { handleFailure(with: Error.protoConversionFailed, using: transaction); return promise } // Serialize the protobuf let plaintext: Data do { From 348c7af191ad1746c4e65e7a6f7495a8da86fd07 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 13:37:24 +1100 Subject: [PATCH 131/177] Disable legacy closed groups --- .../ConversationView/ConversationViewController.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index be2b1fe3f..9fdced163 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -561,7 +561,9 @@ typedef enum : NSUInteger { return; } - if (self.userLeftGroup) { + if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).usesSharedSenderKeys) { + self.inputToolbar.hidden = YES; + } else if (self.userLeftGroup) { self.inputToolbar.hidden = YES; // user has requested they leave the group. further sends disallowed [self dismissKeyBoard]; } else { @@ -1191,6 +1193,13 @@ typedef enum : NSUInteger { [self updateInputBarLayout]; [self ensureScrollDownButton]; + + if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).usesSharedSenderKeys) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Session" + message:@"Legacy closed groups are no longer supported. Please create a new group to continue." preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alert animated:YES completion:nil]; + } } // `viewWillDisappear` is called whenever the view *starts* to disappear, From a6b99ea17ca5c8b1939e5dad72a652a4a2011619 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 13:38:04 +1100 Subject: [PATCH 132/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 5f0e8fc44..66c7a32a2 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 147; + CURRENT_PROJECT_VERSION = 148; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 147; + CURRENT_PROJECT_VERSION = 148; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 147; + CURRENT_PROJECT_VERSION = 148; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 147; + CURRENT_PROJECT_VERSION = 148; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 147; + CURRENT_PROJECT_VERSION = 148; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 147; + CURRENT_PROJECT_VERSION = 148; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From f9201631312d364d9b3633cb029d1687d5a3047d Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 13:48:18 +1100 Subject: [PATCH 133/177] Fix migration --- Session/Signal/AppDelegate.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 6972c9232..2f9843b23 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -166,9 +166,10 @@ static NSTimeInterval launchStartedAt; [LKAppModeManager configureWithDelegate:self]; - // OWSLinkPreview is now in SessionMessagingKit, so to still be able to deserialize link previews we - // need to tell NSKeyedUnarchiver about the change. + // OWSLinkPreview and OpenGroup are now in SessionMessagingKit, so to still be able to deserialize them we + // need to tell NSKeyedUnarchiver about the changes. [NSKeyedUnarchiver setClass:OWSLinkPreview.class forClassName:@"SessionServiceKit.OWSLinkPreview"]; + [NSKeyedUnarchiver setClass:SNOpenGroup.class forClassName:@"SessionServiceKit.LKPublicChat"]; BOOL isLoggingEnabled; #ifdef DEBUG From 1ac0e14d0427407de6df8ddf708f06c8c8281d2c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 14:22:12 +1100 Subject: [PATCH 134/177] Fix typo --- .../Signal/ConversationView/ConversationViewController.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 9fdced163..3b5369e1a 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -561,7 +561,8 @@ typedef enum : NSUInteger { return; } - if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).usesSharedSenderKeys) { + if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).isOpenGroup + && !((TSGroupThread *)self.thread).usesSharedSenderKeys) { self.inputToolbar.hidden = YES; } else if (self.userLeftGroup) { self.inputToolbar.hidden = YES; // user has requested they leave the group. further sends disallowed @@ -1194,7 +1195,8 @@ typedef enum : NSUInteger { [self updateInputBarLayout]; [self ensureScrollDownButton]; - if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).usesSharedSenderKeys) { + if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).isOpenGroup + && !((TSGroupThread *)self.thread).usesSharedSenderKeys) { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Session" message:@"Legacy closed groups are no longer supported. Please create a new group to continue." preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; From d1abf0d95df5adb72852379fcca34b1c6ad547cd Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 14:23:15 +1100 Subject: [PATCH 135/177] Update build number --- Signal.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 66c7a32a2..68e72ab5f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 148; + CURRENT_PROJECT_VERSION = 149; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 148; + CURRENT_PROJECT_VERSION = 149; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; From 2fef71ffa0ce2cb0b326089d2b4293eaa7fab7db Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 14:32:05 +1100 Subject: [PATCH 136/177] Fix build number --- Signal.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 68e72ab5f..1ee070636 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 148; + CURRENT_PROJECT_VERSION = 149; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 148; + CURRENT_PROJECT_VERSION = 149; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 148; + CURRENT_PROJECT_VERSION = 149; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 148; + CURRENT_PROJECT_VERSION = 149; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 7b564021facbb53a2dd38bc570c30d480db6e80e Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 16:23:14 +1100 Subject: [PATCH 137/177] Fix migration --- Session/Signal/AppDelegate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index 2f9843b23..f02985166 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -169,7 +169,7 @@ static NSTimeInterval launchStartedAt; // OWSLinkPreview and OpenGroup are now in SessionMessagingKit, so to still be able to deserialize them we // need to tell NSKeyedUnarchiver about the changes. [NSKeyedUnarchiver setClass:OWSLinkPreview.class forClassName:@"SessionServiceKit.OWSLinkPreview"]; - [NSKeyedUnarchiver setClass:SNOpenGroup.class forClassName:@"SessionServiceKit.LKPublicChat"]; + [NSKeyedUnarchiver setClass:SNOpenGroup.class forClassName:@"LKPublicChat"]; BOOL isLoggingEnabled; #ifdef DEBUG From 0902b695d75b065a84d8e989cd044f93970a0fc1 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 8 Dec 2020 16:24:09 +1100 Subject: [PATCH 138/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 1ee070636..d86334a8f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 149; + CURRENT_PROJECT_VERSION = 150; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 149; + CURRENT_PROJECT_VERSION = 150; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 149; + CURRENT_PROJECT_VERSION = 150; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 149; + CURRENT_PROJECT_VERSION = 150; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 149; + CURRENT_PROJECT_VERSION = 150; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 149; + CURRENT_PROJECT_VERSION = 150; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From c0a5bf263ffca84b86b231a952706303ee23a7dd Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 09:59:40 +1100 Subject: [PATCH 139/177] Remove session reset from conversation settings --- .../OWSConversationSettingsViewController.m | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index 3a34330f7..9cc33cbf6 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -637,18 +637,6 @@ const CGFloat kIconViewLength = 24; // Block Conversation section. if (!isNoteToSelf && [self.thread isKindOfClass:TSContactThread.class]) { - [mainSection addItem:[OWSTableItem - itemWithCustomCellBlock:^{ - return [weakSelf - disclosureCellWithName:@"Reset Secure Session" - iconName:@"system_message_security" - accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( - OWSConversationSettingsViewController, @"reset_secure_ession")]; - } - actionBlock:^{ - [weakSelf resetSecureSession]; - }]]; - mainSection.footerTitle = NSLocalizedString( @"BLOCK_USER_BEHAVIOR_EXPLANATION", @"An explanation of the consequences of blocking another user."); @@ -1188,11 +1176,6 @@ static CGRect oldframe; [self.conversationSettingsViewDelegate conversationSettingsDidRequestConversationSearch:self]; } -- (void)resetSecureSession -{ - -} - #pragma mark - Notifications - (void)identityStateDidChange:(NSNotification *)notification From 97d0160138af33030cd615792b3932b29dc6cd23 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 10:15:59 +1100 Subject: [PATCH 140/177] Fix promise not completing --- SessionMessagingKit/Sending & Receiving/MessageSender.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 078b19c47..30aa77af3 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -249,7 +249,8 @@ public final class MessageSender : NSObject { seal.fulfill(()) // Always fulfill because the notify PN server job isn't critical. } } - + } else { + seal.fulfill(()) } }, completion: { }) } From f0f0a627ec31f193fa64e0f918527457633cfa28 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 10:25:19 +1100 Subject: [PATCH 141/177] Fix Android compatibility issue --- .../Messages/Visible Messages/VisibleMessage.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 522bd5169..2b1f62abc 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -86,6 +86,11 @@ public final class VisibleMessage : Message { let attachmentProtos = attachments.compactMap { $0.buildProto() } dataMessage.setAttachments(attachmentProtos) // TODO: Contact + // Expiration timer + // TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation + // if it receives a message without the current expiration timer value attached to it... + let expiration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction)?.durationSeconds ?? 0 + dataMessage.setExpireTimer(expiration) // Group context do { try setGroupContextIfNeeded(on: dataMessage, using: transaction) From 524abebd4cd2aacce2663e3af6f0d9f15d66e2a2 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 10:25:56 +1100 Subject: [PATCH 142/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d86334a8f..d88567ad9 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 150; + CURRENT_PROJECT_VERSION = 151; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 150; + CURRENT_PROJECT_VERSION = 151; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 150; + CURRENT_PROJECT_VERSION = 151; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 150; + CURRENT_PROJECT_VERSION = 151; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 150; + CURRENT_PROJECT_VERSION = 151; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 150; + CURRENT_PROJECT_VERSION = 151; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From bc4be99070a1cac1a010d125775195a71f59568c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 13:06:15 +1100 Subject: [PATCH 143/177] Fix Android compatibility issue --- .../Messages/Control Messages/ClosedGroupUpdate.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift index 2e2bc18f9..1a0931e51 100644 --- a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift @@ -158,6 +158,11 @@ public final class ClosedGroupUpdate : ControlMessage { dataMessageProto.setClosedGroupUpdate(try closedGroupUpdate.build()) // Group context try setGroupContextIfNeeded(on: dataMessageProto, using: transaction) + // Expiration timer + // TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation + // if it receives a message without the current expiration timer value attached to it... + let expiration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction)?.durationSeconds ?? 0 + dataMessageProto.setExpireTimer(expiration) contentProto.setDataMessage(try dataMessageProto.build()) return try contentProto.build() } catch { From 0d5e4d1e258e37306f0b7edd24b1328d2c7283c8 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 13:17:05 +1100 Subject: [PATCH 144/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d88567ad9..66afb430f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 151; + CURRENT_PROJECT_VERSION = 152; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 151; + CURRENT_PROJECT_VERSION = 152; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 151; + CURRENT_PROJECT_VERSION = 152; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 151; + CURRENT_PROJECT_VERSION = 152; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 151; + CURRENT_PROJECT_VERSION = 152; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 151; + CURRENT_PROJECT_VERSION = 152; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 3c3f1ed7b8578d69e3cb63b863c8713f5324720d Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 14:59:14 +1100 Subject: [PATCH 145/177] Disable problematic code --- SessionMessagingKit/Utilities/OWSAudioSession.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SessionMessagingKit/Utilities/OWSAudioSession.swift b/SessionMessagingKit/Utilities/OWSAudioSession.swift index 057ff15f5..eb534c60a 100644 --- a/SessionMessagingKit/Utilities/OWSAudioSession.swift +++ b/SessionMessagingKit/Utilities/OWSAudioSession.swift @@ -137,9 +137,12 @@ public class OWSAudioSession: NSObject { // Without this delay, we sometimes error when deactivating the audio session with: // Error Domain=NSOSStatusErrorDomain Code=560030580 “The operation couldn’t be completed. (OSStatus error 560030580.)” // aka "AVAudioSessionErrorCodeIsBusy" + // FIXME: The code below was causing a bug, and disabling it * seems * fine. Don't feel super confident about it though... + /* DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { self.ensureAudioSessionActivationState() } + */ } private func ensureAudioSessionActivationState() { From e2dca1efaed9f4979b768c01a3b3753b61307e05 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 15:47:48 +1100 Subject: [PATCH 146/177] Fix desktop compatibility issue --- .../Sending & Receiving/MessageSender+Encryption.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift index f3acba30d..ce582d24a 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift @@ -18,7 +18,7 @@ internal extension MessageSender { SNLog("Couldn't find user key pair.") throw Error.noUserPublicKey } - let (ivAndCiphertext, keyIndex) = try SharedSenderKeys.encrypt(plaintext, for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let (ivAndCiphertext, keyIndex) = try SharedSenderKeys.encrypt((plaintext as NSData).paddedMessageBody(), for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let encryptedMessage = ClosedGroupCiphertextMessage(_throws_withIVAndCiphertext: ivAndCiphertext, senderPublicKey: Data(hex: userPublicKey), keyIndex: UInt32(keyIndex)) // 2. ) Encrypt the result for the group's public key to hide the sender public key and key index let intermediate = try AESGCM.encrypt(encryptedMessage.serialized, for: groupPublicKey.removing05PrefixIfNeeded()) From 5f85265229ad8f09ff45d45a78d8c14b885d9895 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 16:01:57 +1100 Subject: [PATCH 147/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 66afb430f..115de1676 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 152; + CURRENT_PROJECT_VERSION = 153; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 152; + CURRENT_PROJECT_VERSION = 153; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 152; + CURRENT_PROJECT_VERSION = 153; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 152; + CURRENT_PROJECT_VERSION = 153; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 152; + CURRENT_PROJECT_VERSION = 153; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 152; + CURRENT_PROJECT_VERSION = 153; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From d3f0ed81f71fe9386dd21ef8ac5432828c9b4ef4 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 9 Dec 2020 16:14:49 +1100 Subject: [PATCH 148/177] Fix another compatibility issue --- .../Messages/Control Messages/ClosedGroupUpdate.swift | 5 ++++- .../Messages/Visible Messages/VisibleMessage.swift | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift index 1a0931e51..6b76ac2ec 100644 --- a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift @@ -161,7 +161,10 @@ public final class ClosedGroupUpdate : ControlMessage { // Expiration timer // TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation // if it receives a message without the current expiration timer value attached to it... - let expiration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction)?.durationSeconds ?? 0 + var expiration: UInt32 = 0 + if let disappearingMessagesConfiguration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction) { + expiration = disappearingMessagesConfiguration.isEnabled ? disappearingMessagesConfiguration.durationSeconds : 0 + } dataMessageProto.setExpireTimer(expiration) contentProto.setDataMessage(try dataMessageProto.build()) return try contentProto.build() diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 2b1f62abc..c2e30818f 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -89,7 +89,10 @@ public final class VisibleMessage : Message { // Expiration timer // TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation // if it receives a message without the current expiration timer value attached to it... - let expiration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction)?.durationSeconds ?? 0 + var expiration: UInt32 = 0 + if let disappearingMessagesConfiguration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction) { + expiration = disappearingMessagesConfiguration.isEnabled ? disappearingMessagesConfiguration.durationSeconds : 0 + } dataMessage.setExpireTimer(expiration) // Group context do { From 0ce74e9a8e20374f9f5db3dd997a4ca43c3881ef Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 10 Dec 2020 09:22:45 +1100 Subject: [PATCH 149/177] Fix desktop compatibility issue --- SessionMessagingKit/Utilities/DotNetAPI.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Utilities/DotNetAPI.swift b/SessionMessagingKit/Utilities/DotNetAPI.swift index e3f154071..93a2d8370 100644 --- a/SessionMessagingKit/Utilities/DotNetAPI.swift +++ b/SessionMessagingKit/Utilities/DotNetAPI.swift @@ -158,7 +158,7 @@ public class DotNetAPI : NSObject { if isEncryptionRequired { var encryptionKey = NSData() var digest = NSData() - guard let encryptedAttachmentData = Cryptography.encryptAttachmentData(unencryptedAttachmentData, shouldPad: true, outKey: &encryptionKey, outDigest: &digest) else { + guard let encryptedAttachmentData = Cryptography.encryptAttachmentData(unencryptedAttachmentData, shouldPad: false, outKey: &encryptionKey, outDigest: &digest) else { SNLog("Couldn't encrypt attachment.") return seal.reject(Error.encryptionFailed) } From f696e0e0bb8d743888f5703a7e66ed51de347e35 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 10 Dec 2020 09:23:28 +1100 Subject: [PATCH 150/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 115de1676..70fa473e6 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 153; + CURRENT_PROJECT_VERSION = 154; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 153; + CURRENT_PROJECT_VERSION = 154; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 153; + CURRENT_PROJECT_VERSION = 154; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 153; + CURRENT_PROJECT_VERSION = 154; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 153; + CURRENT_PROJECT_VERSION = 154; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 153; + CURRENT_PROJECT_VERSION = 154; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 6e9dca4b86432a5370344f578b54d087ac3db08b Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 10 Dec 2020 10:43:40 +1100 Subject: [PATCH 151/177] Update version number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 70fa473e6..7302b399a 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5687,7 +5687,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0; + MARKETING_VERSION = 1.7.0.1; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5761,7 +5761,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0; + MARKETING_VERSION = 1.7.0.1; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5815,7 +5815,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0; + MARKETING_VERSION = 1.7.0.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5890,7 +5890,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0; + MARKETING_VERSION = 1.7.0.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6921,7 +6921,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.0; + MARKETING_VERSION = 1.7.0.1; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6989,7 +6989,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.0; + MARKETING_VERSION = 1.7.0.1; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From 4cb17b388de72fa23765a9924c5425f5e52a1579 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 10 Dec 2020 10:54:21 +1100 Subject: [PATCH 152/177] Update version number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7302b399a..7b2d9ad8c 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5687,7 +5687,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0.1; + MARKETING_VERSION = 1.7.1; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5761,7 +5761,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0.1; + MARKETING_VERSION = 1.7.1; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5815,7 +5815,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0.1; + MARKETING_VERSION = 1.7.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5890,7 +5890,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.0.1; + MARKETING_VERSION = 1.7.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6921,7 +6921,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.0.1; + MARKETING_VERSION = 1.7.1; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6989,7 +6989,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.0.1; + MARKETING_VERSION = 1.7.1; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From 7ca3b73fd8635ccd18b2b3cb7207a97c0fe40173 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 14 Dec 2020 08:57:59 +1100 Subject: [PATCH 153/177] Fix crash --- SessionSnodeKit/OnionRequestAPI.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index ddf93b0fd..7713d8b8b 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -405,7 +405,7 @@ public enum OnionRequestAPI { } } promise.catch2 { error in // Must be invoked on Threading.workQueue - guard case HTTP.Error.httpRequestFailed(let statusCode, let json) = error else { return } + guard case HTTP.Error.httpRequestFailed(let statusCode, let json) = error, let guardSnode = guardSnode else { return } let path = paths.first { $0.contains(guardSnode) } func handleUnspecificError() { guard let path = path else { return } From 9ebb448b5ff860f1096f276513576a4fc724a270 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 14 Dec 2020 09:00:50 +1100 Subject: [PATCH 154/177] Fix crash --- SessionSnodeKit/OnionRequestAPI.swift | 4 ++-- SignalUtilitiesKit/To Do/OWSProfileManager.m | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index 7713d8b8b..b4d2afa61 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -349,11 +349,11 @@ public enum OnionRequestAPI { public static func sendOnionRequest(with payload: JSON, to destination: Destination, isJSONRequired: Bool = true) -> Promise { let (promise, seal) = Promise.pending() - var guardSnode: Snode! + var guardSnode: Snode? Threading.workQueue.async { // Avoid race conditions on `guardSnodes` and `paths` buildOnion(around: payload, targetedAt: destination).done2 { intermediate in guardSnode = intermediate.guardSnode - let url = "\(guardSnode.address):\(guardSnode.port)/onion_req/v2" + let url = "\(guardSnode!.address):\(guardSnode!.port)/onion_req/v2" let finalEncryptionResult = intermediate.finalEncryptionResult let onion = finalEncryptionResult.ciphertext if case Destination.server = destination, Double(onion.count) > 0.75 * Double(maxFileSize) { diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m index 79934c779..b536d429c 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -970,12 +970,16 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); result = [self profileNameForRecipientWithID:recipientID transaction:transaction]; }]; - NSString *shortID = [recipientID substringWithRange:NSMakeRange(recipientID.length - 8, 8)]; - NSString *suffix = [NSString stringWithFormat:@" (...%@)", shortID]; - if ([result hasSuffix:suffix]) { - return [result substringToIndex:result.length - suffix.length]; + if (recipientID.length > 8) { + NSString *shortID = [recipientID substringWithRange:NSMakeRange(recipientID.length - 8, 8)]; + NSString *suffix = [NSString stringWithFormat:@" (...%@)", shortID]; + if ([result hasSuffix:suffix]) { + return [result substringToIndex:result.length - suffix.length]; + } else { + return result; + } } else { - return result; + return result; // Should never occur } } else { return recipientID; From 2a4977d26953b1f62ba1e5e544388401dc7cb009 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 10 Dec 2020 16:12:22 +1100 Subject: [PATCH 155/177] Implement Session protocol --- Podfile | 1 + Podfile.lock | 2 +- .../Database/Storage+Shared.swift | 11 +++++ .../MessageReceiver+Decryption.swift | 43 +++++++++++++++++-- .../Sending & Receiving/MessageReceiver.swift | 29 ++++++++++--- .../MessageSender+Encryption.swift | 16 ++++++- .../Sending & Receiving/MessageSender.swift | 12 ++++-- SessionMessagingKit/Storage.swift | 2 + .../Utilities/Sodium+Conversion.swift | 0 SessionUtilitiesKit/String+SSK.swift | 1 + SessionUtilitiesKit/UIView+OWS.m | 1 - Signal.xcodeproj/project.pbxproj | 6 +-- 12 files changed, 106 insertions(+), 18 deletions(-) rename {Session => SessionMessagingKit}/Utilities/Sodium+Conversion.swift (100%) diff --git a/Podfile b/Podfile index 59d3020d3..40b9f4a76 100644 --- a/Podfile +++ b/Podfile @@ -71,6 +71,7 @@ target 'SessionMessagingKit' do pod 'Reachability', :inhibit_warnings => true pod 'SAMKeychain', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true + pod 'Sodium', :inhibit_warnings => true pod 'SwiftProtobuf', '~> 1.5.0', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true end diff --git a/Podfile.lock b/Podfile.lock index e843a6e1c..caf962654 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -230,6 +230,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 7699c2a380fc803ef7f51157f1f75da756aa3b45 +PODFILE CHECKSUM: 3263ab95f60e220882ca53cca4c6bdc2e7a80381 COCOAPODS: 1.10.0.rc.1 diff --git a/SessionMessagingKit/Database/Storage+Shared.swift b/SessionMessagingKit/Database/Storage+Shared.swift index 4ceec0b9a..19ee7a1a6 100644 --- a/SessionMessagingKit/Database/Storage+Shared.swift +++ b/SessionMessagingKit/Database/Storage+Shared.swift @@ -1,4 +1,5 @@ import PromiseKit +import Sodium extension Storage { @@ -23,6 +24,16 @@ extension Storage { public func getUserKeyPair() -> ECKeyPair? { return OWSIdentityManager.shared().identityKeyPair() } + + public func getUserED25519KeyPair() -> Box.KeyPair? { + let dbConnection = OWSIdentityManager.shared().dbConnection + let collection = OWSPrimaryStorageIdentityKeyStoreCollection + guard let hexEncodedPublicKey = dbConnection.object(forKey: LKED25519PublicKey, inCollection: collection) as? String, + let hexEncodedSecretKey = dbConnection.object(forKey: LKED25519SecretKey, inCollection: collection) as? String else { return nil } + let publicKey = Box.KeyPair.PublicKey(hex: hexEncodedPublicKey) + let secretKey = Box.KeyPair.SecretKey(hex: hexEncodedSecretKey) + return Box.KeyPair(publicKey: publicKey, secretKey: secretKey) + } public func getUserDisplayName() -> String? { return SSKEnvironment.shared.profileManager.localProfileName() diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift index b6d4fd744..ea502640b 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift @@ -1,6 +1,7 @@ import CryptoSwift import SessionProtocolKit import SessionUtilitiesKit +import Sodium internal extension MessageReceiver { @@ -8,7 +9,7 @@ internal extension MessageReceiver { let storage = SNMessagingKitConfiguration.shared.signalStorage let certificateValidator = SNMessagingKitConfiguration.shared.certificateValidator guard let data = envelope.content else { throw Error.noData } - guard let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { throw Error.noUserPublicKey } + guard let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { throw Error.noUserX25519KeyPair } let cipher = try SMKSecretSessionCipher(sessionResetImplementation: SNMessagingKitConfiguration.shared.sessionRestorationImplementation, sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: SNMessagingKitConfiguration.shared.identityKeyStore) let result = try cipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator, cipherTextData: data, @@ -16,6 +17,42 @@ internal extension MessageReceiver { return (result.paddedPayload, result.senderRecipientId) } + static func decryptWithSessionProtocol(envelope: SNProtoEnvelope) throws -> (plaintext: Data, senderX25519PublicKey: String) { + guard let ciphertext = envelope.content else { throw Error.noData } + let recipientX25519PrivateKey: Data + let recipientX25519PublicKey: Data + switch envelope.type { + case .unidentifiedSender: + guard let userX25519KeyPair = SNMessagingKitConfiguration.shared.storage.getUserKeyPair() else { throw Error.noUserX25519KeyPair } + recipientX25519PrivateKey = userX25519KeyPair.privateKey + recipientX25519PublicKey = Data(hex: userX25519KeyPair.hexEncodedPublicKey.removing05PrefixIfNeeded()) + case .closedGroupCiphertext: + guard let hexEncodedGroupPublicKey = envelope.source, SNMessagingKitConfiguration.shared.storage.isClosedGroup(hexEncodedGroupPublicKey) else { throw Error.invalidGroupPublicKey } + guard let hexEncodedGroupPrivateKey = SNMessagingKitConfiguration.shared.storage.getClosedGroupPrivateKey(for: hexEncodedGroupPublicKey) else { throw Error.noGroupPrivateKey } + recipientX25519PrivateKey = Data(hex: hexEncodedGroupPrivateKey) + recipientX25519PublicKey = Data(hex: hexEncodedGroupPublicKey.removing05PrefixIfNeeded()) + default: preconditionFailure() + } + let sodium = Sodium() + let signatureSize = sodium.sign.Bytes + let ed25519PublicKeySize = sodium.sign.PublicKeyBytes + + // 1. ) Decrypt the message + guard let plaintextWithMetadata = sodium.box.open(anonymousCipherText: Bytes(ciphertext), recipientPublicKey: Box.PublicKey(Bytes(recipientX25519PublicKey)), + recipientSecretKey: Bytes(recipientX25519PrivateKey)), plaintextWithMetadata.count > (signatureSize + ed25519PublicKeySize) else { throw Error.decryptionFailed } + // 2. ) Get the message parts + let signature = Bytes(plaintextWithMetadata[plaintextWithMetadata.count - signatureSize ..< plaintextWithMetadata.count]) + let senderED25519PublicKey = Bytes(plaintextWithMetadata[plaintextWithMetadata.count - (signatureSize + ed25519PublicKeySize) ..< plaintextWithMetadata.count - signatureSize]) + let plaintext = Bytes(plaintextWithMetadata[0.. (plaintext: Data, senderPublicKey: String) { // 1. ) Check preconditions guard let groupPublicKey = envelope.source, SNMessagingKitConfiguration.shared.storage.isClosedGroup(groupPublicKey) else { @@ -36,8 +73,8 @@ internal extension MessageReceiver { guard let ephemeralSharedSecret = try? Curve25519.generateSharedSecret(fromPublicKey: ephemeralPublicKey, privateKey: groupPrivateKey) else { throw Error.sharedSecretGenerationFailed } - let salt = "LOKI" - let symmetricKey = try HMAC(key: salt.bytes, variant: .sha256).authenticate(ephemeralSharedSecret.bytes) + let salt = "LOKI".data(using: String.Encoding.utf8, allowLossyConversion: true)!.bytes + let symmetricKey = try HMAC(key: salt, variant: .sha256).authenticate(ephemeralSharedSecret.bytes) let closedGroupCiphertextMessageAsData = try AESGCM.decrypt(ivAndCiphertext, with: Data(symmetricKey)) // 4. ) Parse the closed group ciphertext message let closedGroupCiphertextMessage = ClosedGroupCiphertextMessage(_throws_with: closedGroupCiphertextMessageAsData) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 780383c75..d46d9ae67 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -7,11 +7,14 @@ public enum MessageReceiver { case invalidMessage case unknownMessage case unknownEnvelopeType - case noUserPublicKey + case noUserX25519KeyPair + case noUserED25519KeyPair + case invalidSignature case noData case senderBlocked case noThread case selfSend + case decryptionFailed // Shared sender keys case invalidGroupPublicKey case noGroupPrivateKey @@ -19,7 +22,7 @@ public enum MessageReceiver { public var isRetryable: Bool { switch self { - case .duplicateMessage, .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false + case .duplicateMessage, .invalidMessage, .unknownMessage, .unknownEnvelopeType, .invalidSignature, .noData, .senderBlocked, .selfSend, .decryptionFailed: return false default: return true } } @@ -30,15 +33,18 @@ public enum MessageReceiver { case .invalidMessage: return "Invalid message." case .unknownMessage: return "Unknown message type." case .unknownEnvelopeType: return "Unknown envelope type." - case .noUserPublicKey: return "Couldn't find user key pair." + case .noUserX25519KeyPair: return "Couldn't find user X25519 key pair." + case .noUserED25519KeyPair: return "Couldn't find user ED25519 key pair." + case .invalidSignature: return "Invalid message signature." case .noData: return "Received an empty envelope." case .senderBlocked: return "Received a message from a blocked user." case .noThread: return "Couldn't find thread for message." + case .selfSend: return "Message addressed at self." + case .decryptionFailed: return "Decryption failed." // Shared sender keys case .invalidGroupPublicKey: return "Invalid group public key." case .noGroupPrivateKey: return "Missing group private key." case .sharedSecretGenerationFailed: return "Couldn't generate a shared secret." - case .selfSend: return "Message addressed at self." } } } @@ -59,9 +65,20 @@ public enum MessageReceiver { (plaintext, sender) = (envelope.content!, envelope.source!) } else { switch envelope.type { - case .unidentifiedSender: (plaintext, sender) = try decryptWithSignalProtocol(envelope: envelope, using: transaction) + case .unidentifiedSender: + do { + (plaintext, sender) = try decryptWithSessionProtocol(envelope: envelope) + } catch { + // Migration + (plaintext, sender) = try decryptWithSignalProtocol(envelope: envelope, using: transaction) + } case .closedGroupCiphertext: - (plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) + do { + (plaintext, sender) = try decryptWithSessionProtocol(envelope: envelope) + } catch { + // Migration + (plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction) + } groupPublicKey = envelope.source default: throw Error.unknownEnvelopeType } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift index ce582d24a..7138fa2e6 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift @@ -1,5 +1,6 @@ import SessionProtocolKit import SessionUtilitiesKit +import Sodium internal extension MessageSender { @@ -11,12 +12,25 @@ internal extension MessageSender { return try cipher.throwswrapped_encryptMessage(recipientPublicKey: publicKey, deviceID: 1, paddedPlaintext: (plaintext as NSData).paddedMessageBody(), senderCertificate: certificate, protocolContext: transaction, useFallbackSessionCipher: true) } + + static func encryptWithSessionProtocol(_ plaintext: Data, for recipientHexEncodedX25519PublicKey: String) throws -> Data { + guard let userED25519KeyPair = SNMessagingKitConfiguration.shared.storage.getUserED25519KeyPair() else { throw Error.noUserED25519KeyPair } + let recipientX25519PublicKey = Data(hex: recipientHexEncodedX25519PublicKey.removing05PrefixIfNeeded()) + let sodium = Sodium() + + let data = plaintext + Data(userED25519KeyPair.publicKey) + recipientX25519PublicKey + guard let signature = sodium.sign.signature(message: Bytes(data), secretKey: userED25519KeyPair.secretKey) else { throw Error.signingFailed } + guard let ciphertext = sodium.box.seal(message: Bytes(plaintext + Data(userED25519KeyPair.publicKey) + + Data(signature)), recipientPublicKey: Bytes(recipientX25519PublicKey)) else { throw Error.encryptionFailed } + + return Data(ciphertext) + } static func encryptWithSharedSenderKeys(_ plaintext: Data, for groupPublicKey: String, using transaction: Any) throws -> Data { // 1. ) Encrypt the data with the user's sender key guard let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { SNLog("Couldn't find user key pair.") - throw Error.noUserPublicKey + throw Error.noUserX25519KeyPair } let (ivAndCiphertext, keyIndex) = try SharedSenderKeys.encrypt((plaintext as NSData).paddedMessageBody(), for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let encryptedMessage = ClosedGroupCiphertextMessage(_throws_withIVAndCiphertext: ivAndCiphertext, senderPublicKey: Data(hex: userPublicKey), keyIndex: UInt32(keyIndex)) diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 30aa77af3..998d7693c 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -10,7 +10,10 @@ public final class MessageSender : NSObject { case invalidMessage case protoConversionFailed case proofOfWorkCalculationFailed - case noUserPublicKey + case noUserX25519KeyPair + case noUserED25519KeyPair + case signingFailed + case encryptionFailed // Closed groups case noThread case noPrivateKey @@ -18,7 +21,7 @@ public final class MessageSender : NSObject { internal var isRetryable: Bool { switch self { - case .invalidMessage, .protoConversionFailed, .proofOfWorkCalculationFailed, .invalidClosedGroupUpdate: return false + case .invalidMessage, .protoConversionFailed, .proofOfWorkCalculationFailed, .invalidClosedGroupUpdate, .signingFailed, .encryptionFailed: return false default: return true } } @@ -28,7 +31,10 @@ public final class MessageSender : NSObject { case .invalidMessage: return "Invalid message." case .protoConversionFailed: return "Couldn't convert message to proto." case .proofOfWorkCalculationFailed: return "Proof of work calculation failed." - case .noUserPublicKey: return "Couldn't find user key pair." + case .noUserX25519KeyPair: return "Couldn't find user X25519 key pair." + case .noUserED25519KeyPair: return "Couldn't find user ED25519 key pair." + case .signingFailed: return "Couldn't sign message." + case .encryptionFailed: return "Couldn't encrypt message." // Closed groups case .noThread: return "Couldn't find a thread associated with the given group public key." case .noPrivateKey: return "Couldn't find a private key associated with the given group public key." diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 0a0ad7b2d..590f66092 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -1,5 +1,6 @@ import SessionProtocolKit import PromiseKit +import Sodium public protocol SessionMessagingKitStorageProtocol { @@ -15,6 +16,7 @@ public protocol SessionMessagingKitStorageProtocol { func getUserPublicKey() -> String? func getUserKeyPair() -> ECKeyPair? + func getUserED25519KeyPair() -> Box.KeyPair? func getUserDisplayName() -> String? func getUserProfileKey() -> Data? func getUserProfilePictureURL() -> String? diff --git a/Session/Utilities/Sodium+Conversion.swift b/SessionMessagingKit/Utilities/Sodium+Conversion.swift similarity index 100% rename from Session/Utilities/Sodium+Conversion.swift rename to SessionMessagingKit/Utilities/Sodium+Conversion.swift diff --git a/SessionUtilitiesKit/String+SSK.swift b/SessionUtilitiesKit/String+SSK.swift index 3d13c9180..ae50abb28 100644 --- a/SessionUtilitiesKit/String+SSK.swift +++ b/SessionUtilitiesKit/String+SSK.swift @@ -5,6 +5,7 @@ import Foundation public extension String { + var digitsOnly: String { return (self as NSString).digitsOnly() } diff --git a/SessionUtilitiesKit/UIView+OWS.m b/SessionUtilitiesKit/UIView+OWS.m index d4d8ae493..aca47ba45 100644 --- a/SessionUtilitiesKit/UIView+OWS.m +++ b/SessionUtilitiesKit/UIView+OWS.m @@ -500,7 +500,6 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) - (UIView *)addBorderViewWithColor:(UIColor *)color strokeWidth:(CGFloat)strokeWidth cornerRadius:(CGFloat)cornerRadius { - UIView *borderView = [UIView new]; borderView.userInteractionEnabled = NO; borderView.backgroundColor = UIColor.clearColor; diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7b2d9ad8c..dc7d26319 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -244,6 +244,7 @@ B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8566C62256F55930045A0B9 /* OWSLinkPreview+Conversion.swift */; }; B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; B8566C7D256F62030045A0B9 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B866CE112581C1A900535CC4 /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; @@ -914,7 +915,6 @@ C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; - C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; }; C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; }; D2179CFC16BB0B3A0006F3AB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */; }; @@ -2603,7 +2603,6 @@ C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */, B84664F4235022F30083A1CD /* MentionUtilities.swift */, B886B4A82398BA1500211ABE /* QRCode.swift */, - C3E7134E251C867C009649BB /* Sodium+Conversion.swift */, B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */, B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */, C31A6C59247F214E001123EF /* UIView+Glow.swift */, @@ -3372,6 +3371,7 @@ C33FDB91255A581200E217F9 /* ProtoUtils.h */, C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */, C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, + C3E7134E251C867C009649BB /* Sodium+Conversion.swift */, C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, @@ -5253,6 +5253,7 @@ C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */, C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */, C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */, + B866CE112581C1A900535CC4 /* Sodium+Conversion.swift in Sources */, C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */, C32C5C1B256DC9E0003C73A2 /* General.swift in Sources */, C32C5A02256DB658003C73A2 /* MessageSender+Convenience.swift in Sources */, @@ -5522,7 +5523,6 @@ 34D1F0831F8678AA0066283D /* ConversationInputTextView.m in Sources */, 340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */, 4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */, - C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */, 340FC8B5204DAC8D007AEB0F /* AboutTableViewController.m in Sources */, C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */, B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */, From a46e9e3eb5b3f4a28e267c54634d54bfab60dfbd Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 14 Dec 2020 10:20:10 +1100 Subject: [PATCH 156/177] Recommend that users migrate --- Session/View Controllers/HomeVC.swift | 14 ++++++ .../KeyPairMigrationSheet.swift | 48 +++++++++++++++++++ SessionUtilitiesKit/LKUserDefaults.swift | 1 + Signal.xcodeproj/project.pbxproj | 4 ++ 4 files changed, 67 insertions(+) create mode 100644 Session/View Controllers/KeyPairMigrationSheet.swift diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index 940766973..8664d5f16 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -161,6 +161,20 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol super.viewDidAppear(animated) isViewVisible = true UserDefaults.standard[.hasLaunchedOnce] = true + showKeyPairMigrationNudgeIfNeeded() + } + + private func showKeyPairMigrationNudgeIfNeeded() { + guard !KeyPairUtilities.hasV2KeyPair() else { return } + let lastNudge = UserDefaults.standard[.lastKeyPairMigrationNudge] + let nudgeInterval: Double = 3 * 24 * 60 * 60 // 3 days + let nudge = given(lastNudge) { Date().timeIntervalSince($0) > nudgeInterval } ?? true + guard nudge else { return } + let sheet = KeyPairMigrationSheet() + sheet.modalPresentationStyle = .overFullScreen + sheet.modalTransitionStyle = .crossDissolve + present(sheet, animated: true, completion: nil) + UserDefaults.standard[.lastKeyPairMigrationNudge] = Date() } override func viewWillDisappear(_ animated: Bool) { diff --git a/Session/View Controllers/KeyPairMigrationSheet.swift b/Session/View Controllers/KeyPairMigrationSheet.swift new file mode 100644 index 000000000..154ae8c19 --- /dev/null +++ b/Session/View Controllers/KeyPairMigrationSheet.swift @@ -0,0 +1,48 @@ + +final class KeyPairMigrationSheet : Sheet { + + override func populateContentView() { + // Set up image view + let imageView = UIImageView(image: #imageLiteral(resourceName: "Sun")) + // Set up title label + let titleLabel = UILabel() + titleLabel.textColor = Colors.text + titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize) + titleLabel.text = "Session IDs Just Got Better" + titleLabel.numberOfLines = 0 + titleLabel.lineBreakMode = .byWordWrapping + // Set up top stack view + let topStackView = UIStackView(arrangedSubviews: [ imageView, titleLabel ]) + topStackView.axis = .vertical + topStackView.spacing = Values.largeSpacing + topStackView.alignment = .center + // Set up explanation label + let explanationLabel = UILabel() + explanationLabel.textColor = Colors.text + explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) + explanationLabel.textAlignment = .center + explanationLabel.text = """ + We upgraded the way Session IDs work. They're now even more secure bla bla bla. + + Migrate now to ensure your account is as secure as possible. + """ + explanationLabel.numberOfLines = 0 + explanationLabel.lineBreakMode = .byWordWrapping + // Set up OK button + let okButton = Button(style: .prominentOutline, size: .large) + okButton.set(.width, to: 240) + okButton.setTitle(NSLocalizedString("OK", comment: ""), for: UIControl.State.normal) + okButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside) + // Set up main stack view + let stackView = UIStackView(arrangedSubviews: [ topStackView, explanationLabel, okButton ]) + stackView.axis = .vertical + stackView.spacing = Values.veryLargeSpacing + stackView.alignment = .center + // Set up constraints + contentView.addSubview(stackView) + stackView.pin(.leading, to: .leading, of: contentView, withInset: Values.veryLargeSpacing) + stackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) + contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.veryLargeSpacing) + contentView.pin(.bottom, to: .bottom, of: stackView, withInset: Values.veryLargeSpacing + overshoot) + } +} diff --git a/SessionUtilitiesKit/LKUserDefaults.swift b/SessionUtilitiesKit/LKUserDefaults.swift index 077c7c2a9..1286814ab 100644 --- a/SessionUtilitiesKit/LKUserDefaults.swift +++ b/SessionUtilitiesKit/LKUserDefaults.swift @@ -11,6 +11,7 @@ public enum LKUserDefaults { public enum Date : Swift.String { case lastProfilePictureUpload + case lastKeyPairMigrationNudge } public enum Double : Swift.String { diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index dc7d26319..d9f81cbd3 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -236,6 +236,7 @@ B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408D239DC00D00A248E7 /* DisplayNameVC.swift */; }; B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408F239DD75000A248E7 /* RestoreVC.swift */; }; B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B4093239DF15900A248E7 /* ConversationTitleView.swift */; }; + B83786802586D296003CE78E /* KeyPairMigrationSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B837867F2586D296003CE78E /* KeyPairMigrationSheet.swift */; }; B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */; }; B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; }; B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; @@ -1362,6 +1363,7 @@ B82B408D239DC00D00A248E7 /* DisplayNameVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayNameVC.swift; sourceTree = ""; }; B82B408F239DD75000A248E7 /* RestoreVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreVC.swift; sourceTree = ""; }; B82B4093239DF15900A248E7 /* ConversationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationTitleView.swift; sourceTree = ""; }; + B837867F2586D296003CE78E /* KeyPairMigrationSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPairMigrationSheet.swift; sourceTree = ""; }; B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationButtonSet.swift; sourceTree = ""; }; B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; B84072952565E9F50037CB17 /* TSOutgoingMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSOutgoingMessage+Conversion.swift"; sourceTree = ""; }; @@ -2620,6 +2622,7 @@ B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */, B8BB82A4238F627000BA5194 /* HomeVC.swift */, B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */, + B837867F2586D296003CE78E /* KeyPairMigrationSheet.swift */, B82B40872399EB0E00A248E7 /* LandingVC.swift */, C329FEEB24F7277900B1C64C /* LightModeSheet.swift */, B86BD08323399ACF000F5AE3 /* Modal.swift */, @@ -5532,6 +5535,7 @@ 340FC8AC204DAC8D007AEB0F /* PrivacySettingsTableViewController.m in Sources */, B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */, B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */, + B83786802586D296003CE78E /* KeyPairMigrationSheet.swift in Sources */, C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */, 340FC8AE204DAC8D007AEB0F /* OWSSoundSettingsViewController.m in Sources */, 340FC8B0204DAC8D007AEB0F /* AddToBlockListViewController.m in Sources */, From d6ac7ea79fc2cc3fcbbd61d1cc34e10ed9aa5538 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 14 Dec 2020 13:35:56 +1100 Subject: [PATCH 157/177] Update version number --- Signal.xcodeproj/project.pbxproj | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7b2d9ad8c..5b02e70fe 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5666,7 +5666,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 154; + CURRENT_PROJECT_VERSION = 155; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5687,7 +5687,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5735,7 +5735,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 154; + CURRENT_PROJECT_VERSION = 155; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5761,7 +5761,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5796,7 +5796,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 154; + CURRENT_PROJECT_VERSION = 155; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5815,7 +5815,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5866,7 +5866,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 154; + CURRENT_PROJECT_VERSION = 155; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5890,7 +5890,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6885,7 +6885,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 154; + CURRENT_PROJECT_VERSION = 155; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6921,7 +6921,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6953,7 +6953,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 154; + CURRENT_PROJECT_VERSION = 155; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6989,7 +6989,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From 6df2878d21d46d8a657e153f0084805a53a6cd55 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 14 Dec 2020 14:30:34 +1100 Subject: [PATCH 158/177] Implement actual prompt design --- .../KeyPairMigrationSheet.swift | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/Session/View Controllers/KeyPairMigrationSheet.swift b/Session/View Controllers/KeyPairMigrationSheet.swift index 154ae8c19..9240d81c4 100644 --- a/Session/View Controllers/KeyPairMigrationSheet.swift +++ b/Session/View Controllers/KeyPairMigrationSheet.swift @@ -2,47 +2,70 @@ final class KeyPairMigrationSheet : Sheet { override func populateContentView() { - // Set up image view + // Image view let imageView = UIImageView(image: #imageLiteral(resourceName: "Sun")) - // Set up title label + // Title label let titleLabel = UILabel() titleLabel.textColor = Colors.text titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize) titleLabel.text = "Session IDs Just Got Better" titleLabel.numberOfLines = 0 titleLabel.lineBreakMode = .byWordWrapping - // Set up top stack view + // Top stack view let topStackView = UIStackView(arrangedSubviews: [ imageView, titleLabel ]) topStackView.axis = .vertical topStackView.spacing = Values.largeSpacing topStackView.alignment = .center - // Set up explanation label + // Explanation label let explanationLabel = UILabel() explanationLabel.textColor = Colors.text explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) explanationLabel.textAlignment = .center explanationLabel.text = """ - We upgraded the way Session IDs work. They're now even more secure bla bla bla. + We’ve upgraded Session IDs to make them even more private and secure. We recommend upgrading to a new Session ID now. - Migrate now to ensure your account is as secure as possible. + You will lose existing contacts and conversations, but you’ll gain even more privacy and security. You will need to upgrade your Session ID eventually, but you can choose to delay the upgrade if you need to save contacts or conversations. """ explanationLabel.numberOfLines = 0 explanationLabel.lineBreakMode = .byWordWrapping - // Set up OK button - let okButton = Button(style: .prominentOutline, size: .large) - okButton.set(.width, to: 240) - okButton.setTitle(NSLocalizedString("OK", comment: ""), for: UIControl.State.normal) - okButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside) - // Set up main stack view - let stackView = UIStackView(arrangedSubviews: [ topStackView, explanationLabel, okButton ]) + // Upgrade now button + let upgradeNowButton = Button(style: .prominentOutline, size: .large) + upgradeNowButton.set(.width, to: 240) + upgradeNowButton.setTitle(NSLocalizedString("Upgrade Now", comment: ""), for: UIControl.State.normal) + upgradeNowButton.addTarget(self, action: #selector(upgradeNow), for: UIControl.Event.touchUpInside) + // Upgrade later button + let upgradeLaterButton = Button(style: .prominentOutline, size: .large) + upgradeLaterButton.set(.width, to: 240) + upgradeLaterButton.setTitle(NSLocalizedString("Upgrade Later", comment: ""), for: UIControl.State.normal) + upgradeLaterButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside) + // Button stack view + let buttonStackView = UIStackView(arrangedSubviews: [ upgradeNowButton, upgradeLaterButton ]) + buttonStackView.axis = .vertical + buttonStackView.spacing = Values.mediumSpacing + buttonStackView.alignment = .center + // Main stack view + let stackView = UIStackView(arrangedSubviews: [ topStackView, explanationLabel, buttonStackView ]) stackView.axis = .vertical stackView.spacing = Values.veryLargeSpacing stackView.alignment = .center - // Set up constraints + // Constraints contentView.addSubview(stackView) stackView.pin(.leading, to: .leading, of: contentView, withInset: Values.veryLargeSpacing) stackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.veryLargeSpacing) contentView.pin(.bottom, to: .bottom, of: stackView, withInset: Values.veryLargeSpacing + overshoot) } + + @objc private func upgradeNow() { + guard let presentingVC = presentingViewController else { return } + let message = "You’re upgrading to a new Session ID. This will give you improved privacy and security, but it will clear ALL app data. Contacts and conversations will be lost. Proceed?" + let alert = UIAlertController(title: "Upgrade Session ID?", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in + NotificationCenter.default.post(name: .dataNukeRequested, object: nil) + }) + alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) + presentingVC.dismiss(animated: true) { // Dismiss self first + presentingVC.present(alert, animated: true, completion: nil) + } + } } From 0864873d317759a0c1f042740a55fc3fa1100ffd Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 14 Dec 2020 14:43:17 +1100 Subject: [PATCH 159/177] Clean --- Session/Signal/AppDelegate.m | 4 ++-- Session/Utilities/Storage+Resetting.swift | 23 +++++++++++++++++++ Session/View Controllers/HomeVC.swift | 4 ++-- .../KeyPairMigrationSheet.swift | 2 +- .../Notifications/PushNotificationAPI.swift | 10 ++++---- SessionMessagingKit/To Do/TSAccountManager.m | 2 +- Signal.xcodeproj/project.pbxproj | 4 ++++ 7 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 Session/Utilities/Storage+Resetting.swift diff --git a/Session/Signal/AppDelegate.m b/Session/Signal/AppDelegate.m index f02985166..ed8040a59 100644 --- a/Session/Signal/AppDelegate.m +++ b/Session/Signal/AppDelegate.m @@ -633,7 +633,7 @@ static NSTimeInterval launchStartedAt; if (isUsingFullAPNs) { __unused AnyPromise *promise = [LKPushNotificationAPI registerWithToken:deviceToken hexEncodedPublicKey:self.tsAccountManager.localNumber isForcedUpdate:NO]; } else { - __unused AnyPromise *promise = [LKPushNotificationAPI unregisterWithToken:deviceToken isForcedUpdate:NO]; + __unused AnyPromise *promise = [LKPushNotificationAPI unregisterToken:deviceToken]; } } @@ -817,7 +817,7 @@ static NSTimeInterval launchStartedAt; NSString *hexEncodedDeviceToken = [userDefaults stringForKey:@"deviceToken"]; if (isUsingFullAPNs && hexEncodedDeviceToken != nil) { NSData *deviceToken = [NSData dataFromHexString:hexEncodedDeviceToken]; - [[LKPushNotificationAPI unregisterWithToken:deviceToken isForcedUpdate:YES] retainUntilComplete]; + [[LKPushNotificationAPI unregisterToken:deviceToken] retainUntilComplete]; } [ThreadUtil deleteAllContent]; [SSKEnvironment.shared.identityManager clearIdentityKey]; diff --git a/Session/Utilities/Storage+Resetting.swift b/Session/Utilities/Storage+Resetting.swift new file mode 100644 index 000000000..ed132c393 --- /dev/null +++ b/Session/Utilities/Storage+Resetting.swift @@ -0,0 +1,23 @@ + +extension Storage { + + static func reset() { + let userDefaults = UserDefaults.standard + if userDefaults[.isUsingFullAPNs], let hexEncodedToken = userDefaults[.deviceToken] { + let token = Data(hex: hexEncodedToken) + PushNotificationAPI.unregister(token).retainUntilComplete() // TODO: Wait for this to complete? + } + + let appDelegate = UIApplication.shared.delegate as! AppDelegate + appDelegate.stopPoller() + appDelegate.stopClosedGroupPoller() + appDelegate.stopOpenGroupPollers() + + OWSStorage.resetAllStorage() + OWSUserProfile.resetProfileStorage() + Environment.shared.preferences.clear() + AppEnvironment.shared.notificationPresenter.clearAllNotifications() + + exit(0) + } +} diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index 8664d5f16..f342aa496 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -165,11 +165,11 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol } private func showKeyPairMigrationNudgeIfNeeded() { - guard !KeyPairUtilities.hasV2KeyPair() else { return } +// guard !KeyPairUtilities.hasV2KeyPair() else { return } let lastNudge = UserDefaults.standard[.lastKeyPairMigrationNudge] let nudgeInterval: Double = 3 * 24 * 60 * 60 // 3 days let nudge = given(lastNudge) { Date().timeIntervalSince($0) > nudgeInterval } ?? true - guard nudge else { return } +// guard nudge else { return } let sheet = KeyPairMigrationSheet() sheet.modalPresentationStyle = .overFullScreen sheet.modalTransitionStyle = .crossDissolve diff --git a/Session/View Controllers/KeyPairMigrationSheet.swift b/Session/View Controllers/KeyPairMigrationSheet.swift index 9240d81c4..12e2e0b40 100644 --- a/Session/View Controllers/KeyPairMigrationSheet.swift +++ b/Session/View Controllers/KeyPairMigrationSheet.swift @@ -61,7 +61,7 @@ final class KeyPairMigrationSheet : Sheet { let message = "You’re upgrading to a new Session ID. This will give you improved privacy and security, but it will clear ALL app data. Contacts and conversations will be lost. Proceed?" let alert = UIAlertController(title: "Upgrade Session ID?", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in - NotificationCenter.default.post(name: .dataNukeRequested, object: nil) + Storage.reset() }) alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) presentingVC.dismiss(animated: true) { // Dismiss self first diff --git a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift index a7076ad8c..e4783fc94 100644 --- a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift +++ b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift @@ -19,7 +19,7 @@ public final class PushNotificationAPI : NSObject { private override init() { } // MARK: Registration - static func unregister(with token: Data, isForcedUpdate: Bool) -> Promise { + public static func unregister(_ token: Data) -> Promise { let hexEncodedToken = token.toHexString() let parameters = [ "token" : hexEncodedToken ] let url = URL(string: "\(server)/unregister")! @@ -45,12 +45,12 @@ public final class PushNotificationAPI : NSObject { return promise } - @objc(unregisterWithToken:isForcedUpdate:) - public static func objc_unregister(with token: Data, isForcedUpdate: Bool) -> AnyPromise { - return AnyPromise.from(unregister(with: token, isForcedUpdate: isForcedUpdate)) + @objc(unregisterToken:) + public static func objc_unregister(token: Data) -> AnyPromise { + return AnyPromise.from(unregister(token)) } - static func register(with token: Data, publicKey: String, isForcedUpdate: Bool) -> Promise { + public static func register(with token: Data, publicKey: String, isForcedUpdate: Bool) -> Promise { let hexEncodedToken = token.toHexString() let userDefaults = UserDefaults.standard let oldToken = userDefaults[.deviceToken] diff --git a/SessionMessagingKit/To Do/TSAccountManager.m b/SessionMessagingKit/To Do/TSAccountManager.m index 2ee6e4b8c..03c1cfcc4 100644 --- a/SessionMessagingKit/To Do/TSAccountManager.m +++ b/SessionMessagingKit/To Do/TSAccountManager.m @@ -277,7 +277,7 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"]; NSData *pushTokenAsData = [NSData dataFromHexString:pushToken]; AnyPromise *promise = isUsingFullAPNs ? [LKPushNotificationAPI registerWithToken:pushTokenAsData hexEncodedPublicKey:self.localNumber isForcedUpdate:isForcedUpdate] - : [LKPushNotificationAPI unregisterWithToken:pushTokenAsData isForcedUpdate:isForcedUpdate]; + : [LKPushNotificationAPI unregisterToken:pushTokenAsData]; promise .then(^() { successHandler(); diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d9f81cbd3..f038f3459 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -245,6 +245,7 @@ B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8566C62256F55930045A0B9 /* OWSLinkPreview+Conversion.swift */; }; B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; B8566C7D256F62030045A0B9 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B85A68B12587141A008CC492 /* Storage+Resetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85A68B02587141A008CC492 /* Storage+Resetting.swift */; }; B866CE112581C1A900535CC4 /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; @@ -1375,6 +1376,7 @@ B8544E3023D16CA500299F14 /* DeviceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceUtilities.swift; sourceTree = ""; }; B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceUtilities.swift; sourceTree = ""; }; B8566C62256F55930045A0B9 /* OWSLinkPreview+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OWSLinkPreview+Conversion.swift"; sourceTree = ""; }; + B85A68B02587141A008CC492 /* Storage+Resetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Resetting.swift"; sourceTree = ""; }; B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = ""; }; B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; @@ -2605,6 +2607,7 @@ C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */, B84664F4235022F30083A1CD /* MentionUtilities.swift */, B886B4A82398BA1500211ABE /* QRCode.swift */, + B85A68B02587141A008CC492 /* Storage+Resetting.swift */, B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */, B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */, C31A6C59247F214E001123EF /* UIView+Glow.swift */, @@ -5432,6 +5435,7 @@ C396DAF42518408B00FF6DC5 /* Parser.swift in Sources */, 4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */, 4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */, + B85A68B12587141A008CC492 /* Storage+Resetting.swift in Sources */, 3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */, 45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */, 340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */, From f7919b8d4f33277a9758da24090e4c0b1076e655 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 14 Dec 2020 15:20:25 +1100 Subject: [PATCH 160/177] Undo accidental commit --- Session/View Controllers/HomeVC.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index f342aa496..8664d5f16 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -165,11 +165,11 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol } private func showKeyPairMigrationNudgeIfNeeded() { -// guard !KeyPairUtilities.hasV2KeyPair() else { return } + guard !KeyPairUtilities.hasV2KeyPair() else { return } let lastNudge = UserDefaults.standard[.lastKeyPairMigrationNudge] let nudgeInterval: Double = 3 * 24 * 60 * 60 // 3 days let nudge = given(lastNudge) { Date().timeIntervalSince($0) > nudgeInterval } ?? true -// guard nudge else { return } + guard nudge else { return } let sheet = KeyPairMigrationSheet() sheet.modalPresentationStyle = .overFullScreen sheet.modalTransitionStyle = .crossDissolve From cf274f122c13a5a31be9d913794145ecdcc9b09a Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 14 Dec 2020 15:48:53 +1100 Subject: [PATCH 161/177] Create TRANSLATION.md --- TRANSLATION.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 TRANSLATION.md diff --git a/TRANSLATION.md b/TRANSLATION.md new file mode 100644 index 000000000..7d62892b0 --- /dev/null +++ b/TRANSLATION.md @@ -0,0 +1,54 @@ +## How to translate Session into new languages quickly and easily + +There are people all around the world who can benefit from access to Session — and that means we need to make Session available in as many languages as possible. We’ve had a number of requests from community members wanting to help out by translating Session into currently unsupported (or only partially supported) languages. If you speak multiple languages and you want to help us make Session available in another language you speak, this guide will show you how to translate Session’s iOS and Android apps quickly and easily. + +### Translating Session for iOS: + +Translating Session iOS into a new language is easy! You’ll need a web browser, a plaintext editor (TextEdit on macOS or Notepad on Windows will do), and a little bit of time and patience. + +#### Step 1: Retrieving English strings +- Go to Session’s iOS GitHub page +- In the list of folders and files, click **Session** +- Click **Meta** +- Click **Translations** +- Click **en.lproj** +- Click **localizable.strings** +- Scroll down to Line #2557 (using the line numbers on the left-hand side of the text). This line should contain the text `// MARK: - Session` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text) +- Select and copy all text from that line down to the end of the file +- Open a plaintext editor (TextEdit on macOS, Notepad on Windows, or your preferred plaintext editor) and create a new file +- Paste the text you copied earlier into this blank file + +#### Step 2: Translate! +This file will now have a large number of lines of code. Each line contains 2 sets of information, both in quotation marks, like this: + +`"continue_2" = "Continue";` + +For each line of code, translate the word or sentence to the **right** of the equals sign into the language you are translating into. Do **not** edit the text to the **left** of the equals sign. + +Once you are finished translating, save the file with a filename that specifies which language you have translated the app into, and email the file to us at support@getsession.org along with information about the language you have translated the app into. Be sure to specify in your email that you have translated the iOS app (for information on translating the Android app, see below). Our developers will then take your translation and apply it to the Session iOS app. Thank you for helping make Session more accessible for everyone! + + +### Translating for Android: + +It’s just as easy to add new translations on Session Android! Once again, you’ll need a web browser, a plaintext editor (TextEdit on macOS or Notepad on Windows will do), and a little bit of time and patience. + +#### Step 1: Retrieving English strings +- Go to Session’s Android GitHub page +- In the list of files and folders, click **res** +- Click **values** (you will need to scroll down to find this folder; make sure you click the folder named **values** and not any of the folders named **values-xx** or with other suffixes) +- Click **strings.xml** +- Scroll down to Line #1657 (using the line numbers on the left-hand side of the text). This line should contain the text `` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text) +- Select and copy all text from that line down to the end of the file +- Open a plaintext editor (TextEdit on macOS, Notepad on Windows, or your preferred plaintext editor) and create a new file +- Paste the text you copied earlier into this blank file + +#### Step 2: Translate! +This file will now have a large number of lines of code. Each line will contain `` and `` tags. To translate Session Android, translate the text between these tags. For example: + +`Continue` + +In this line, translate the word **Continue** into the language you are translating into. Do not translate any other text. Do **not** translate the text inside either pair of angled brackets <>. + +Translate the word or sentence between each pair of `` tags, on each line. + +Once you are finished translating, save the file with a filename that specifies which language you have translated the app into, and email the file to us at support@getsession.org along with information about the language you have translated the app into. Be sure to specify in your email that you have translated the Android app (for information on translating the iOS app, see above). Our developers will then take your translation and apply it to the Session Android app. Thank you for helping make Session more accessible for everyone! From ca5cd0003f5b073c4852a01b604bdc84aeedd11e Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 14 Dec 2020 15:50:17 +1100 Subject: [PATCH 162/177] Update TRANSLATION.md --- TRANSLATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 7d62892b0..ff32809c1 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -7,7 +7,7 @@ There are people all around the world who can benefit from access to Session — Translating Session iOS into a new language is easy! You’ll need a web browser, a plaintext editor (TextEdit on macOS or Notepad on Windows will do), and a little bit of time and patience. #### Step 1: Retrieving English strings -- Go to Session’s iOS GitHub page +- Go to [Session’s iOS GitHub page](https://github.com/loki-project/session-ios) - In the list of folders and files, click **Session** - Click **Meta** - Click **Translations** @@ -33,7 +33,7 @@ Once you are finished translating, save the file with a filename that specifies It’s just as easy to add new translations on Session Android! Once again, you’ll need a web browser, a plaintext editor (TextEdit on macOS or Notepad on Windows will do), and a little bit of time and patience. #### Step 1: Retrieving English strings -- Go to Session’s Android GitHub page +- Go to [Session’s Android GitHub page](https://github.com/loki-project/session-android) - In the list of files and folders, click **res** - Click **values** (you will need to scroll down to find this folder; make sure you click the folder named **values** and not any of the folders named **values-xx** or with other suffixes) - Click **strings.xml** From fa02ea11de17a3d0306142403d3dbf04d5a45d25 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 14 Dec 2020 16:09:11 +1100 Subject: [PATCH 163/177] Show message sending status bar earlier --- .../Sending & Receiving/MessageSender+Convenience.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift index bb7279306..ee7742dd9 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift @@ -3,6 +3,7 @@ import PromiseKit extension MessageSender { + // MARK: Durable @objc(send:withAttachments:inThread:usingTransaction:) public static func send(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { prep(attachments, for: message, using: transaction) @@ -15,8 +16,16 @@ extension MessageSender { let destination = Message.Destination.from(thread) let job = MessageSendJob(message: message, destination: destination) JobQueue.shared.add(job, using: transaction) + guard let userPublicKey = SNMessagingKitConfiguration.shared.storage.getUserPublicKey() else { return } + if case .contact(let recipientPublicKey) = destination, message is VisibleMessage, recipientPublicKey != userPublicKey { + DispatchQueue.main.async { + // Not strictly true, but nicer from a UX perspective + NotificationCenter.default.post(name: .encryptingMessage, object: NSNumber(value: message.sentTimestamp!)) + } + } } + // MARK: Non-Durable @objc(sendNonDurably:withAttachments:inThread:usingTransaction:) public static func objc_sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { return AnyPromise.from(sendNonDurably(message, with: attachments, in: thread, using: transaction)) From a4235aff17c7f0b6d80922aeaca5978035f3872d Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Tue, 15 Dec 2020 08:17:45 +1100 Subject: [PATCH 164/177] Update TRANSLATION.md --- TRANSLATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index ff32809c1..7ca0848a5 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -13,7 +13,7 @@ Translating Session iOS into a new language is easy! You’ll need a web browser - Click **Translations** - Click **en.lproj** - Click **localizable.strings** -- Scroll down to Line #2557 (using the line numbers on the left-hand side of the text). This line should contain the text `// MARK: - Session` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text) +- Scroll down to line #2557 (using the line numbers on the left-hand side of the text). This line should contain the text `// MARK: - Session` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text) - Select and copy all text from that line down to the end of the file - Open a plaintext editor (TextEdit on macOS, Notepad on Windows, or your preferred plaintext editor) and create a new file - Paste the text you copied earlier into this blank file @@ -37,7 +37,7 @@ It’s just as easy to add new translations on Session Android! Once again, you - In the list of files and folders, click **res** - Click **values** (you will need to scroll down to find this folder; make sure you click the folder named **values** and not any of the folders named **values-xx** or with other suffixes) - Click **strings.xml** -- Scroll down to Line #1657 (using the line numbers on the left-hand side of the text). This line should contain the text `` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text) +- Scroll down to line #1657 (using the line numbers on the left-hand side of the text). This line should contain the text `` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text) - Select and copy all text from that line down to the end of the file - Open a plaintext editor (TextEdit on macOS, Notepad on Windows, or your preferred plaintext editor) and create a new file - Paste the text you copied earlier into this blank file From 414029fae5bd9b886b367c1455cc34d97735845f Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Tue, 15 Dec 2020 08:19:38 +1100 Subject: [PATCH 165/177] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index fdaee4f89..2115edd8f 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ Please search for any [existing issues](https://github.com/loki-project/session- Build instructions can be found in [BUILDING.md](BUILDING.md). +## Translations + +Want to help us translate Session into your language? See [TRANSLATION.md](TRANSLATION.md) for instructions on how to do that! + ## License Copyright 2011 Whisper Systems From 057a0c04c557d2e94d353df0675b002a005301fc Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Tue, 15 Dec 2020 08:20:43 +1100 Subject: [PATCH 166/177] Update BUILDING.md --- BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index 859385764..ff08a28f9 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -49,7 +49,7 @@ open Signal.xcworkspace In the TARGETS area of the General tab, change the Team dropdown to your own. You will need to do that for all the listed targets, for ex. -Session, SessionShareExtension, and SessionPushNotificationExtension. You +Session, SessionShareExtension, and SessionNotificationServiceExtension. You will need an Apple Developer account for this. On the Capabilities tab, turn off Push Notifications and Data Protection, From a15eec83eb0478541ddda7550528fe7a352f8076 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 16 Dec 2020 11:45:01 +1100 Subject: [PATCH 167/177] Minor refactoring --- .../Sending & Receiving/MessageReceiver+Decryption.swift | 3 ++- .../Sending & Receiving/MessageSender+Encryption.swift | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift index ea502640b..a20313452 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift @@ -45,7 +45,8 @@ internal extension MessageReceiver { let senderED25519PublicKey = Bytes(plaintextWithMetadata[plaintextWithMetadata.count - (signatureSize + ed25519PublicKeySize) ..< plaintextWithMetadata.count - signatureSize]) let plaintext = Bytes(plaintextWithMetadata[0.. Date: Wed, 16 Dec 2020 14:22:31 +1100 Subject: [PATCH 168/177] Use actual icon --- .../Loki V2/Shield.imageset/Contents.json | 12 ++++++++++++ .../Loki V2/Shield.imageset/Shield.pdf | Bin 0 -> 1275 bytes .../View Controllers/KeyPairMigrationSheet.swift | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Session/Meta/Images.xcassets/Loki V2/Shield.imageset/Contents.json create mode 100644 Session/Meta/Images.xcassets/Loki V2/Shield.imageset/Shield.pdf diff --git a/Session/Meta/Images.xcassets/Loki V2/Shield.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Shield.imageset/Contents.json new file mode 100644 index 000000000..c6de4ea4e --- /dev/null +++ b/Session/Meta/Images.xcassets/Loki V2/Shield.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Shield.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Loki V2/Shield.imageset/Shield.pdf b/Session/Meta/Images.xcassets/Loki V2/Shield.imageset/Shield.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f03001d0aa8dd011d8dff16a5b64ec9c474e843f GIT binary patch literal 1275 zcmah}TWC{B7bRTxeoPXw<|NNJ4 zz7tP09I23en&252z5ZEH5k~g5?Lsh!#P!5VvJRvH6cZ3aV#MrZgo5of7zvZOoghM0 zmEbT+j4mN_wkuk1&6G;+eqOMrt>nz%Y~!{s_w48fk1E`SVEj<>hC-?9GD%Z+2Oe)%}^R2(F3 z%BBbsqehY-50c!tQG*hT!K;OP+CUPfQDbM&W`HnK0;)S(UGI=>F>rSfzv|q*)=@j1 zDk>_M!$k{qHbG`;SWb%Pif0ROJz_LX3cC<^g~={6PGWU69L)71#)xC5X`DESGZHK6 zjMrR{+xN~K{;t?yCLHL1Hy=ZV+S9zzq5yhPfGD*S={N|~8#hd9BgrS}K8(B_jHR5_ zBG3zHk{YQFGw%3onk+AO6NNy&%%&(9sf|Q1Rx2^qYhl)4>{r0@DZv_p)i9R9DzKNq z2aa-<@A*0aJ}~`iegej0DAjNVvH8^hFFwx=etrn3LsGfYRfOo4Y1&qpE65vOEkj00 zmUJj4plU7UMXdOXSjo{EGMLe6C*6Lzc$~akzKbkFNxOhiK!B3-1L>NkXs8_(FkJ~C z_Y7H6m@0$D_$a~@^}l{tf{$dnpA7dm4fA6V$uz7o075BXj2dPqq3&N)li5w6WG Date: Wed, 16 Dec 2020 14:28:14 +1100 Subject: [PATCH 169/177] Fix tint color --- Session/View Controllers/KeyPairMigrationSheet.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Session/View Controllers/KeyPairMigrationSheet.swift b/Session/View Controllers/KeyPairMigrationSheet.swift index 99a7cb4bf..c5ebecaae 100644 --- a/Session/View Controllers/KeyPairMigrationSheet.swift +++ b/Session/View Controllers/KeyPairMigrationSheet.swift @@ -3,7 +3,7 @@ final class KeyPairMigrationSheet : Sheet { override func populateContentView() { // Image view - let imageView = UIImageView(image: #imageLiteral(resourceName: "Shield")) + let imageView = UIImageView(image: #imageLiteral(resourceName: "Shield").withTint(Colors.text)) imageView.set(.width, to: 64) imageView.set(.height, to: 64) imageView.contentMode = .scaleAspectFit From eba82d532e1f35b5685c30b93403a9febbb89367 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 16 Dec 2020 14:41:00 +1100 Subject: [PATCH 170/177] Add persistent upgrade Session ID button for V1 users --- Session/View Controllers/SettingsVC.swift | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Session/View Controllers/SettingsVC.swift b/Session/View Controllers/SettingsVC.swift index 615645038..cbfe660df 100644 --- a/Session/View Controllers/SettingsVC.swift +++ b/Session/View Controllers/SettingsVC.swift @@ -170,19 +170,28 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { button.set(.height, to: Values.settingButtonHeight) return button } - return [ + var result = [ getSeparator(), getSettingButton(withTitle: NSLocalizedString("vc_settings_privacy_button_title", comment: ""), color: Colors.text, action: #selector(showPrivacySettings)), getSeparator(), getSettingButton(withTitle: NSLocalizedString("vc_settings_notifications_button_title", comment: ""), color: Colors.text, action: #selector(showNotificationSettings)), getSeparator(), getSettingButton(withTitle: "Invite", color: Colors.text, action: #selector(sendInvitation)), - getSeparator(), + getSeparator() + ] + if !KeyPairUtilities.hasV2KeyPair() { + result += [ + getSettingButton(withTitle: "Upgrade Session ID", color: Colors.text, action: #selector(upgradeSessionID)), + getSeparator() + ] + } + result += [ getSettingButton(withTitle: NSLocalizedString("vc_settings_recovery_phrase_button_title", comment: ""), color: Colors.text, action: #selector(showSeed)), getSeparator(), getSettingButton(withTitle: NSLocalizedString("vc_settings_clear_all_data_button_title", comment: ""), color: Colors.destructive, action: #selector(clearAllData)), getSeparator() ] + return result } // MARK: General @@ -389,6 +398,16 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { navigationController!.present(shareVC, animated: true, completion: nil) } + @objc private func upgradeSessionID() { + let message = "You’re upgrading to a new Session ID. This will give you improved privacy and security, but it will clear ALL app data. Contacts and conversations will be lost. Proceed?" + let alert = UIAlertController(title: "Upgrade Session ID?", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in + Storage.reset() + }) + alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) + present(alert, animated: true, completion: nil) + } + @objc private func showSeed() { let seedModal = SeedModal() seedModal.modalPresentationStyle = .overFullScreen From 7583661cca2315820d28bd0b227778676d4d67a9 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 16 Dec 2020 16:22:46 +1100 Subject: [PATCH 171/177] Implement auto-migration --- Session/Utilities/Storage+Resetting.swift | 30 +++++- Session/View Controllers/HomeVC.swift | 11 +++ .../KeyPairMigrationSheet.swift | 6 +- .../KeyPairMigrationSuccessSheet.swift | 94 +++++++++++++++++++ Session/View Controllers/LandingVC.swift | 7 ++ Session/View Controllers/SettingsVC.swift | 2 +- SessionUtilitiesKit/LKUserDefaults.swift | 3 + Signal.xcodeproj/project.pbxproj | 4 + 8 files changed, 148 insertions(+), 9 deletions(-) create mode 100644 Session/View Controllers/KeyPairMigrationSuccessSheet.swift diff --git a/Session/Utilities/Storage+Resetting.swift b/Session/Utilities/Storage+Resetting.swift index ed132c393..0cd749f28 100644 --- a/Session/Utilities/Storage+Resetting.swift +++ b/Session/Utilities/Storage+Resetting.swift @@ -1,23 +1,43 @@ +import PromiseKit extension Storage { - static func reset() { + static func prepareForV2KeyPairMigration() { let userDefaults = UserDefaults.standard - if userDefaults[.isUsingFullAPNs], let hexEncodedToken = userDefaults[.deviceToken] { + let isUsingAPNs = userDefaults[.isUsingFullAPNs] + if isUsingAPNs, let hexEncodedToken = userDefaults[.deviceToken] { let token = Data(hex: hexEncodedToken) PushNotificationAPI.unregister(token).retainUntilComplete() // TODO: Wait for this to complete? } - + let displayName = OWSProfileManager.shared().localProfileName() let appDelegate = UIApplication.shared.delegate as! AppDelegate appDelegate.stopPoller() appDelegate.stopClosedGroupPoller() appDelegate.stopOpenGroupPollers() - OWSStorage.resetAllStorage() OWSUserProfile.resetProfileStorage() Environment.shared.preferences.clear() AppEnvironment.shared.notificationPresenter.clearAllNotifications() - + userDefaults[.isUsingFullAPNs] = isUsingAPNs + userDefaults[.displayName] = displayName + userDefaults[.isMigratingToV2KeyPair] = true exit(0) } + + static func finishV2KeyPairMigration(navigationController: UINavigationController) { + let seed = Data.getSecureRandomData(ofSize: 16)! + let (ed25519KeyPair, x25519KeyPair) = KeyPairUtilities.generate(from: seed) + KeyPairUtilities.store(seed: seed, ed25519KeyPair: ed25519KeyPair, x25519KeyPair: x25519KeyPair) + TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = x25519KeyPair.hexEncodedPublicKey + OWSPrimaryStorage.shared().setRestorationTime(0) + UserDefaults.standard[.hasViewedSeed] = false + let displayName = UserDefaults.standard[.displayName]! // Checked earlier + OWSProfileManager.shared().updateLocalProfileName(displayName, avatarImage: nil, success: { }, failure: { _ in }, requiresSync: false) + TSAccountManager.sharedInstance().didRegister() + let homeVC = HomeVC() + navigationController.setViewControllers([ homeVC ], animated: true) + let syncTokensJob = SyncPushTokensJob(accountManager: AppEnvironment.shared.accountManager, preferences: Environment.shared.preferences) + syncTokensJob.uploadOnlyIfStale = false + let _: Promise = syncTokensJob.run() + } } diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index 8664d5f16..aa5982eec 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -162,6 +162,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol isViewVisible = true UserDefaults.standard[.hasLaunchedOnce] = true showKeyPairMigrationNudgeIfNeeded() + showKeyPairMigrationSuccessModalIfNeeded() } private func showKeyPairMigrationNudgeIfNeeded() { @@ -177,6 +178,16 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol UserDefaults.standard[.lastKeyPairMigrationNudge] = Date() } + private func showKeyPairMigrationSuccessModalIfNeeded() { + let userDefaults = UserDefaults.standard + guard KeyPairUtilities.hasV2KeyPair() && userDefaults[.isMigratingToV2KeyPair] else { return } + let sheet = KeyPairMigrationSuccessSheet() + sheet.modalPresentationStyle = .overFullScreen + sheet.modalTransitionStyle = .crossDissolve + present(sheet, animated: true, completion: nil) + UserDefaults.standard[.isMigratingToV2KeyPair] = false + } + override func viewWillDisappear(_ animated: Bool) { isViewVisible = false super.viewWillDisappear(animated) diff --git a/Session/View Controllers/KeyPairMigrationSheet.swift b/Session/View Controllers/KeyPairMigrationSheet.swift index c5ebecaae..9c4c45c01 100644 --- a/Session/View Controllers/KeyPairMigrationSheet.swift +++ b/Session/View Controllers/KeyPairMigrationSheet.swift @@ -34,12 +34,12 @@ final class KeyPairMigrationSheet : Sheet { // Upgrade now button let upgradeNowButton = Button(style: .prominentOutline, size: .large) upgradeNowButton.set(.width, to: 240) - upgradeNowButton.setTitle(NSLocalizedString("Upgrade Now", comment: ""), for: UIControl.State.normal) + upgradeNowButton.setTitle("Upgrade Now", for: UIControl.State.normal) upgradeNowButton.addTarget(self, action: #selector(upgradeNow), for: UIControl.Event.touchUpInside) // Upgrade later button let upgradeLaterButton = Button(style: .prominentOutline, size: .large) upgradeLaterButton.set(.width, to: 240) - upgradeLaterButton.setTitle(NSLocalizedString("Upgrade Later", comment: ""), for: UIControl.State.normal) + upgradeLaterButton.setTitle("Upgrade Later", for: UIControl.State.normal) upgradeLaterButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside) // Button stack view let buttonStackView = UIStackView(arrangedSubviews: [ upgradeNowButton, upgradeLaterButton ]) @@ -64,7 +64,7 @@ final class KeyPairMigrationSheet : Sheet { let message = "You’re upgrading to a new Session ID. This will give you improved privacy and security, but it will clear ALL app data. Contacts and conversations will be lost. Proceed?" let alert = UIAlertController(title: "Upgrade Session ID?", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in - Storage.reset() + Storage.prepareForV2KeyPairMigration() }) alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) presentingVC.dismiss(animated: true) { // Dismiss self first diff --git a/Session/View Controllers/KeyPairMigrationSuccessSheet.swift b/Session/View Controllers/KeyPairMigrationSuccessSheet.swift new file mode 100644 index 000000000..842eef20d --- /dev/null +++ b/Session/View Controllers/KeyPairMigrationSuccessSheet.swift @@ -0,0 +1,94 @@ + +final class KeyPairMigrationSuccessSheet : Sheet { + + private lazy var sessionIDLabel: UILabel = { + let result = UILabel() + result.textColor = Colors.text + result.font = Fonts.spaceMono(ofSize: isIPhone5OrSmaller ? Values.mediumFontSize : 20) + result.numberOfLines = 0 + result.lineBreakMode = .byCharWrapping + return result + }() + + private lazy var copyButton: Button = { + let result = Button(style: .prominentOutline, size: .large) + result.set(.width, to: 240) + result.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal) + result.addTarget(self, action: #selector(copySessionID), for: UIControl.Event.touchUpInside) + return result + }() + + override func populateContentView() { + // Image view + let imageView = UIImageView(image: #imageLiteral(resourceName: "Shield").withTint(Colors.text)) + imageView.set(.width, to: 64) + imageView.set(.height, to: 64) + imageView.contentMode = .scaleAspectFit + // Title label + let titleLabel = UILabel() + titleLabel.textColor = Colors.text + titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize) + titleLabel.text = "Upgrade Successful!" + titleLabel.numberOfLines = 0 + titleLabel.lineBreakMode = .byWordWrapping + // Top stack view + let topStackView = UIStackView(arrangedSubviews: [ imageView, titleLabel ]) + topStackView.axis = .vertical + topStackView.spacing = Values.largeSpacing + topStackView.alignment = .center + // Explanation label + let explanationLabel = UILabel() + explanationLabel.textColor = Colors.text + explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) + explanationLabel.textAlignment = .center + explanationLabel.text = "Your new and improved Session ID is:" + explanationLabel.numberOfLines = 0 + explanationLabel.lineBreakMode = .byWordWrapping + // Session ID label + sessionIDLabel.text = getUserHexEncodedPublicKey() + // Session ID container + let sessionIDContainer = UIView() + sessionIDContainer.addSubview(sessionIDLabel) + sessionIDLabel.pin(to: sessionIDContainer, withInset: Values.mediumSpacing) + sessionIDContainer.layer.cornerRadius = Values.textFieldCornerRadius + sessionIDContainer.layer.borderWidth = Values.borderThickness + sessionIDContainer.layer.borderColor = Colors.text.cgColor + // OK button + let okButton = Button(style: .prominentOutline, size: .large) + okButton.set(.width, to: 240) + okButton.setTitle("OK", for: UIControl.State.normal) + okButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside) + // Button stack view + let buttonStackView = UIStackView(arrangedSubviews: [ copyButton, okButton ]) + buttonStackView.axis = .vertical + buttonStackView.spacing = Values.mediumSpacing + buttonStackView.alignment = .center + // Main stack view + let stackView = UIStackView(arrangedSubviews: [ topStackView, explanationLabel, sessionIDContainer, buttonStackView ]) + stackView.axis = .vertical + stackView.spacing = Values.veryLargeSpacing + stackView.alignment = .center + // Constraints + contentView.addSubview(stackView) + stackView.pin(.leading, to: .leading, of: contentView, withInset: Values.veryLargeSpacing) + stackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) + contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.veryLargeSpacing) + contentView.pin(.bottom, to: .bottom, of: stackView, withInset: Values.veryLargeSpacing + overshoot) + } + + @objc private func copySessionID() { + UIPasteboard.general.string = getUserHexEncodedPublicKey() + copyButton.isUserInteractionEnabled = false + UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { + self.copyButton.setTitle("Copied", for: UIControl.State.normal) + }, completion: nil) + Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false) + } + + @objc private func enableCopyButton() { + copyButton.isUserInteractionEnabled = true + UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { + self.copyButton.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal) + }, completion: nil) + } +} diff --git a/Session/View Controllers/LandingVC.swift b/Session/View Controllers/LandingVC.swift index 5bb68763d..0639d5c12 100644 --- a/Session/View Controllers/LandingVC.swift +++ b/Session/View Controllers/LandingVC.swift @@ -70,6 +70,13 @@ final class LandingVC : BaseVC { view.addSubview(mainStackView) mainStackView.pin(to: view) topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true + // Auto-migrate if needed + let userDefaults = UserDefaults.standard + if userDefaults[.isMigratingToV2KeyPair] { + if userDefaults[.displayName] != nil { + Storage.finishV2KeyPairMigration(navigationController: navigationController!) + } + } } override func viewDidDisappear(_ animated: Bool) { diff --git a/Session/View Controllers/SettingsVC.swift b/Session/View Controllers/SettingsVC.swift index cbfe660df..edb577b90 100644 --- a/Session/View Controllers/SettingsVC.swift +++ b/Session/View Controllers/SettingsVC.swift @@ -402,7 +402,7 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { let message = "You’re upgrading to a new Session ID. This will give you improved privacy and security, but it will clear ALL app data. Contacts and conversations will be lost. Proceed?" let alert = UIAlertController(title: "Upgrade Session ID?", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in - Storage.reset() + Storage.prepareForV2KeyPairMigration() }) alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) present(alert, animated: true, completion: nil) diff --git a/SessionUtilitiesKit/LKUserDefaults.swift b/SessionUtilitiesKit/LKUserDefaults.swift index 1286814ab..052fa58f8 100644 --- a/SessionUtilitiesKit/LKUserDefaults.swift +++ b/SessionUtilitiesKit/LKUserDefaults.swift @@ -7,6 +7,7 @@ public enum LKUserDefaults { case hasSeenGIFMetadataWarning case hasViewedSeed case isUsingFullAPNs + case isMigratingToV2KeyPair } public enum Date : Swift.String { @@ -24,6 +25,8 @@ public enum LKUserDefaults { public enum String : Swift.String { case deviceToken + /// Just used for migration purposes. + case displayName } } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 639462ac6..3a7346d4e 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -281,6 +281,7 @@ B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */; }; B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; }; B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; }; + B8A14D702589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A14D6F2589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift */; }; B8B26C8F234D629C004ED98C /* MentionCandidateSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */; }; B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BB82A4238F627000BA5194 /* HomeVC.swift */; }; B8BC00C0257D90E30032E807 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BC00BF257D90E30032E807 /* General.swift */; }; @@ -1389,6 +1390,7 @@ B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMembersVC.swift; sourceTree = ""; }; B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeWrapperVC.swift; sourceTree = ""; }; B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = ""; }; + B8A14D6F2589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPairMigrationSuccessSheet.swift; sourceTree = ""; }; B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionCandidateSelectionView.swift; sourceTree = ""; }; B8B5BCEB2394D869003823C9 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; B8BB829F238F322400BA5194 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; @@ -2626,6 +2628,7 @@ B8BB82A4238F627000BA5194 /* HomeVC.swift */, B8CCF63E23975CFB0091D419 /* JoinPublicChatVC.swift */, B837867F2586D296003CE78E /* KeyPairMigrationSheet.swift */, + B8A14D6F2589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift */, B82B40872399EB0E00A248E7 /* LandingVC.swift */, C329FEEB24F7277900B1C64C /* LightModeSheet.swift */, B86BD08323399ACF000F5AE3 /* Modal.swift */, @@ -5514,6 +5517,7 @@ B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */, 3488F9362191CC4000E524CC /* ConversationMediaView.swift in Sources */, 45F32C242057297A00A300D5 /* MessageDetailViewController.swift in Sources */, + B8A14D702589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift in Sources */, C396DAEF2518408B00FF6DC5 /* ParsingState.swift in Sources */, 3496955C219B605E00DCFE74 /* ImagePickerController.swift in Sources */, 34D1F0841F8678AA0066283D /* ConversationInputToolbar.m in Sources */, From f83662d24b2d227ca572677105db25a3aad647a8 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 16 Dec 2020 16:23:26 +1100 Subject: [PATCH 172/177] Update version number --- Signal.xcodeproj/project.pbxproj | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 3a7346d4e..95067b013 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5678,7 +5678,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 156; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5699,7 +5699,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.2; + MARKETING_VERSION = 1.7.3; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5747,7 +5747,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 156; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5773,7 +5773,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.2; + MARKETING_VERSION = 1.7.3; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5808,7 +5808,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 156; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5827,7 +5827,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.2; + MARKETING_VERSION = 1.7.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5878,7 +5878,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 156; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5902,7 +5902,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.7.2; + MARKETING_VERSION = 1.7.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6897,7 +6897,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 156; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6933,7 +6933,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.2; + MARKETING_VERSION = 1.7.3; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6965,7 +6965,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 156; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -7001,7 +7001,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.7.2; + MARKETING_VERSION = 1.7.3; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From 7ec6ee1bfc7ac98443a5f478253ca185cb1c9cc6 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 17 Dec 2020 09:50:28 +1100 Subject: [PATCH 173/177] Remove unnecessary dispatch_async --- .../ConversationViewController.m | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 3b5369e1a..dda1cfa72 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3738,22 +3738,20 @@ typedef enum : NSUInteger { [self.conversationViewModel appendUnsavedOutgoingTextMessage:tsMessage]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { message.linkPreview = [SNLinkPreview from:linkPreviewDraft using:transaction]; - } completion:^{ + } completion:^{ // Completes on the main queue + tsMessage.linkPreview = [OWSLinkPreview from:message.linkPreview]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [tsMessage saveWithTransaction:transaction]; + }]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [SNMessageSender send:message withAttachments:@[] inThread:thread usingTransaction:transaction]; + [thread setDraft:@"" transaction:transaction]; + }]; + [self messageWasSent:tsMessage]; + [self.inputToolbar clearTextMessageAnimated:YES]; + [self resetMentions]; dispatch_async(dispatch_get_main_queue(), ^{ - tsMessage.linkPreview = [OWSLinkPreview from:message.linkPreview]; - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [tsMessage saveWithTransaction:transaction]; - }]; - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [SNMessageSender send:message withAttachments:@[] inThread:thread usingTransaction:transaction]; - [thread setDraft:@"" transaction:transaction]; - }]; - [self messageWasSent:tsMessage]; - [self.inputToolbar clearTextMessageAnimated:YES]; - [self resetMentions]; - dispatch_async(dispatch_get_main_queue(), ^{ - [[weakSelf inputToolbar] toggleDefaultKeyboard]; - }); + [[weakSelf inputToolbar] toggleDefaultKeyboard]; }); }]; } From c1595a6e923086be5b582dae63d1336ebbf8ea37 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 17 Dec 2020 09:50:56 +1100 Subject: [PATCH 174/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 95067b013..4c0615aee 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5678,7 +5678,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 156; + CURRENT_PROJECT_VERSION = 157; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5747,7 +5747,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 156; + CURRENT_PROJECT_VERSION = 157; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5808,7 +5808,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 156; + CURRENT_PROJECT_VERSION = 157; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5878,7 +5878,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 156; + CURRENT_PROJECT_VERSION = 157; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6897,7 +6897,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 156; + CURRENT_PROJECT_VERSION = 157; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6965,7 +6965,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 156; + CURRENT_PROJECT_VERSION = 157; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 6de6c8cf5d76bb4d51859e233806f1249297169e Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 17 Dec 2020 11:37:53 +1100 Subject: [PATCH 175/177] Improve accessibility --- Session/Components/NewConversationButtonSet.swift | 8 ++++++++ .../ConversationView/ConversationInputToolbar.m | 6 ++++++ .../ConversationView/ConversationViewController.m | 2 ++ Session/View Controllers/DisplayNameVC.swift | 1 + Session/View Controllers/HomeVC.swift | 14 ++++++++++++-- Session/View Controllers/PNModeVC.swift | 15 +++++++++++++-- Session/View Controllers/QRCodeVC.swift | 2 ++ Session/View Controllers/RegisterVC.swift | 1 + Session/View Controllers/RestoreVC.swift | 1 + Session/View Controllers/SettingsVC.swift | 13 +++++++++++++ 10 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Session/Components/NewConversationButtonSet.swift b/Session/Components/NewConversationButtonSet.swift index 36c4b9d61..46e19d28c 100644 --- a/Session/Components/NewConversationButtonSet.swift +++ b/Session/Components/NewConversationButtonSet.swift @@ -31,6 +31,14 @@ final class NewConversationButtonSet : UIView { } private func setUpViewHierarchy() { + mainButton.accessibilityLabel = "Toggle conversation options button" + mainButton.isAccessibilityElement = true + createNewPrivateChatButton.accessibilityLabel = "Start new one-on-one conversation button" + createNewPrivateChatButton.isAccessibilityElement = true + createNewClosedGroupButton.accessibilityLabel = "Start new closed group button" + createNewClosedGroupButton.isAccessibilityElement = true + joinOpenGroupButton.accessibilityLabel = "Join open group button" + joinOpenGroupButton.isAccessibilityElement = true let inset = (Values.newConversationButtonExpandedSize - Values.newConversationButtonCollapsedSize) / 2 addSubview(joinOpenGroupButton) horizontalButtonConstraints[joinOpenGroupButton] = joinOpenGroupButton.pin(.left, to: .left, of: self, withInset: inset) diff --git a/Session/Signal/ConversationView/ConversationInputToolbar.m b/Session/Signal/ConversationView/ConversationInputToolbar.m index 05a1a00f4..a397466ec 100644 --- a/Session/Signal/ConversationView/ConversationInputToolbar.m +++ b/Session/Signal/ConversationView/ConversationInputToolbar.m @@ -127,6 +127,8 @@ const CGFloat kMaxTextViewHeight = 120; self.inputTextView.backgroundColor = LKColors.composeViewTextFieldBackground; [self.inputTextView setContentHuggingLow]; [self.inputTextView setCompressionResistanceLow]; + self.inputTextView.accessibilityLabel = @"Input text view"; + self.inputTextView.isAccessibilityElement = YES; SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _inputTextView); _textViewHeightConstraint = [self.inputTextView autoSetDimension:ALDimensionHeight toSize:kMinTextViewHeight]; @@ -147,11 +149,15 @@ const CGFloat kMaxTextViewHeight = 120; [self.sendButton autoSetDimensionsToSize:CGSizeMake(40, kMinTextViewHeight)]; SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _sendButton); [self.sendButton addTarget:self action:@selector(sendButtonPressed) forControlEvents:UIControlEventTouchUpInside]; + self.sendButton.accessibilityLabel = @"Send button"; + self.sendButton.isAccessibilityElement = YES; _voiceMemoButton = [UIButton buttonWithType:UIButtonTypeCustom]; UIImage *voiceMemoIcon = [[UIImage imageNamed:@"Microphone"] asTintedImageWithColor:LKColors.text]; [self.voiceMemoButton setImage:voiceMemoIcon forState:UIControlStateNormal]; [self.voiceMemoButton autoSetDimensionsToSize:CGSizeMake(40, kMinTextViewHeight)]; + self.voiceMemoButton.accessibilityLabel = @"Voice message button"; + self.voiceMemoButton.isAccessibilityElement = YES; SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _voiceMemoButton); // We want to be permissive about the voice message gesture, so we hang diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index dda1cfa72..cc8f4c1b4 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -599,6 +599,8 @@ typedef enum : NSUInteger { self.collectionView.backgroundColor = UIColor.clearColor; UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Gear"] style:UIBarButtonItemStylePlain target:self action:@selector(showConversationSettings)]; settingsButton.tintColor = LKColors.text; + settingsButton.accessibilityLabel = @"Conversation settings button"; + settingsButton.isAccessibilityElement = YES; self.navigationItem.rightBarButtonItem = settingsButton; if (self.thread.isGroupThread) { diff --git a/Session/View Controllers/DisplayNameVC.swift b/Session/View Controllers/DisplayNameVC.swift index 1a3232412..fd6e0ce28 100644 --- a/Session/View Controllers/DisplayNameVC.swift +++ b/Session/View Controllers/DisplayNameVC.swift @@ -9,6 +9,7 @@ final class DisplayNameVC : BaseVC { private lazy var displayNameTextField: TextField = { let result = TextField(placeholder: NSLocalizedString("vc_display_name_text_field_hint", comment: "")) result.layer.borderColor = Colors.text.cgColor + result.accessibilityLabel = "Display name text field" return result }() diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index aa5982eec..d05060d1e 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -306,6 +306,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol private func updateNavigationBarButtons() { let profilePictureSize = Values.verySmallProfilePictureSize let profilePictureView = ProfilePictureView() + profilePictureView.accessibilityLabel = "Settings button" profilePictureView.size = profilePictureSize profilePictureView.hexEncodedPublicKey = getUserHexEncodedPublicKey() profilePictureView.update() @@ -314,24 +315,33 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings)) profilePictureView.addGestureRecognizer(tapGestureRecognizer) let profilePictureViewContainer = UIView() + profilePictureViewContainer.accessibilityLabel = "Settings button" profilePictureViewContainer.addSubview(profilePictureView) profilePictureView.pin(.leading, to: .leading, of: profilePictureViewContainer, withInset: 4) profilePictureView.pin(.top, to: .top, of: profilePictureViewContainer) profilePictureView.pin(.trailing, to: .trailing, of: profilePictureViewContainer) profilePictureView.pin(.bottom, to: .bottom, of: profilePictureViewContainer) - navigationItem.leftBarButtonItem = UIBarButtonItem(customView: profilePictureViewContainer) + let leftBarButtonItem = UIBarButtonItem(customView: profilePictureViewContainer) + leftBarButtonItem.accessibilityLabel = "Settings button" + leftBarButtonItem.isAccessibilityElement = true + navigationItem.leftBarButtonItem = leftBarButtonItem let pathStatusViewContainer = UIView() + pathStatusViewContainer.accessibilityLabel = "Current onion routing path button" let pathStatusViewContainerSize = Values.verySmallProfilePictureSize // Match the profile picture view pathStatusViewContainer.set(.width, to: pathStatusViewContainerSize) pathStatusViewContainer.set(.height, to: pathStatusViewContainerSize) let pathStatusView = PathStatusView() + pathStatusView.accessibilityLabel = "Current onion routing path button" pathStatusView.set(.width, to: Values.pathStatusViewSize) pathStatusView.set(.height, to: Values.pathStatusViewSize) pathStatusViewContainer.addSubview(pathStatusView) pathStatusView.center(.horizontal, in: pathStatusViewContainer) pathStatusView.center(.vertical, in: pathStatusViewContainer) pathStatusViewContainer.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(showPath))) - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: pathStatusViewContainer) + let rightBarButtonItem = UIBarButtonItem(customView: pathStatusViewContainer) + rightBarButtonItem.accessibilityLabel = "Current onion routing path button" + rightBarButtonItem.isAccessibilityElement = true + navigationItem.rightBarButtonItem = rightBarButtonItem } @objc override internal func handleAppModeChangedNotification(_ notification: Notification) { diff --git a/Session/View Controllers/PNModeVC.swift b/Session/View Controllers/PNModeVC.swift index 1a84e3b09..7fb50d6ab 100644 --- a/Session/View Controllers/PNModeVC.swift +++ b/Session/View Controllers/PNModeVC.swift @@ -11,8 +11,19 @@ final class PNModeVC : BaseVC, OptionViewDelegate { } // MARK: Components - private lazy var apnsOptionView = OptionView(title: "Fast Mode", explanation: "You’ll be notified of new messages reliably and immediately using Apple’s notification servers. The contents of your messages, and who you’re messaging, are never exposed to Apple.", delegate: self, isRecommended: true) - private lazy var backgroundPollingOptionView = OptionView(title: "Slow Mode", explanation: "Session will occasionally check for new messages in the background. Full metadata protection is guaranteed, but message notifications will be unreliable.", delegate: self) + private lazy var apnsOptionView: OptionView = { + let explanation = "You’ll be notified of new messages reliably and immediately using Apple’s notification servers. The contents of your messages, and who you’re messaging, are never exposed to Apple." + let result = OptionView(title: "Fast Mode", explanation: explanation, delegate: self, isRecommended: true) + result.accessibilityLabel = "Fast mode option" + return result + }() + + private lazy var backgroundPollingOptionView: OptionView = { + let explanation = "Session will occasionally check for new messages in the background. Full metadata protection is guaranteed, but message notifications will be unreliable." + let result = OptionView(title: "Slow Mode", explanation: explanation, delegate: self) + result.accessibilityLabel = "Slow mode option" + return result + }() // MARK: Lifecycle override func viewDidLoad() { diff --git a/Session/View Controllers/QRCodeVC.swift b/Session/View Controllers/QRCodeVC.swift index 7d35f1725..ffdf62a8d 100644 --- a/Session/View Controllers/QRCodeVC.swift +++ b/Session/View Controllers/QRCodeVC.swift @@ -159,6 +159,8 @@ private final class ViewMyQRCodeVC : UIViewController { qrCodeImageView.set(.width, to: isIPhone5OrSmaller ? 180 : 240) // Set up QR code image view container let qrCodeImageViewContainer = UIView() + qrCodeImageViewContainer.accessibilityLabel = "Your QR code" + qrCodeImageViewContainer.isAccessibilityElement = true qrCodeImageViewContainer.addSubview(qrCodeImageView) qrCodeImageView.center(.horizontal, in: qrCodeImageViewContainer) qrCodeImageView.pin(.top, to: .top, of: qrCodeImageViewContainer) diff --git a/Session/View Controllers/RegisterVC.swift b/Session/View Controllers/RegisterVC.swift index 08920d4d0..b6f2f651c 100644 --- a/Session/View Controllers/RegisterVC.swift +++ b/Session/View Controllers/RegisterVC.swift @@ -12,6 +12,7 @@ final class RegisterVC : BaseVC { result.font = Fonts.spaceMono(ofSize: isIPhone5OrSmaller ? Values.mediumFontSize : 20) result.numberOfLines = 0 result.lineBreakMode = .byCharWrapping + result.accessibilityLabel = "Session ID label" return result }() diff --git a/Session/View Controllers/RestoreVC.swift b/Session/View Controllers/RestoreVC.swift index e4c15109e..c35b834b8 100644 --- a/Session/View Controllers/RestoreVC.swift +++ b/Session/View Controllers/RestoreVC.swift @@ -10,6 +10,7 @@ final class RestoreVC : BaseVC { private lazy var mnemonicTextView: TextView = { let result = TextView(placeholder: NSLocalizedString("vc_restore_seed_text_field_hint", comment: "")) result.layer.borderColor = Colors.text.cgColor + result.accessibilityLabel = "Recovery phrase text view" return result }() diff --git a/Session/View Controllers/SettingsVC.swift b/Session/View Controllers/SettingsVC.swift index edb577b90..c7cadabb7 100644 --- a/Session/View Controllers/SettingsVC.swift +++ b/Session/View Controllers/SettingsVC.swift @@ -11,6 +11,8 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { result.size = size result.set(.width, to: size) result.set(.height, to: size) + result.accessibilityLabel = "Edit profile picture button" + result.isAccessibilityElement = true return result }() @@ -32,6 +34,7 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { private lazy var displayNameTextField: TextField = { let result = TextField(placeholder: NSLocalizedString("vc_settings_display_name_text_field_hint", comment: ""), usesDefaultHeight: false) result.textAlignment = .center + result.accessibilityLabel = "Edit display name text field" return result }() @@ -69,6 +72,8 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { displayNameLabel.text = OWSProfileManager.shared().profileNameForRecipient(withID: getUserHexEncodedPublicKey()) // Set up display name container let displayNameContainer = UIView() + displayNameContainer.accessibilityLabel = "Edit display name text field" + displayNameContainer.isAccessibilityElement = true displayNameContainer.addSubview(displayNameLabel) displayNameLabel.pin(to: displayNameContainer) displayNameContainer.addSubview(displayNameTextField) @@ -236,13 +241,19 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { if isEditingDisplayName { let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(handleCancelDisplayNameEditingButtonTapped)) cancelButton.tintColor = Colors.text + cancelButton.accessibilityLabel = "Cancel button" + cancelButton.isAccessibilityElement = true navigationItem.leftBarButtonItem = cancelButton let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleSaveDisplayNameButtonTapped)) doneButton.tintColor = Colors.text + doneButton.accessibilityLabel = "Done button" + doneButton.isAccessibilityElement = true navigationItem.rightBarButtonItem = doneButton } else { let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) closeButton.tintColor = Colors.text + closeButton.accessibilityLabel = "Close button" + closeButton.isAccessibilityElement = true navigationItem.leftBarButtonItem = closeButton if #available(iOS 13, *) { // Pre iOS 13 the user can't switch actively but the app still responds to system changes let appModeIcon = isDarkMode ? #imageLiteral(resourceName: "ic_dark_theme_on").withTintColor(.white) : #imageLiteral(resourceName: "ic_dark_theme_off").withTintColor(.black) @@ -250,11 +261,13 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { appModeButton.setImage(appModeIcon, for: UIControl.State.normal) appModeButton.tintColor = Colors.text appModeButton.addTarget(self, action: #selector(switchAppMode), for: UIControl.Event.touchUpInside) + appModeButton.accessibilityLabel = "Switch app mode button" let qrCodeIcon = isDarkMode ? #imageLiteral(resourceName: "QRCode").withTintColor(.white) : #imageLiteral(resourceName: "QRCode").withTintColor(.black) let qrCodeButton = UIButton() qrCodeButton.setImage(qrCodeIcon, for: UIControl.State.normal) qrCodeButton.tintColor = Colors.text qrCodeButton.addTarget(self, action: #selector(showQRCode), for: UIControl.Event.touchUpInside) + qrCodeButton.accessibilityLabel = "Show QR code button" let stackView = UIStackView(arrangedSubviews: [ appModeButton, qrCodeButton ]) stackView.axis = .horizontal stackView.spacing = Values.mediumSpacing From 6fafdf270cdecc576c1bf7e5b95bfe75c8fd488e Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 17 Dec 2020 11:40:40 +1100 Subject: [PATCH 176/177] Update build number --- Signal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 4c0615aee..258d07ee6 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -5678,7 +5678,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 157; + CURRENT_PROJECT_VERSION = 158; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5747,7 +5747,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 157; + CURRENT_PROJECT_VERSION = 158; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5808,7 +5808,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 157; + CURRENT_PROJECT_VERSION = 158; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5878,7 +5878,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 157; + CURRENT_PROJECT_VERSION = 158; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6897,7 +6897,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 157; + CURRENT_PROJECT_VERSION = 158; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6965,7 +6965,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 157; + CURRENT_PROJECT_VERSION = 158; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 451e62960564afb58e873117228f68162cb3e000 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 18 Dec 2020 11:12:07 +1100 Subject: [PATCH 177/177] Fix open group profile picture bug #314 without merge conflicts --- SessionMessagingKit/Open Groups/OpenGroupAPI.swift | 11 +++++++++-- .../Attachments/OWSThumbnailService.swift | 2 +- SignalUtilitiesKit/UI/ProfilePictureView.swift | 6 +----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 714cbdddc..ad0f2c63b 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -382,8 +382,15 @@ public final class OpenGroupAPI : DotNetAPI { var sanitizedProfilePictureURL = profilePictureURL while sanitizedProfilePictureURL.hasPrefix("/") { sanitizedProfilePictureURL.removeFirst() } let url = "\(sanitizedServerURL)/\(sanitizedProfilePictureURL)" - FileServerAPI.downloadAttachment(from: url).map2 { data in - let attachmentStream = TSAttachmentStream(contentType: OWSMimeTypeImageJpeg, byteCount: UInt32(data.count), sourceFilename: nil, caption: nil, albumMessageId: nil) + FileServerAPI.downloadAttachment(from: url).map2 { rawData in + let attachmentStream: TSAttachmentStream + let data: Data + if let rawImage = UIImage(data: rawData), let jpegData = rawImage.jpegData(compressionQuality: 0.8) { + data = jpegData + } else { + data = rawData + } + attachmentStream = TSAttachmentStream(contentType: OWSMimeTypeImageJpeg, byteCount: UInt32(data.count), sourceFilename: nil, caption: nil, albumMessageId: nil) try attachmentStream.write(data) thread.updateAvatar(with: attachmentStream) } diff --git a/SessionMessagingKit/Sending & Receiving/Attachments/OWSThumbnailService.swift b/SessionMessagingKit/Sending & Receiving/Attachments/OWSThumbnailService.swift index 0b6601fc2..ac20fe716 100644 --- a/SessionMessagingKit/Sending & Receiving/Attachments/OWSThumbnailService.swift +++ b/SessionMessagingKit/Sending & Receiving/Attachments/OWSThumbnailService.swift @@ -158,7 +158,7 @@ private struct OWSThumbnailRequest { throw OWSThumbnailError.failure(description: "Could not convert thumbnail to JPEG.") } do { - try thumbnailData.write(to: URL(fileURLWithPath: thumbnailPath), options: .atomicWrite) + try thumbnailData.write(to: URL(fileURLWithPath: thumbnailPath, isDirectory: false), options: .atomic) } catch let error as NSError { throw OWSThumbnailError.externalError(description: "File write failed: \(thumbnailPath), \(error)", underlyingError: error) } diff --git a/SignalUtilitiesKit/UI/ProfilePictureView.swift b/SignalUtilitiesKit/UI/ProfilePictureView.swift index a53f34532..bb4d30f96 100644 --- a/SignalUtilitiesKit/UI/ProfilePictureView.swift +++ b/SignalUtilitiesKit/UI/ProfilePictureView.swift @@ -60,11 +60,7 @@ public final class ProfilePictureView : UIView { public func update(for thread: TSThread) { openGroupProfilePicture = nil if let thread = thread as? TSGroupThread { - if thread.name() == "Loki Public Chat" - || thread.name() == "Session Public Chat" { // Override the profile picture for the Loki Public Chat and the Session Public Chat - hexEncodedPublicKey = "" - isRSSFeed = true - } else if let openGroupProfilePicture = thread.groupModel.groupImage { // An open group with a profile picture + if let openGroupProfilePicture = thread.groupModel.groupImage { // An open group with a profile picture self.openGroupProfilePicture = openGroupProfilePicture isRSSFeed = false hasTappableProfilePicture = true