Re-implement message wrapping

This commit is contained in:
nielsandriesse 2020-11-09 08:36:33 +11:00
parent 4c69388c6c
commit 8f443a38af
9 changed files with 1035 additions and 10 deletions

View File

@ -6,8 +6,6 @@ import Foundation
// WARNING: This code is generated. Only edit within the markers.
private let logTag = "SNProto"
public enum SNProtoError: Error {
case invalidProtobuf(description: String)
}

View File

@ -0,0 +1,486 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
// WARNING: This code is generated. Only edit within the markers.
public enum WebSocketProtoError: Error {
case invalidProtobuf(description: String)
}
// MARK: - WebSocketProtoWebSocketRequestMessage
@objc public class WebSocketProtoWebSocketRequestMessage: NSObject {
// MARK: - WebSocketProtoWebSocketRequestMessageBuilder
@objc public class func builder(verb: String, path: String, requestID: UInt64) -> WebSocketProtoWebSocketRequestMessageBuilder {
return WebSocketProtoWebSocketRequestMessageBuilder(verb: verb, path: path, requestID: requestID)
}
// asBuilder() constructs a builder that reflects the proto's contents.
@objc public func asBuilder() -> WebSocketProtoWebSocketRequestMessageBuilder {
let builder = WebSocketProtoWebSocketRequestMessageBuilder(verb: verb, path: path, requestID: requestID)
if let _value = body {
builder.setBody(_value)
}
builder.setHeaders(headers)
return builder
}
@objc public class WebSocketProtoWebSocketRequestMessageBuilder: NSObject {
private var proto = WebSocketProtos_WebSocketRequestMessage()
@objc fileprivate override init() {}
@objc fileprivate init(verb: String, path: String, requestID: UInt64) {
super.init()
setVerb(verb)
setPath(path)
setRequestID(requestID)
}
@objc public func setVerb(_ valueParam: String) {
proto.verb = valueParam
}
@objc public func setPath(_ valueParam: String) {
proto.path = valueParam
}
@objc public func setBody(_ valueParam: Data) {
proto.body = valueParam
}
@objc public func addHeaders(_ valueParam: String) {
var items = proto.headers
items.append(valueParam)
proto.headers = items
}
@objc public func setHeaders(_ wrappedItems: [String]) {
proto.headers = wrappedItems
}
@objc public func setRequestID(_ valueParam: UInt64) {
proto.requestID = valueParam
}
@objc public func build() throws -> WebSocketProtoWebSocketRequestMessage {
return try WebSocketProtoWebSocketRequestMessage.parseProto(proto)
}
@objc public func buildSerializedData() throws -> Data {
return try WebSocketProtoWebSocketRequestMessage.parseProto(proto).serializedData()
}
}
fileprivate let proto: WebSocketProtos_WebSocketRequestMessage
@objc public let verb: String
@objc public let path: String
@objc public let requestID: UInt64
@objc public var body: Data? {
guard proto.hasBody else {
return nil
}
return proto.body
}
@objc public var hasBody: Bool {
return proto.hasBody
}
@objc public var headers: [String] {
return proto.headers
}
private init(proto: WebSocketProtos_WebSocketRequestMessage,
verb: String,
path: String,
requestID: UInt64) {
self.proto = proto
self.verb = verb
self.path = path
self.requestID = requestID
}
@objc
public func serializedData() throws -> Data {
return try self.proto.serializedData()
}
@objc public class func parseData(_ serializedData: Data) throws -> WebSocketProtoWebSocketRequestMessage {
let proto = try WebSocketProtos_WebSocketRequestMessage(serializedData: serializedData)
return try parseProto(proto)
}
fileprivate class func parseProto(_ proto: WebSocketProtos_WebSocketRequestMessage) throws -> WebSocketProtoWebSocketRequestMessage {
guard proto.hasVerb else {
throw WebSocketProtoError.invalidProtobuf(description: "\(logTag) missing required field: verb")
}
let verb = proto.verb
guard proto.hasPath else {
throw WebSocketProtoError.invalidProtobuf(description: "\(logTag) missing required field: path")
}
let path = proto.path
guard proto.hasRequestID else {
throw WebSocketProtoError.invalidProtobuf(description: "\(logTag) missing required field: requestID")
}
let requestID = proto.requestID
// MARK: - Begin Validation Logic for WebSocketProtoWebSocketRequestMessage -
// MARK: - End Validation Logic for WebSocketProtoWebSocketRequestMessage -
let result = WebSocketProtoWebSocketRequestMessage(proto: proto,
verb: verb,
path: path,
requestID: requestID)
return result
}
@objc public override var debugDescription: String {
return "\(proto)"
}
}
#if DEBUG
extension WebSocketProtoWebSocketRequestMessage {
@objc public func serializedDataIgnoringErrors() -> Data? {
return try! self.serializedData()
}
}
extension WebSocketProtoWebSocketRequestMessage.WebSocketProtoWebSocketRequestMessageBuilder {
@objc public func buildIgnoringErrors() -> WebSocketProtoWebSocketRequestMessage? {
return try! self.build()
}
}
#endif
// MARK: - WebSocketProtoWebSocketResponseMessage
@objc public class WebSocketProtoWebSocketResponseMessage: NSObject {
// MARK: - WebSocketProtoWebSocketResponseMessageBuilder
@objc public class func builder(requestID: UInt64, status: UInt32) -> WebSocketProtoWebSocketResponseMessageBuilder {
return WebSocketProtoWebSocketResponseMessageBuilder(requestID: requestID, status: status)
}
// asBuilder() constructs a builder that reflects the proto's contents.
@objc public func asBuilder() -> WebSocketProtoWebSocketResponseMessageBuilder {
let builder = WebSocketProtoWebSocketResponseMessageBuilder(requestID: requestID, status: status)
if let _value = message {
builder.setMessage(_value)
}
builder.setHeaders(headers)
if let _value = body {
builder.setBody(_value)
}
return builder
}
@objc public class WebSocketProtoWebSocketResponseMessageBuilder: NSObject {
private var proto = WebSocketProtos_WebSocketResponseMessage()
@objc fileprivate override init() {}
@objc fileprivate init(requestID: UInt64, status: UInt32) {
super.init()
setRequestID(requestID)
setStatus(status)
}
@objc public func setRequestID(_ valueParam: UInt64) {
proto.requestID = valueParam
}
@objc public func setStatus(_ valueParam: UInt32) {
proto.status = valueParam
}
@objc public func setMessage(_ valueParam: String) {
proto.message = valueParam
}
@objc public func addHeaders(_ valueParam: String) {
var items = proto.headers
items.append(valueParam)
proto.headers = items
}
@objc public func setHeaders(_ wrappedItems: [String]) {
proto.headers = wrappedItems
}
@objc public func setBody(_ valueParam: Data) {
proto.body = valueParam
}
@objc public func build() throws -> WebSocketProtoWebSocketResponseMessage {
return try WebSocketProtoWebSocketResponseMessage.parseProto(proto)
}
@objc public func buildSerializedData() throws -> Data {
return try WebSocketProtoWebSocketResponseMessage.parseProto(proto).serializedData()
}
}
fileprivate let proto: WebSocketProtos_WebSocketResponseMessage
@objc public let requestID: UInt64
@objc public let status: UInt32
@objc public var message: String? {
guard proto.hasMessage else {
return nil
}
return proto.message
}
@objc public var hasMessage: Bool {
return proto.hasMessage
}
@objc public var headers: [String] {
return proto.headers
}
@objc public var body: Data? {
guard proto.hasBody else {
return nil
}
return proto.body
}
@objc public var hasBody: Bool {
return proto.hasBody
}
private init(proto: WebSocketProtos_WebSocketResponseMessage,
requestID: UInt64,
status: UInt32) {
self.proto = proto
self.requestID = requestID
self.status = status
}
@objc
public func serializedData() throws -> Data {
return try self.proto.serializedData()
}
@objc public class func parseData(_ serializedData: Data) throws -> WebSocketProtoWebSocketResponseMessage {
let proto = try WebSocketProtos_WebSocketResponseMessage(serializedData: serializedData)
return try parseProto(proto)
}
fileprivate class func parseProto(_ proto: WebSocketProtos_WebSocketResponseMessage) throws -> WebSocketProtoWebSocketResponseMessage {
guard proto.hasRequestID else {
throw WebSocketProtoError.invalidProtobuf(description: "\(logTag) missing required field: requestID")
}
let requestID = proto.requestID
guard proto.hasStatus else {
throw WebSocketProtoError.invalidProtobuf(description: "\(logTag) missing required field: status")
}
let status = proto.status
// MARK: - Begin Validation Logic for WebSocketProtoWebSocketResponseMessage -
// MARK: - End Validation Logic for WebSocketProtoWebSocketResponseMessage -
let result = WebSocketProtoWebSocketResponseMessage(proto: proto,
requestID: requestID,
status: status)
return result
}
@objc public override var debugDescription: String {
return "\(proto)"
}
}
#if DEBUG
extension WebSocketProtoWebSocketResponseMessage {
@objc public func serializedDataIgnoringErrors() -> Data? {
return try! self.serializedData()
}
}
extension WebSocketProtoWebSocketResponseMessage.WebSocketProtoWebSocketResponseMessageBuilder {
@objc public func buildIgnoringErrors() -> WebSocketProtoWebSocketResponseMessage? {
return try! self.build()
}
}
#endif
// MARK: - WebSocketProtoWebSocketMessage
@objc public class WebSocketProtoWebSocketMessage: NSObject {
// MARK: - WebSocketProtoWebSocketMessageType
@objc public enum WebSocketProtoWebSocketMessageType: Int32 {
case unknown = 0
case request = 1
case response = 2
}
private class func WebSocketProtoWebSocketMessageTypeWrap(_ value: WebSocketProtos_WebSocketMessage.TypeEnum) -> WebSocketProtoWebSocketMessageType {
switch value {
case .unknown: return .unknown
case .request: return .request
case .response: return .response
}
}
private class func WebSocketProtoWebSocketMessageTypeUnwrap(_ value: WebSocketProtoWebSocketMessageType) -> WebSocketProtos_WebSocketMessage.TypeEnum {
switch value {
case .unknown: return .unknown
case .request: return .request
case .response: return .response
}
}
// MARK: - WebSocketProtoWebSocketMessageBuilder
@objc public class func builder(type: WebSocketProtoWebSocketMessageType) -> WebSocketProtoWebSocketMessageBuilder {
return WebSocketProtoWebSocketMessageBuilder(type: type)
}
// asBuilder() constructs a builder that reflects the proto's contents.
@objc public func asBuilder() -> WebSocketProtoWebSocketMessageBuilder {
let builder = WebSocketProtoWebSocketMessageBuilder(type: type)
if let _value = request {
builder.setRequest(_value)
}
if let _value = response {
builder.setResponse(_value)
}
return builder
}
@objc public class WebSocketProtoWebSocketMessageBuilder: NSObject {
private var proto = WebSocketProtos_WebSocketMessage()
@objc fileprivate override init() {}
@objc fileprivate init(type: WebSocketProtoWebSocketMessageType) {
super.init()
setType(type)
}
@objc public func setType(_ valueParam: WebSocketProtoWebSocketMessageType) {
proto.type = WebSocketProtoWebSocketMessageTypeUnwrap(valueParam)
}
@objc public func setRequest(_ valueParam: WebSocketProtoWebSocketRequestMessage) {
proto.request = valueParam.proto
}
@objc public func setResponse(_ valueParam: WebSocketProtoWebSocketResponseMessage) {
proto.response = valueParam.proto
}
@objc public func build() throws -> WebSocketProtoWebSocketMessage {
return try WebSocketProtoWebSocketMessage.parseProto(proto)
}
@objc public func buildSerializedData() throws -> Data {
return try WebSocketProtoWebSocketMessage.parseProto(proto).serializedData()
}
}
fileprivate let proto: WebSocketProtos_WebSocketMessage
@objc public let type: WebSocketProtoWebSocketMessageType
@objc public let request: WebSocketProtoWebSocketRequestMessage?
@objc public let response: WebSocketProtoWebSocketResponseMessage?
private init(proto: WebSocketProtos_WebSocketMessage,
type: WebSocketProtoWebSocketMessageType,
request: WebSocketProtoWebSocketRequestMessage?,
response: WebSocketProtoWebSocketResponseMessage?) {
self.proto = proto
self.type = type
self.request = request
self.response = response
}
@objc
public func serializedData() throws -> Data {
return try self.proto.serializedData()
}
@objc public class func parseData(_ serializedData: Data) throws -> WebSocketProtoWebSocketMessage {
let proto = try WebSocketProtos_WebSocketMessage(serializedData: serializedData)
return try parseProto(proto)
}
fileprivate class func parseProto(_ proto: WebSocketProtos_WebSocketMessage) throws -> WebSocketProtoWebSocketMessage {
guard proto.hasType else {
throw WebSocketProtoError.invalidProtobuf(description: "\(logTag) missing required field: type")
}
let type = WebSocketProtoWebSocketMessageTypeWrap(proto.type)
var request: WebSocketProtoWebSocketRequestMessage? = nil
if proto.hasRequest {
request = try WebSocketProtoWebSocketRequestMessage.parseProto(proto.request)
}
var response: WebSocketProtoWebSocketResponseMessage? = nil
if proto.hasResponse {
response = try WebSocketProtoWebSocketResponseMessage.parseProto(proto.response)
}
// MARK: - Begin Validation Logic for WebSocketProtoWebSocketMessage -
// MARK: - End Validation Logic for WebSocketProtoWebSocketMessage -
let result = WebSocketProtoWebSocketMessage(proto: proto,
type: type,
request: request,
response: response)
return result
}
@objc public override var debugDescription: String {
return "\(proto)"
}
}
#if DEBUG
extension WebSocketProtoWebSocketMessage {
@objc public func serializedDataIgnoringErrors() -> Data? {
return try! self.serializedData()
}
}
extension WebSocketProtoWebSocketMessage.WebSocketProtoWebSocketMessageBuilder {
@objc public func buildIgnoringErrors() -> WebSocketProtoWebSocketMessage? {
return try! self.build()
}
}
#endif

