From 78adfabf0c7746a6a42595c9e7a2bc98df6a5a8c Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 7 May 2019 10:10:15 +1000 Subject: [PATCH] Implement new messaging API --- SignalServiceKit/src/Loki/LokiMessage.swift | 49 +++++++++++++++++++ .../src/Loki/LokiMessagingAPI.swift | 25 ++++++++-- SignalServiceKit/src/Loki/SignalMessage.swift | 2 + .../Network/API/Requests/OWSRequestFactory.m | 2 +- 4 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 SignalServiceKit/src/Loki/LokiMessage.swift create mode 100644 SignalServiceKit/src/Loki/SignalMessage.swift diff --git a/SignalServiceKit/src/Loki/LokiMessage.swift b/SignalServiceKit/src/Loki/LokiMessage.swift new file mode 100644 index 000000000..55060e832 --- /dev/null +++ b/SignalServiceKit/src/Loki/LokiMessage.swift @@ -0,0 +1,49 @@ +import PromiseKit + +@objc public final class LokiMessage : NSObject { + /// The hex encoded public key of the receiver. + let destination: String + /// The content of the message. + let data: LosslessStringConvertible + /// The time to live for the message. + let ttl: UInt64 + /// When the proof of work was calculated. + let timestamp: UInt64 + /// The base 64 encoded proof of work. + let nonce: String + + init(destination: String, data: LosslessStringConvertible, ttl: UInt64, timestamp: UInt64, nonce: String) { + self.destination = destination + self.data = data + self.ttl = ttl + self.timestamp = timestamp + self.nonce = nonce + } + + public static func fromSignalMessage(_ signalMessage: SignalMessage) -> Promise { + return Promise { seal in + DispatchQueue.global(qos: .default).async { + let destination = signalMessage["destination"]! + let data = signalMessage["content"]! + let ttl = LokiMessagingAPI.defaultTTL + let timestamp = UInt64(Date().timeIntervalSince1970) + if let nonce = ProofOfWork.calculate(data: data, pubKey: destination, timestamp: timestamp, ttl: Int(ttl)) { + let result = LokiMessage(destination: destination, data: data, ttl: ttl, timestamp: timestamp, nonce: nonce) + seal.fulfill(result) + } else { + seal.reject(LokiMessagingAPI.Error.proofOfWorkCalculationFailed) + } + } + } + } + + func toJSON() -> [String:String] { + return [ + "destination" : destination, + "data" : data.description, + "ttl" : String(ttl), + "timestamp" : String(timestamp), + "nonce" : nonce + ] + } +} diff --git a/SignalServiceKit/src/Loki/LokiMessagingAPI.swift b/SignalServiceKit/src/Loki/LokiMessagingAPI.swift index f3a23402a..73567f642 100644 --- a/SignalServiceKit/src/Loki/LokiMessagingAPI.swift +++ b/SignalServiceKit/src/Loki/LokiMessagingAPI.swift @@ -5,6 +5,7 @@ import PromiseKit private static var baseURL: String { return textSecureServerURL } private static var port: String { return "8080" } private static var apiVersion: String { return "v1" } + public static let defaultTTL: UInt64 = 4 * 24 * 60 * 60 // MARK: Types private enum Method : String { @@ -14,18 +15,32 @@ import PromiseKit public typealias RawResponse = TSNetworkManager.NetworkManagerResult + public enum Error : LocalizedError { + case proofOfWorkCalculationFailed + + public var errorDescription: String? { + switch self { + case .proofOfWorkCalculationFailed: return NSLocalizedString("Failed to calculate proof of work.", comment: "") + } + } + } + // MARK: Lifecycle override private init() { } // MARK: API - private static func invoke(_ method: Method, parameters: [String:String] = [:]) -> (request: TSRequest, promise: Promise) { + private static func invoke(_ method: Method, parameters: [String:String] = [:]) -> Promise { let url = URL(string: "\(baseURL):\(port)/\(apiVersion)/storage_rpc")! let request = TSRequest(url: url, method: "POST", parameters: [ "method" : method.rawValue, "params" : parameters ]) - return (request, TSNetworkManager.shared().makePromise(request: request)) + return TSNetworkManager.shared().makePromise(request: request) } - @objc public static func sendMessage(_ message: [String:String]) -> TSRequest { - return invoke(.sendMessage, parameters: message).request + public static func sendSignalMessage(_ signalMessage: SignalMessage, to destination: String) -> Promise { + return LokiMessage.fromSignalMessage(signalMessage).then(sendMessage) + } + + public static func sendMessage(_ lokiMessage: LokiMessage) -> Promise { + return invoke(.sendMessage, parameters: lokiMessage.toJSON()) } public static func retrieveAllMessages() -> Promise { @@ -33,6 +48,6 @@ import PromiseKit "pubKey" : OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey, "lastHash" : "" // TODO: Implement ] - return invoke(.retrieveAllMessages, parameters: parameters).promise + return invoke(.retrieveAllMessages, parameters: parameters) } } diff --git a/SignalServiceKit/src/Loki/SignalMessage.swift b/SignalServiceKit/src/Loki/SignalMessage.swift new file mode 100644 index 000000000..f6c9fb6a3 --- /dev/null +++ b/SignalServiceKit/src/Loki/SignalMessage.swift @@ -0,0 +1,2 @@ + +public typealias SignalMessage = [String:String] diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index 704d95d81..72d1fd5bf 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -405,7 +405,7 @@ NS_ASSUME_NONNULL_BEGIN NSString *path = [textSecureMessagesAPI stringByAppendingString:recipientId]; NSDictionary *parameters = [lokiMessages objectAtIndex:0]; - return [LokiMessagingAPI sendMessage:parameters]; + return [TSRequest new]; // TODO: Just here to make things build } + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId