diff --git a/Pods b/Pods index 0018c3f03d8..1ab1cbbeb63 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 0018c3f03d84f90cd1c0e49fd4e4bf8da8e14d77 +Subproject commit 1ab1cbbeb63409bd78306e358eb99de4a8ad3e42 diff --git a/SignalServiceKit/src/Loki/Multidevice/LokiPairingAuthorisation.swift b/SignalServiceKit/src/Loki/Multidevice/LokiPairingAuthorisation.swift index 8e7bf31511c..55fb844ba7f 100644 --- a/SignalServiceKit/src/Loki/Multidevice/LokiPairingAuthorisation.swift +++ b/SignalServiceKit/src/Loki/Multidevice/LokiPairingAuthorisation.swift @@ -1,16 +1,37 @@ @objc(LKPairingAuthorisation) -public final class LokiPairingAuthorisation : NSObject { +public final class LokiPairingAuthorisation : NSObject, NSCoding { @objc public let primaryDevicePubKey: String @objc public let secondaryDevicePubKey: String - @objc public let isGranted: Bool @objc public let requestSignature: Data? @objc public let grantSignature: Data? - @objc public init(primaryDevicePubKey: String, secondaryDevicePubKey: String, isGranted: Bool, requestSignature: Data? = nil, grantSignature: Data? = nil) { + @objc public var isGranted: Bool { + return grantSignature != nil + } + + @objc public init(primaryDevicePubKey: String, secondaryDevicePubKey: String, requestSignature: Data? = nil, grantSignature: Data? = nil) { self.primaryDevicePubKey = primaryDevicePubKey self.secondaryDevicePubKey = secondaryDevicePubKey - self.isGranted = isGranted self.requestSignature = requestSignature self.grantSignature = grantSignature } + + public convenience init?(coder aDecoder: NSCoder) { + guard let primaryDevicePubKey = aDecoder.decodeObject(forKey: "primaryDevicePubKey") as? String, + let secondaryDevicePubKey = aDecoder.decodeObject(forKey: "secondaryDevicePubKey") as? String else { + return nil + } + + let requestSignature = aDecoder.decodeObject(forKey: "requestSignature") as? Data + let grantSignature = aDecoder.decodeObject(forKey: "grantSignature") as? Data + + self.init(primaryDevicePubKey: primaryDevicePubKey, secondaryDevicePubKey: secondaryDevicePubKey, requestSignature: requestSignature, grantSignature: grantSignature) + } + + public func encode(with aCoder: NSCoder) { + aCoder.encode(primaryDevicePubKey, forKey: "primaryDevicePubKey") + aCoder.encode(secondaryDevicePubKey, forKey: "secondaryDevicePubKey") + aCoder.encode(requestSignature, forKey: "requestSignature") + aCoder.encode(grantSignature, forKey: "grantSignature") + } } diff --git a/SignalServiceKit/src/Loki/Multidevice/OWSPrimaryStorage+Multidevice.swift b/SignalServiceKit/src/Loki/Multidevice/OWSPrimaryStorage+Multidevice.swift new file mode 100644 index 00000000000..fb7c452bfc4 --- /dev/null +++ b/SignalServiceKit/src/Loki/Multidevice/OWSPrimaryStorage+Multidevice.swift @@ -0,0 +1,31 @@ +extension OWSPrimaryStorage { + private func getCollection(for primaryDevice: String) -> String { + return "LokiMultiDevice-\(primaryDevice)" + } + + public func getAuthorisation(forSecondaryDevice secondaryDevice: String, with transaction: YapDatabaseReadTransaction) -> LokiPairingAuthorisation? { + let query = YapDatabaseQuery(string: "WHERE \(PairingAuthorisationsIndex.secondaryDevicePubKey) = ?", parameters: [secondaryDevice]) + let authorisations = PairingAuthorisationsIndex.getPairingAuthorisations(with: query, transaction: transaction) + + // This should never be the case + if (authorisations.count > 1) { owsFailDebug("[Loki][Multidevice] Found multiple authorisations for secondary device: \(secondaryDevice)") } + + return authorisations.first + } + + public func createOrUpdatePairingAuthorisation(_ authorisation: LokiPairingAuthorisation, with transaction: YapDatabaseReadWriteTransaction) { + // iOS makes this easy, we can group all authorizations into the primary device collection + // Then we associate an authorisation with the secondary device key + transaction.setObject(authorisation, forKey: authorisation.secondaryDevicePubKey, inCollection: getCollection(for: authorisation.primaryDevicePubKey)) + } + + public func getSecondaryDevices(forPrimaryDevice primaryDevice: String, with transaction: YapDatabaseReadTransaction) -> [String] { + // primary device collection should have secondary devices as its keys + return transaction.allKeys(inCollection: getCollection(for: primaryDevice)) + } + + public func getPrimaryDevice(forSecondaryDevice secondaryDevice: String, with transaction: YapDatabaseReadTransaction) -> String? { + let authorisation = getAuthorisation(forSecondaryDevice: secondaryDevice, with: transaction) + return authorisation?.primaryDevicePubKey + } +} diff --git a/SignalServiceKit/src/Loki/Multidevice/PairingAuthorisationsIndex.swift b/SignalServiceKit/src/Loki/Multidevice/PairingAuthorisationsIndex.swift index aa25cc157ef..ec718fd9547 100644 --- a/SignalServiceKit/src/Loki/Multidevice/PairingAuthorisationsIndex.swift +++ b/SignalServiceKit/src/Loki/Multidevice/PairingAuthorisationsIndex.swift @@ -7,6 +7,8 @@ public final class PairingAuthorisationsIndex : NSObject { @objc public static let secondaryDevicePubKey = "pairing_secondary_device_pub_key" @objc public static let isGranted = "pairing_is_granted" + // MARK: Database Extension + @objc public static var indexDatabaseExtension: YapDatabaseSecondaryIndex { let setup = YapDatabaseSecondaryIndexSetup() setup.addColumn(primaryDevicePubKey, with: .text) @@ -14,15 +16,10 @@ public final class PairingAuthorisationsIndex : NSObject { setup.addColumn(isGranted, with: .integer) let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock { (transaction, dict, collection, key, object) in - // TODO: Handle pairing authorisations object - /* - guard let message = object as? TSMessage else { return } - - // Only select sent friend requests which are pending - guard message is TSOutgoingMessage && message.friendRequestStatus == .pending else { return } - - dict[friendRequestExpireColumn] = message.friendRequestExpiresAt - */ + guard let pairing = object as? LokiPairingAuthorisation else { return } + dict[primaryDevicePubKey] = pairing.primaryDevicePubKey + dict[secondaryDevicePubKey] = pairing.secondaryDevicePubKey + dict[isGranted] = pairing.isGranted } return YapDatabaseSecondaryIndex(setup: setup, handler: handler) @@ -35,4 +32,22 @@ public final class PairingAuthorisationsIndex : NSObject { @objc public static func asyncRegisterDatabaseExtensions(_ storage: OWSStorage) { storage.register(indexDatabaseExtension, withName: name) } + + // MARK: Helper + + public static func enumeratePairingAuthorisations(with query: YapDatabaseQuery, transaction: YapDatabaseReadTransaction, block: @escaping (LokiPairingAuthorisation, UnsafeMutablePointer) -> Void) { + let ext = transaction.ext(PairingAuthorisationsIndex.name) as? YapDatabaseSecondaryIndexTransaction + ext?.enumerateKeysAndObjects(matching: query) { (collection, key, object, stop) in + guard let authorisation = object as? LokiPairingAuthorisation else { return } + block(authorisation, stop) + } + } + + public static func getPairingAuthorisations(with query: YapDatabaseQuery, transaction: YapDatabaseReadTransaction) -> [LokiPairingAuthorisation] { + var authorisations = [LokiPairingAuthorisation]() + enumeratePairingAuthorisations(with: query, transaction: transaction) { (authorisation, _) in + authorisations.append(authorisation) + } + return authorisations + } }