Added LokiP2PMessageHandler.

Moved wrapping and unwrapping of proto envelopes to LokiMessageWrapper.
pull/18/head
Mikunj 6 years ago
parent 748b7eff12
commit 865bb1932f

@ -1 +1 @@
Subproject commit 077f345d2993bf2a7dab8df935986e6495e764c7 Subproject commit 32ca94b0b45a1f55059ee500c5e217a0f55a0313

@ -1,6 +1,13 @@
import GCDWebServer import GCDWebServer
// Convenience functions // Convenience functions
fileprivate extension GCDWebServerResponse {
convenience init<E: RawRepresentable>(statusCode: E) where E.RawValue == Int {
self.init(statusCode: statusCode.rawValue)
}
}
fileprivate extension GCDWebServerDataRequest { fileprivate extension GCDWebServerDataRequest {
var truncatedContentType: String? { var truncatedContentType: String? {
guard let contentType = contentType else { return nil } guard let contentType = contentType else { return nil }
@ -27,7 +34,7 @@ fileprivate extension GCDWebServerDataRequest {
@objc class LokiP2PServer : NSObject { @objc class LokiP2PServer : NSObject {
private enum StatusCode: Int { fileprivate enum StatusCode: Int {
case ok = 200 case ok = 200
case badRequest = 400 case badRequest = 400
case notFound = 404 case notFound = 404
@ -40,7 +47,7 @@ fileprivate extension GCDWebServerDataRequest {
// Don't allow specific methods // Don't allow specific methods
let invalidMethodProcessBlock: (GCDWebServerRequest) -> GCDWebServerResponse? = { _ in let invalidMethodProcessBlock: (GCDWebServerRequest) -> GCDWebServerResponse? = { _ in
return GCDWebServerResponse(statusCode: StatusCode.methodNotAllowed.rawValue) return GCDWebServerResponse(statusCode: StatusCode.methodNotAllowed)
} }
let invalidMethods = ["GET", "PUT", "DELETE"] let invalidMethods = ["GET", "PUT", "DELETE"]
@ -50,27 +57,31 @@ fileprivate extension GCDWebServerDataRequest {
// By default send 404 for any path // By default send 404 for any path
webServer.addDefaultHandler(forMethod: "POST", request: GCDWebServerRequest.self, processBlock: { _ in webServer.addDefaultHandler(forMethod: "POST", request: GCDWebServerRequest.self, processBlock: { _ in
return GCDWebServerResponse(statusCode: StatusCode.notFound.rawValue) return GCDWebServerResponse(statusCode: StatusCode.notFound)
}) })
// Handle our specific storage path // Handle our specific storage path
webServer.addHandler(forMethod: "POST", path: "/v1/storage_rpc", request: GCDWebServerDataRequest.self, asyncProcessBlock: { (request, completionBlock) in webServer.addHandler(forMethod: "POST", path: "/v1/storage_rpc", request: GCDWebServerDataRequest.self, processBlock: { request in
// Make sure we were sent a good request // Make sure we were sent a good request
guard let dataRequest = request as? GCDWebServerDataRequest, let json = dataRequest.jsonObject else { guard let dataRequest = request as? GCDWebServerDataRequest, let json = dataRequest.jsonObject else {
completionBlock(GCDWebServerResponse(statusCode: StatusCode.badRequest.rawValue)) return GCDWebServerResponse(statusCode: StatusCode.badRequest)
return
} }
// Only allow the store method // Only allow the store method
guard let method = json["method"] as? String, method == "store" else { guard let method = json["method"] as? String, method == "store" else {
completionBlock(GCDWebServerResponse(statusCode: StatusCode.notFound.rawValue)) return GCDWebServerResponse(statusCode: StatusCode.notFound)
return }
// Make sure we have the data
guard let params = json["params"] as? [String: String], let data = params["data"] else {
return GCDWebServerResponse(statusCode: StatusCode.badRequest)
} }
// TODO: Decrypt message here // Pass it off to the message handler
LokiP2PMessageHandler.shared.handleReceivedMessage(base64EncodedData: data)
let response = GCDWebServerResponse(statusCode: StatusCode.ok.rawValue) // Send a response back
completionBlock(response) return GCDWebServerResponse(statusCode: StatusCode.ok.rawValue)
}) })
return webServer return webServer

@ -38,6 +38,10 @@ message Envelope {
optional string serverGuid = 9; optional string serverGuid = 9;
// We may eventually want to make this required. // We may eventually want to make this required.
optional uint64 serverTimestamp = 10; optional uint64 serverTimestamp = 10;
// Loki: This field is only here as a helper
// It shouldn't be set when sending a message
optional bool isPtpMessage = 999;
} }
message TypingMessage { message TypingMessage {

@ -32,7 +32,7 @@ public extension LokiAPI {
return Promise<Message> { seal in return Promise<Message> { seal in
DispatchQueue.global(qos: .default).async { DispatchQueue.global(qos: .default).async {
do { do {
let wrappedMessage = try wrap(message: signalMessage, timestamp: timestamp) let wrappedMessage = try LokiMessageWrapper.wrap(message: signalMessage, timestamp: timestamp)
let data = wrappedMessage.base64EncodedString() let data = wrappedMessage.base64EncodedString()
let destination = signalMessage["destination"] as! String let destination = signalMessage["destination"] as! String
let ttl = LokiAPI.defaultMessageTTL let ttl = LokiAPI.defaultMessageTTL

@ -57,7 +57,7 @@ import PromiseKit
Logger.warn("[Loki] Failed to decode data for message: \(message).") Logger.warn("[Loki] Failed to decode data for message: \(message).")
return nil return nil
} }
guard let envelope = try? unwrap(data: data) else { guard let envelope = try? LokiMessageWrapper.unwrap(data: data) else {
Logger.warn("[Loki] Failed to unwrap data for message: \(message).") Logger.warn("[Loki] Failed to unwrap data for message: \(message).")
return nil return nil
} }

@ -1,7 +1,8 @@
extension LokiAPI { public class LokiMessageWrapper {
private init() {}
enum WrappingError : LocalizedError { public enum WrappingError : LocalizedError {
case failedToWrapData case failedToWrapData
case failedToWrapMessageInEnvelope case failedToWrapMessageInEnvelope
case failedToWrapEnvelopeInWebSocketMessage case failedToWrapEnvelopeInWebSocketMessage
@ -25,7 +26,7 @@ extension LokiAPI {
/// - timestamp: The original message timestamp (`TSOutgoingMessage.timestamp`). /// - timestamp: The original message timestamp (`TSOutgoingMessage.timestamp`).
/// - Returns: The wrapped message data. /// - Returns: The wrapped message data.
/// - Throws: A `WrappingError` if something went wrong. /// - Throws: A `WrappingError` if something went wrong.
static func wrap(message: SignalMessage, timestamp: UInt64) throws -> Data { public static func wrap(message: SignalMessage, timestamp: UInt64) throws -> Data {
do { do {
let envelope = try createEnvelope(around: message, timestamp: timestamp) let envelope = try createEnvelope(around: message, timestamp: timestamp)
let webSocketMessage = try createWebSocketMessage(around: envelope) let webSocketMessage = try createWebSocketMessage(around: envelope)
@ -40,7 +41,7 @@ extension LokiAPI {
/// - Parameter data: The data from the storage server (not base 64 encoded). /// - Parameter data: The data from the storage server (not base 64 encoded).
/// - Returns: An `SSKProtoEnvelope` object. /// - Returns: An `SSKProtoEnvelope` object.
/// - Throws: A `WrappingError` if something went wrong. /// - Throws: A `WrappingError` if something went wrong.
static func unwrap(data: Data) throws -> SSKProtoEnvelope { public static func unwrap(data: Data) throws -> SSKProtoEnvelope {
do { do {
let webSocketMessage = try WebSocketProtoWebSocketMessage.parseData(data) let webSocketMessage = try WebSocketProtoWebSocketMessage.parseData(data)
let envelope = webSocketMessage.request!.body! let envelope = webSocketMessage.request!.body!

@ -0,0 +1,37 @@
public class LokiP2PMessageHandler {
public static let shared = LokiP2PMessageHandler()
private var messageReceiver: OWSMessageReceiver {
return SSKEnvironment.shared.messageReceiver
}
private init() {}
public func handleReceivedMessage(base64EncodedData: String) {
guard let data = Data(base64Encoded: base64EncodedData) else {
Logger.warn("[LokiP2PMessageHandler] Failed to decode p2p message data")
return
}
guard let envelope = try? LokiMessageWrapper.unwrap(data: data) else {
Logger.warn("[LokiP2PMessageHandler] Failed to unwrap p2p data")
return
}
// We need to set the p2p field on the envelope
let builder = envelope.asBuilder()
builder.setIsPtpMessage(true)
// Send it to message receiver
do {
let newEnvelope = try builder.build()
let envelopeData = try newEnvelope.serializedData()
messageReceiver.handleReceivedEnvelopeData(envelopeData)
} catch let error {
Logger.warn("[LokiP2PMessageHandler] Something went wrong while converting proto: \(error)")
owsFailDebug("Failed to build envelope")
}
}
}

@ -80,6 +80,9 @@ public enum SSKProtoError: Error {
if hasServerTimestamp { if hasServerTimestamp {
builder.setServerTimestamp(serverTimestamp) builder.setServerTimestamp(serverTimestamp)
} }
if hasIsPtpMessage {
builder.setIsPtpMessage(isPtpMessage)
}
return builder return builder
} }
@ -132,6 +135,10 @@ public enum SSKProtoError: Error {
proto.serverTimestamp = valueParam proto.serverTimestamp = valueParam
} }
@objc public func setIsPtpMessage(_ valueParam: Bool) {
proto.isPtpMessage = valueParam
}
@objc public func build() throws -> SSKProtoEnvelope { @objc public func build() throws -> SSKProtoEnvelope {
return try SSKProtoEnvelope.parseProto(proto) return try SSKProtoEnvelope.parseProto(proto)
} }
@ -211,6 +218,13 @@ public enum SSKProtoError: Error {
return proto.hasServerTimestamp return proto.hasServerTimestamp
} }
@objc public var isPtpMessage: Bool {
return proto.isPtpMessage
}
@objc public var hasIsPtpMessage: Bool {
return proto.hasIsPtpMessage
}
private init(proto: SignalServiceProtos_Envelope, private init(proto: SignalServiceProtos_Envelope,
type: SSKProtoEnvelopeType, type: SSKProtoEnvelopeType,
timestamp: UInt64) { timestamp: UInt64) {

@ -119,6 +119,17 @@ struct SignalServiceProtos_Envelope {
/// Clears the value of `serverTimestamp`. Subsequent reads from it will return its default value. /// Clears the value of `serverTimestamp`. Subsequent reads from it will return its default value.
mutating func clearServerTimestamp() {self._serverTimestamp = nil} mutating func clearServerTimestamp() {self._serverTimestamp = nil}
/// Loki: This field is only here as a helper
/// It shouldn't be set when sending a message
var isPtpMessage: Bool {
get {return _isPtpMessage ?? false}
set {_isPtpMessage = newValue}
}
/// Returns true if `isPtpMessage` has been explicitly set.
var hasIsPtpMessage: Bool {return self._isPtpMessage != nil}
/// Clears the value of `isPtpMessage`. Subsequent reads from it will return its default value.
mutating func clearIsPtpMessage() {self._isPtpMessage = nil}
var unknownFields = SwiftProtobuf.UnknownStorage() var unknownFields = SwiftProtobuf.UnknownStorage()
enum TypeEnum: SwiftProtobuf.Enum { enum TypeEnum: SwiftProtobuf.Enum {
@ -175,6 +186,7 @@ struct SignalServiceProtos_Envelope {
fileprivate var _content: Data? = nil fileprivate var _content: Data? = nil
fileprivate var _serverGuid: String? = nil fileprivate var _serverGuid: String? = nil
fileprivate var _serverTimestamp: UInt64? = nil fileprivate var _serverTimestamp: UInt64? = nil
fileprivate var _isPtpMessage: Bool? = nil
} }
#if swift(>=4.2) #if swift(>=4.2)
@ -437,6 +449,7 @@ struct SignalServiceProtos_LokiAddressMessage {
// methods supported on all messages. // methods supported on all messages.
/// The naming is a bit different from desktop because of swift auto generation /// The naming is a bit different from desktop because of swift auto generation
/// It doesn't like p2p much :(
var ptpAddress: String { var ptpAddress: String {
get {return _ptpAddress ?? String()} get {return _ptpAddress ?? String()}
set {_ptpAddress = newValue} set {_ptpAddress = newValue}
@ -2473,6 +2486,7 @@ extension SignalServiceProtos_Envelope: SwiftProtobuf.Message, SwiftProtobuf._Me
8: .same(proto: "content"), 8: .same(proto: "content"),
9: .same(proto: "serverGuid"), 9: .same(proto: "serverGuid"),
10: .same(proto: "serverTimestamp"), 10: .same(proto: "serverTimestamp"),
999: .same(proto: "isPtpMessage"),
] ]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws { mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -2487,6 +2501,7 @@ extension SignalServiceProtos_Envelope: SwiftProtobuf.Message, SwiftProtobuf._Me
case 8: try decoder.decodeSingularBytesField(value: &self._content) case 8: try decoder.decodeSingularBytesField(value: &self._content)
case 9: try decoder.decodeSingularStringField(value: &self._serverGuid) case 9: try decoder.decodeSingularStringField(value: &self._serverGuid)
case 10: try decoder.decodeSingularUInt64Field(value: &self._serverTimestamp) case 10: try decoder.decodeSingularUInt64Field(value: &self._serverTimestamp)
case 999: try decoder.decodeSingularBoolField(value: &self._isPtpMessage)
default: break default: break
} }
} }
@ -2520,6 +2535,9 @@ extension SignalServiceProtos_Envelope: SwiftProtobuf.Message, SwiftProtobuf._Me
if let v = self._serverTimestamp { if let v = self._serverTimestamp {
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 10) try visitor.visitSingularUInt64Field(value: v, fieldNumber: 10)
} }
if let v = self._isPtpMessage {
try visitor.visitSingularBoolField(value: v, fieldNumber: 999)
}
try unknownFields.traverse(visitor: &visitor) try unknownFields.traverse(visitor: &visitor)
} }
@ -2533,6 +2551,7 @@ extension SignalServiceProtos_Envelope: SwiftProtobuf.Message, SwiftProtobuf._Me
if lhs._content != rhs._content {return false} if lhs._content != rhs._content {return false}
if lhs._serverGuid != rhs._serverGuid {return false} if lhs._serverGuid != rhs._serverGuid {return false}
if lhs._serverTimestamp != rhs._serverTimestamp {return false} if lhs._serverTimestamp != rhs._serverTimestamp {return false}
if lhs._isPtpMessage != rhs._isPtpMessage {return false}
if lhs.unknownFields != rhs.unknownFields {return false} if lhs.unknownFields != rhs.unknownFields {return false}
return true return true
} }

Loading…
Cancel
Save