// // NCEntoToEndInterface.swift // Nextcloud // // Created by Marino Faggiana on 03/04/17. // Copyright © 2017 TWS. All rights reserved. // // Author Marino Faggiana // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // import Foundation class NCEntoToEndInterface : NSObject, OCNetworkingDelegate { let appDelegate = UIApplication.shared.delegate as! AppDelegate let ASYMMETRIC_STRING_TEST = "Nextcloud a safe home for all your data" override init() { } // -------------------------------------------------------------------------------------------- // MARK: Initialize // -------------------------------------------------------------------------------------------- @objc func initEndToEndEncryption() { // Clear all keys CCUtility.clearAllKeysEnd(toEnd: appDelegate.activeAccount) let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionGetEndToEndPublicKeys appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } func getPrivateKeyCipher() { let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionGetEndToEndPrivateKeyCipher appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } func getPublicKeyServer() { let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionGetEndToEndServerPublicKey appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } // -------------------------------------------------------------------------------------------- // MARK: Manage PublicKey // -------------------------------------------------------------------------------------------- func getEndToEndPublicKeysSuccess(_ metadataNet: CCMetadataNet!) { CCUtility.setEndToEndPublicKey(appDelegate.activeAccount, publicKey: metadataNet.key) // Request PrivateKey chiper to Server getPrivateKeyCipher() NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPublicKeys, note: "E2E PublicKey present on Server and stored to keychain", type: k_activityTypeSuccess, verbose: false, activeUrl: "") } func getEndToEndPublicKeysFailure(_ metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPublicKeys, note: message as String!, type: k_activityTypeFailure, verbose: false, activeUrl: "") switch errorCode { case 400: appDelegate.messageNotification("E2E publicKey", description: "bad request: unpredictable internal error", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) case 404: guard let csr = NCEndToEndEncryption.sharedManager().createCSR(appDelegate.activeUserID, directoryUser: appDelegate.directoryUser) else { appDelegate.messageNotification("E2E Csr", description: "Error to create Csr", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPublicKeys, note: "E2E Error to create Csr", type: k_activityTypeFailure, verbose: false, activeUrl: "") return } let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionSignEndToEndPublicKey; metadataNet.key = csr; appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) case 409: appDelegate.messageNotification("E2E publicKey", description: "forbidden: the user can't access the public keys", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) default: appDelegate.messageNotification("E2E publicKey", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } func signEnd(toEndPublicKeySuccess metadataNet: CCMetadataNet!) { guard let publicKey = metadataNet.key else { appDelegate.messageNotification("E2E publicKey", description: "Error : publicKey not present", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: 0) return } CCUtility.setEndToEndPublicKey(appDelegate.activeAccount, publicKey: publicKey) // Request PrivateKey chiper to Server getPrivateKeyCipher() NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionSignEndToEndPublicKey, note: "E2E Csr - publicKey sign on Server and stored publicKey locally", type: k_activityTypeFailure, verbose: false, activeUrl: "") } func signEnd(toEndPublicKeyFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { appDelegate.messageNotification("E2E sign Csr - publicKey", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionSignEndToEndPublicKey, note: message, type: k_activityTypeFailure, verbose: false, activeUrl: "") } func deleteEnd(toEndPublicKeySuccess metadataNet: CCMetadataNet!) { appDelegate.messageNotification("E2E delete publicKey", description: "Success", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.success, errorCode: 0) } func deleteEnd(toEndPublicKeyFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { appDelegate.messageNotification("E2E delete publicKey", description: message, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } // -------------------------------------------------------------------------------------------- // MARK: Manage PrivateKey // -------------------------------------------------------------------------------------------- func getEndToEndPrivateKeyCipherSuccess(_ metadataNet: CCMetadataNet!) { // request Passphrase var passphraseTextField: UITextField? let alertController = UIAlertController(title: NSLocalizedString("_e2e_passphrase_request_title_", comment: ""), message: NSLocalizedString("_e2e_passphrase_request_message_", comment: ""), preferredStyle: .alert) let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in let passphrase = passphraseTextField?.text guard let privateKey = (NCEndToEndEncryption.sharedManager().decryptPrivateKey(metadataNet.key, passphrase: passphrase)) else { self.appDelegate.messageNotification("E2E decrypt privateKey", description: "Error to decrypt Private Key", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: 0) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPrivateKeyCipher, note: "E2E Error to decrypt PrivateKey", type: k_activityTypeFailure, verbose: false, activeUrl: "") return } // --------- verify privateKey encrypt/decrypt asymmetric key --------- let publicKey = CCUtility.getEndToEndPublicKey(self.appDelegate.activeAccount) guard let encryptData = NCEndToEndEncryption.sharedManager().encryptAsymmetricString(self.ASYMMETRIC_STRING_TEST, publicKey: publicKey) else { self.appDelegate.messageNotification("E2E Verify privateKey", description: "Error to encrypt asymmetric key", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: 0) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPrivateKeyCipher, note: "E2E Verify privateKey, error to encrypt asymmetric key", type: k_activityTypeFailure, verbose: false, activeUrl: "") return } guard let decryptString = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(encryptData, privateKey: privateKey) else { self.appDelegate.messageNotification("E2E Verify privateKey", description: "Error to decrypt asymmetric key", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: 0) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPrivateKeyCipher, note: "E2E Verify privateKey, error to decrypt asymmetric key", type: k_activityTypeFailure, verbose: false, activeUrl: "") return } if (decryptString != self.ASYMMETRIC_STRING_TEST) { self.appDelegate.messageNotification("E2E Verify privateKey", description: "Error verify data encrypt/decrypt", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: 0) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPrivateKeyCipher, note: "E2E Verify privateKey, error verify data encrypt/decrypt", type: k_activityTypeFailure, verbose: false, activeUrl: "") return } // Save to keychain CCUtility.setEndToEndPrivateKeyCipher(self.appDelegate.activeAccount, privateKeyCipher: metadataNet.key) CCUtility.setEndToEndPassphrase(self.appDelegate.activeAccount, passphrase:passphrase) // request publicKey Server() self.getPublicKeyServer() NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPrivateKeyCipher, note: "E2E PrivateKey present on Server and stored to keychain", type: k_activityTypeSuccess, verbose: false, activeUrl: "") }) let cancel = UIAlertAction(title: "Cancel", style: .cancel) { (action) -> Void in } alertController.addAction(ok) alertController.addAction(cancel) alertController.addTextField { (textField) -> Void in passphraseTextField = textField passphraseTextField?.placeholder = "Enter passphrase (12 words)" } appDelegate.activeMain.present(alertController, animated: true) } func getEndToEndPrivateKeyCipherFailure(_ metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPrivateKeyCipher, note: message as String!, type: k_activityTypeFailure, verbose: false, activeUrl: "") switch errorCode { case 400: appDelegate.messageNotification("E2E privateKey", description: "bad request: unpredictable internal error", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) case 404: // message let e2ePassphrase = NYMnemonic.generateString(128, language: "english") let message = "\n" + NSLocalizedString("_e2e_settings_view_passphrase_", comment: "") + "\n\n" + e2ePassphrase! let alertController = UIAlertController(title: NSLocalizedString("_e2e_settings_title_", comment: ""), message: NSLocalizedString(message, comment: ""), preferredStyle: .alert) let OKAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { action in guard let privateKeyChiper = NCEndToEndEncryption.sharedManager().encryptPrivateKey(self.appDelegate.activeUserID, directoryUser: self.appDelegate.directoryUser, passphrase: e2ePassphrase) else { self.appDelegate.messageNotification("E2E privateKey", description: "Error to create PrivateKey chiper", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndPrivateKeyCipher, note: "E2E Error to create PrivateKey chiper", type: k_activityTypeFailure, verbose: false, activeUrl: "") return } let metadataNet: CCMetadataNet = CCMetadataNet.init(account: self.appDelegate.activeAccount) metadataNet.action = actionStoreEndToEndPrivateKeyCipher metadataNet.key = privateKeyChiper metadataNet.password = e2ePassphrase self.appDelegate.addNetworkingOperationQueue(self.appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } alertController.addAction(OKAction) appDelegate.activeMain.present(alertController, animated: true) case 409: appDelegate.messageNotification("E2E privateKey", description: "forbidden: the user can't access the private key", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) default: appDelegate.messageNotification("E2E privateKey", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } func storeEnd(toEndPrivateKeyCipherSuccess metadataNet: CCMetadataNet!) { guard let privateKeyCipher = metadataNet.key else { appDelegate.messageNotification("E2E privateKey", description: "Error : privateKey not present", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: 0) return } CCUtility.setEndToEndPrivateKeyCipher(appDelegate.activeAccount, privateKeyCipher: privateKeyCipher) CCUtility.setEndToEndPassphrase(appDelegate.activeAccount, passphrase:metadataNet.password) // request publicKey Server() self.getPublicKeyServer() NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionStoreEndToEndPrivateKeyCipher, note: "E2E PrivateKey stored on Server and stored locally", type: k_activityTypeSuccess, verbose: false, activeUrl: "") } func storeEnd(toEndPrivateKeyCipherFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { appDelegate.messageNotification("E2E sign privateKey", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionStoreEndToEndPrivateKeyCipher, note: message, type: k_activityTypeFailure, verbose: false, activeUrl: "") } func deleteEnd(toEndPrivateKeySuccess metadataNet: CCMetadataNet!) { appDelegate.messageNotification("E2E delete privateKey", description: "Success", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.success, errorCode: 0) } func deleteEnd(toEndPrivateKeyFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { appDelegate.messageNotification("E2E delete privateKey", description: message, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } // -------------------------------------------------------------------------------------------- // MARK: Manage Server PublicKey // -------------------------------------------------------------------------------------------- func getEndToEndServerPublicKeySuccess(_ metadataNet: CCMetadataNet!) { CCUtility.setEndToEndPublicKeyServer(appDelegate.activeAccount, publicKey: metadataNet.key) // OK Activated NotificationCenter.default.post(name: Notification.Name("reloadManageEndToEndEncryption"), object: nil) NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndServerPublicKey, note: "E2E Server PublicKey present on Server and stored to keychain", type: k_activityTypeSuccess, verbose: false, activeUrl: "") } func getEndToEndServerPublicKeyFailure(_ metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { NCManageDatabase.sharedInstance.addActivityClient("", fileID: "", action: k_activityDebugActionEndToEndEncryption, selector: actionGetEndToEndServerPublicKey, note: message as String!, type: k_activityTypeFailure, verbose: false, activeUrl: "") switch (errorCode) { case 400: appDelegate.messageNotification("E2E Server publicKey", description: "bad request: unpredictable internal error", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) case 404: appDelegate.messageNotification("E2E Server publicKey", description: "Server publickey doesn't exists", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) case 409: appDelegate.messageNotification("E2E Server publicKey", description: "forbidden: the user can't access the Server publickey", visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) default: appDelegate.messageNotification("E2E Server publicKey", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } // -------------------------------------------------------------------------------------------- // MARK: Mark/Delete Encrypted Folder // -------------------------------------------------------------------------------------------- func markEnd(toEndFolderEncryptedSuccess metadataNet: CCMetadataNet!) { print("E2E mark folder success") } func markEnd(toEndFolderEncryptedFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { // Unauthorized if (errorCode == kOCErrorServerUnauthorized) { appDelegate.openLoginView(appDelegate.activeMain, loginType: loginModifyPasswordUser) } if (errorCode != kOCErrorServerUnauthorized) { appDelegate.messageNotification("_error_", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } @objc func markEndToEndFolderEncrypted(_ metadata: tableMetadata) { let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionMarkEndToEndFolderEncrypted; metadataNet.fileID = metadata.fileID; appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } func deletemarkEnd(toEndFolderEncryptedSuccess metadataNet: CCMetadataNet!) { print("E2E delete mark folder success") } func deletemarkEnd(toEndFolderEncryptedFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { // Unauthorized if (errorCode == kOCErrorServerUnauthorized) { appDelegate.openLoginView(appDelegate.activeMain, loginType: loginModifyPasswordUser) } if (errorCode != kOCErrorServerUnauthorized) { appDelegate.messageNotification("_error_", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } @objc func deletemarkEndToEndFolderEncrypted(_ metadata: tableMetadata) { let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionDeletemarkEndToEndFolderEncrypted; metadataNet.fileID = metadata.fileID; appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } // -------------------------------------------------------------------------------------------- // MARK: Lock/Unlock Encrypted Folder // -------------------------------------------------------------------------------------------- func unlockEnd(toEndFolderEncryptedSuccess metadataNet: CCMetadataNet!) { print("E2E lock file success") } func unlockEnd(toEndFolderEncryptedFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { // Unauthorized if (errorCode == kOCErrorServerUnauthorized) { appDelegate.openLoginView(appDelegate.activeMain, loginType: loginModifyPasswordUser) } if (errorCode != kOCErrorServerUnauthorized) { appDelegate.messageNotification("_error_", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } @objc func unlockEndToEndFolderEncrypted(_ metadata: tableMetadata) { let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionUnlockEndToEndFolderEncrypted; metadataNet.fileID = metadata.fileID; appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } func lockEnd(toEndFolderEncryptedSuccess metadataNet: CCMetadataNet!) { print("E2E lock file success") } func lockEnd(toEndFolderEncryptedFailure metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { // Unauthorized if (errorCode == kOCErrorServerUnauthorized) { appDelegate.openLoginView(appDelegate.activeMain, loginType: loginModifyPasswordUser) } if (errorCode != kOCErrorServerUnauthorized) { appDelegate.messageNotification("_error_", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } @objc func lockEndToEndFolderEncrypted(_ metadata: tableMetadata) { let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionLockEndToEndFolderEncrypted; metadataNet.fileID = metadata.fileID; appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } // -------------------------------------------------------------------------------------------- // MARK: Manage Metadata // -------------------------------------------------------------------------------------------- func getEndToEndMetadataSuccess(_ metadataNet: CCMetadataNet!) { print("E2E get metadata file success") } func getEndToEndMetadataFailure(_ metadataNet: CCMetadataNet!, message: String!, errorCode: Int) { // Unauthorized if (errorCode == kOCErrorServerUnauthorized) { appDelegate.openLoginView(appDelegate.activeMain, loginType: loginModifyPasswordUser) } if (errorCode != kOCErrorServerUnauthorized) { appDelegate.messageNotification("_error_", description: message as String!, visible: true, delay: TimeInterval(k_dismissAfterSecond), type: TWMessageBarMessageType.error, errorCode: errorCode) } } @objc func getEndToEndMetadata(_ metadata: tableMetadata) { let metadataNet: CCMetadataNet = CCMetadataNet.init(account: appDelegate.activeAccount) metadataNet.action = actionGetEndToEndMetadata; metadataNet.fileID = metadata.fileID; appDelegate.addNetworkingOperationQueue(appDelegate.netQueue, delegate: self, metadataNet: metadataNet) } }