From b1250380e6e5f146097a16a7244bb7e0daf3172d Mon Sep 17 00:00:00 2001 From: Bruno Muniz Azevedo Filho <bruno@elixxir.io> Date: Wed, 13 Jul 2022 18:47:16 -0300 Subject: [PATCH] Fixing sftp download --- Sources/InputField/OutlinedInputField.swift | 1 + Sources/LaunchFeature/LaunchViewModel.swift | 4 + .../ViewModels/RestoreViewModel.swift | 16 ++- Sources/SFTPFeature/SFTPService.swift | 121 +++++++++++++----- 4 files changed, 103 insertions(+), 39 deletions(-) diff --git a/Sources/InputField/OutlinedInputField.swift b/Sources/InputField/OutlinedInputField.swift index 01e1511d..3bb8ad30 100644 --- a/Sources/InputField/OutlinedInputField.swift +++ b/Sources/InputField/OutlinedInputField.swift @@ -24,6 +24,7 @@ public final class OutlinedInputField: UIView { textField.delegate = self textField.backgroundColor = .clear + textField.textColor = Asset.neutralDark.color placeholderLabel.textColor = Asset.neutralWeak.color placeholderLabel.font = Fonts.Mulish.regular.font(size: 16.0) diff --git a/Sources/LaunchFeature/LaunchViewModel.swift b/Sources/LaunchFeature/LaunchViewModel.swift index 054432b4..4e1b25ea 100644 --- a/Sources/LaunchFeature/LaunchViewModel.swift +++ b/Sources/LaunchFeature/LaunchViewModel.swift @@ -5,6 +5,7 @@ import Models import Combine import Defaults import XXModels +import Keychain import Foundation import Integration import Permissions @@ -31,6 +32,7 @@ final class LaunchViewModel { @Dependency private var network: XXNetworking @Dependency private var versionChecker: VersionChecker @Dependency private var dropboxService: DropboxInterface + @Dependency private var keychainHandler: KeychainHandling @Dependency private var permissionHandler: PermissionHandling @KeyObject(.username, defaultValue: nil) var username: String? @@ -90,6 +92,7 @@ final class LaunchViewModel { self.hudSubject.send(.none) self.routeSubject.send(.onboarding(ndf)) self.dropboxService.unlink() + try? self.keychainHandler.clear() return } @@ -98,6 +101,7 @@ final class LaunchViewModel { self.hudSubject.send(.none) self.routeSubject.send(.onboarding(ndf)) self.dropboxService.unlink() + try? self.keychainHandler.clear() return } diff --git a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift index 5f1d4414..09147154 100644 --- a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift +++ b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift @@ -90,11 +90,17 @@ final class RestoreViewModel { } private func downloadBackupForSFTP(_ backup: Backup) { - do { - try sftpService.downloadBackup(backup.id) - } catch { - print(error.localizedDescription) - } + sftpService.downloadBackup(backup.id, { [weak self] in + guard let self = self else { return } + self.stepRelay.send(.downloading(backup.size, backup.size)) + + switch $0 { + case .success(let data): + self.continueRestoring(data: data) + case .failure(let error): + self.stepRelay.send(.failDownload(error)) + } + }) } private func downloadBackupForDropbox(_ backup: Backup) { diff --git a/Sources/SFTPFeature/SFTPService.swift b/Sources/SFTPFeature/SFTPService.swift index aca3e200..b751f396 100644 --- a/Sources/SFTPFeature/SFTPService.swift +++ b/Sources/SFTPFeature/SFTPService.swift @@ -1,5 +1,6 @@ import UIKit import Shout +import Socket import Models import Combine import Keychain @@ -7,16 +8,17 @@ import Foundation import Presentation import DependencyInjection -public typealias SFTPFetchResult = (Result<RestoreSettings?, Error>) -> Void +public typealias SFTPDownloadResult = (Result<Data, Error>) -> Void public typealias SFTPAuthorizationParams = (UIViewController, () -> Void) +public typealias SFTPFetchResult = (Result<RestoreSettings?, Error>) -> Void public struct SFTPService { public var isAuthorized: () -> Bool 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 + public var authenticate: (String, String, String) throws -> Void + public var downloadBackup: (String, SFTPDownloadResult) -> Void } public extension SFTPService { @@ -29,23 +31,23 @@ public extension SFTPService { print("^^^ Requested upload on sftp service") print("^^^ URL path: \(url.path)") }, - downloadBackup: { path in - print("^^^ Requested backup download on sftp service.") - print("^^^ Path: \(path)") - }, fetchMetadata: { completion in print("^^^ Requested backup metadata on sftp service.") completion(.success(nil)) }, + authorizeFlow: { (_, completion) in + print("^^^ Requested authorizing flow on sftp service.") + completion() + }, authenticate: { host, username, password in print("^^^ Requested authentication on sftp service.") print("^^^ Host: \(host)") print("^^^ Username: \(username)") print("^^^ Password: \(password)") }, - authorizeFlow: { (_, completion) in - print("^^^ Requested authorizing flow on sftp service.") - completion() + downloadBackup: { path, completion in + print("^^^ Requested backup download on sftp service.") + print("^^^ Path: \(path)") } ) @@ -72,20 +74,6 @@ public extension SFTPService { try sftp.upload(localURL: url, remotePath: "backup/backup.xxm") }, - 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) - - let ssh = try SSH(host: host!, port: 22) - try ssh.authenticate(username: username!, password: password!) - let sftp = try ssh.openSftp() - - 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 @@ -113,22 +101,87 @@ public extension SFTPService { completion(.success(nil)) } catch { + if let error = error as? SSHError { + print(error.kind) + print(error.message) + print(error.description) + } else if let error = error as? Socket.Error { + print(error.errorCode) + print(error.description) + print(error.errorReason) + print(error.localizedDescription) + } else { + print(error.localizedDescription) + } + completion(.failure(error)) } }, - 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) - }, authorizeFlow: { controller, completion in var pushPresenter: Presenting = PushPresenter() pushPresenter.present(SFTPController(completion), from: controller) + }, + authenticate: { host, username, password in + do { + try SSH.connect( + host: host, + port: 22, + username: username, + authMethod: SSHPassword(password)) { ssh in + _ = 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) + } + } catch { + if let error = error as? SSHError { + print(error.kind) + print(error.message) + print(error.description) + } else if let error = error as? Socket.Error { + print(error.errorCode) + print(error.description) + print(error.errorReason) + print(error.localizedDescription) + } else { + print(error.localizedDescription) + } + + throw error + } + }, + downloadBackup: { path, completion in + do { + 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() + + let localURL = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.elixxir.messenger")! + .appendingPathComponent("sftp") + + try sftp.download(remotePath: path, localURL: localURL) + + let data = try Data(contentsOf: localURL) + completion(.success(data)) + } catch { + completion(.failure(error)) + + if var error = error as? SSHError { + print(error.kind) + print(error.message) + print(error.description) + } else { + print(error.localizedDescription) + } + } } ) } -- GitLab