diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 56f3fc499..5f7b2203c 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -226,6 +226,7 @@ B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; B879D449247E1BE300DB3608 /* PathVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B879D448247E1BE300DB3608 /* PathVC.swift */; }; + B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87EF17026367CF800124B3C /* FileServerAPIV2.swift */; }; B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; }; B8856CB1256F0F47001CE70E /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */; }; @@ -1249,6 +1250,7 @@ B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; B879D448247E1BE300DB3608 /* PathVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathVC.swift; sourceTree = ""; }; B879D44A247E1D9200DB3608 /* PathStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathStatusView.swift; sourceTree = ""; }; + B87EF17026367CF800124B3C /* FileServerAPIV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileServerAPIV2.swift; sourceTree = ""; }; B8856D5F256F129B001CE70E /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSAlerts.swift; sourceTree = ""; }; B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraints.swift"; sourceTree = ""; }; B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = ""; }; @@ -3243,6 +3245,7 @@ isa = PBXGroup; children = ( C3A7218F2558C0CD0043A11F /* FileServerAPI.swift */, + B87EF17026367CF800124B3C /* FileServerAPIV2.swift */, ); path = "File Server"; sourceTree = ""; @@ -4909,6 +4912,7 @@ C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */, B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */, C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */, + B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */, C3A3A18A256E2092004D228D /* SignalRecipient.m in Sources */, C3C2A74425539EB700C340D1 /* Message.swift in Sources */, C32C5F11256DF79A003C73A2 /* SSKIncrementingIdFinder.swift in Sources */, diff --git a/SessionMessagingKit/File Server/FileServerAPIV2.swift b/SessionMessagingKit/File Server/FileServerAPIV2.swift new file mode 100644 index 000000000..8b6eafda5 --- /dev/null +++ b/SessionMessagingKit/File Server/FileServerAPIV2.swift @@ -0,0 +1,87 @@ +import PromiseKit +import SessionSnodeKit + +public enum FileServerAPIV2 { + + public static let server = "http://88.99.175.227" + public static let serverPublicKey = "7cb31905b55cd5580c686911debf672577b3fb0bff81df4ce2d5c4cb3a7aaa69" + + // MARK: Error + public enum Error : LocalizedError { + case parsingFailed + case invalidURL + + public var errorDescription: String? { + switch self { + case .parsingFailed: return "Invalid response." + case .invalidURL: return "Invalid URL." + } + } + } + + // MARK: Request + private struct Request { + let verb: HTTP.Verb + let endpoint: String + let queryParameters: [String:String] + let parameters: JSON + let headers: [String:String] + /// Always `true` under normal circumstances. You might want to disable + /// this when running over Lokinet. + let useOnionRouting: Bool + + init(verb: HTTP.Verb, endpoint: String, queryParameters: [String:String] = [:], parameters: JSON = [:], + headers: [String:String] = [:], useOnionRouting: Bool = true) { + self.verb = verb + self.endpoint = endpoint + self.queryParameters = queryParameters + self.parameters = parameters + self.headers = headers + self.useOnionRouting = useOnionRouting + } + } + + // MARK: Convenience + private static func send(_ request: Request) -> Promise { + let tsRequest: TSRequest + switch request.verb { + case .get: + var rawURL = "\(server)/\(request.endpoint)" + if !request.queryParameters.isEmpty { + let queryString = request.queryParameters.map { key, value in "\(key)=\(value)" }.joined(separator: "&") + rawURL += "?\(queryString)" + } + guard let url = URL(string: rawURL) else { return Promise(error: Error.invalidURL) } + tsRequest = TSRequest(url: url) + case .post, .put, .delete: + let rawURL = "\(server)/\(request.endpoint)" + guard let url = URL(string: rawURL) else { return Promise(error: Error.invalidURL) } + tsRequest = TSRequest(url: url, method: request.verb.rawValue, parameters: request.parameters) + } + tsRequest.allHTTPHeaderFields = request.headers + if request.useOnionRouting { + return OnionRequestAPI.sendOnionRequest(tsRequest, to: server, using: serverPublicKey) + } else { + preconditionFailure("It's currently not allowed to send non onion routed requests.") + } + } + + // MARK: File Storage + public static func upload(_ file: Data) -> Promise { + let base64EncodedFile = file.base64EncodedString() + let parameters = [ "file" : base64EncodedFile ] + let request = Request(verb: .post, endpoint: "files", parameters: parameters) + return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { json in + guard let fileID = json["result"] as? UInt64 else { throw Error.parsingFailed } + return fileID + } + } + + public static func download(_ file: UInt64) -> Promise { + let request = Request(verb: .get, endpoint: "files/\(file)") + return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { json in + guard let base64EncodedFile = json["result"] as? String, let file = Data(base64Encoded: base64EncodedFile) else { throw Error.parsingFailed } + return file + } + } +}