Create AttachmentUploadJob & AttachmentDownloadJob

Also conform SnodeMessage to NSCoding
This commit is contained in:
nielsandriesse 2020-11-08 12:34:08 +11:00
parent b4545903b1
commit 28172b4ed2
16 changed files with 199 additions and 57 deletions

View File

@ -1,6 +1,8 @@
public struct Configuration {
public let storage: SessionMessagingKitStorageProtocol
public let pnServerURL: String
public let pnServerPublicKey: String
internal static var shared: Configuration!
}

View File

@ -0,0 +1,22 @@
import SessionUtilities
// TODO: Implementation
public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
// MARK: Settings
private static let maxRetryCount: UInt = 20
// MARK: Coding
public init?(coder: NSCoder) { }
public func encode(with coder: NSCoder) { }
// MARK: Running
public func execute() { }
private func handleSuccess() { }
private func handleFailure(error: Error) { }
}

View File

@ -0,0 +1,22 @@
import SessionUtilities
// TODO: Implementation
public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
// MARK: Settings
private static let maxRetryCount: UInt = 20
// MARK: Coding
public init?(coder: NSCoder) { }
public func encode(with coder: NSCoder) { }
// MARK: Running
public func execute() { }
private func handleSuccess() { }
private func handleFailure(error: Error) { }
}

View File

@ -1,5 +1,8 @@
import SessionUtilities
// TODO: Result handling
// TODO: Retrying
public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
private let data: Data
private var failureCount: UInt

View File

@ -1,6 +1,8 @@
import SessionUtilities
// TODO: Destination encoding & decoding
// TODO: Result handling
// TODO: Retrying
public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
private let message: Message

View File

@ -0,0 +1,47 @@
import PromiseKit
import SessionSnodeKit
import SessionUtilities
// TODO: Implementation
// TODO: Result handling
// TODO: Retrying
public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
private let message: SnodeMessage
private var failureCount: UInt
// MARK: Settings
private static let maxRetryCount: UInt = 20
// MARK: Initialization
init(message: SnodeMessage) {
self.message = message
self.failureCount = 0
}
// MARK: Coding
public init?(coder: NSCoder) {
guard let message = coder.decodeObject(forKey: "message") as! SnodeMessage? else { return nil }
self.message = message
self.failureCount = coder.decodeObject(forKey: "failureCount") as! UInt? ?? 0
}
public func encode(with coder: NSCoder) {
coder.encode(message, forKey: "message")
coder.encode(failureCount, forKey: "failureCount")
}
// MARK: Running
public func execute() {
}
private func handleSuccess() {
}
private func handleFailure(error: Error) {
self.failureCount += 1
}
}

View File

@ -2,7 +2,7 @@ import CryptoSwift
import SessionProtocolKit
import SessionUtilities
public extension MessageReceiver {
internal extension MessageReceiver {
static func decryptWithSharedSenderKeys(envelope: SNProtoEnvelope, using transaction: Any) throws -> (plaintext: Data, senderPublicKey: String) {
// 1. ) Check preconditions

View File

@ -1,8 +1,10 @@
import SessionUtilities
public enum MessageReceiver {
// TODO: Decryption
public enum Error : LocalizedError {
internal enum MessageReceiver {
internal enum Error : LocalizedError {
case invalidMessage
case unknownMessage
// Shared sender keys
@ -12,7 +14,7 @@ public enum MessageReceiver {
case sharedSecretGenerationFailed
case selfSend
public var errorDescription: String? {
internal var errorDescription: String? {
switch self {
case .invalidMessage: return "Invalid message."
case .unknownMessage: return "Unknown message type."
@ -26,8 +28,8 @@ public enum MessageReceiver {
}
}
public static func parse(_ ciphertext: Data) throws -> Message {
let plaintext = ciphertext // TODO: Decryption
internal static func parse(_ ciphertext: Data) throws -> Message {
let plaintext = ciphertext
let proto: SNProtoContent
do {
proto = try SNProtoContent.parseData(plaintext)

View File

@ -1,7 +1,7 @@
import SessionProtocolKit
import SessionUtilities
public extension MessageSender {
internal extension MessageSender {
static func encryptWithSignalProtocol(_ plaintext: Data, for publicKey: String, using transaction: Any) throws -> Data {
return Data()

View File

@ -2,17 +2,18 @@ import PromiseKit
import SessionSnodeKit
import SessionUtilities
// TODO: Notify PN server
// TODO: Open group encryption
// TODO: Signal protocol encryption
public enum MessageSender {
internal enum MessageSender {
public enum Error : LocalizedError {
internal enum Error : LocalizedError {
case invalidMessage
case protoConversionFailed
case proofOfWorkCalculationFailed
case noUserPublicKey
public var errorDescription: String? {
internal var errorDescription: String? {
switch self {
case .invalidMessage: return "Invalid message."
case .protoConversionFailed: return "Couldn't convert message to proto."
@ -22,7 +23,7 @@ public enum MessageSender {
}
}
public static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise<Void> {
internal static func send(_ message: Message, to destination: Message.Destination, using transaction: Any) -> Promise<Void> {
// Validate the message
guard message.isValid else { return Promise(error: Error.invalidMessage) }
// Convert it to protobuf
@ -96,6 +97,9 @@ public enum MessageSender {
if case .contact(_) = destination {
NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!))
}
let notifyPNServerJob = NotifyPNServerJob(message: snodeMessage)
Configuration.shared.storage.persist(notifyPNServerJob)
notifyPNServerJob.execute()
}
let _ = promise.catch(on: DispatchQueue.main) { _ in
if case .contact(_) = destination {

View File

@ -8,4 +8,5 @@ public protocol SessionMessagingKitStorageProtocol {
func getOrGenerateRegistrationID(using transaction: Any) -> UInt32
func isClosedGroup(_ publicKey: String) -> Bool
func getClosedGroupPrivateKey(for publicKey: String) -> String?
func persist(_ job: Job)
}

View File

@ -1,35 +0,0 @@
import PromiseKit
import SessionUtilities
public struct SnodeMessage {
/// The hex encoded public key of the recipient.
let recipient: String
/// The content of the message.
let data: LosslessStringConvertible
/// The time to live for the message in milliseconds.
let ttl: UInt64
/// When the proof of work was calculated.
///
/// - Note: Expressed as milliseconds since 00:00:00 UTC on 1 January 1970.
let timestamp: UInt64
/// The base 64 encoded proof of work.
let nonce: String
public init(recipient: String, data: LosslessStringConvertible, ttl: UInt64, timestamp: UInt64, nonce: String) {
self.recipient = recipient
self.data = data
self.ttl = ttl
self.timestamp = timestamp
self.nonce = nonce
}
public func toJSON() -> JSON {
return [
"pubKey" : recipient,
"data" : data.description,
"ttl" : String(ttl),
"timestamp" : String(timestamp),
"nonce" : nonce
]
}
}

View File

@ -24,7 +24,7 @@ public enum OnionRequestAPI {
private static var targetGuardSnodeCount: UInt { return targetPathCount } // One per path
// MARK: Destination
internal enum Destination {
public enum Destination {
case snode(Snode)
case server(host: String, x25519PublicKey: String)
}
@ -275,7 +275,7 @@ public enum OnionRequestAPI {
// MARK: Internal API
/// Sends an onion request to `snode`. Builds new paths as needed.
internal static func sendOnionRequest(to snode: Snode, invoking method: Snode.Method, with parameters: JSON, associatedWith publicKey: String) -> Promise<JSON> {
public static func sendOnionRequest(to snode: Snode, invoking method: Snode.Method, with parameters: JSON, associatedWith publicKey: String) -> Promise<JSON> {
let payload: JSON = [ "method" : method.rawValue, "params" : parameters ]
return sendOnionRequest(with: payload, to: Destination.snode(snode)).recover2 { error -> Promise<JSON> in
guard case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, let json) = error else { throw error }
@ -284,7 +284,7 @@ public enum OnionRequestAPI {
}
/// Sends an onion request to `server`. Builds new paths as needed.
internal static func sendOnionRequest(_ request: NSURLRequest, to server: String, using x25519PublicKey: String, isJSONRequired: Bool = true) -> Promise<JSON> {
public static func sendOnionRequest(_ request: NSURLRequest, to server: String, using x25519PublicKey: String, isJSONRequired: Bool = true) -> Promise<JSON> {
var rawHeaders = request.allHTTPHeaderFields ?? [:]
rawHeaders.removeValue(forKey: "User-Agent")
var headers: JSON = rawHeaders.mapValues { value in
@ -322,7 +322,7 @@ public enum OnionRequestAPI {
return promise
}
internal static func sendOnionRequest(with payload: JSON, to destination: Destination, isJSONRequired: Bool = true) -> Promise<JSON> {
public static func sendOnionRequest(with payload: JSON, to destination: Destination, isJSONRequired: Bool = true) -> Promise<JSON> {
let (promise, seal) = Promise<JSON>.pending()
var guardSnode: Snode!
Threading.workQueue.async { // Avoid race conditions on `guardSnodes` and `paths`

View File

@ -10,7 +10,7 @@ public final class Snode : NSObject, NSCoding { // NSObject/NSCoding conformance
}
// MARK: Nested Types
internal enum Method : String {
public enum Method : String {
case getSwarm = "get_snodes_for_pubkey"
case getMessages = "retrieve"
case sendMessage = "store"

View File

@ -0,0 +1,60 @@
import PromiseKit
import SessionUtilities
public final class SnodeMessage : NSObject, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
/// The hex encoded public key of the recipient.
public let recipient: String
/// The content of the message.
public let data: LosslessStringConvertible
/// The time to live for the message in milliseconds.
public let ttl: UInt64
/// When the proof of work was calculated.
///
/// - Note: Expressed as milliseconds since 00:00:00 UTC on 1 January 1970.
public let timestamp: UInt64
/// The base 64 encoded proof of work.
public let nonce: String
// MARK: Initialization
public init(recipient: String, data: LosslessStringConvertible, ttl: UInt64, timestamp: UInt64, nonce: String) {
self.recipient = recipient
self.data = data
self.ttl = ttl
self.timestamp = timestamp
self.nonce = nonce
}
// MARK: Coding
public init?(coder: NSCoder) {
guard let recipient = coder.decodeObject(forKey: "recipient") as! String?,
let data = coder.decodeObject(forKey: "data") as! String?,
let ttl = coder.decodeObject(forKey: "ttl") as! UInt64?,
let timestamp = coder.decodeObject(forKey: "timestamp") as! UInt64?,
let nonce = coder.decodeObject(forKey: "nonce") as! String? else { return nil }
self.recipient = recipient
self.data = data
self.ttl = ttl
self.timestamp = timestamp
self.nonce = nonce
super.init()
}
public func encode(with coder: NSCoder) {
coder.encode(recipient, forKey: "recipient")
coder.encode(data, forKey: "data")
coder.encode(ttl, forKey: "ttl")
coder.encode(timestamp, forKey: "timestamp")
coder.encode(nonce, forKey: "nonce")
}
// MARK: JSON Conversion
public func toJSON() -> JSON {
return [
"pubKey" : recipient,
"data" : data.description,
"ttl" : String(ttl),
"timestamp" : String(timestamp),
"nonce" : nonce
]
}
}

View File

@ -600,6 +600,9 @@
C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A2FE25574B6300338F3E /* MessageSendJob.swift */; };
C352A30925574D8500338F3E /* Message+Destination.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A30825574D8400338F3E /* Message+Destination.swift */; };
C352A31325574F5200338F3E /* MessageReceiveJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A31225574F5200338F3E /* MessageReceiveJob.swift */; };
C352A32F2557549C00338F3E /* NotifyPNServerJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A32E2557549C00338F3E /* NotifyPNServerJob.swift */; };
C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A348255781F400338F3E /* AttachmentDownloadJob.swift */; };
C352A35B2557824E00338F3E /* AttachmentUploadJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A35A2557824E00338F3E /* AttachmentUploadJob.swift */; };
C353F8F9244809150011121A /* PNOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C353F8F8244809150011121A /* PNOptionView.swift */; };
C3548F0624456447009433A8 /* PNModeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0524456447009433A8 /* PNModeVC.swift */; };
C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */; };
@ -634,7 +637,7 @@
C3C2A5A3255385C100C340D1 /* SessionSnodeKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C3C2A5A1255385C100C340D1 /* SessionSnodeKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3C2A5A6255385C100C340D1 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; };
C3C2A5A7255385C100C340D1 /* SessionSnodeKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
C3C2A5BF255385EE00C340D1 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5B6255385EC00C340D1 /* Message.swift */; };
C3C2A5BF255385EE00C340D1 /* SnodeMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5B6255385EC00C340D1 /* SnodeMessage.swift */; };
C3C2A5C0255385EE00C340D1 /* Snode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5B7255385EC00C340D1 /* Snode.swift */; };
C3C2A5C1255385EE00C340D1 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5B8255385EC00C340D1 /* Storage.swift */; };
C3C2A5C2255385EE00C340D1 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5B9255385ED00C340D1 /* Configuration.swift */; };
@ -1603,6 +1606,9 @@
C352A2FE25574B6300338F3E /* MessageSendJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSendJob.swift; sourceTree = "<group>"; };
C352A30825574D8400338F3E /* Message+Destination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+Destination.swift"; sourceTree = "<group>"; };
C352A31225574F5200338F3E /* MessageReceiveJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiveJob.swift; sourceTree = "<group>"; };
C352A32E2557549C00338F3E /* NotifyPNServerJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyPNServerJob.swift; sourceTree = "<group>"; };
C352A348255781F400338F3E /* AttachmentDownloadJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentDownloadJob.swift; sourceTree = "<group>"; };
C352A35A2557824E00338F3E /* AttachmentUploadJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentUploadJob.swift; sourceTree = "<group>"; };
C353F8F8244809150011121A /* PNOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNOptionView.swift; sourceTree = "<group>"; };
C3548F0524456447009433A8 /* PNModeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeVC.swift; sourceTree = "<group>"; };
C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Wrapping.swift"; sourceTree = "<group>"; };
@ -1636,7 +1642,7 @@
C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SessionSnodeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C3C2A5A1255385C100C340D1 /* SessionSnodeKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SessionSnodeKit.h; sourceTree = "<group>"; };
C3C2A5A2255385C100C340D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C3C2A5B6255385EC00C340D1 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
C3C2A5B6255385EC00C340D1 /* SnodeMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnodeMessage.swift; sourceTree = "<group>"; };
C3C2A5B7255385EC00C340D1 /* Snode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Snode.swift; sourceTree = "<group>"; };
C3C2A5B8255385EC00C340D1 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
C3C2A5B9255385ED00C340D1 /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
@ -3244,8 +3250,11 @@
isa = PBXGroup;
children = (
C352A2F425574B4700338F3E /* Job.swift */,
C352A2FE25574B6300338F3E /* MessageSendJob.swift */,
C352A348255781F400338F3E /* AttachmentDownloadJob.swift */,
C352A35A2557824E00338F3E /* AttachmentUploadJob.swift */,
C352A31225574F5200338F3E /* MessageReceiveJob.swift */,
C352A2FE25574B6300338F3E /* MessageSendJob.swift */,
C352A32E2557549C00338F3E /* NotifyPNServerJob.swift */,
);
path = Jobs;
sourceTree = "<group>";
@ -3296,12 +3305,12 @@
children = (
C3C2A5B0255385C700C340D1 /* Meta */,
C3C2A5B9255385ED00C340D1 /* Configuration.swift */,
C3C2A5B6255385EC00C340D1 /* Message.swift */,
C3C2A5BD255385EE00C340D1 /* Notification+OnionRequestAPI.swift */,
C3C2A5BA255385ED00C340D1 /* OnionRequestAPI.swift */,
C3C2A5BB255385ED00C340D1 /* OnionRequestAPI+Encryption.swift */,
C3C2A5B7255385EC00C340D1 /* Snode.swift */,
C3C2A5BE255385EE00C340D1 /* SnodeAPI.swift */,
C3C2A5B6255385EC00C340D1 /* SnodeMessage.swift */,
C3C2A5B8255385EC00C340D1 /* Storage.swift */,
C3C2A5CD255385F300C340D1 /* Utilities */,
);
@ -4889,7 +4898,7 @@
buildActionMask = 2147483647;
files = (
C3C2A5E02553860B00C340D1 /* Threading.swift in Sources */,
C3C2A5BF255385EE00C340D1 /* Message.swift in Sources */,
C3C2A5BF255385EE00C340D1 /* SnodeMessage.swift in Sources */,
C3C2A5C0255385EE00C340D1 /* Snode.swift in Sources */,
C3C2A5C7255385EE00C340D1 /* SnodeAPI.swift in Sources */,
C3C2A5C6255385EE00C340D1 /* Notification+OnionRequestAPI.swift in Sources */,
@ -4930,6 +4939,7 @@
C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */,
C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */,
C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */,
C352A32F2557549C00338F3E /* NotifyPNServerJob.swift in Sources */,
C300A5F22554B09800555489 /* MessageSender.swift in Sources */,
C3C2A74D2553A39700C340D1 /* VisibleMessage.swift in Sources */,
C352A31325574F5200338F3E /* MessageReceiveJob.swift in Sources */,
@ -4946,12 +4956,14 @@
C3471F4225553A4D00297E91 /* Threading.swift in Sources */,
C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */,
C3471FA42555439E00297E91 /* Notification+MessageSender.swift in Sources */,
C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */,
C352A30925574D8500338F3E /* Message+Destination.swift in Sources */,
C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */,
C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */,
C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */,
C3C2A74425539EB700C340D1 /* Message.swift in Sources */,
C300A5C92554B04E00555489 /* SessionRequest.swift in Sources */,
C352A35B2557824E00338F3E /* AttachmentUploadJob.swift in Sources */,
C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */,
C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */,
C352A2F525574B4700338F3E /* Job.swift in Sources */,