Skip to content
Snippets Groups Projects
SFTPService.swift 5.16 KiB
Newer Older
Bruno Muniz's avatar
Bruno Muniz committed
import UIKit
import Shout
Bruno Muniz's avatar
Bruno Muniz committed
import Combine
import Keychain
import Foundation
Bruno Muniz's avatar
Bruno Muniz committed
import Presentation
import DependencyInjection

public typealias SFTPFetchResult = (Result<RestoreSettings?, Error>) -> Void
Bruno Muniz's avatar
Bruno Muniz committed
public typealias SFTPAuthorizationParams = (UIViewController, () -> Void)
Bruno Muniz's avatar
Bruno Muniz committed
public struct SFTPService {
    public var isAuthorized: () -> Bool
Bruno Muniz's avatar
Bruno Muniz committed
    public var uploadBackup: (URL) throws -> Void
    public var downloadBackup: (String) throws -> Void
    public var fetchMetadata: (SFTPFetchResult) -> Void
    public var authenticate: (String, String, String) throws -> Void
    public var authorizeFlow: (SFTPAuthorizationParams) -> Void
Bruno Muniz's avatar
Bruno Muniz committed
}

public extension SFTPService {
    static var mock = SFTPService(
        isAuthorized: {
            print("^^^ Requested auth status on sftp service")
            return true
        },
Bruno Muniz's avatar
Bruno Muniz committed
        uploadBackup: { url in
            print("^^^ Requested upload on sftp service")
            print("^^^ URL path: \(url.path)")
Bruno Muniz's avatar
Bruno Muniz committed
        downloadBackup: { path in
            print("^^^ Requested backup download on sftp service.")
            print("^^^ Path: \(path)")
Bruno Muniz's avatar
Bruno Muniz committed
        fetchMetadata: { completion in
            print("^^^ Requested backup metadata on sftp service.")
            completion(.success(nil))
        },
        authenticate: { host, username, password in
            print("^^^ Requested authentication on sftp service.")
            print("^^^ Host: \(host)")
            print("^^^ Username: \(username)")
            print("^^^ Password: \(password)")
Bruno Muniz's avatar
Bruno Muniz committed
        },
        authorizeFlow: { (_, completion) in
            print("^^^ Requested authorizing flow on sftp service.")
            completion()
        }
    )
Bruno Muniz's avatar
Bruno Muniz committed
    static var live = SFTPService(
        isAuthorized: {
            if let keychain = try? DependencyInjection.Container.shared.resolve() as KeychainHandling,
               let pwd = try? keychain.get(key: .pwd),
               let host = try? keychain.get(key: .host),
               let username = try? keychain.get(key: .username) {
                return true
            }
Bruno Muniz's avatar
Bruno Muniz committed

            return false
Bruno Muniz's avatar
Bruno Muniz committed
        },
Bruno Muniz's avatar
Bruno Muniz committed
        uploadBackup: { url in
            let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling
            let host = try keychain.get(key: .host)
            let password = try keychain.get(key: .pwd)
            let username = try keychain.get(key: .username)

            let ssh = try SSH(host: host!, port: 22)
            try ssh.authenticate(username: username!, password: password!)
            let sftp = try ssh.openSftp()

            try sftp.upload(localURL: url, remotePath: "backup/backup.xxm")
        },
Bruno Muniz's avatar
Bruno Muniz committed
        downloadBackup: { path in
            let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling
            let host = try keychain.get(key: .host)
            let password = try keychain.get(key: .pwd)
            let username = try keychain.get(key: .username)
Bruno Muniz's avatar
Bruno Muniz committed
            let ssh = try SSH(host: host!, port: 22)
            try ssh.authenticate(username: username!, password: password!)
            let sftp = try ssh.openSftp()
Bruno Muniz's avatar
Bruno Muniz committed
            let temp = NSTemporaryDirectory()
            try sftp.download(remotePath: path, localURL: URL(string: temp)!)
            print(FileManager.default.fileExists(atPath: temp))
        },
        fetchMetadata: { completion in
            do {
                let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling
Bruno Muniz's avatar
Bruno Muniz committed
                let host = try keychain.get(key: .host)
                let password = try keychain.get(key: .pwd)
                let username = try keychain.get(key: .username)

                let ssh = try SSH(host: host!, port: 22)
                try ssh.authenticate(username: username!, password: password!)
                let sftp = try ssh.openSftp()

                if let files = try? sftp.listFiles(in: "backup"),
                   let backup = files.filter({ file in file.0 == "backup.xxm" }).first {
                    completion(.success(.init(
                        backup: .init(
                            id: "backup/backup.xxm",
                            date: backup.value.lastModified,
                            size: Float(backup.value.size)
                        ),
                        cloudService: .sftp
                    )))

                    return
                }

                completion(.success(nil))
            } catch {
                completion(.failure(error))
            }
        },
Bruno Muniz's avatar
Bruno Muniz committed
        authenticate: { host, username, password in
            let ssh = try SSH(host: host, port: 22)
            try ssh.authenticate(username: username, password: password)
            let sftp = try ssh.openSftp()

            let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling
            try keychain.store(key: .host, value: host)
            try keychain.store(key: .pwd, value: password)
            try keychain.store(key: .username, value: username)
Bruno Muniz's avatar
Bruno Muniz committed
        },
        authorizeFlow: { controller, completion in
            var pushPresenter: Presenting = PushPresenter()
            pushPresenter.present(SFTPController(completion), from: controller)