View File

@ -0,0 +1,378 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: WebSocketResources.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 WebSocketProtos_WebSocketRequestMessage {
// 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 verb: String {
get {return _verb ?? String()}
set {_verb = newValue}
}
/// Returns true if `verb` has been explicitly set.
var hasVerb: Bool {return self._verb != nil}
/// Clears the value of `verb`. Subsequent reads from it will return its default value.
mutating func clearVerb() {self._verb = nil}
/// @required
var path: String {
get {return _path ?? String()}
set {_path = newValue}
}
/// Returns true if `path` has been explicitly set.
var hasPath: Bool {return self._path != nil}
/// Clears the value of `path`. Subsequent reads from it will return its default value.
mutating func clearPath() {self._path = nil}
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 headers: [String] = []
/// @required
var requestID: UInt64 {
get {return _requestID ?? 0}
set {_requestID = newValue}
}
/// Returns true if `requestID` has been explicitly set.
var hasRequestID: Bool {return self._requestID != nil}
/// Clears the value of `requestID`. Subsequent reads from it will return its default value.
mutating func clearRequestID() {self._requestID = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _verb: String? = nil
fileprivate var _path: String? = nil
fileprivate var _body: Data? = nil
fileprivate var _requestID: UInt64? = nil
}
struct WebSocketProtos_WebSocketResponseMessage {
// 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 requestID: UInt64 {
get {return _requestID ?? 0}
set {_requestID = newValue}
}
/// Returns true if `requestID` has been explicitly set.
var hasRequestID: Bool {return self._requestID != nil}
/// Clears the value of `requestID`. Subsequent reads from it will return its default value.
mutating func clearRequestID() {self._requestID = nil}
/// @required
var status: UInt32 {
get {return _status ?? 0}
set {_status = newValue}
}
/// Returns true if `status` has been explicitly set.
var hasStatus: Bool {return self._status != nil}
/// Clears the value of `status`. Subsequent reads from it will return its default value.
mutating func clearStatus() {self._status = nil}
var message: String {
get {return _message ?? String()}
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 headers: [String] = []
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 _requestID: UInt64? = nil
fileprivate var _status: UInt32? = nil
fileprivate var _message: String? = nil
fileprivate var _body: Data? = nil
}
struct WebSocketProtos_WebSocketMessage {
// 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: WebSocketProtos_WebSocketMessage.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 request: WebSocketProtos_WebSocketRequestMessage {
get {return _request ?? WebSocketProtos_WebSocketRequestMessage()}
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 response: WebSocketProtos_WebSocketResponseMessage {
get {return _response ?? WebSocketProtos_WebSocketResponseMessage()}
set {_response = newValue}
}
/// Returns true if `response` has been explicitly set.
var hasResponse: Bool {return self._response != nil}
/// Clears the value of `response`. Subsequent reads from it will return its default value.
mutating func clearResponse() {self._response = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum TypeEnum: SwiftProtobuf.Enum {
typealias RawValue = Int
case unknown // = 0
case request // = 1
case response // = 2
init() {
self = .unknown
}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .unknown
case 1: self = .request
case 2: self = .response
default: return nil
}
}
var rawValue: Int {
switch self {
case .unknown: return 0
case .request: return 1
case .response: return 2
}
}
}
init() {}
fileprivate var _type: WebSocketProtos_WebSocketMessage.TypeEnum? = nil
fileprivate var _request: WebSocketProtos_WebSocketRequestMessage? = nil
fileprivate var _response: WebSocketProtos_WebSocketResponseMessage? = nil
}
#if swift(>=4.2)
extension WebSocketProtos_WebSocketMessage.TypeEnum: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "WebSocketProtos"
extension WebSocketProtos_WebSocketRequestMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".WebSocketRequestMessage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "verb"),
2: .same(proto: "path"),
3: .same(proto: "body"),
5: .same(proto: "headers"),
4: .same(proto: "requestId"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self._verb)
case 2: try decoder.decodeSingularStringField(value: &self._path)
case 3: try decoder.decodeSingularBytesField(value: &self._body)
case 4: try decoder.decodeSingularUInt64Field(value: &self._requestID)
case 5: try decoder.decodeRepeatedStringField(value: &self.headers)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._verb {
try visitor.visitSingularStringField(value: v, fieldNumber: 1)
}
if let v = self._path {
try visitor.visitSingularStringField(value: v, fieldNumber: 2)
}
if let v = self._body {
try visitor.visitSingularBytesField(value: v, fieldNumber: 3)
}
if let v = self._requestID {
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 4)
}
if !self.headers.isEmpty {
try visitor.visitRepeatedStringField(value: self.headers, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: WebSocketProtos_WebSocketRequestMessage, rhs: WebSocketProtos_WebSocketRequestMessage) -> Bool {
if lhs._verb != rhs._verb {return false}
if lhs._path != rhs._path {return false}
if lhs._body != rhs._body {return false}
if lhs.headers != rhs.headers {return false}
if lhs._requestID != rhs._requestID {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension WebSocketProtos_WebSocketResponseMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".WebSocketResponseMessage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "requestId"),
2: .same(proto: "status"),
3: .same(proto: "message"),
5: .same(proto: "headers"),
4: .same(proto: "body"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularUInt64Field(value: &self._requestID)
case 2: try decoder.decodeSingularUInt32Field(value: &self._status)
case 3: try decoder.decodeSingularStringField(value: &self._message)
case 4: try decoder.decodeSingularBytesField(value: &self._body)
case 5: try decoder.decodeRepeatedStringField(value: &self.headers)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._requestID {
try visitor.visitSingularUInt64Field(value: v, fieldNumber: 1)
}
if let v = self._status {
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2)
}
if let v = self._message {
try visitor.visitSingularStringField(value: v, fieldNumber: 3)
}
if let v = self._body {
try visitor.visitSingularBytesField(value: v, fieldNumber: 4)
}
if !self.headers.isEmpty {
try visitor.visitRepeatedStringField(value: self.headers, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: WebSocketProtos_WebSocketResponseMessage, rhs: WebSocketProtos_WebSocketResponseMessage) -> Bool {
if lhs._requestID != rhs._requestID {return false}
if lhs._status != rhs._status {return false}
if lhs._message != rhs._message {return false}
if lhs.headers != rhs.headers {return false}
if lhs._body != rhs._body {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension WebSocketProtos_WebSocketMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".WebSocketMessage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "type"),
2: .same(proto: "request"),
3: .same(proto: "response"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularEnumField(value: &self._type)
case 2: try decoder.decodeSingularMessageField(value: &self._request)
case 3: try decoder.decodeSingularMessageField(value: &self._response)
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._type {
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
}
if let v = self._request {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
if let v = self._response {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: WebSocketProtos_WebSocketMessage, rhs: WebSocketProtos_WebSocketMessage) -> Bool {
if lhs._type != rhs._type {return false}
if lhs._request != rhs._request {return false}
if lhs._response != rhs._response {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension WebSocketProtos_WebSocketMessage.TypeEnum: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "UNKNOWN"),
1: .same(proto: "REQUEST"),
2: .same(proto: "RESPONSE"),
]
}

View File

@ -4,9 +4,15 @@ PROTOC=protoc \
WRAPPER_SCRIPT=../../Scripts/ProtoWrappers.py \
--proto-dir='./' --verbose
all: session_protos
all: session_protos websocket_protos
session_protos: SessionProtos.proto
$(PROTOC) --swift_out=./Generated \SessionProtos.proto
$(WRAPPER_SCRIPT) --dst-dir=./Generated \
--wrapper-prefix=SNProto --proto-prefix=SessionProtos --proto-file=SessionProtos.proto
websocket_protos: WebSocketResources.proto
$(PROTOC) --swift_out=./Generated \WebSocketResources.proto
$(WRAPPER_SCRIPT) --dst-dir=./Generated \
--wrapper-prefix=WebSocketProto --proto-prefix=WebSocketProtos --proto-file=WebSocketResources.proto

View File

@ -0,0 +1,49 @@
/**
* 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.
syntax = "proto2";
// iOS - package name determines class prefix
package WebSocketProtos;
option java_package = "org.whispersystems.signalservice.internal.websocket";
option java_outer_classname = "WebSocketProtos";
message WebSocketRequestMessage {
// @required
optional string verb = 1;
// @required
optional string path = 2;
optional bytes body = 3;
repeated string headers = 5;
// @required
optional uint64 requestId = 4;
}
message WebSocketResponseMessage {
// @required
optional uint64 requestId = 1;
// @required
optional uint32 status = 2;
optional string message = 3;
repeated string headers = 5;
optional bytes body = 4;
}
message WebSocketMessage {
enum Type {
UNKNOWN = 0;
REQUEST = 1;
RESPONSE = 2;
}
// @required
optional Type type = 1;
optional WebSocketRequestMessage request = 2;
optional WebSocketResponseMessage response = 3;
}

View File

@ -1,7 +1,5 @@
import SessionUtilities
// TODO: Decryption
internal enum MessageReceiver {
internal enum Error : LocalizedError {

View File

@ -2,9 +2,6 @@ import PromiseKit
import SessionSnodeKit
import SessionUtilities
// TODO: Open group encryption
// TODO: Signal protocol encryption
internal enum MessageSender {
internal enum Error : LocalizedError {
@ -24,6 +21,13 @@ internal enum MessageSender {
}
internal static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise<Void> {
switch destination {
case .contact(_), .closedGroup(_): return sendToSnodeDestination(destination, message: message, using: transaction)
default: fatalError("Not implemented.")
}
}
internal static func sendToSnodeDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise<Void> {
// Validate the message
guard message.isValid else { return Promise(error: Error.invalidMessage) }
// Convert it to protobuf
@ -47,12 +51,32 @@ internal enum MessageSender {
switch destination {
case .contact(let publicKey): ciphertext = try encryptWithSignalProtocol(plaintext, for: publicKey, using: transaction)
case .closedGroup(let groupPublicKey): ciphertext = try encryptWithSharedSenderKeys(plaintext, for: groupPublicKey, using: transaction)
case .openGroup(_, _): fatalError("Not implemented.")
case .openGroup(_, _): preconditionFailure()
}
} catch {
SNLog("Couldn't encrypt message for destination: \(destination) due to error: \(error).")
return Promise(error: error)
}
// Wrap the result
let kind: SNProtoEnvelope.SNProtoEnvelopeType
let senderPublicKey: String
switch destination {
case .contact(_):
kind = .unidentifiedSender
senderPublicKey = ""
case .closedGroup(let groupPublicKey):
kind = .closedGroupCiphertext
senderPublicKey = groupPublicKey
case .openGroup(_, _): preconditionFailure()
}
let wrappedMessage: Data
do {
wrappedMessage = try MessageWrapper.wrap(type: kind, timestamp: message.sentTimestamp!,
senderPublicKey: senderPublicKey, base64EncodedContent: ciphertext.base64EncodedString())
} catch {
SNLog("Couldn't wrap message due to error: \(error).")
return Promise(error: error)
}
// Calculate proof of work
if case .contact(_) = destination {
DispatchQueue.main.async {
@ -60,7 +84,7 @@ internal enum MessageSender {
}
}
let recipient = message.recipient!
let base64EncodedData = ciphertext.base64EncodedString()
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)

View File

@ -0,0 +1,74 @@
import SessionSnodeKit
import SessionUtilities
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 the given parameters in an `SNProtoEnvelope` and then a `WebSocketProtoWebSocketMessage` to match the desktop application.
public static func wrap(type: SNProtoEnvelope.SNProtoEnvelopeType, timestamp: UInt64, senderPublicKey: String, base64EncodedContent: String) throws -> Data {
do {
let envelope = try createEnvelope(type: type, timestamp: timestamp, senderPublicKey: senderPublicKey, base64EncodedContent: base64EncodedContent)
let webSocketMessage = try createWebSocketMessage(around: envelope)
return try webSocketMessage.serializedData()
} catch let error {
throw error as? Error ?? Error.failedToWrapData
}
}
private static func createEnvelope(type: SNProtoEnvelope.SNProtoEnvelopeType, timestamp: UInt64, senderPublicKey: String, base64EncodedContent: String) throws -> SNProtoEnvelope {
do {
let builder = SNProtoEnvelope.builder(type: type, timestamp: timestamp)
builder.setSource(senderPublicKey)
builder.setSourceDevice(1)
if let content = Data(base64Encoded: base64EncodedContent, options: .ignoreUnknownCharacters) {
builder.setContent(content)
} else {
throw Error.failedToWrapMessageInEnvelope
}
return try builder.build()
} catch let error {
SNLog("Failed to wrap message in envelope: \(error).")
throw Error.failedToWrapMessageInEnvelope
}
}
private static func createWebSocketMessage(around envelope: SNProtoEnvelope) throws -> WebSocketProtoWebSocketMessage {
do {
let requestBuilder = WebSocketProtoWebSocketRequestMessage.builder(verb: "PUT", path: "/api/v1/message", requestID: UInt64.random(in: 1..<UInt64.max))
requestBuilder.setBody(try envelope.serializedData())
let messageBuilder = WebSocketProtoWebSocketMessage.builder(type: .request)
messageBuilder.setRequest(try requestBuilder.build())
return try messageBuilder.build()
} catch let error {
SNLog("Failed to wrap envelope in web socket message: \(error).")
throw Error.failedToWrapEnvelopeInWebSocketMessage
}
}
/// - Note: `data` shouldn't be base 64 encoded.
public static func unwrap(data: Data) throws -> SNProtoEnvelope {
do {
let webSocketMessage = try WebSocketProtoWebSocketMessage.parseData(data)
let envelope = webSocketMessage.request!.body!
return try SNProtoEnvelope.parseData(envelope)
} catch let error {
SNLog("Failed to unwrap data: \(error).")
throw Error.failedToUnwrapData
}
}
}

View File

@ -631,6 +631,9 @@
C39DD28824F3318C008590FC /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C39DD28724F3318C008590FC /* Colors.xcassets */; };
C39DD28A24F3336E008590FC /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C39DD28724F3318C008590FC /* Colors.xcassets */; };
C39DD28B24F3336F008590FC /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C39DD28724F3318C008590FC /* Colors.xcassets */; };
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 */; };
C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Description.swift */; };
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; };
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE07F2554CDD70050F1E3 /* Storage.swift */; };
@ -1645,6 +1648,9 @@
C396DAED2518408B00FF6DC5 /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = "<group>"; };
C396DAEE2518408B00FF6DC5 /* CSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSV.swift; sourceTree = "<group>"; };
C39DD28724F3318C008590FC /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = "<group>"; };
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageWrapper.swift; sourceTree = "<group>"; };
C3A71D1C25589AC30043A11F /* WebSocketProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketProto.swift; sourceTree = "<group>"; };
C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketResources.pb.swift; sourceTree = "<group>"; };
C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "Migrating Translations from Android.md"; sourceTree = "<group>"; };
C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = translations/fa.lproj/Localizable.strings; sourceTree = "<group>"; };
C3BBE0752554CDA60050F1E3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
@ -3308,6 +3314,7 @@
isa = PBXGroup;
children = (
C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */,
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */,
C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */,
C3471F4125553A4D00297E91 /* Threading.swift */,
);
@ -3424,6 +3431,8 @@
children = (
C3C2A7832553AAF300C340D1 /* SessionProtos.pb.swift */,
C3C2A7822553AAF200C340D1 /* SNProto.swift */,
C3A71D1C25589AC30043A11F /* WebSocketProto.swift */,
C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */,
);
path = Generated;
sourceTree = "<group>";
@ -4973,6 +4982,8 @@
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */,
C3C2A7842553AAF300C340D1 /* SNProto.swift in Sources */,
C3C2A7682553A3D900C340D1 /* VisibleMessage+Contact.swift in Sources */,
C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */,
C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */,
C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */,
C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */,
C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */,
@ -4980,6 +4991,7 @@
C3471F4225553A4D00297E91 /* Threading.swift in Sources */,
C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */,
C3471FA42555439E00297E91 /* Notification+MessageSender.swift in Sources */,
C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */,
C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */,
C352A30925574D8500338F3E /* Message+Destination.swift in Sources */,
C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */,