From 45454db09125929c70908398f346fca329e79fa2 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 30 Apr 2024 13:35:05 +0200 Subject: [PATCH 01/31] Enable login v2 Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 6ddb4e18f3..27983a832e 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -68,7 +68,7 @@ let userAgent: String = { @objc public var use_themingColor: Bool = true @objc public var use_themingLogo: Bool = false @objc public var use_storeLocalAutoUploadAll: Bool = false - @objc public var use_loginflowv2: Bool = false // Don't touch me !! + @objc public var use_loginflowv2: Bool = true // Don't touch me !! @objc public var disable_intro: Bool = false @objc public var disable_request_login_url: Bool = false From d8b1e53c943c369d632a24f1940db3b936aea7c5 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Thu, 2 May 2024 17:59:54 +0200 Subject: [PATCH 02/31] Add external browser option Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 1 - iOSClient/Login/NCLogin.swift | 8 ++--- iOSClient/Login/NCLoginWeb.swift | 52 ++++++++++++++++++++------------ 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 27983a832e..5166a54711 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -68,7 +68,6 @@ let userAgent: String = { @objc public var use_themingColor: Bool = true @objc public var use_themingLogo: Bool = false @objc public var use_storeLocalAutoUploadAll: Bool = false - @objc public var use_loginflowv2: Bool = true // Don't touch me !! @objc public var disable_intro: Bool = false @objc public var disable_request_login_url: Bool = false diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index fdbadba711..bc243cd885 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -272,16 +272,16 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.loginButton.isEnabled = true // Login Flow V2 - if error == .success && NCBrandOptions.shared.use_loginflowv2 && token != nil && endpoint != nil && login != nil { + if error == .success, let token, let endpoint, let login { if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb { loginWeb.urlBase = url loginWeb.user = user loginWeb.loginFlowV2Available = true - loginWeb.loginFlowV2Token = token! - loginWeb.loginFlowV2Endpoint = endpoint! - loginWeb.loginFlowV2Login = login! + loginWeb.loginFlowV2Token = token + loginWeb.loginFlowV2Endpoint = endpoint + loginWeb.loginFlowV2Login = login self.navigationController?.pushViewController(loginWeb, animated: true) } diff --git a/iOSClient/Login/NCLoginWeb.swift b/iOSClient/Login/NCLoginWeb.swift index ee735b7072..28acaffead 100644 --- a/iOSClient/Login/NCLoginWeb.swift +++ b/iOSClient/Login/NCLoginWeb.swift @@ -47,6 +47,9 @@ class NCLoginWeb: UIViewController { var loginFlowV2Endpoint = "" var loginFlowV2Login = "" + // Opens the login URL in external browser instead of in app. User must manually go back to the app. + let loginFlowv2ExternalBrowser = false + // MARK: - View Life Cycle override func viewDidLoad() { @@ -145,6 +148,8 @@ class NCLoginWeb: UIViewController { } } self.title = titleView + + NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) } override func viewDidAppear(_ animated: Bool) { @@ -169,21 +174,32 @@ class NCLoginWeb: UIViewController { } func loadWebPage(webView: WKWebView, url: URL) { + if loginFlowV2Available, loginFlowv2ExternalBrowser { + UIApplication.shared.open(url) + } else { + let language = NSLocale.preferredLanguages[0] as String + var request = URLRequest(url: url) - let language = NSLocale.preferredLanguages[0] as String - var request = URLRequest(url: url) + if let deviceName = "\(UIDevice.current.name) (\(NCBrandOptions.shared.brand) iOS)".cString(using: .utf8), + let deviceUserAgent = String(cString: deviceName, encoding: .ascii) { + webView.customUserAgent = deviceUserAgent + } else { + webView.customUserAgent = userAgent + } - if let deviceName = "\(UIDevice.current.name) (\(NCBrandOptions.shared.brand) iOS)".cString(using: .utf8), - let deviceUserAgent = String(cString: deviceName, encoding: .ascii) { - webView.customUserAgent = deviceUserAgent - } else { - webView.customUserAgent = userAgent - } + request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") + request.addValue(language, forHTTPHeaderField: "Accept-Language") - request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") - request.addValue(language, forHTTPHeaderField: "Accept-Language") + webView.load(request) + } + } - webView.load(request) + private func pollLogin() { + NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in + if error == .success, let server, let loginName, let appPassword { + self.createAccount(server: server, username: loginName, password: appPassword) + } + } } func getAppPassword(serverUrl: String, username: String, password: String) { @@ -205,6 +221,10 @@ class NCLoginWeb: UIViewController { @objc func changeUser(sender: UIBarButtonItem) { toggleMenu() } + + @objc func applicationDidBecomeActive(_ notification: NSNotification) { + pollLogin() + } } extension NCLoginWeb: WKNavigationDelegate { @@ -271,15 +291,7 @@ extension NCLoginWeb: WKNavigationDelegate { NCActivityIndicator.shared.stop() - if loginFlowV2Available { - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in - if error == .success && server != nil && loginName != nil && appPassword != nil { - self.createAccount(server: server!, username: loginName!, password: appPassword!) - } - } - } - } + pollLogin() } // MARK: - From b7051208e4e763146b0e0b42db037ae4ac1cd9b3 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Fri, 3 May 2024 16:32:31 +0200 Subject: [PATCH 03/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Data/NCManageDatabase+Directory.swift | 2 +- iOSClient/Login/NCLoginWeb.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Directory.swift b/iOSClient/Data/NCManageDatabase+Directory.swift index e9e9fcdc65..05168f3a40 100644 --- a/iOSClient/Data/NCManageDatabase+Directory.swift +++ b/iOSClient/Data/NCManageDatabase+Directory.swift @@ -69,7 +69,7 @@ extension NCManageDatabase { if let richWorkspace { result.richWorkspace = richWorkspace } result.serverUrl = serverUrl result.account = account - realm.add(result) + realm.add(result, update: .modified) } } } catch let error { diff --git a/iOSClient/Login/NCLoginWeb.swift b/iOSClient/Login/NCLoginWeb.swift index 28acaffead..1481552f0e 100644 --- a/iOSClient/Login/NCLoginWeb.swift +++ b/iOSClient/Login/NCLoginWeb.swift @@ -48,7 +48,7 @@ class NCLoginWeb: UIViewController { var loginFlowV2Login = "" // Opens the login URL in external browser instead of in app. User must manually go back to the app. - let loginFlowv2ExternalBrowser = false + let loginFlowv2ExternalBrowser = true // MARK: - View Life Cycle From 498882ef46fb45c20018ccceeef2f00782591815 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 14 May 2024 12:48:43 +0200 Subject: [PATCH 04/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Login/NCLogin.swift | 28 +++++++++++++++++++ iOSClient/Networking/NCNetworking.swift | 25 +++++++++++++++++ .../en.lproj/Localizable.strings | 4 +++ 3 files changed, 57 insertions(+) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index e4cc34d06c..d1cd296e57 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -143,6 +143,8 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) + + NCNetworking.shared.delegate = self } override func viewDidAppear(_ animated: Bool) { @@ -457,3 +459,29 @@ extension NCLogin: NCShareAccountsDelegate { isUrlValid(url: url, user: user) } } + +extension NCLogin: ClientCertificateDelegate, UIDocumentPickerDelegate { + func didAskForClientCertificate() { + let alert = UIAlertController(title: NSLocalizedString("_no_client_cert_found_", comment: ""), message: NSLocalizedString("_no_client_cert_found_desc_", comment: ""), preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) + + alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in + let documentProviderMenu = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.pkcs12]) + +// documentProviderMenu.modalPresentationStyle = .formSheet +// documentProviderMenu.popoverPresentationController?.sourceView = mainTabBarController.tabBar +// documentProviderMenu.popoverPresentationController?.sourceRect = mainTabBarController.tabBar.bounds + documentProviderMenu.delegate = self + + self.present(documentProviderMenu, animated: true, completion: nil) + })) + + present(alert, animated: true) + } + + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + NCNetworking.shared.p12Data = try? Data(contentsOf: urls[0]) + actionButtonLogin(self) + } +} diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index bbda81c032..8a87de87c1 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -31,6 +31,10 @@ import Queuer @objc protocol uploadE2EEDelegate: AnyObject { } #endif +@objc protocol ClientCertificateDelegate { + func didAskForClientCertificate() +} + @objcMembers class NCNetworking: NSObject, NKCommonDelegate { public static let shared: NCNetworking = { @@ -58,6 +62,9 @@ class NCNetworking: NSObject, NKCommonDelegate { let uploadMetadataInBackground = ThreadSafeDictionary() let downloadMetadataInBackground = ThreadSafeDictionary() var transferInForegorund: TransferInForegorund? + weak var delegate: ClientCertificateDelegate? + + var p12Data: Data? lazy var nkBackground: NKBackground = { let nckb = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance) @@ -168,6 +175,24 @@ class NCNetworking: NSObject, NKCommonDelegate { func authenticationChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { + DispatchQueue.main.async { + if let p12Data = self.p12Data { +// completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) + + } else { + self.delegate?.didAskForClientCertificate() + } + } + +// let alert = UIAlertController(title: NSLocalizedString("_edit_comment_", comment: ""), message: nil, preferredStyle: .alert) +// alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) +// UIApplication.shared.?.rootViewController?.present(alert, animated: true) +// let p12Data = try? Data(contentsOf: URL(fileURLWithPath: Bundle.module.path(forResource: "identity", ofType: "p12")!)) + // let certificate = PKCS12(pkcs12Data: p12Data!, password: "") + +// completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) + } DispatchQueue.global().async { self.checkTrustedChallenge(session, didReceive: challenge, completionHandler: completionHandler) } diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index c0dbea23ff..d53b82f7fe 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -1063,3 +1063,7 @@ "_no_types_" = "No provider found"; "_no_types_subtitle_" = "AI Providers need to be installed to use the Assistant"; +// MARK: Client certificate +"_no_client_cert_found_" = "No client certificate was found"; +"_no_client_cert_found_desc_" = "Do you want to install a TLS client certificate?"; + From dbfb2f2fd8210b6b412516ceafb58e2db3454853 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 15 May 2024 12:49:33 +0200 Subject: [PATCH 05/31] WIP Signed-off-by: Milen Pivchev --- Nextcloud.xcodeproj/project.pbxproj | 100 +++++++++++++++++- .../E2EE/NCNetworkingE2EECreateFolder.swift | 1 - .../E2EE/NCNetworkingE2EEUpload.swift | 1 - iOSClient/Networking/NCNetworking.swift | 3 +- iOSClient/Utility/PKCS12.swift | 80 ++++++++++++++ 5 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 iOSClient/Utility/PKCS12.swift diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 72796f44fd..04fb614bf1 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -82,6 +82,21 @@ F3391B142B4C52EF001C0C4B /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B132B4C52EF001C0C4B /* JGProgressHUD */; }; F3391B162B4C52F6001C0C4B /* FirebaseDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B152B4C52F6001C0C4B /* FirebaseDatabase */; }; F33AAF9A2A60394C006ECCBD /* NCMoreUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */; }; + F33EE6E12BF4BDA500CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6E02BF4BDA500CA1A51 /* NIOSSL */; }; + F33EE6E32BF4C00700CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6E22BF4C00700CA1A51 /* NIOSSL */; }; + F33EE6E52BF4C02000CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6E42BF4C02000CA1A51 /* NIOSSL */; }; + F33EE6E72BF4C02600CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6E62BF4C02600CA1A51 /* NIOSSL */; }; + F33EE6E92BF4C02D00CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6E82BF4C02D00CA1A51 /* NIOSSL */; }; + F33EE6EB2BF4C03200CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6EA2BF4C03200CA1A51 /* NIOSSL */; }; + F33EE6ED2BF4C03800CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6EC2BF4C03800CA1A51 /* NIOSSL */; }; + F33EE6F02BF4C0FF00CA1A51 /* NIO in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6EF2BF4C0FF00CA1A51 /* NIO */; }; + F33EE6F22BF4C9B200CA1A51 /* PKCS12.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */; }; + F33EE6F32BF4C9B200CA1A51 /* PKCS12.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */; }; + F33EE6F42BF4C9B200CA1A51 /* PKCS12.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */; }; + F33EE6F52BF4C9B200CA1A51 /* PKCS12.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */; }; + F33EE6F62BF4C9B200CA1A51 /* PKCS12.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */; }; + F33EE6F72BF4C9B200CA1A51 /* PKCS12.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */; }; + F33EE6F82BF4C9B200CA1A51 /* PKCS12.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */; }; F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; }; F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; }; F343A4B52A1E084200DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; }; @@ -1108,6 +1123,7 @@ F3131EDA2B038DB90018DB28 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/System/iOSSupport/System/Library/Frameworks/WidgetKit.framework; sourceTree = DEVELOPER_DIR; }; F321DA892B71205A00DDA0E6 /* NCTrashSelectTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTrashSelectTabBar.swift; sourceTree = ""; }; F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCMoreUserCell.xib; sourceTree = ""; }; + F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKCS12.swift; sourceTree = ""; }; F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAsset+Extension.swift"; sourceTree = ""; }; F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = ""; }; F359D8662A7D03420023F405 /* NCUtility+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCUtility+Exif.swift"; sourceTree = ""; }; @@ -1680,6 +1696,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F33EE6ED2BF4C03800CA1A51 /* NIOSSL in Frameworks */, F72AD71128C24BBB006CB92D /* NextcloudKit in Frameworks */, F710FC88277B7D3F00AA9FBF /* RealmSwift in Frameworks */, F7160A8E2BE933710034DCB3 /* Realm in Frameworks */, @@ -1748,6 +1765,7 @@ files = ( F7490E8B29882CE4009DCE94 /* NextcloudKit in Frameworks */, F7490E8929882CC8009DCE94 /* SwiftEntryKit in Frameworks */, + F33EE6EB2BF4C03200CA1A51 /* NIOSSL in Frameworks */, F7490E7229882BB4009DCE94 /* RealmSwift in Frameworks */, F760DE0D2AE66EDF0027D78A /* KeychainAccess in Frameworks */, F7160A8C2BE9336A0034DCB3 /* Realm in Frameworks */, @@ -1763,6 +1781,7 @@ F710FC80277B7D2700AA9FBF /* RealmSwift in Frameworks */, F74C863D2AEFBFD9009A1D4A /* LRUCache in Frameworks */, F72AD70F28C24BA1006CB92D /* NextcloudKit in Frameworks */, + F33EE6E72BF4C02600CA1A51 /* NIOSSL in Frameworks */, F737DA992B7B864E0063BAFC /* TOPasscodeViewController.xcframework in Frameworks */, F72CD01227A7E92400E59476 /* JGProgressHUD in Frameworks */, F77CB6A92AA08053000C3CA4 /* OpenSSL in Frameworks */, @@ -1782,6 +1801,7 @@ F787AC0B298BCB540001BB00 /* SVGKitSwift in Frameworks */, F783034428B5142B00B84583 /* NextcloudKit in Frameworks */, F7346E1328B0EF5B006CE2D2 /* SwiftUI.framework in Frameworks */, + F33EE6E32BF4C00700CA1A51 /* NIOSSL in Frameworks */, F7160A7D2BE931DE0034DCB3 /* RealmSwift in Frameworks */, F7160A842BE933430034DCB3 /* Realm in Frameworks */, F760DE052AE66EBE0027D78A /* KeychainAccess in Frameworks */, @@ -1802,6 +1822,7 @@ F73ADD2426554FE20069EA0D /* SwiftEntryKit in Frameworks */, F710FC84277B7D3500AA9FBF /* RealmSwift in Frameworks */, F75379202AE2AD9400C0250E /* JGProgressHUD in Frameworks */, + F33EE6E92BF4C02D00CA1A51 /* NIOSSL in Frameworks */, F72AD71328C24BCC006CB92D /* NextcloudKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1815,9 +1836,11 @@ F788ECC7263AAAFA00ADC67F /* MarkdownKit in Frameworks */, F77BC3EB293E5268005F2B08 /* Swifter in Frameworks */, F7BB7E4727A18C56009B9F29 /* Parchment in Frameworks */, + F33EE6E12BF4BDA500CA1A51 /* NIOSSL in Frameworks */, F734B06628E75C0100E180D5 /* TLPhotoPicker in Frameworks */, F787AC09298BCB4A0001BB00 /* SVGKitSwift in Frameworks */, F760DE032AE66EA80027D78A /* KeychainAccess in Frameworks */, + F33EE6F02BF4C0FF00CA1A51 /* NIO in Frameworks */, F3A0479E2BD268B500658E7B /* PopupView in Frameworks */, F770768E263A8C3400A1BA94 /* FloatingPanel in Frameworks */, F758A01227A7F03E0069468B /* JGProgressHUD in Frameworks */, @@ -1847,6 +1870,7 @@ files = ( F7A8D72828F17728008BBE1C /* RealmSwift in Frameworks */, F7A8D72428F1771B008BBE1C /* NextcloudKit in Frameworks */, + F33EE6E52BF4C02000CA1A51 /* NIOSSL in Frameworks */, F7C9739228F17131002C43E2 /* Intents.framework in Frameworks */, F760DE072AE66EC70027D78A /* KeychainAccess in Frameworks */, F7160A862BE9334B0034DCB3 /* Realm in Frameworks */, @@ -2629,6 +2653,7 @@ AF36077027BFA4E8001A243D /* ParallelWorker.swift */, F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */, F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */, + F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */, ); path = Utility; sourceTree = ""; @@ -3034,6 +3059,7 @@ F72AD71028C24BBB006CB92D /* NextcloudKit */, F760DE0E2AE66EE60027D78A /* KeychainAccess */, F7160A8D2BE933710034DCB3 /* Realm */, + F33EE6EC2BF4C03800CA1A51 /* NIOSSL */, ); productName = "Notification Service Extension"; productReference = 2C33C47F23E2C475005F963B /* Notification Service Extension.appex */; @@ -3156,6 +3182,7 @@ F7490E8A29882CE4009DCE94 /* NextcloudKit */, F760DE0C2AE66EDF0027D78A /* KeychainAccess */, F7160A8B2BE9336A0034DCB3 /* Realm */, + F33EE6EA2BF4C03200CA1A51 /* NIOSSL */, ); productName = "File Provider Extension UI"; productReference = F70716E32987F81500E72C1D /* File Provider Extension UI.appex */; @@ -3189,6 +3216,7 @@ F74C863C2AEFBFD9009A1D4A /* LRUCache */, F711A4EE2AF932B900095DD8 /* SVGKitSwift */, F7160A872BE933510034DCB3 /* Realm */, + F33EE6E62BF4C02600CA1A51 /* NIOSSL */, ); productName = "Share Ext"; productReference = F7CE8AFB1DC1F8D8009CAE48 /* Share.appex */; @@ -3217,6 +3245,7 @@ F760DE042AE66EBE0027D78A /* KeychainAccess */, F7160A7C2BE931DE0034DCB3 /* RealmSwift */, F7160A832BE933430034DCB3 /* Realm */, + F33EE6E22BF4C00700CA1A51 /* NIOSSL */, ); productName = DashboardWidgetExtension; productReference = F7346E1028B0EF5B006CE2D2 /* Widget.appex */; @@ -3244,6 +3273,7 @@ F753791F2AE2AD9400C0250E /* JGProgressHUD */, F760DE0A2AE66ED80027D78A /* KeychainAccess */, F7160A892BE933610034DCB3 /* Realm */, + F33EE6E82BF4C02D00CA1A51 /* NIOSSL */, ); productName = "File Provider Extension"; productReference = F771E3D020E2392D00AFB62D /* File Provider Extension.appex */; @@ -3298,6 +3328,8 @@ F3A0479D2BD268B500658E7B /* PopupView */, F7160A7F2BE933390034DCB3 /* Realm */, F7160A812BE933390034DCB3 /* RealmSwift */, + F33EE6E02BF4BDA500CA1A51 /* NIOSSL */, + F33EE6EF2BF4C0FF00CA1A51 /* NIO */, ); productName = "Crypto Cloud"; productReference = F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */; @@ -3322,6 +3354,7 @@ F7A8D72728F17728008BBE1C /* RealmSwift */, F760DE062AE66EC70027D78A /* KeychainAccess */, F7160A852BE9334B0034DCB3 /* Realm */, + F33EE6E42BF4C02000CA1A51 /* NIOSSL */, ); productName = WidgetDashboardIntentHandler; productReference = F7C9739028F17131002C43E2 /* WidgetDashboardIntentHandler.appex */; @@ -3470,6 +3503,8 @@ F76B649A2ADFFAD200014640 /* XCRemoteSwiftPackageReference "LRUCache" */, F760DE012AE66E860027D78A /* XCRemoteSwiftPackageReference "KeychainAccess" */, F3A0479C2BD268B500658E7B /* XCRemoteSwiftPackageReference "PopupView" */, + F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */, + F33EE6EE2BF4C0FF00CA1A51 /* XCRemoteSwiftPackageReference "swift-nio" */, ); productRefGroup = F7F67B9F1A24D27800EE80DA; projectDirPath = ""; @@ -3721,6 +3756,7 @@ 2C33C48223E2C475005F963B /* NotificationService.swift in Sources */, F7183BD92AEBDCD9000CD020 /* NCKeychain.swift in Sources */, F73EF7A52B021FAE0087E6E9 /* NCLivePhoto.swift in Sources */, + F33EE6F82BF4C9B200CA1A51 /* PKCS12.swift in Sources */, AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, F7BF9D872934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, F749B64F297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, @@ -3830,6 +3866,7 @@ F7490E8729882CA8009DCE94 /* ThreadSafeDictionary.swift in Sources */, F73EF7A42B021FAD0087E6E9 /* NCLivePhoto.swift in Sources */, F757CC8729E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, + F33EE6F72BF4C9B200CA1A51 /* PKCS12.swift in Sources */, F7B769AD2B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, F73EF7BC2B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, F73EF7B42B0224350087E6E9 /* NCManageDatabase+DirectEditing.swift in Sources */, @@ -3922,6 +3959,7 @@ F73EF7B22B0224350087E6E9 /* NCManageDatabase+DirectEditing.swift in Sources */, AF22B217277D196700DAB0CC /* NCShareExtension+DataSource.swift in Sources */, F73EF7E22B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, + F33EE6F52BF4C9B200CA1A51 /* PKCS12.swift in Sources */, F76D364728A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, F73EF7CA2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */, F749B654297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */, @@ -3969,6 +4007,7 @@ F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */, F793E59F28B764F6005E4B02 /* NCContentPresenter.swift in Sources */, F76DEE9828F808AF0041B1C9 /* LockscreenWidgetProvider.swift in Sources */, + F33EE6F32BF4C9B200CA1A51 /* PKCS12.swift in Sources */, F78A10C029322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */, F78302FA28B4C3EA00B84583 /* NCManageDatabase+Metadata.swift in Sources */, F7B769A92B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, @@ -4051,6 +4090,7 @@ F7327E2C2B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */, F7D68FCF28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */, F73EF7CB2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */, + F33EE6F62BF4C9B200CA1A51 /* PKCS12.swift in Sources */, F73EF7C32B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */, F7C9B9212B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, F359D86B2A7D03420023F405 /* NCUtility+Exif.swift in Sources */, @@ -4230,6 +4270,7 @@ F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */, AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */, F718C24E254D507B00C5C256 /* NCViewerMediaDetailView.swift in Sources */, + F33EE6F22BF4C9B200CA1A51 /* PKCS12.swift in Sources */, F7145610296433C80038D028 /* NCDocumentCamera.swift in Sources */, F7381EE1218218C9000B1560 /* NCOffline.swift in Sources */, F719D9E2288D396100762E33 /* NCColorPicker.swift in Sources */, @@ -4385,6 +4426,7 @@ F73EF7C92B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */, F73EF7B92B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, F71F6D092B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, + F33EE6F42BF4C9B200CA1A51 /* PKCS12.swift in Sources */, F757CC8429E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, F78E2D6729AF02DB0024D4F3 /* Database.swift in Sources */, F7A8D73628F17E1A008BBE1C /* NCManageDatabase+Activity.swift in Sources */, @@ -5476,6 +5518,22 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-nio-ssl"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.26.0; + }; + }; + F33EE6EE2BF4C0FF00CA1A51 /* XCRemoteSwiftPackageReference "swift-nio" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-nio.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.65.0; + }; + }; F3A0479C2BD268B500658E7B /* XCRemoteSwiftPackageReference "PopupView" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/exyte/PopupView.git"; @@ -5609,7 +5667,7 @@ repositoryURL = "https://github.com/krzyzanowskim/OpenSSL"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.0.0; + minimumVersion = 3.1.5004; }; }; F77BC3E9293E5268005F2B08 /* XCRemoteSwiftPackageReference "swifter" */ = { @@ -5724,6 +5782,46 @@ package = F70B86732642CE3B00ED5349 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseDatabase; }; + F33EE6E02BF4BDA500CA1A51 /* NIOSSL */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */; + productName = NIOSSL; + }; + F33EE6E22BF4C00700CA1A51 /* NIOSSL */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */; + productName = NIOSSL; + }; + F33EE6E42BF4C02000CA1A51 /* NIOSSL */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */; + productName = NIOSSL; + }; + F33EE6E62BF4C02600CA1A51 /* NIOSSL */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */; + productName = NIOSSL; + }; + F33EE6E82BF4C02D00CA1A51 /* NIOSSL */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */; + productName = NIOSSL; + }; + F33EE6EA2BF4C03200CA1A51 /* NIOSSL */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */; + productName = NIOSSL; + }; + F33EE6EC2BF4C03800CA1A51 /* NIOSSL */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6DF2BF4BDA500CA1A51 /* XCRemoteSwiftPackageReference "swift-nio-ssl" */; + productName = NIOSSL; + }; + F33EE6EF2BF4C0FF00CA1A51 /* NIO */ = { + isa = XCSwiftPackageProductDependency; + package = F33EE6EE2BF4C0FF00CA1A51 /* XCRemoteSwiftPackageReference "swift-nio" */; + productName = NIO; + }; F37208A32BAB63EE006B5430 /* QRCodeReader */ = { isa = XCSwiftPackageProductDependency; package = F7ED547A25EEA65400956C55 /* XCRemoteSwiftPackageReference "QRCodeReader" */; diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift index db5de14520..64cf55fcfe 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift @@ -20,7 +20,6 @@ // import UIKit -import OpenSSL import NextcloudKit import CFNetwork import Alamofire diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index ef669e096f..76cc8fdbd8 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -20,7 +20,6 @@ // import UIKit -import OpenSSL import NextcloudKit import CFNetwork import Alamofire diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index 8a87de87c1..7733e8da15 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -178,8 +178,7 @@ class NCNetworking: NSObject, NKCommonDelegate { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { DispatchQueue.main.async { if let p12Data = self.p12Data { -// completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) - + completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) } else { self.delegate?.didAskForClientCertificate() } diff --git a/iOSClient/Utility/PKCS12.swift b/iOSClient/Utility/PKCS12.swift new file mode 100644 index 0000000000..1e18591cca --- /dev/null +++ b/iOSClient/Utility/PKCS12.swift @@ -0,0 +1,80 @@ +// +// PKCS12.swift +// Nextcloud +// +// Created by Milen on 15.05.24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import Foundation + +typealias UserCertificate = (data: Data, password: String) + +class PKCS12 { + let label: String? + let keyID: NSData? + let trust: SecTrust? + let certChain: [SecTrust]? + let identity: SecIdentity? + + /// Creates a PKCS12 instance from a piece of data. + /// - Parameters: + /// - pkcs12Data: the actual data we want to parse. + /// - password: he password required to unlock the PKCS12 data. + public init(pkcs12Data: Data, password: String) { + let importPasswordOption: NSDictionary + = [kSecImportExportPassphrase as NSString: password] + var items: CFArray? + let secError: OSStatus + = SecPKCS12Import(pkcs12Data as NSData, + importPasswordOption, &items) + guard secError == errSecSuccess else { + if secError == errSecAuthFailed { + NSLog("Incorrect password?") + } + fatalError("Error trying to import PKCS12 data") + } + guard let theItemsCFArray = items else { fatalError() } + let theItemsNSArray: NSArray = theItemsCFArray as NSArray + guard let dictArray + = theItemsNSArray as? [[String: AnyObject]] + else { + fatalError() + } + + label = dictArray.element(for: kSecImportItemLabel) + keyID = dictArray.element(for: kSecImportItemKeyID) + trust = dictArray.element(for: kSecImportItemTrust) + certChain = dictArray.element(for: kSecImportItemCertChain) + identity = dictArray.element(for: kSecImportItemIdentity) + } + + static func urlCredential(for userCertificate: UserCertificate?) -> URLCredential? { + guard let userCertificate = userCertificate else { return nil } + + let p12Contents = PKCS12(pkcs12Data: userCertificate.data, password: userCertificate.password) + + guard let identity = p12Contents.identity else { + return nil + } + + // In most cases you should pass nil to the certArray parameter. You only need to supply an array of intermediate certificates if the server needs those intermediate certificates to authenticate the client. Typically this isn’t necessary because the server already has a copy of the relevant intermediate certificates. + // See https://developer.apple.com/documentation/foundation/urlcredential/1418121-init + return URLCredential(identity: identity, + certificates: nil, + persistence: .none) + + } +} + +extension Array where Element == [String: AnyObject] { + func element(for key: CFString) -> T? { + for dictElement in self { + if let value = dictElement[key as String] as? T { + return value + } + } + return nil + } +} + From 33feeaf85a560f23b0f46a52b4a4c0ebffae948e Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 15 May 2024 14:13:30 +0200 Subject: [PATCH 06/31] Remove NCLoginWeb for v2 Signed-off-by: Milen Pivchev --- iOSClient/Login/NCLogin.swift | 88 +++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 7a63b03a07..4c48bc5183 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -44,6 +44,10 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { private var shareAccounts: [NKShareAccounts.DataAccounts]? + var loginFlowV2Token = "" + var loginFlowV2Endpoint = "" + var loginFlowV2Login = "" + // MARK: - View Life Cycle override func viewDidLoad() { @@ -143,6 +147,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) } override func viewDidAppear(_ animated: Bool) { @@ -165,6 +170,10 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { appDelegate.timerErrorNetworkingDisabled = false } + @objc func applicationDidBecomeActive(_ notification: NSNotification) { + pollLogin() + } + // MARK: - TextField func textFieldShouldReturn(_ textField: UITextField) -> Bool { @@ -273,32 +282,14 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // Login Flow V2 if error == .success, let token, let endpoint, let login { + self.pollLogin() - if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb { - - loginWeb.urlBase = url - loginWeb.user = user - loginWeb.loginFlowV2Available = true - loginWeb.loginFlowV2Token = token - loginWeb.loginFlowV2Endpoint = endpoint - loginWeb.loginFlowV2Login = login - - self.navigationController?.pushViewController(loginWeb, animated: true) - } - - // Login Flow - } else if serverInfo.versionMajor >= NCGlobal.shared.nextcloudVersion12 { - - if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb { + self.loginFlowV2Token = token + self.loginFlowV2Endpoint = endpoint + self.loginFlowV2Login = login - loginWeb.urlBase = url - loginWeb.user = user - - self.navigationController?.pushViewController(loginWeb, animated: true) - } - - // NO Login flow available - } else if serverInfo.versionMajor < NCGlobal.shared.nextcloudVersion12 { + UIApplication.shared.open(URL(string: login)!) + } else if serverInfo.versionMajor < NCGlobal.shared.nextcloudVersion12 { // No login flow available let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_webflow_not_available_", comment: ""), preferredStyle: .alert) @@ -449,6 +440,55 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.present(alertController, animated: true, completion: { }) } } + + private func pollLogin() { + NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in + if error == .success, let server, let loginName, let appPassword { + self.createAccount(server: server, username: loginName, password: appPassword) + } + } + } + + func createAccount(server: String, username: String, password: String) { + + var urlBase = server + if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } + let account: String = "\(username) \(urlBase)" + let user = username + + NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase) + NextcloudKit.shared.getUserProfile { _, userProfile, _, error in + + if error == .success, let userProfile { + + NCManageDatabase.shared.deleteAccount(account) + NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) + + self.appDelegate.changeAccount(account, userProfile: userProfile) + + let window = UIApplication.shared.firstWindow + if window?.rootViewController is NCMainTabBarController { + self.dismiss(animated: true) + } else { + if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { + mainTabBarController.modalPresentationStyle = .fullScreen + mainTabBarController.view.alpha = 0 + window?.rootViewController = mainTabBarController + window?.makeKeyAndVisible() + UIView.animate(withDuration: 0.5) { + mainTabBarController.view.alpha = 1 + } + } + } + + } else { + + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + self.present(alertController, animated: true) + } + } + } } extension NCLogin: NCShareAccountsDelegate { From c1eb3b03c0fa60a035176da50d042ab81c6da977 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 15 May 2024 14:20:07 +0200 Subject: [PATCH 07/31] Cleanup Signed-off-by: Milen Pivchev --- iOSClient/Login/NCLoginWeb.swift | 62 ++++++++------------------------ 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/iOSClient/Login/NCLoginWeb.swift b/iOSClient/Login/NCLoginWeb.swift index 57d37b4b27..c4e2475441 100644 --- a/iOSClient/Login/NCLoginWeb.swift +++ b/iOSClient/Login/NCLoginWeb.swift @@ -42,14 +42,6 @@ class NCLoginWeb: UIViewController { var configPassword: String? var configAppPassword: String? - var loginFlowV2Available = false - var loginFlowV2Token = "" - var loginFlowV2Endpoint = "" - var loginFlowV2Login = "" - - // Opens the login URL in external browser instead of in app. User must manually go back to the app. - let loginFlowv2ExternalBrowser = true - // MARK: - View Life Cycle override func viewDidLoad() { @@ -123,13 +115,9 @@ class NCLoginWeb: UIViewController { // ADD end point for Web Flow if urlBase != NCBrandOptions.shared.linkloginPreferredProviders { - if loginFlowV2Available { - urlBase = loginFlowV2Login - } else { - urlBase += "/index.php/login/flow" - if let user = self.user { - urlBase += "?user=\(user)" - } + urlBase += "/index.php/login/flow" + if let user = self.user { + urlBase += "?user=\(user)" } } @@ -147,9 +135,8 @@ class NCLoginWeb: UIViewController { titleView = NSLocalizedString("_user_", comment: "") + " " + account.userId + " " + NSLocalizedString("_in_", comment: "") + " " + host } } - self.title = titleView - NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) + self.title = titleView } override func viewDidAppear(_ animated: Bool) { @@ -174,32 +161,20 @@ class NCLoginWeb: UIViewController { } func loadWebPage(webView: WKWebView, url: URL) { - if loginFlowV2Available, loginFlowv2ExternalBrowser { - UIApplication.shared.open(url) - } else { - let language = NSLocale.preferredLanguages[0] as String - var request = URLRequest(url: url) - - if let deviceName = "\(UIDevice.current.name) (\(NCBrandOptions.shared.brand) iOS)".cString(using: .utf8), - let deviceUserAgent = String(cString: deviceName, encoding: .ascii) { - webView.customUserAgent = deviceUserAgent - } else { - webView.customUserAgent = userAgent - } + let language = NSLocale.preferredLanguages[0] as String + var request = URLRequest(url: url) - request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") - request.addValue(language, forHTTPHeaderField: "Accept-Language") - - webView.load(request) + if let deviceName = "\(UIDevice.current.name) (\(NCBrandOptions.shared.brand) iOS)".cString(using: .utf8), + let deviceUserAgent = String(cString: deviceName, encoding: .ascii) { + webView.customUserAgent = deviceUserAgent + } else { + webView.customUserAgent = userAgent } - } - private func pollLogin() { - NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in - if error == .success, let server, let loginName, let appPassword { - self.createAccount(server: server, username: loginName, password: appPassword) - } - } + request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") + request.addValue(language, forHTTPHeaderField: "Accept-Language") + + webView.load(request) } func getAppPassword(serverUrl: String, username: String, password: String) { @@ -221,10 +196,6 @@ class NCLoginWeb: UIViewController { @objc func changeUser(sender: UIBarButtonItem) { toggleMenu() } - - @objc func applicationDidBecomeActive(_ notification: NSNotification) { - pollLogin() - } } extension NCLoginWeb: WKNavigationDelegate { @@ -288,10 +259,7 @@ extension NCLoginWeb: WKNavigationDelegate { } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - NCActivityIndicator.shared.stop() - - pollLogin() } // MARK: - From 90ce7e58fd79e66361ab03aa4b3aa4432308200d Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Fri, 17 May 2024 11:49:04 +0200 Subject: [PATCH 08/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/AppDelegate.swift | 38 ++++++++++----------- iOSClient/Login/NCLogin.swift | 62 ++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 2428c94ef5..36930e2332 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -363,42 +363,42 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // [WEBPersonalized] [AppConfig] if NCBrandOptions.shared.use_login_web_personalized || NCBrandOptions.shared.use_AppConfig { - if activeLoginWeb?.view.window == nil { - activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb - activeLoginWeb?.urlBase = NCBrandOptions.shared.loginBaseUrl - showLoginViewController(activeLoginWeb) + if activeLogin?.view.window == nil { + activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin +// activeLogin? = NCBrandOptions.shared.loginBaseUrl + showLoginViewController(activeLogin) } return } // Nextcloud standard login if selector == NCGlobal.shared.introSignup { - if activeLoginWeb?.view.window == nil { - activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb + if activeLogin?.view.window == nil { + activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin + if selector == NCGlobal.shared.introSignup { - activeLoginWeb?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders +// activeLogin?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders } else { - activeLoginWeb?.urlBase = self.urlBase +// activeLogin?.urlBase = self.urlBase } - showLoginViewController(activeLoginWeb) + showLoginViewController(activeLogin) } } else if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url { - if activeLoginWeb?.view.window == nil { - activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb - activeLoginWeb?.urlBase = NCBrandOptions.shared.loginBaseUrl - showLoginViewController(activeLoginWeb) + if activeLogin?.view.window == nil { + activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin +// activeLogin?.urlBase = NCBrandOptions.shared.loginBaseUrl + showLoginViewController(activeLogin) } } else if openLoginWeb { // Used also for reinsert the account (change passwd) - if activeLoginWeb?.view.window == nil { - activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb - activeLoginWeb?.urlBase = urlBase - activeLoginWeb?.user = user - showLoginViewController(activeLoginWeb) + if activeLogin?.view.window == nil { + activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin + activeLogin?.urlBase = urlBase +// activeLogin?.user = user + showLoginViewController(activeLogin) } - } else { if activeLogin?.view.window == nil { activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 4c48bc5183..86ff654b80 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -48,6 +48,14 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { var loginFlowV2Endpoint = "" var loginFlowV2Login = "" + var urlBase = "" +// var user = "" + + var configServerUrl: String? + var configUsername: String? + var configPassword: String? + var configAppPassword: String? + // MARK: - View Life Cycle override func viewDidLoad() { @@ -148,6 +156,10 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) + + handleLoginWithAppConfig() + + baseUrl.text = urlBase } override func viewDidAppear(_ animated: Bool) { @@ -174,6 +186,44 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { pollLogin() } + private func handleLoginWithAppConfig() { + let accountCount = NCManageDatabase.shared.getAccounts()?.count ?? 0 + + // load AppConfig + if (NCBrandOptions.shared.disable_multiaccount == false) || (NCBrandOptions.shared.disable_multiaccount == true && accountCount == 0) { + if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), NCBrandOptions.shared.use_AppConfig { + if let serverUrl = configurationManaged[NCGlobal.shared.configuration_serverUrl] as? String { + self.configServerUrl = serverUrl + } + + if let username = configurationManaged[NCGlobal.shared.configuration_username] as? String, !username.isEmpty, username.lowercased() != "username" { + self.configUsername = username + } + + if let password = configurationManaged[NCGlobal.shared.configuration_password] as? String, !password.isEmpty, password.lowercased() != "password" { + self.configPassword = password + } + + if let apppassword = configurationManaged[NCGlobal.shared.configuration_apppassword] as? String, !apppassword.isEmpty, apppassword.lowercased() != "apppassword" { + self.configAppPassword = apppassword + } + } + } + + // AppConfig + if let serverUrl = configServerUrl { + if let username = self.configUsername, let password = configAppPassword { + createAccount(server: serverUrl, username: username, password: password) + return + } else if let username = self.configUsername, let password = configPassword { + getAppPassword(serverUrl: serverUrl, username: username, password: password) + return + } else { + urlBase = serverUrl + } + } + } + // MARK: - TextField func textFieldShouldReturn(_ textField: UITextField) -> Bool { @@ -450,7 +500,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } func createAccount(server: String, username: String, password: String) { - var urlBase = server if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } let account: String = "\(username) \(urlBase)" @@ -489,6 +538,17 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } } + + func getAppPassword(serverUrl: String, username: String, password: String) { + NextcloudKit.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password) { token, _, error in + if error == .success, let password = token { + self.createAccount(server: serverUrl, username: username, password: password) + } else { + NCContentPresenter().showError(error: error) + self.dismiss(animated: true, completion: nil) + } + } + } } extension NCLogin: NCShareAccountsDelegate { From 1edaba3ed8845885911980ca5891280662e22413 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 21 May 2024 12:11:08 +0200 Subject: [PATCH 09/31] WIP Signed-off-by: Milen Pivchev --- Brand/Intro/NCIntroViewController.swift | 17 ++++++ Brand/NCBrand.swift | 2 +- iOSClient/AppDelegate.swift | 77 ++++++++++++++++++++++--- iOSClient/Login/NCLogin.swift | 73 +++++++++++++++-------- 4 files changed, 135 insertions(+), 34 deletions(-) diff --git a/Brand/Intro/NCIntroViewController.swift b/Brand/Intro/NCIntroViewController.swift index 14d2d06043..afa80076f7 100644 --- a/Brand/Intro/NCIntroViewController.swift +++ b/Brand/Intro/NCIntroViewController.swift @@ -98,6 +98,23 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol view.backgroundColor = NCBrandColor.shared.customer timerAutoScroll = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(NCIntroViewController.autoScroll)), userInfo: nil, repeats: true) + + NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in + let window = UIApplication.shared.firstWindow + if window?.rootViewController is NCMainTabBarController { + self.dismiss(animated: true) + } else { + if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { + mainTabBarController.modalPresentationStyle = .fullScreen + mainTabBarController.view.alpha = 0 + window?.rootViewController = mainTabBarController + window?.makeKeyAndVisible() + UIView.animate(withDuration: 0.5) { + mainTabBarController.view.alpha = 1 + } + } + } + } } override var preferredStatusBarStyle: UIStatusBarStyle { diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index c506211b09..6d56eef558 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -59,7 +59,7 @@ let userAgent: String = { @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps" // BRAND ONLY - @objc public var use_login_web_personalized: Bool = false // Don't touch me !! + @objc public var use_login_web_personalized: Bool = true // Don't touch me !! @objc public var use_AppConfig: Bool = false // Don't touch me !! @objc public var use_GroupApps: Bool = true // Don't touch me !! diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 36930e2332..f8ffcb9cea 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -51,6 +51,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD return ProcessInfo.processInfo.arguments.contains("UI_TESTING") } + var loginFlowV2Token = "" + var loginFlowV2Endpoint = "" + var loginFlowV2Login = "" + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { if isUiTestingEnabled { deleteAllAccounts() @@ -144,10 +148,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD self.handleProcessingTask(task) } + NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive2(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) + return true } - // L'applicazione terminerà func applicationWillTerminate(_ application: UIApplication) { if UIApplication.shared.backgroundRefreshStatus == .available { @@ -273,6 +278,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } + @objc private func applicationDidBecomeActive2(_ notification: NSNotification) { + pollLogin() + } + // MARK: - Background Networking Session func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { @@ -364,11 +373,28 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // [WEBPersonalized] [AppConfig] if NCBrandOptions.shared.use_login_web_personalized || NCBrandOptions.shared.use_AppConfig { if activeLogin?.view.window == nil { - activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin -// activeLogin? = NCBrandOptions.shared.loginBaseUrl - showLoginViewController(activeLogin) + urlBase = NCBrandOptions.shared.loginBaseUrl + pollLogin() + + NextcloudKit.shared.getLoginFlowV2(serverUrl: urlBase) { token, endpoint, login, _, error in + + // Login Flow V2 + if error == .success, let token, let endpoint, let login { + self.pollLogin() + + self.loginFlowV2Token = token + self.loginFlowV2Endpoint = endpoint + self.loginFlowV2Login = login + + UIApplication.shared.open(URL(string: login)!) + } + } + // activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin + // activeLogin? = NCBrandOptions.shared.loginBaseUrl + // showLoginViewController(activeLogin) + + return } - return } // Nextcloud standard login @@ -377,9 +403,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin if selector == NCGlobal.shared.introSignup { -// activeLogin?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders + activeLogin?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders } else { -// activeLogin?.urlBase = self.urlBase + activeLogin?.urlBase = self.urlBase } showLoginViewController(activeLogin) } @@ -390,12 +416,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // activeLogin?.urlBase = NCBrandOptions.shared.loginBaseUrl showLoginViewController(activeLogin) } - } else if openLoginWeb { // Used also for reinsert the account (change passwd) if activeLogin?.view.window == nil { activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin activeLogin?.urlBase = urlBase + activeLogin?.disableUrlField = true // activeLogin?.user = user showLoginViewController(activeLogin) } @@ -406,6 +432,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } } +// + @objc func pollLogin() { + NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in + if error == .success, let server, let loginName, let appPassword { + self.createAccount(server: server, username: loginName, password: appPassword, completion: { error in }) + } + } + } // MARK: - Error Networking @@ -458,6 +492,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // MARK: - Account + func createAccount(server: String, username: String, password: String, completion: @escaping (_ error: NKError) -> Void) { + var urlBase = server + if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } + let account: String = "\(username) \(urlBase)" + let user = username + + NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase) + NextcloudKit.shared.getUserProfile { _, userProfile, _, error in + + if error == .success, let userProfile { + + NCManageDatabase.shared.deleteAccount(account) + NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) + + self.changeAccount(account, userProfile: userProfile) + } else { + + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + UIApplication.shared.firstWindow?.rootViewController?.present(alertController, animated: true) + } + + completion(error) + } + } + @objc func changeAccount(_ account: String, userProfile: NKUserProfile?) { NCNetworking.shared.cancelAllQueue() @@ -568,7 +628,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // MARK: - Reset Application @objc func resetApplication() { - let utilityFileSystem = NCUtilityFileSystem() NCNetworking.shared.cancelAllTask() diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 86ff654b80..595877f0ba 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -48,9 +48,11 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { var loginFlowV2Endpoint = "" var loginFlowV2Login = "" + /// The URL that will show up on the URL field when this screen appears var urlBase = "" -// var user = "" - + var disableUrlField = false + + // Used for MDM var configServerUrl: String? var configUsername: String? var configPassword: String? @@ -88,6 +90,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { baseUrl.rightViewMode = .always baseUrl.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("_login_url_", comment: ""), attributes: [NSAttributedString.Key.foregroundColor: textColor.withAlphaComponent(0.5)]) baseUrl.delegate = self + baseUrl.isEnabled = !disableUrlField // Login button loginAddressDetail.textColor = textColor @@ -499,23 +502,11 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } - func createAccount(server: String, username: String, password: String) { - var urlBase = server - if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } - let account: String = "\(username) \(urlBase)" - let user = username - - NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase) - NextcloudKit.shared.getUserProfile { _, userProfile, _, error in - - if error == .success, let userProfile { - - NCManageDatabase.shared.deleteAccount(account) - NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) - - self.appDelegate.changeAccount(account, userProfile: userProfile) - + private func createAccount(server: String, username: String, password: String) { + appDelegate.createAccount(server: server, username: username, password: password) { error in + if error == .success { let window = UIApplication.shared.firstWindow + if window?.rootViewController is NCMainTabBarController { self.dismiss(animated: true) } else { @@ -529,16 +520,50 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } } - - } else { - - let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) - self.present(alertController, animated: true) } } } +// func createAccount(server: String, username: String, password: String) { +// var urlBase = server +// if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } +// let account: String = "\(username) \(urlBase)" +// let user = username +// +// NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase) +// NextcloudKit.shared.getUserProfile { _, userProfile, _, error in +// +// if error == .success, let userProfile { +// +// NCManageDatabase.shared.deleteAccount(account) +// NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) +// +// self.appDelegate.changeAccount(account, userProfile: userProfile) +// +// let window = UIApplication.shared.firstWindow +// if window?.rootViewController is NCMainTabBarController { +// self.dismiss(animated: true) +// } else { +// if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { +// mainTabBarController.modalPresentationStyle = .fullScreen +// mainTabBarController.view.alpha = 0 +// window?.rootViewController = mainTabBarController +// window?.makeKeyAndVisible() +// UIView.animate(withDuration: 0.5) { +// mainTabBarController.view.alpha = 1 +// } +// } +// } +// +// } else { +// +// let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) +// alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) +// self.present(alertController, animated: true) +// } +// } +// } + func getAppPassword(serverUrl: String, username: String, password: String) { NextcloudKit.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password) { token, _, error in if error == .success, let password = token { From e68f305d3405dd2adc6f42c1c40a0cb2ebdee058 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 21 May 2024 15:09:18 +0200 Subject: [PATCH 10/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/AppDelegate.swift | 2 +- iOSClient/Login/NCLogin.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index a8259280d2..b935dfa168 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -152,7 +152,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD self.handleProcessingTask(task) } - NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive2(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive2(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) return true } diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 595877f0ba..e625f94953 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -158,7 +158,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) handleLoginWithAppConfig() From 4d3b6b280143548ef1b0e04a946b4c63c23f6277 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 22 May 2024 11:21:59 +0200 Subject: [PATCH 11/31] WIP Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 2 +- Nextcloud.xcodeproj/project.pbxproj | 4 ++ iOSClient/AppDelegate.swift | 5 ++- iOSClient/Login/NCLoginPoll.swift | 63 +++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 iOSClient/Login/NCLoginPoll.swift diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 59449a3d90..9edbdad1e1 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -59,7 +59,7 @@ let userAgent: String = { @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps" // BRAND ONLY - @objc public var use_login_web_personalized: Bool = true // Don't touch me !! + @objc public var use_login_web_personalized: Bool = false // Don't touch me !! @objc public var use_AppConfig: Bool = false // Don't touch me !! @objc public var use_GroupApps: Bool = true // Don't touch me !! diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index f230dd2fa6..a00a866d11 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ F3BB464F2A39EBE500461F6E /* NCMoreUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */; }; F3BB46522A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */; }; F3BB46542A3A1E9D00461F6E /* CCCellMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */; }; + F3EF2E0C2BFCF3810025EF46 /* NCLoginPoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EF2E0B2BFCF3810025EF46 /* NCLoginPoll.swift */; }; F3F0419B2B9F7E6700D5155F /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F3F0419A2B9F7E6700D5155F /* RealmSwift */; }; F3F0419D2B9F7E6E00D5155F /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F3F0419C2B9F7E6E00D5155F /* RealmSwift */; }; F3F0419F2B9F7E7900D5155F /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F3F0419E2B9F7E7900D5155F /* RealmSwift */; }; @@ -1129,6 +1130,7 @@ F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreUserCell.swift; sourceTree = ""; }; F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreAppSuggestionsCell.swift; sourceTree = ""; }; F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCCellMore.swift; sourceTree = ""; }; + F3EF2E0B2BFCF3810025EF46 /* NCLoginPoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginPoll.swift; sourceTree = ""; }; F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = ""; }; F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = ""; }; F700510222DF6897003A3356 /* Parchment.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Parchment.framework; path = Carthage/Build/iOS/Parchment.framework; sourceTree = ""; }; @@ -2600,6 +2602,7 @@ F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */, F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */, F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */, + F3EF2E0B2BFCF3810025EF46 /* NCLoginPoll.swift */, ); path = Login; sourceTree = ""; @@ -4130,6 +4133,7 @@ AF1A9B6427D0CA1E00F17A9E /* UIAlertController+Extension.swift in Sources */, F73B422C2476764F00A30FD3 /* NCNotification.swift in Sources */, 371B5A2E23D0B04500FAFAE9 /* NCMenu.swift in Sources */, + F3EF2E0C2BFCF3810025EF46 /* NCLoginPoll.swift in Sources */, F757CC8229E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, F7B769A82B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, F79EDAA326B004980007D134 /* NCPlayerToolBar.swift in Sources */, diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index b935dfa168..fcf7f4d960 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -406,10 +406,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if selector == NCGlobal.shared.introSignup { activeLogin?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders + let web = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb + web?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders + showLoginViewController(web) } else { activeLogin?.urlBase = self.urlBase + showLoginViewController(activeLogin) } - showLoginViewController(activeLogin) } } else if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url { diff --git a/iOSClient/Login/NCLoginPoll.swift b/iOSClient/Login/NCLoginPoll.swift new file mode 100644 index 0000000000..7a06837bfd --- /dev/null +++ b/iOSClient/Login/NCLoginPoll.swift @@ -0,0 +1,63 @@ +// +// SwiftUIView.swift +// Nextcloud +// +// Created by Milen on 21.05.24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import NextcloudKit +import SwiftUI + +struct NCLoginPoll: View { + var body: some View { + Text("Please continue in your browser") + + Button("Cancel") { + + } + .buttonStyle(.borderedProminent) + } +} + +#Preview { + NCLoginPoll() +} + +class Polling: ObservableObject { + private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + + var loginFlowV2Token = "" + var loginFlowV2Endpoint = "" + var loginFlowV2Login = "" + + func poll() { + NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in + if error == .success, let server, let loginName, let appPassword { + self.createAccount(server: server, username: loginName, password: appPassword) + } + } + } + + private func createAccount(server: String, username: String, password: String) { + appDelegate.createAccount(server: server, username: username, password: password) { error in + if error == .success { + let window = UIApplication.shared.firstWindow + + if window?.rootViewController is NCMainTabBarController { + self.dismiss(animated: true) + } else { + if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { + mainTabBarController.modalPresentationStyle = .fullScreen + mainTabBarController.view.alpha = 0 + window?.rootViewController = mainTabBarController + window?.makeKeyAndVisible() + UIView.animate(withDuration: 0.5) { + mainTabBarController.view.alpha = 1 + } + } + } + } + } + } +} From fbb8fb32369620ceab966306425017b25f161f49 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 22 May 2024 13:07:56 +0200 Subject: [PATCH 12/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Extensions/View+Extension.swift | 21 ++++ iOSClient/Login/NCLogin.swift | 123 +++++++++++----------- iOSClient/Login/NCLoginPoll.swift | 78 ++++++++++---- 3 files changed, 141 insertions(+), 81 deletions(-) diff --git a/iOSClient/Extensions/View+Extension.swift b/iOSClient/Extensions/View+Extension.swift index c8732fa8dc..77aab3bea7 100644 --- a/iOSClient/Extensions/View+Extension.swift +++ b/iOSClient/Extensions/View+Extension.swift @@ -50,4 +50,25 @@ extension View { self } } + + func onFirstAppear(perform action: @escaping () -> Void) -> some View { + modifier(ViewFirstAppearModifier(perform: action)) + } +} + +struct ViewFirstAppearModifier: ViewModifier { + @State private var didAppearBefore = false + private let action: () -> Void + + init(perform action: @escaping () -> Void) { + self.action = action + } + + func body(content: Content) -> some View { + content.onAppear { + guard !didAppearBefore else { return } + didAppearBefore = true + action() + } + } } diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index e625f94953..95e81c582e 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -24,6 +24,7 @@ import UIKit import NextcloudKit import SwiftEntryKit +import SwiftUI class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { @@ -158,7 +159,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) +// NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) handleLoginWithAppConfig() @@ -185,9 +186,9 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { appDelegate.timerErrorNetworkingDisabled = false } - @objc func applicationDidBecomeActive(_ notification: NSNotification) { - pollLogin() - } +// @objc func applicationDidBecomeActive(_ notification: NSNotification) { +// pollLogin() +// } private func handleLoginWithAppConfig() { let accountCount = NCManageDatabase.shared.getAccounts()?.count ?? 0 @@ -335,13 +336,15 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // Login Flow V2 if error == .success, let token, let endpoint, let login { - self.pollLogin() +// self.pollLogin() +// +// self.loginFlowV2Token = token +// self.loginFlowV2Endpoint = endpoint +// self.loginFlowV2Login = login - self.loginFlowV2Token = token - self.loginFlowV2Endpoint = endpoint - self.loginFlowV2Login = login + let vc = UIHostingController(rootView: NCLoginPoll(loginFlowV2Token: token, loginFlowV2Endpoint: endpoint, loginFlowV2Login: login)) - UIApplication.shared.open(URL(string: login)!) + self.present(vc, animated: true) } else if serverInfo.versionMajor < NCGlobal.shared.nextcloudVersion12 { // No login flow available let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_webflow_not_available_", comment: ""), preferredStyle: .alert) @@ -494,53 +497,19 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } - private func pollLogin() { - NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in - if error == .success, let server, let loginName, let appPassword { - self.createAccount(server: server, username: loginName, password: appPassword) - } - } - } - - private func createAccount(server: String, username: String, password: String) { - appDelegate.createAccount(server: server, username: username, password: password) { error in - if error == .success { - let window = UIApplication.shared.firstWindow - - if window?.rootViewController is NCMainTabBarController { - self.dismiss(animated: true) - } else { - if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { - mainTabBarController.modalPresentationStyle = .fullScreen - mainTabBarController.view.alpha = 0 - window?.rootViewController = mainTabBarController - window?.makeKeyAndVisible() - UIView.animate(withDuration: 0.5) { - mainTabBarController.view.alpha = 1 - } - } - } - } - } - } - -// func createAccount(server: String, username: String, password: String) { -// var urlBase = server -// if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } -// let account: String = "\(username) \(urlBase)" -// let user = username -// -// NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase) -// NextcloudKit.shared.getUserProfile { _, userProfile, _, error in -// -// if error == .success, let userProfile { -// -// NCManageDatabase.shared.deleteAccount(account) -// NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) -// -// self.appDelegate.changeAccount(account, userProfile: userProfile) +// private func pollLogin() { +// NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in +// if error == .success, let server, let loginName, let appPassword { +// self.createAccount(server: server, username: loginName, password: appPassword) +// } +// } +// } // +// private func createAccount(server: String, username: String, password: String) { +// appDelegate.createAccount(server: server, username: username, password: password) { error in +// if error == .success { // let window = UIApplication.shared.firstWindow +// // if window?.rootViewController is NCMainTabBarController { // self.dismiss(animated: true) // } else { @@ -554,16 +523,50 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // } // } // } -// -// } else { -// -// let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) -// alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) -// self.present(alertController, animated: true) // } // } // } + func createAccount(server: String, username: String, password: String) { + var urlBase = server + if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } + let account: String = "\(username) \(urlBase)" + let user = username + + NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase) + NextcloudKit.shared.getUserProfile { _, userProfile, _, error in + + if error == .success, let userProfile { + + NCManageDatabase.shared.deleteAccount(account) + NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) + + self.appDelegate.changeAccount(account, userProfile: userProfile) + + let window = UIApplication.shared.firstWindow + if window?.rootViewController is NCMainTabBarController { + self.dismiss(animated: true) + } else { + if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { + mainTabBarController.modalPresentationStyle = .fullScreen + mainTabBarController.view.alpha = 0 + window?.rootViewController = mainTabBarController + window?.makeKeyAndVisible() + UIView.animate(withDuration: 0.5) { + mainTabBarController.view.alpha = 1 + } + } + } + + } else { + + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + self.present(alertController, animated: true) + } + } + } + func getAppPassword(serverUrl: String, username: String, password: String) { NextcloudKit.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password) { token, _, error in if error == .success, let password = token { diff --git a/iOSClient/Login/NCLoginPoll.swift b/iOSClient/Login/NCLoginPoll.swift index 7a06837bfd..16ef43354a 100644 --- a/iOSClient/Login/NCLoginPoll.swift +++ b/iOSClient/Login/NCLoginPoll.swift @@ -10,28 +10,74 @@ import NextcloudKit import SwiftUI struct NCLoginPoll: View { + let loginFlowV2Token: String + let loginFlowV2Endpoint: String + let loginFlowV2Login: String + + @ObservedObject private var loginManager = LoginManager() + @Environment(\.dismiss) private var dismiss + var body: some View { - Text("Please continue in your browser") + VStack { + Text("Please continue in your browser") - Button("Cancel") { + Button("Cancel") { + } + .buttonStyle(.borderedProminent) + } + .onChange(of: loginManager.pollFinished) { value in + if value { + let window = UIApplication.shared.firstWindow + + if window?.rootViewController is NCMainTabBarController { + window?.rootViewController?.dismiss(animated: true, completion: nil) + } else { + if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { + mainTabBarController.modalPresentationStyle = .fullScreen + mainTabBarController.view.alpha = 0 + window?.rootViewController = mainTabBarController + window?.makeKeyAndVisible() + UIView.animate(withDuration: 0.5) { + mainTabBarController.view.alpha = 1 + } + } + } + } + } + .onAppear { + loginManager.poll(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) + loginManager.openLoginInBrowser() } - .buttonStyle(.borderedProminent) } } #Preview { - NCLoginPoll() + NCLoginPoll(loginFlowV2Token: "", loginFlowV2Endpoint: "", loginFlowV2Login: "") } -class Polling: ObservableObject { +private class LoginManager: ObservableObject { private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! var loginFlowV2Token = "" var loginFlowV2Endpoint = "" var loginFlowV2Login = "" - func poll() { + init() { + NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) + } + + @Published var pollFinished = false + + @objc func applicationDidBecomeActive(_ notification: NSNotification) { + poll(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) + } + + func poll(loginFlowV2Token: String, loginFlowV2Endpoint: String, loginFlowV2Login: String) { + self.loginFlowV2Token = loginFlowV2Token + self.loginFlowV2Endpoint = loginFlowV2Endpoint + self.loginFlowV2Login = loginFlowV2Login + NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in if error == .success, let server, let loginName, let appPassword { self.createAccount(server: server, username: loginName, password: appPassword) @@ -39,24 +85,14 @@ class Polling: ObservableObject { } } + func openLoginInBrowser() { + UIApplication.shared.open(URL(string: loginFlowV2Login)!) + } + private func createAccount(server: String, username: String, password: String) { appDelegate.createAccount(server: server, username: username, password: password) { error in if error == .success { - let window = UIApplication.shared.firstWindow - - if window?.rootViewController is NCMainTabBarController { - self.dismiss(animated: true) - } else { - if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { - mainTabBarController.modalPresentationStyle = .fullScreen - mainTabBarController.view.alpha = 0 - window?.rootViewController = mainTabBarController - window?.makeKeyAndVisible() - UIView.animate(withDuration: 0.5) { - mainTabBarController.view.alpha = 1 - } - } - } + self.pollFinished = true } } } From e57151ae34581e2fc1b229cadaa8f8f02d6d9c63 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 22 May 2024 18:33:55 +0200 Subject: [PATCH 13/31] WIP Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 2 +- iOSClient/AppDelegate.swift | 11 ++++------- iOSClient/Login/NCLoginPoll.swift | 30 +++++++++++++++++++++++------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 9edbdad1e1..59449a3d90 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -59,7 +59,7 @@ let userAgent: String = { @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps" // BRAND ONLY - @objc public var use_login_web_personalized: Bool = false // Don't touch me !! + @objc public var use_login_web_personalized: Bool = true // Don't touch me !! @objc public var use_AppConfig: Bool = false // Don't touch me !! @objc public var use_GroupApps: Bool = true // Don't touch me !! diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index a639292ef9..d202be95a6 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -29,6 +29,7 @@ import Firebase import WidgetKit import Queuer import EasyTipView +import SwiftUI @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, NCUserBaseUrl { @@ -387,13 +388,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // Login Flow V2 if error == .success, let token, let endpoint, let login { - self.pollLogin() + let vc = UIHostingController(rootView: NCLoginPoll(loginFlowV2Token: token, loginFlowV2Endpoint: endpoint, loginFlowV2Login: login, cancelButtonDisabled: NCManageDatabase.shared.getAccounts().isEmptyOrNil)) - self.loginFlowV2Token = token - self.loginFlowV2Endpoint = endpoint - self.loginFlowV2Login = login - - UIApplication.shared.open(URL(string: login)!) + UIApplication.shared.firstWindow?.rootViewController?.present(vc, animated: true) } } // activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin @@ -423,7 +420,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } else if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url { if activeLogin?.view.window == nil { activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin -// activeLogin?.urlBase = NCBrandOptions.shared.loginBaseUrl + activeLogin?.urlBase = NCBrandOptions.shared.loginBaseUrl showLoginViewController(activeLogin) } } else if openLoginWeb { diff --git a/iOSClient/Login/NCLoginPoll.swift b/iOSClient/Login/NCLoginPoll.swift index 16ef43354a..a32ab6658d 100644 --- a/iOSClient/Login/NCLoginPoll.swift +++ b/iOSClient/Login/NCLoginPoll.swift @@ -14,6 +14,8 @@ struct NCLoginPoll: View { let loginFlowV2Endpoint: String let loginFlowV2Login: String + var cancelButtonDisabled = false + @ObservedObject private var loginManager = LoginManager() @Environment(\.dismiss) private var dismiss @@ -21,10 +23,19 @@ struct NCLoginPoll: View { VStack { Text("Please continue in your browser") - Button("Cancel") { + HStack { + Button("Cancel") { + dismiss() + } + .disabled(loginManager.isLoading || cancelButtonDisabled) + .buttonStyle(.bordered) + Button("Retry") { + loginManager.openLoginInBrowser() + } + .buttonStyle(.borderedProminent) } - .buttonStyle(.borderedProminent) + .padding() } .onChange(of: loginManager.pollFinished) { value in if value { @@ -46,9 +57,10 @@ struct NCLoginPoll: View { } } .onAppear { - loginManager.poll(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) + loginManager.configure(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) loginManager.openLoginInBrowser() } + .interactiveDismissDisabled() } } @@ -63,23 +75,27 @@ private class LoginManager: ObservableObject { var loginFlowV2Endpoint = "" var loginFlowV2Login = "" + @Published var pollFinished = false + @Published var isLoading = false + init() { NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) } - @Published var pollFinished = false - @objc func applicationDidBecomeActive(_ notification: NSNotification) { - poll(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) + poll() } - func poll(loginFlowV2Token: String, loginFlowV2Endpoint: String, loginFlowV2Login: String) { + func configure(loginFlowV2Token: String, loginFlowV2Endpoint: String, loginFlowV2Login: String) { self.loginFlowV2Token = loginFlowV2Token self.loginFlowV2Endpoint = loginFlowV2Endpoint self.loginFlowV2Login = loginFlowV2Login + } + func poll() { NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in if error == .success, let server, let loginName, let appPassword { + self.isLoading = true self.createAccount(server: server, username: loginName, password: appPassword) } } From 077e5d2fc6eb6010573b4993f91336e6f5b56c20 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 22 May 2024 18:47:00 +0200 Subject: [PATCH 14/31] WIP Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 2 +- iOSClient/AppDelegate.swift | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 59449a3d90..2204b54c65 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -69,7 +69,7 @@ let userAgent: String = { @objc public var use_themingLogo: Bool = false @objc public var use_storeLocalAutoUploadAll: Bool = false - @objc public var disable_intro: Bool = false + @objc public var disable_intro: Bool = true @objc public var disable_request_login_url: Bool = false @objc public var disable_multiaccount: Bool = false @objc public var disable_manage_account: Bool = false diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index d202be95a6..1a1bfbadbe 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -393,9 +393,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD UIApplication.shared.firstWindow?.rootViewController?.present(vc, animated: true) } } - // activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin - // activeLogin? = NCBrandOptions.shared.loginBaseUrl - // showLoginViewController(activeLogin) return } From 99f1e2d05a1165945e063dc89f3eb0c046dbb33c Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Thu, 23 May 2024 17:35:43 +0200 Subject: [PATCH 15/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Networking/NCNetworking.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index f24c193dde..d55e2e4801 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -198,6 +198,7 @@ class NCNetworking: NSObject, NKCommonDelegate { completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { DispatchQueue.main.async { + // Use openssl pkcs12 -export -legacy -out identity.p12 -inkey key.pem -in cert.pem if let p12Data = self.p12Data { completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) } else { @@ -211,10 +212,11 @@ class NCNetworking: NSObject, NKCommonDelegate { // let p12Data = try? Data(contentsOf: URL(fileURLWithPath: Bundle.module.path(forResource: "identity", ofType: "p12")!)) // let certificate = PKCS12(pkcs12Data: p12Data!, password: "") -// completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) - } - DispatchQueue.global().async { - self.checkTrustedChallenge(session, didReceive: challenge, completionHandler: completionHandler) + // completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) + } else { + DispatchQueue.global().async { + self.checkTrustedChallenge(session, didReceive: challenge, completionHandler: completionHandler) + } } } From e6e97340783d8e07595fbbfc62a114883116a709 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 28 May 2024 15:31:02 +0200 Subject: [PATCH 16/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Login/NCLoginPoll.swift | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/iOSClient/Login/NCLoginPoll.swift b/iOSClient/Login/NCLoginPoll.swift index a32ab6658d..26b6eb2f88 100644 --- a/iOSClient/Login/NCLoginPoll.swift +++ b/iOSClient/Login/NCLoginPoll.swift @@ -22,6 +22,7 @@ struct NCLoginPoll: View { var body: some View { VStack { Text("Please continue in your browser") + .foregroundStyle(.white) HStack { Button("Cancel") { @@ -29,14 +30,18 @@ struct NCLoginPoll: View { } .disabled(loginManager.isLoading || cancelButtonDisabled) .buttonStyle(.bordered) + .tint(.white) Button("Retry") { loginManager.openLoginInBrowser() } .buttonStyle(.borderedProminent) + .foregroundStyle(Color(NCBrandColor.shared.customer)) + .tint(.white) } .padding() } + .frame(maxWidth: .infinity, maxHeight: .infinity) .onChange(of: loginManager.pollFinished) { value in if value { let window = UIApplication.shared.firstWindow @@ -56,10 +61,11 @@ struct NCLoginPoll: View { } } } - .onAppear { - loginManager.configure(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) - loginManager.openLoginInBrowser() - } + .background(Color(NCBrandColor.shared.customer)) +// .onAppear { +// loginManager.configure(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) +// loginManager.openLoginInBrowser() +// } .interactiveDismissDisabled() } } From 8de1a2ded126a5cdc219b8fee7c2693f83726cfc Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Thu, 30 May 2024 13:30:22 +0200 Subject: [PATCH 17/31] WIP Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 2 +- iOSClient/Login/NCLoginPoll.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 2204b54c65..cf18148b0f 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -59,7 +59,7 @@ let userAgent: String = { @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps" // BRAND ONLY - @objc public var use_login_web_personalized: Bool = true // Don't touch me !! + @objc public var use_login_web_personalized: Bool = false // Don't touch me !! @objc public var use_AppConfig: Bool = false // Don't touch me !! @objc public var use_GroupApps: Bool = true // Don't touch me !! diff --git a/iOSClient/Login/NCLoginPoll.swift b/iOSClient/Login/NCLoginPoll.swift index 26b6eb2f88..fe5715d90c 100644 --- a/iOSClient/Login/NCLoginPoll.swift +++ b/iOSClient/Login/NCLoginPoll.swift @@ -62,10 +62,10 @@ struct NCLoginPoll: View { } } .background(Color(NCBrandColor.shared.customer)) -// .onAppear { -// loginManager.configure(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) -// loginManager.openLoginInBrowser() -// } + .onAppear { + loginManager.configure(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) + loginManager.openLoginInBrowser() + } .interactiveDismissDisabled() } } From 7d9ab9f967c2c8f3f482f9fc7c91fa9aea9f07e4 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Thu, 30 May 2024 20:01:43 +0200 Subject: [PATCH 18/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/AppDelegate.swift | 5 ++++- iOSClient/Login/NCLogin.swift | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 66945fd801..7abe58f6c7 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -413,17 +413,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD activeLogin?.urlBase = NCBrandOptions.shared.loginBaseUrl showLoginViewController(activeLogin) } - } else if openLoginWeb { + } else if openLoginWeb { // remove this, create a bool for no accounts // Used also for reinsert the account (change passwd) if activeLogin?.view.window == nil { activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin activeLogin?.urlBase = urlBase activeLogin?.disableUrlField = true + activeLogin?.disableCloseButton = true // activeLogin?.user = user showLoginViewController(activeLogin) } } else { if activeLogin?.view.window == nil { + activeLogin?.disableCloseButton = true + activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin showLoginViewController(activeLogin) } diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 95e81c582e..833ae71f85 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -52,6 +52,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { /// The URL that will show up on the URL field when this screen appears var urlBase = "" var disableUrlField = false + var disableCloseButton = false // Used for MDM var configServerUrl: String? @@ -125,7 +126,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.navigationController?.view.backgroundColor = NCBrandColor.shared.customer self.navigationController?.navigationBar.tintColor = textColor - if !NCManageDatabase.shared.getAllAccount().isEmpty { + if !NCManageDatabase.shared.getAllAccount().isEmpty && !disableCloseButton { let navigationItemCancel = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(self.actionCancel)) navigationItemCancel.tintColor = textColor navigationItem.leftBarButtonItem = navigationItemCancel From 6d776a56f27e36ea9fdc433d0eac2ea5228ba140 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 10 Jun 2024 14:48:19 +0200 Subject: [PATCH 19/31] Change design Signed-off-by: Milen Pivchev --- iOSClient/Extensions/View+Extension.swift | 4 ++++ iOSClient/Login/NCLoginPoll.swift | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/iOSClient/Extensions/View+Extension.swift b/iOSClient/Extensions/View+Extension.swift index 77aab3bea7..25ed0dfed1 100644 --- a/iOSClient/Extensions/View+Extension.swift +++ b/iOSClient/Extensions/View+Extension.swift @@ -72,3 +72,7 @@ struct ViewFirstAppearModifier: ViewModifier { } } } + +var isRunningForPreviews: Bool { + return ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" +} diff --git a/iOSClient/Login/NCLoginPoll.swift b/iOSClient/Login/NCLoginPoll.swift index fe5715d90c..aadcd6431b 100644 --- a/iOSClient/Login/NCLoginPoll.swift +++ b/iOSClient/Login/NCLoginPoll.swift @@ -21,8 +21,15 @@ struct NCLoginPoll: View { var body: some View { VStack { - Text("Please continue in your browser") + Text("Please complete the log in process your browser") + .multilineTextAlignment(.center) .foregroundStyle(.white) + .padding() + + ProgressView() + .scaleEffect(1.5) + .tint(.white) + .padding() HStack { Button("Cancel") { @@ -64,7 +71,10 @@ struct NCLoginPoll: View { .background(Color(NCBrandColor.shared.customer)) .onAppear { loginManager.configure(loginFlowV2Token: loginFlowV2Token, loginFlowV2Endpoint: loginFlowV2Endpoint, loginFlowV2Login: loginFlowV2Login) - loginManager.openLoginInBrowser() + + if !isRunningForPreviews { + loginManager.openLoginInBrowser() + } } .interactiveDismissDisabled() } From 86ccf8a6da8a54695c2faac48c9d3b67c35371be Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 10 Jun 2024 15:41:09 +0200 Subject: [PATCH 20/31] Rename Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 2 +- Nextcloud.xcodeproj/project.pbxproj | 8 ++++---- iOSClient/AppDelegate.swift | 4 ++-- iOSClient/Login/NCLogin.storyboard | 8 ++++---- .../Login/{NCLoginWeb.swift => NCLoginProvider.swift} | 4 ++-- iOSClient/Menu/NCLoginWeb+Menu.swift | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) rename iOSClient/Login/{NCLoginWeb.swift => NCLoginProvider.swift} (99%) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index cf18148b0f..9edbdad1e1 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -69,7 +69,7 @@ let userAgent: String = { @objc public var use_themingLogo: Bool = false @objc public var use_storeLocalAutoUploadAll: Bool = false - @objc public var disable_intro: Bool = true + @objc public var disable_intro: Bool = false @objc public var disable_request_login_url: Bool = false @objc public var disable_multiaccount: Bool = false @objc public var disable_manage_account: Bool = false diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 35bd687911..73138d95da 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -744,7 +744,7 @@ F7A8D74428F1827B008BBE1C /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; }; F7AC1CB028AB94490032D99F /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AC1CAF28AB94490032D99F /* Array+Extension.swift */; }; F7AC934A296193050002BC0F /* Reasons to use Nextcloud.pdf in Resources */ = {isa = PBXBuildFile; fileRef = F7AC9349296193050002BC0F /* Reasons to use Nextcloud.pdf */; }; - F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */; }; + F7AE00F5230D5F9E007ACF8A /* NCLoginProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F4230D5F9E007ACF8A /* NCLoginProvider.swift */; }; F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */; }; F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */; }; F7B398422A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */; }; @@ -1537,7 +1537,7 @@ F7AA41E127C7CF8100494705 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/InfoPlist.strings"; sourceTree = ""; }; F7AC1CAF28AB94490032D99F /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = ""; }; F7AC9349296193050002BC0F /* Reasons to use Nextcloud.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "Reasons to use Nextcloud.pdf"; sourceTree = SOURCE_ROOT; }; - F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginWeb.swift; sourceTree = ""; }; + F7AE00F4230D5F9E007ACF8A /* NCLoginProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginProvider.swift; sourceTree = ""; }; F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCBrowserWeb.swift; sourceTree = ""; }; F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCBrowserWeb.storyboard; sourceTree = ""; }; F7AF7632246BEDFE00B86E3C /* TOPasscodeViewController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TOPasscodeViewController.framework; path = Carthage/Build/iOS/TOPasscodeViewController.framework; sourceTree = ""; }; @@ -2668,7 +2668,7 @@ F702F2F625EE5CEC008F8E80 /* NCLogin.swift */, F738D48F2756740100CD1D38 /* NCLoginNavigationController.swift */, F745B252222D88AE00346520 /* NCLoginQRCode.swift */, - F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */, + F7AE00F4230D5F9E007ACF8A /* NCLoginProvider.swift */, F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */, F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */, F3EF2E0B2BFCF3810025EF46 /* NCLoginPoll.swift */, @@ -4364,7 +4364,7 @@ F7FAFD3A28BFA948000777FE /* NCNotification+Menu.swift in Sources */, F74C0436253F1CDC009762AB /* NCShares.swift in Sources */, F7AC1CB028AB94490032D99F /* Array+Extension.swift in Sources */, - F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */, + F7AE00F5230D5F9E007ACF8A /* NCLoginProvider.swift in Sources */, F707C26521A2DC5200F6181E /* NCStoreReview.swift in Sources */, F7BAADCB1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */, F768822A2C0DD1E7001CF441 /* NCSettingsModel.swift in Sources */, diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 7abe58f6c7..5a5692ba3f 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -43,7 +43,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD var tipView: EasyTipView? var backgroundSessionCompletionHandler: (() -> Void)? var activeLogin: NCLogin? - var activeLoginWeb: NCLoginWeb? + var activeLoginWeb: NCLoginProvider? var timerErrorNetworking: Timer? var timerErrorNetworkingDisabled: Bool = false var taskAutoUploadDate: Date = Date() @@ -398,7 +398,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if selector == NCGlobal.shared.introSignup { activeLogin?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders - let web = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb + let web = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginProvider web?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders showLoginViewController(web) } else { diff --git a/iOSClient/Login/NCLogin.storyboard b/iOSClient/Login/NCLogin.storyboard index 2ee73cae9a..f30d0583f4 100644 --- a/iOSClient/Login/NCLogin.storyboard +++ b/iOSClient/Login/NCLogin.storyboard @@ -1,9 +1,9 @@ - + - + @@ -118,10 +118,10 @@ - + - + diff --git a/iOSClient/Login/NCLoginWeb.swift b/iOSClient/Login/NCLoginProvider.swift similarity index 99% rename from iOSClient/Login/NCLoginWeb.swift rename to iOSClient/Login/NCLoginProvider.swift index 82f7d0f528..14785426a5 100644 --- a/iOSClient/Login/NCLoginWeb.swift +++ b/iOSClient/Login/NCLoginProvider.swift @@ -26,7 +26,7 @@ import WebKit import NextcloudKit import FloatingPanel -class NCLoginWeb: UIViewController { +class NCLoginProvider: UIViewController { var webView: WKWebView? let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! @@ -198,7 +198,7 @@ class NCLoginWeb: UIViewController { } } -extension NCLoginWeb: WKNavigationDelegate { +extension NCLoginProvider: WKNavigationDelegate { func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { diff --git a/iOSClient/Menu/NCLoginWeb+Menu.swift b/iOSClient/Menu/NCLoginWeb+Menu.swift index b5fa0fcbe9..eb9f6d4e90 100644 --- a/iOSClient/Menu/NCLoginWeb+Menu.swift +++ b/iOSClient/Menu/NCLoginWeb+Menu.swift @@ -24,7 +24,7 @@ import UIKit import FloatingPanel -extension NCLoginWeb { +extension NCLoginProvider { func toggleMenu() { From d5601330fd51739cfc1939fbb41ecf68f3a6d7e9 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 10 Jun 2024 17:09:39 +0200 Subject: [PATCH 21/31] Remove unneeded code Signed-off-by: Milen Pivchev --- Nextcloud.xcodeproj/project.pbxproj | 4 - iOSClient/AppDelegate.swift | 7 +- iOSClient/Login/NCLogin.storyboard | 2 +- iOSClient/Login/NCLogin.swift | 42 ----------- iOSClient/Login/NCLoginProvider.swift | 102 +------------------------- iOSClient/Menu/NCLoginWeb+Menu.swift | 89 ---------------------- 6 files changed, 8 insertions(+), 238 deletions(-) delete mode 100644 iOSClient/Menu/NCLoginWeb+Menu.swift diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 73138d95da..b7a14033e7 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -480,7 +480,6 @@ F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */ = {isa = PBXBuildFile; fileRef = F757CC8129E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift */; }; F757CC8C29E82D0500F31428 /* NCGroupfolders.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F757CC8A29E82D0500F31428 /* NCGroupfolders.storyboard */; }; F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */ = {isa = PBXBuildFile; fileRef = F757CC8B29E82D0500F31428 /* NCGroupfolders.swift */; }; - F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */; }; F758A01227A7F03E0069468B /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F758A01127A7F03E0069468B /* JGProgressHUD */; }; F758B45A212C564000515F55 /* NCScan.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F758B457212C564000515F55 /* NCScan.storyboard */; }; F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F758B45D212C569C00515F55 /* NCScanCell.swift */; }; @@ -1324,7 +1323,6 @@ F757CC8129E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Groupfolders.swift"; sourceTree = ""; }; F757CC8A29E82D0500F31428 /* NCGroupfolders.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCGroupfolders.storyboard; sourceTree = ""; }; F757CC8B29E82D0500F31428 /* NCGroupfolders.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCGroupfolders.swift; sourceTree = ""; }; - F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCLoginWeb+Menu.swift"; sourceTree = ""; }; F758B457212C564000515F55 /* NCScan.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCScan.storyboard; sourceTree = ""; }; F758B45D212C569C00515F55 /* NCScanCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCScanCell.swift; sourceTree = ""; }; F758B45F212C56A400515F55 /* NCScan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCScan.swift; sourceTree = ""; }; @@ -1886,7 +1884,6 @@ 3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */, 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */, F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */, - F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */, F75D19E225EFE09000D74598 /* NCTrash+Menu.swift */, AF93471127E2341B002537EE /* NCShare+Menu.swift */, F710D2012405826100A6033D /* NCViewer+Menu.swift */, @@ -4401,7 +4398,6 @@ F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */, F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */, F78B87E72B62527100C65ADC /* NCMediaDataSource.swift in Sources */, - F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */, F76882272C0DD1E7001CF441 /* NCManageE2EEView.swift in Sources */, F7864ACC2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */, F7327E302B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */, diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 5a5692ba3f..b6529db523 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -398,7 +398,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if selector == NCGlobal.shared.introSignup { activeLogin?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders - let web = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginProvider + let web = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginProvider") as? NCLoginProvider web?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders showLoginViewController(web) } else { @@ -413,14 +413,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD activeLogin?.urlBase = NCBrandOptions.shared.loginBaseUrl showLoginViewController(activeLogin) } - } else if openLoginWeb { // remove this, create a bool for no accounts + } else if openLoginWeb { // Used also for reinsert the account (change passwd) if activeLogin?.view.window == nil { activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin activeLogin?.urlBase = urlBase activeLogin?.disableUrlField = true activeLogin?.disableCloseButton = true -// activeLogin?.user = user showLoginViewController(activeLogin) } } else { @@ -432,7 +431,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } } -// + @objc func pollLogin() { NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in if error == .success, let server, let loginName, let appPassword { diff --git a/iOSClient/Login/NCLogin.storyboard b/iOSClient/Login/NCLogin.storyboard index f30d0583f4..9841743f53 100644 --- a/iOSClient/Login/NCLogin.storyboard +++ b/iOSClient/Login/NCLogin.storyboard @@ -121,7 +121,7 @@ - + diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index ffc9579016..ec8a1965ec 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -160,7 +160,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) -// NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) handleLoginWithAppConfig() @@ -187,10 +186,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { appDelegate.timerErrorNetworkingDisabled = false } -// @objc func applicationDidBecomeActive(_ notification: NSNotification) { -// pollLogin() -// } - private func handleLoginWithAppConfig() { let accountCount = NCManageDatabase.shared.getAccounts()?.count ?? 0 @@ -337,12 +332,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // Login Flow V2 if error == .success, let token, let endpoint, let login { -// self.pollLogin() -// -// self.loginFlowV2Token = token -// self.loginFlowV2Endpoint = endpoint -// self.loginFlowV2Login = login - let vc = UIHostingController(rootView: NCLoginPoll(loginFlowV2Token: token, loginFlowV2Endpoint: endpoint, loginFlowV2Login: login)) self.present(vc, animated: true) @@ -498,36 +487,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } -// private func pollLogin() { -// NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in -// if error == .success, let server, let loginName, let appPassword { -// self.createAccount(server: server, username: loginName, password: appPassword) -// } -// } -// } -// -// private func createAccount(server: String, username: String, password: String) { -// appDelegate.createAccount(server: server, username: username, password: password) { error in -// if error == .success { -// let window = UIApplication.shared.firstWindow -// -// if window?.rootViewController is NCMainTabBarController { -// self.dismiss(animated: true) -// } else { -// if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { -// mainTabBarController.modalPresentationStyle = .fullScreen -// mainTabBarController.view.alpha = 0 -// window?.rootViewController = mainTabBarController -// window?.makeKeyAndVisible() -// UIView.animate(withDuration: 0.5) { -// mainTabBarController.view.alpha = 1 -// } -// } -// } -// } -// } -// } - func createAccount(server: String, username: String, password: String) { var urlBase = server if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } @@ -581,7 +540,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } extension NCLogin: NCShareAccountsDelegate { - func selected(url: String, user: String) { isUrlValid(url: url, user: user) } diff --git a/iOSClient/Login/NCLoginProvider.swift b/iOSClient/Login/NCLoginProvider.swift index 14785426a5..14930a6d35 100644 --- a/iOSClient/Login/NCLoginProvider.swift +++ b/iOSClient/Login/NCLoginProvider.swift @@ -1,5 +1,5 @@ // -// NCLoginWeb.swift +// NCLoginProvider.swift // Nextcloud // // Created by Marino Faggiana on 21/08/2019. @@ -35,62 +35,14 @@ class NCLoginProvider: UIViewController { var titleView: String = "" var urlBase = "" - var user: String? - - var configServerUrl: String? - var configUsername: String? - var configPassword: String? - var configAppPassword: String? // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(self.closeView(sender:))) - let accountCount = NCManageDatabase.shared.getAccounts()?.count ?? 0 - - // load AppConfig - if (NCBrandOptions.shared.disable_multiaccount == false) || (NCBrandOptions.shared.disable_multiaccount == true && accountCount == 0) { - if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), NCBrandOptions.shared.use_AppConfig { - - if let serverUrl = configurationManaged[NCGlobal.shared.configuration_serverUrl] as? String { - self.configServerUrl = serverUrl - } - if let username = configurationManaged[NCGlobal.shared.configuration_username] as? String, !username.isEmpty, username.lowercased() != "username" { - self.configUsername = username - } - if let password = configurationManaged[NCGlobal.shared.configuration_password] as? String, !password.isEmpty, password.lowercased() != "password" { - self.configPassword = password - } - if let apppassword = configurationManaged[NCGlobal.shared.configuration_apppassword] as? String, !apppassword.isEmpty, apppassword.lowercased() != "apppassword" { - self.configAppPassword = apppassword - } - } - } - - if (NCBrandOptions.shared.use_login_web_personalized || NCBrandOptions.shared.use_AppConfig) && accountCount > 0 { - navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(self.closeView(sender:))) - } - - if accountCount > 0 { - navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "users")!.image(color: NCBrandColor.shared.iconImageColor, size: 35), style: .plain, target: self, action: #selector(self.changeUser(sender:))) - } - - let config = WKWebViewConfiguration() - config.websiteDataStore = WKWebsiteDataStore.nonPersistent() - - let source: String = "var meta = document.createElement('meta');" + - "meta.name = 'viewport';" + - "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" + - "var head = document.getElementsByTagName('head')[0];" + - "head.appendChild(meta);" - - let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true) - let userContentController: WKUserContentController = WKUserContentController() - config.userContentController = userContentController - userContentController.addUserScript(script) - - webView = WKWebView(frame: CGRect.zero, configuration: config) + webView = WKWebView(frame: CGRect.zero, configuration: WKWebViewConfiguration()) webView!.navigationDelegate = self view.addSubview(webView!) @@ -100,27 +52,6 @@ class NCLoginProvider: UIViewController { webView!.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true webView!.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true - // AppConfig - if let serverUrl = configServerUrl { - if let username = self.configUsername, let password = configAppPassword { - createAccount(server: serverUrl, username: username, password: password) - return - } else if let username = self.configUsername, let password = configPassword { - getAppPassword(serverUrl: serverUrl, username: username, password: password) - return - } else { - urlBase = serverUrl - } - } - - // ADD end point for Web Flow - if urlBase != NCBrandOptions.shared.linkloginPreferredProviders { - urlBase += "/index.php/login/flow" - if let user = self.user { - urlBase += "?user=\(user)" - } - } - if let url = URL(string: urlBase) { loadWebPage(webView: webView!, url: url) } else { @@ -128,7 +59,6 @@ class NCLoginProvider: UIViewController { NCContentPresenter().showError(error: error, priority: .max) } - // TITLE if let host = URL(string: urlBase)?.host { titleView = host if let account = NCManageDatabase.shared.getActiveAccount(), NCKeychain().getPassword(account: account.account).isEmpty { @@ -144,14 +74,6 @@ class NCLoginProvider: UIViewController { // Stop timer error network appDelegate.timerErrorNetworkingDisabled = true - - if let account = NCManageDatabase.shared.getActiveAccount(), NCKeychain().getPassword(account: account.account).isEmpty { - - let message = "\n" + NSLocalizedString("_password_not_present_", comment: "") - let alertController = UIAlertController(title: titleView, message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) - present(alertController, animated: true) - } } override func viewDidDisappear(_ animated: Bool) { @@ -177,25 +99,9 @@ class NCLoginProvider: UIViewController { webView.load(request) } - func getAppPassword(serverUrl: String, username: String, password: String) { - - NextcloudKit.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password) { token, _, error in - if error == .success, let password = token { - self.createAccount(server: serverUrl, username: username, password: password) - } else { - NCContentPresenter().showError(error: error) - self.dismiss(animated: true, completion: nil) - } - } - } - @objc func closeView(sender: UIBarButtonItem) { self.dismiss(animated: true, completion: nil) } - - @objc func changeUser(sender: UIBarButtonItem) { - toggleMenu() - } } extension NCLoginProvider: WKNavigationDelegate { @@ -297,7 +203,7 @@ extension NCLoginProvider: WKNavigationDelegate { } } else { - + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) self.present(alertController, animated: true) diff --git a/iOSClient/Menu/NCLoginWeb+Menu.swift b/iOSClient/Menu/NCLoginWeb+Menu.swift deleted file mode 100644 index eb9f6d4e90..0000000000 --- a/iOSClient/Menu/NCLoginWeb+Menu.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// NCLoginWeb+Menu.swift -// Nextcloud -// -// Created by Marino Faggiana on 03/03/2021. -// Copyright © 2021 Marino Faggiana. 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 UIKit -import FloatingPanel - -extension NCLoginProvider { - - func toggleMenu() { - - var actions = [NCMenuAction]() - - let accounts = NCManageDatabase.shared.getAllAccount() - var avatar = utility.loadImage(named: "person.crop.circle", colors: [NCBrandColor.shared.iconImageColor]) - - for account in accounts { - - let title = account.user + " " + (URL(string: account.urlBase)?.host ?? "") - - avatar = utility.loadUserImage( - for: account.user, - displayName: account.displayName, - userBaseUrl: account) - - actions.append( - NCMenuAction( - title: title, - icon: avatar, - onTitle: title, - onIcon: avatar, - selected: account.active == true, - on: account.active == true, - action: { _ in - if self.appDelegate.account != account.account { - self.dismiss(animated: true) { - self.appDelegate.changeAccount(account.account, userProfile: nil) - } - } - } - ) - ) - } - - actions.append( - NCMenuAction( - title: NSLocalizedString("_delete_active_account_", comment: ""), - destructive: true, - icon: utility.loadImage(named: "trash", colors: [.red]), - onTitle: NSLocalizedString("_delete_active_account_", comment: ""), - onIcon: avatar, - selected: false, - on: false, - action: { _ in - self.appDelegate.deleteAccount(self.appDelegate.account, wipe: false) - self.dismiss(animated: true) { - let accounts = NCManageDatabase.shared.getAllAccount() - if accounts.isEmpty { - self.appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) - } else { - self.appDelegate.changeAccount(accounts.first!.account, userProfile: nil) - } - } - } - ) - ) - - presentMenu(with: actions) - } -} From b86242c3f43fbbf1cc76b550ea543c9033a170e1 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 10 Jun 2024 17:24:41 +0200 Subject: [PATCH 22/31] Refactor Signed-off-by: Milen Pivchev --- iOSClient/Login/NCLoginProvider.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/iOSClient/Login/NCLoginProvider.swift b/iOSClient/Login/NCLoginProvider.swift index 14930a6d35..081f783500 100644 --- a/iOSClient/Login/NCLoginProvider.swift +++ b/iOSClient/Login/NCLoginProvider.swift @@ -203,7 +203,6 @@ extension NCLoginProvider: WKNavigationDelegate { } } else { - let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) self.present(alertController, animated: true) From e87f4a1b8196ef57bb0dc4f49063652cd84d7fcc Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 11 Jun 2024 14:59:53 +0200 Subject: [PATCH 23/31] Fix acknowldgements Signed-off-by: Milen Pivchev --- iOSClient/Settings/Acknowledgements.rtf | 39 ++++++------------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/iOSClient/Settings/Acknowledgements.rtf b/iOSClient/Settings/Acknowledgements.rtf index 0256340b18..f10f6d5889 100644 --- a/iOSClient/Settings/Acknowledgements.rtf +++ b/iOSClient/Settings/Acknowledgements.rtf @@ -2,7 +2,7 @@ \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} -\margl1440\margr1440\vieww31960\viewh28240\viewkind0 +\margl1440\margr1440\vieww25280\viewh28800\viewkind0 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 \f0\fs24 \cf0 \ @@ -258,35 +258,6 @@ MIT License\ Copyright (c) LIU Dongyuan\ __________________________________\ \ - -\f1\b swift-snapshot-testing\ -\ - -\f0\b0 MIT License\ -\ -Copyright (c) Point-Free, Inc.\ -__________________________________\ -\ -\pard\pardeftab720\partightenfactor0 - -\f1\b \cf0 swiftui-preview-snapshots \ -\ - -\f0\b0 Apache License 2.0\ -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 -\cf0 __________________________________\ -\ -\pard\pardeftab720\partightenfactor0 - -\f1\b \cf0 SnapshotTestingHEIC\ -\ - -\f0\b0 MIT License\ -\ -Copyright (c) Aleksei Kakoulin\ -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 -\cf0 __________________________________\ -\ \pard\pardeftab720\partightenfactor0 \f1\b \cf0 GzipSwift\ @@ -308,4 +279,12 @@ MIT License\ \ Copyright (c) Nick Lockwood\ __________________________________\ +\ +PopupView\ +\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 +\cf0 MIT License\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 +\cf0 \ +Copyright (c) 2019 exyte \ } \ No newline at end of file From b01a8bb38de26f8a2c10b6a577369835ca7c2550 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 12 Jun 2024 12:10:59 +0200 Subject: [PATCH 24/31] Remove unneeded brand flags Signed-off-by: Milen Pivchev --- Brand/NCBrand.swift | 14 -------------- iOSClient/AppDelegate.swift | 2 +- iOSClient/Data/NCManageDatabase+Account.swift | 16 ++++++++-------- iOSClient/Login/NCLogin.swift | 2 +- iOSClient/Login/NCLoginPoll.swift | 6 +++--- .../en.lproj/Localizable.strings | 5 ++++- 6 files changed, 17 insertions(+), 28 deletions(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 9edbdad1e1..537731126f 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -47,10 +47,6 @@ let userAgent: String = { @objc public var sourceCode: String = "https://github.com/nextcloud/ios" @objc public var mobileconfig: String = "/remote.php/dav/provisioning/apple-provisioning.mobileconfig" - // Personalized - @objc public var webCloseViewProtocolPersonalized: String = "" // example "abc://change/plan" Don't touch me !! - @objc public var folderBrandAutoUpload: String = "" // example "_auto_upload_folder_" Don't touch me !! - // Auto Upload default folder @objc public var folderDefaultAutoUpload: String = "Photos" @@ -59,15 +55,10 @@ let userAgent: String = { @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps" // BRAND ONLY - @objc public var use_login_web_personalized: Bool = false // Don't touch me !! @objc public var use_AppConfig: Bool = false // Don't touch me !! - @objc public var use_GroupApps: Bool = true // Don't touch me !! // Options - @objc public var use_default_auto_upload: Bool = false @objc public var use_themingColor: Bool = true - @objc public var use_themingLogo: Bool = false - @objc public var use_storeLocalAutoUploadAll: Bool = false @objc public var disable_intro: Bool = false @objc public var disable_request_login_url: Bool = false @@ -98,11 +89,6 @@ let userAgent: String = { } override init() { - - if folderBrandAutoUpload != "" { - folderDefaultAutoUpload = folderBrandAutoUpload - } - // wrapper AppConfig if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), use_AppConfig { diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index b6529db523..0b39c15250 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -372,7 +372,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } // [WEBPersonalized] [AppConfig] - if NCBrandOptions.shared.use_login_web_personalized || NCBrandOptions.shared.use_AppConfig { + if NCBrandOptions.shared.use_AppConfig { if activeLogin?.view.window == nil { urlBase = NCBrandOptions.shared.loginBaseUrl pollLogin() diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index f365de359a..77abd08eca 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -97,14 +97,14 @@ extension NCManageDatabase { addObject.account = account - // Brand - if NCBrandOptions.shared.use_default_auto_upload { - - addObject.autoUpload = true - addObject.autoUploadImage = true - addObject.autoUploadVideo = true - addObject.autoUploadWWAnVideo = true - } +// // Brand +// if NCBrandOptions.shared.use_default_auto_upload { +// +// addObject.autoUpload = true +// addObject.autoUploadImage = true +// addObject.autoUploadVideo = true +// addObject.autoUploadWWAnVideo = true +// } NCKeychain().setPassword(account: account, password: password) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index ec8a1965ec..b0143a77be 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -132,7 +132,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { navigationItem.leftBarButtonItem = navigationItemCancel } - if NCBrandOptions.shared.use_GroupApps, let dirGroupApps = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroupApps) { + if let dirGroupApps = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroupApps) { // Nextcloud update share accounts if let error = appDelegate.updateShareAccounts() { NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Create share accounts \(error.localizedDescription)") diff --git a/iOSClient/Login/NCLoginPoll.swift b/iOSClient/Login/NCLoginPoll.swift index aadcd6431b..6c37ffec9e 100644 --- a/iOSClient/Login/NCLoginPoll.swift +++ b/iOSClient/Login/NCLoginPoll.swift @@ -21,7 +21,7 @@ struct NCLoginPoll: View { var body: some View { VStack { - Text("Please complete the log in process your browser") + Text(NSLocalizedString("_poll_desc_", comment: "")) .multilineTextAlignment(.center) .foregroundStyle(.white) .padding() @@ -32,14 +32,14 @@ struct NCLoginPoll: View { .padding() HStack { - Button("Cancel") { + Button(NSLocalizedString("_cancel_", comment: "")) { dismiss() } .disabled(loginManager.isLoading || cancelButtonDisabled) .buttonStyle(.bordered) .tint(.white) - Button("Retry") { + Button(NSLocalizedString("_retry_", comment: "")) { loginManager.openLoginInBrowser() } .buttonStyle(.borderedProminent) diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index ee09a0971e..9a206eb53a 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -158,7 +158,8 @@ "_disabled_" = "Disabled"; "_standard_" = "Standard"; "_maximum_" = "Maximum"; -"_error_occurred_" = "An error occurred, please try again"; +"_error_occurred_" = "An error occurred, please try again"; +"_retry_" = "Retry"; /* MARK: Files lock */ @@ -1075,3 +1076,5 @@ "_no_types_" = "No provider found"; "_no_types_subtitle_" = "AI Providers need to be installed to use the Assistant"; +// MARK: Login poll +"_poll_desc_" = "Please complete the log in process your browser"; From 91b5322abde739279fa485650358f4a64334d9fe Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Thu, 13 Jun 2024 16:32:36 +0200 Subject: [PATCH 25/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Networking/NCNetworking.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index d55e2e4801..d295800c0c 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -200,9 +200,10 @@ class NCNetworking: NSObject, NKCommonDelegate { DispatchQueue.main.async { // Use openssl pkcs12 -export -legacy -out identity.p12 -inkey key.pem -in cert.pem if let p12Data = self.p12Data { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) + completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "12345") as? UserCertificate)) } else { self.delegate?.didAskForClientCertificate() + completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) } } From 527cb47dd5abc105c55502d9dc2ea204b6fd3a01 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 17 Jun 2024 16:34:45 +0200 Subject: [PATCH 26/31] WIP Signed-off-by: Milen Pivchev --- Nextcloud.xcodeproj/project.pbxproj | 5 +- .../File Provider Extension.xcscheme | 2 +- .../xcshareddata/xcschemes/Nextcloud.xcscheme | 2 +- .../Notification Service Extension.xcscheme | 2 +- .../xcshareddata/xcschemes/Share.xcscheme | 2 +- .../xcshareddata/xcschemes/Widget.xcscheme | 2 +- iOSClient/AppDelegate.swift | 2 + iOSClient/Login/NCLogin.swift | 51 +++++++++++++++---- iOSClient/Networking/NCNetworking.swift | 38 +++++++++----- iOSClient/Settings/NCKeychain.swift | 20 ++++++++ .../en.lproj/Localizable.strings | 8 ++- iOSClient/Utility/PKCS12.swift | 39 +++++++------- 12 files changed, 122 insertions(+), 51 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 14dd519b6c..afa1131001 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -3439,8 +3439,9 @@ F7F67BA01A24D27800EE80DA /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1430; - LastUpgradeCheck = 1400; + LastUpgradeCheck = 1540; ORGANIZATIONNAME = "Marino Faggiana"; TargetAttributes = { 2C33C47E23E2C475005F963B = { @@ -5390,6 +5391,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_TESTING_SEARCH_PATHS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -5454,6 +5456,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_TESTING_SEARCH_PATHS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", diff --git a/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme b/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme index a9d6cd4d35..82a2e51c2b 100755 --- a/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme +++ b/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme @@ -1,6 +1,6 @@ . // +import UniformTypeIdentifiers import UIKit import NextcloudKit import SwiftEntryKit @@ -60,6 +61,9 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { var configPassword: String? var configAppPassword: String? + private var p12Data: Data? + private var p12Password: String? + // MARK: - View Life Cycle override func viewDidLoad() { @@ -452,6 +456,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } + NCKeychain().setClientCertificate(account: account, p12Data: NCNetworking.shared.tempP12Data, p12Password: NCNetworking.shared.tempP12Password) } else { let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) @@ -520,6 +525,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } + NCKeychain().setClientCertificate(account: account, p12Data: NCNetworking.shared.tempP12Data, p12Password: NCNetworking.shared.tempP12Password) } else { let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) @@ -549,26 +555,51 @@ extension NCLogin: NCShareAccountsDelegate { extension NCLogin: ClientCertificateDelegate, UIDocumentPickerDelegate { func didAskForClientCertificate() { - let alert = UIAlertController(title: NSLocalizedString("_no_client_cert_found_", comment: ""), message: NSLocalizedString("_no_client_cert_found_desc_", comment: ""), preferredStyle: .alert) + let alertNoCertFound = UIAlertController(title: NSLocalizedString("_no_client_cert_found_", comment: ""), message: NSLocalizedString("_no_client_cert_found_desc_", comment: ""), preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) + alertNoCertFound.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) - alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in + alertNoCertFound.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in let documentProviderMenu = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.pkcs12]) - -// documentProviderMenu.modalPresentationStyle = .formSheet -// documentProviderMenu.popoverPresentationController?.sourceView = mainTabBarController.tabBar -// documentProviderMenu.popoverPresentationController?.sourceRect = mainTabBarController.tabBar.bounds documentProviderMenu.delegate = self self.present(documentProviderMenu, animated: true, completion: nil) })) - present(alert, animated: true) + present(alertNoCertFound, animated: true) } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - NCNetworking.shared.p12Data = try? Data(contentsOf: urls[0]) - actionButtonLogin(self) + NCNetworking.shared.tempP12Data = try? Data(contentsOf: urls[0]) + + let alertEnterPassword = UIAlertController(title: NSLocalizedString("_client_cert_enter_password_", comment: ""), message: "", preferredStyle: .alert) + + alertEnterPassword.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) + + alertEnterPassword.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in + let documentProviderMenu = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.pkcs12]) + NCNetworking.shared.tempP12Password = alertEnterPassword.textFields?[0].text + +// NCKeychain().setClientCertificate(account: acco, p12Data: p12Data, p12Password: p12Password) + + self.actionButtonLogin(self) + })) + + alertEnterPassword.addTextField { textField in + textField.isSecureTextEntry = true + } + + present(alertEnterPassword, animated: true) + } + + func onIncorrectPassword() { +// NCNetworking.shared.p12Data = nil +// NCNetworking.shared.p12Password = nil + + let alertWrongPassword = UIAlertController(title: NSLocalizedString("_client_cert_wrong_password_", comment: ""), message: "", preferredStyle: .alert) + + alertWrongPassword.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default)) + + present(alertWrongPassword, animated: true) } } diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index 0019c66cce..458b92106e 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -32,6 +32,7 @@ import Queuer #endif @objc protocol ClientCertificateDelegate { + func onIncorrectPassword() func didAskForClientCertificate() } @@ -65,7 +66,10 @@ class NCNetworking: NSObject, NKCommonDelegate { var transferInForegorund: TransferInForegorund? weak var delegate: ClientCertificateDelegate? - var p12Data: Data? + var tempP12Data: Data? + var tempP12Password: String? + private var p12Data: Data? + private var p12Password: String? let transferInError = ThreadSafeDictionary() @@ -157,6 +161,16 @@ class NCNetworking: NSObject, NKCommonDelegate { override init() { super.init() +// if let account = NCManageDatabase.shared.getActiveAccount()?.account { +// (self.p12Data, self.p12Password) = NCKeychain().getClientCertificate(account: account) +// } + + NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in + if let account = NCManageDatabase.shared.getActiveAccount()?.account { + (self.p12Data, self.p12Password) = NCKeychain().getClientCertificate(account: account) + } + } + #if EXTENSION print("Start Background Upload Extension: ", sessionUploadBackgroundExtension) #else @@ -197,22 +211,22 @@ class NCNetworking: NSObject, NKCommonDelegate { completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { DispatchQueue.main.async { - // Use openssl pkcs12 -export -legacy -out identity.p12 -inkey key.pem -in cert.pem - if let p12Data = self.p12Data { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "12345") as? UserCertificate)) + + (self.p12Data, self.p12Password) = NCKeychain().getClientCertificate(account: NCManageDatabase.shared.getActiveAccount()!.account) + + if let p12Data = self.tempP12Data ?? self.p12Data, + let cert = (p12Data, self.tempP12Password ?? self.p12Password) as? UserCertificate, + let pkcs12 = try? PKCS12(pkcs12Data: cert.data, password: cert.password, onIncorrectPassword: { + self.delegate?.onIncorrectPassword() + }) { + let creds = PKCS12.urlCredential(for: pkcs12) + + completionHandler(URLSession.AuthChallengeDisposition.useCredential, creds) } else { self.delegate?.didAskForClientCertificate() completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) } } - -// let alert = UIAlertController(title: NSLocalizedString("_edit_comment_", comment: ""), message: nil, preferredStyle: .alert) -// alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) -// UIApplication.shared.?.rootViewController?.present(alert, animated: true) -// let p12Data = try? Data(contentsOf: URL(fileURLWithPath: Bundle.module.path(forResource: "identity", ofType: "p12")!)) - // let certificate = PKCS12(pkcs12Data: p12Data!, password: "") - - // completionHandler(URLSession.AuthChallengeDisposition.useCredential, PKCS12.urlCredential(for: (p12Data, "velikana100") as? UserCertificate)) } else { DispatchQueue.global().async { self.checkTrustedChallenge(session, didReceive: challenge, completionHandler: completionHandler) diff --git a/iOSClient/Settings/NCKeychain.swift b/iOSClient/Settings/NCKeychain.swift index 3204c3b712..25c39961a6 100644 --- a/iOSClient/Settings/NCKeychain.swift +++ b/iOSClient/Settings/NCKeychain.swift @@ -577,6 +577,26 @@ import KeychainAccess setPushNotificationDeviceIdentifierSignature(account: account, deviceIdentifierSignature: nil) } + // MARK: - Certificates + + func setClientCertificate(account: String, p12Data: Data?, p12Password: String?) { + var key = "ClientCertificateData" + account + keychain[data: key] = p12Data + + key = "ClientCertificatePassword" + account + keychain[key] = p12Password + } + + func getClientCertificate(account: String) -> (p12Data: Data?, p12Password: String?) { + var key = "ClientCertificateData" + account + let data = try? keychain.getData(key) + + key = "ClientCertificatePassword" + account + let password = keychain[key] + + return (data, password) + } + // MARK: - private func migrate(key: String) { diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 55bae7721a..98b5c633da 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -1078,11 +1078,9 @@ // MARK: Client certificate "_no_client_cert_found_" = "No client certificate was found"; -"_no_client_cert_found_desc_" = "Do you want to install a TLS client certificate?"; - -// MARK: Client certificate -"_no_client_cert_found_" = "No client certificate was found"; -"_no_client_cert_found_desc_" = "Do you want to install a TLS client certificate?"; +"_no_client_cert_found_desc_" = "Do you want to install a TLS client certificate? \n Note: Only .p12 created through OpenSSL with the -legacy flag can work on Apple devices."; +"_client_cert_enter_password_" = "Enter the password for the chosen certificate"; +"_client_cert_wrong_password_" = "Sorry, you entered an invalid password"; // MARK: Login poll "_poll_desc_" = "Please complete the log in process your browser"; diff --git a/iOSClient/Utility/PKCS12.swift b/iOSClient/Utility/PKCS12.swift index 1e18591cca..919a11c836 100644 --- a/iOSClient/Utility/PKCS12.swift +++ b/iOSClient/Utility/PKCS12.swift @@ -10,6 +10,12 @@ import Foundation typealias UserCertificate = (data: Data, password: String) +enum PKCS12Error: Error { + case wrongPasswordError(String) + case runtimeError(String) +} + + class PKCS12 { let label: String? let keyID: NSData? @@ -21,25 +27,26 @@ class PKCS12 { /// - Parameters: /// - pkcs12Data: the actual data we want to parse. /// - password: he password required to unlock the PKCS12 data. - public init(pkcs12Data: Data, password: String) { + public init(pkcs12Data: Data, password: String, onIncorrectPassword: () -> Void) throws { let importPasswordOption: NSDictionary - = [kSecImportExportPassphrase as NSString: password] + = [kSecImportExportPassphrase as NSString: password] var items: CFArray? let secError: OSStatus - = SecPKCS12Import(pkcs12Data as NSData, - importPasswordOption, &items) - guard secError == errSecSuccess else { - if secError == errSecAuthFailed { - NSLog("Incorrect password?") - } - fatalError("Error trying to import PKCS12 data") + = SecPKCS12Import(pkcs12Data as NSData, + importPasswordOption, &items) + + if secError == errSecAuthFailed { + onIncorrectPassword() + throw PKCS12Error.wrongPasswordError("Wrong password entered") } - guard let theItemsCFArray = items else { fatalError() } + + guard let theItemsCFArray = items else { throw PKCS12Error.runtimeError("") } + let theItemsNSArray: NSArray = theItemsCFArray as NSArray guard let dictArray - = theItemsNSArray as? [[String: AnyObject]] + = theItemsNSArray as? [[String: AnyObject]] else { - fatalError() + throw PKCS12Error.runtimeError("") } label = dictArray.element(for: kSecImportItemLabel) @@ -49,12 +56,8 @@ class PKCS12 { identity = dictArray.element(for: kSecImportItemIdentity) } - static func urlCredential(for userCertificate: UserCertificate?) -> URLCredential? { - guard let userCertificate = userCertificate else { return nil } - - let p12Contents = PKCS12(pkcs12Data: userCertificate.data, password: userCertificate.password) - - guard let identity = p12Contents.identity else { + static func urlCredential(for pkcs12: PKCS12) -> URLCredential? { + guard let identity = pkcs12.identity else { return nil } From 0b68bebddb868cf966734e53bdb1d87c1abf53b1 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 17 Jun 2024 17:14:44 +0200 Subject: [PATCH 27/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/AppDelegate.swift | 2 +- iOSClient/Login/NCLogin.swift | 70 +++++++++---------------- iOSClient/Networking/NCNetworking.swift | 29 +++++----- 3 files changed, 39 insertions(+), 62 deletions(-) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 694468bd67..d11b637230 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -505,7 +505,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD NCManageDatabase.shared.deleteAccount(account) NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) - NCKeychain().setClientCertificate(account: account, p12Data: NCNetworking.shared.tempP12Data, p12Password: NCNetworking.shared.tempP12Password) + NCKeychain().setClientCertificate(account: account, p12Data: NCNetworking.shared.p12Data, p12Password: NCNetworking.shared.p12Password) self.changeAccount(account, userProfile: userProfile) } else { diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index a826118af8..e7b3d85549 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -273,17 +273,9 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } @IBAction func actionButtonLogin(_ sender: Any) { - - guard var url = baseUrl.text?.trimmingCharacters(in: .whitespacesAndNewlines) else { return } - if url.hasSuffix("/") { url = String(url.dropLast()) } - if url.isEmpty { return } - - // Check whether baseUrl contain protocol. If not add https:// by default. - if url.hasPrefix("https") == false && url.hasPrefix("http") == false { - url = "https://" + url - } - self.baseUrl.text = url - isUrlValid(url: url) + NCNetworking.shared.p12Data = nil + NCNetworking.shared.p12Password = nil + login() } @IBAction func actionQRCode(_ sender: Any) { @@ -319,6 +311,19 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // MARK: - Login + private func login() { + guard var url = baseUrl.text?.trimmingCharacters(in: .whitespacesAndNewlines) else { return } + if url.hasSuffix("/") { url = String(url.dropLast()) } + if url.isEmpty { return } + + // Check whether baseUrl contain protocol. If not add https:// by default. + if url.hasPrefix("https") == false && url.hasPrefix("http") == false { + url = "https://" + url + } + self.baseUrl.text = url + isUrlValid(url: url) + } + func isUrlValid(url: String, user: String? = nil) { loginButton.isEnabled = false @@ -455,8 +460,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } } - - NCKeychain().setClientCertificate(account: account, p12Data: NCNetworking.shared.tempP12Data, p12Password: NCNetworking.shared.tempP12Password) } else { let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) @@ -494,22 +497,9 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } - func createAccount(server: String, username: String, password: String) { - var urlBase = server - if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } - let account: String = "\(username) \(urlBase)" - let user = username - - NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase) - NextcloudKit.shared.getUserProfile { _, userProfile, _, error in - - if error == .success, let userProfile { - - NCManageDatabase.shared.deleteAccount(account) - NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password) - - self.appDelegate.changeAccount(account, userProfile: userProfile) - + private func createAccount(server: String, username: String, password: String) { + appDelegate.createAccount(server: server, username: username, password: password) { error in + if error == .success { let window = UIApplication.shared.firstWindow if window?.rootViewController is NCMainTabBarController { self.dismiss(animated: true) @@ -524,18 +514,11 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } } - - NCKeychain().setClientCertificate(account: account, p12Data: NCNetworking.shared.tempP12Data, p12Password: NCNetworking.shared.tempP12Password) - } else { - - let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) - self.present(alertController, animated: true) } } } - func getAppPassword(serverUrl: String, username: String, password: String) { + private func getAppPassword(serverUrl: String, username: String, password: String) { NextcloudKit.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password) { token, _, error in if error == .success, let password = token { self.createAccount(server: serverUrl, username: username, password: password) @@ -570,19 +553,16 @@ extension NCLogin: ClientCertificateDelegate, UIDocumentPickerDelegate { } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - NCNetworking.shared.tempP12Data = try? Data(contentsOf: urls[0]) - let alertEnterPassword = UIAlertController(title: NSLocalizedString("_client_cert_enter_password_", comment: ""), message: "", preferredStyle: .alert) alertEnterPassword.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) alertEnterPassword.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in let documentProviderMenu = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.pkcs12]) - NCNetworking.shared.tempP12Password = alertEnterPassword.textFields?[0].text - -// NCKeychain().setClientCertificate(account: acco, p12Data: p12Data, p12Password: p12Password) + NCNetworking.shared.p12Data = try? Data(contentsOf: urls[0]) + NCNetworking.shared.p12Password = alertEnterPassword.textFields?[0].text - self.actionButtonLogin(self) + self.login() })) alertEnterPassword.addTextField { textField in @@ -593,8 +573,8 @@ extension NCLogin: ClientCertificateDelegate, UIDocumentPickerDelegate { } func onIncorrectPassword() { -// NCNetworking.shared.p12Data = nil -// NCNetworking.shared.p12Password = nil + NCNetworking.shared.p12Data = nil + NCNetworking.shared.p12Password = nil let alertWrongPassword = UIAlertController(title: NSLocalizedString("_client_cert_wrong_password_", comment: ""), message: "", preferredStyle: .alert) diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index 458b92106e..2103ce2217 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -66,10 +66,8 @@ class NCNetworking: NSObject, NKCommonDelegate { var transferInForegorund: TransferInForegorund? weak var delegate: ClientCertificateDelegate? - var tempP12Data: Data? - var tempP12Password: String? - private var p12Data: Data? - private var p12Password: String? + var p12Data: Data? + var p12Password: String? let transferInError = ThreadSafeDictionary() @@ -161,14 +159,10 @@ class NCNetworking: NSObject, NKCommonDelegate { override init() { super.init() -// if let account = NCManageDatabase.shared.getActiveAccount()?.account { -// (self.p12Data, self.p12Password) = NCKeychain().getClientCertificate(account: account) -// } - + getActiveAccountCertificate() + NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in - if let account = NCManageDatabase.shared.getActiveAccount()?.account { - (self.p12Data, self.p12Password) = NCKeychain().getClientCertificate(account: account) - } + self.getActiveAccountCertificate() } #if EXTENSION @@ -211,11 +205,8 @@ class NCNetworking: NSObject, NKCommonDelegate { completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { DispatchQueue.main.async { - - (self.p12Data, self.p12Password) = NCKeychain().getClientCertificate(account: NCManageDatabase.shared.getActiveAccount()!.account) - - if let p12Data = self.tempP12Data ?? self.p12Data, - let cert = (p12Data, self.tempP12Password ?? self.p12Password) as? UserCertificate, + if let p12Data = self.p12Data, + let cert = (p12Data, self.p12Password) as? UserCertificate, let pkcs12 = try? PKCS12(pkcs12Data: cert.data, password: cert.password, onIncorrectPassword: { self.delegate?.onIncorrectPassword() }) { @@ -384,4 +375,10 @@ class NCNetworking: NSObject, NKCommonDelegate { } } } + + private func getActiveAccountCertificate() { + if let account = NCManageDatabase.shared.getActiveAccount()?.account { + (self.p12Data, self.p12Password) = NCKeychain().getClientCertificate(account: account) + } + } } From ce53ed7bf392441ec36da7624e96f94740bdae86 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 18 Jun 2024 12:58:20 +0200 Subject: [PATCH 28/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Networking/NCNetworking.swift | 2 +- .../Settings/E2EE/NCEndToEndInitialize.swift | 38 +++++++++---------- .../en.lproj/Localizable.strings | 10 ++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index 2103ce2217..3079f7c24a 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -68,7 +68,7 @@ class NCNetworking: NSObject, NKCommonDelegate { var p12Data: Data? var p12Password: String? - + let transferInError = ThreadSafeDictionary() func transferInError(ocId: String) { diff --git a/iOSClient/Settings/Settings/E2EE/NCEndToEndInitialize.swift b/iOSClient/Settings/Settings/E2EE/NCEndToEndInitialize.swift index 66a80424e0..f09ec905fc 100644 --- a/iOSClient/Settings/Settings/E2EE/NCEndToEndInitialize.swift +++ b/iOSClient/Settings/Settings/E2EE/NCEndToEndInitialize.swift @@ -73,12 +73,12 @@ class NCEndToEndInitialize: NSObject { switch error.errorCode { case NCGlobal.shared.errorBadRequest: - let error = NKError(errorCode: error.errorCode, errorDescription: "bad request: unpredictable internal error") + let error = NKError(errorCode: error.errorCode, errorDescription: "Bad request: internal error") NCContentPresenter().messageNotification("E2E get publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorResourceNotFound: guard let csr = NCEndToEndEncryption.sharedManager().createCSR(self.appDelegate.userId, directory: self.utilityFileSystem.directoryUserData) else { - let error = NKError(errorCode: error.errorCode, errorDescription: "Error to create Csr") + let error = NKError(errorCode: error.errorCode, errorDescription: "Error creating CSR") NCContentPresenter().messageNotification("E2E Csr", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) return @@ -107,11 +107,11 @@ class NCEndToEndInitialize: NSObject { switch error.errorCode { case NCGlobal.shared.errorBadRequest: - let error = NKError(errorCode: error.errorCode, errorDescription: "bad request: unpredictable internal error") + let error = NKError(errorCode: error.errorCode, errorDescription: "Bad request: internal error") NCContentPresenter().messageNotification("E2E sign publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorConflict: - let error = NKError(errorCode: error.errorCode, errorDescription: "conflict: a public key for the user already exists") + let error = NKError(errorCode: error.errorCode, errorDescription: "Conflict: a public key for the user already exists") NCContentPresenter().messageNotification("E2E sign publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) default: @@ -121,7 +121,7 @@ class NCEndToEndInitialize: NSObject { } case NCGlobal.shared.errorConflict: - let error = NKError(errorCode: error.errorCode, errorDescription: "forbidden: the user can't access the public keys") + let error = NKError(errorCode: error.errorCode, errorDescription: "Forbidden: the user can't access the public keys") NCContentPresenter().messageNotification("E2E get publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) default: @@ -180,15 +180,15 @@ class NCEndToEndInitialize: NSObject { switch error.errorCode { case NCGlobal.shared.errorBadRequest: - let error = NKError(errorCode: error.errorCode, errorDescription: "bad request: unpredictable internal error") + let error = NKError(errorCode: error.errorCode, errorDescription: "Bad request: internal error") NCContentPresenter().messageNotification("E2E Server publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorResourceNotFound: - let error = NKError(errorCode: error.errorCode, errorDescription: "Server publickey doesn't exists") + let error = NKError(errorCode: error.errorCode, errorDescription: "Server public key doesn't exist") NCContentPresenter().messageNotification("E2E Server publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorConflict: - let error = NKError(errorCode: error.errorCode, errorDescription: "forbidden: the user can't access the Server publickey") + let error = NKError(errorCode: error.errorCode, errorDescription: "Forbidden: the user can't access the Server public key") NCContentPresenter().messageNotification("E2E Server publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) default: @@ -215,7 +215,7 @@ class NCEndToEndInitialize: NSObject { switch error.errorCode { case NCGlobal.shared.errorBadRequest: - let error = NKError(errorCode: error.errorCode, errorDescription: "bad request: unpredictable internal error") + let error = NKError(errorCode: error.errorCode, errorDescription: "Bad request: internal error") NCContentPresenter().messageNotification("E2E get privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorResourceNotFound: @@ -239,7 +239,7 @@ class NCEndToEndInitialize: NSObject { self.viewController?.present(alertController, animated: true) case NCGlobal.shared.errorConflict: - let error = NKError(errorCode: error.errorCode, errorDescription: "forbidden: the user can't access the private key") + let error = NKError(errorCode: error.errorCode, errorDescription: "Forbidden: the user can't access the private key") NCContentPresenter().messageNotification("E2E get privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) default: @@ -253,16 +253,16 @@ class NCEndToEndInitialize: NSObject { var privateKeyString: NSString? - guard let privateKeyChiper = NCEndToEndEncryption.sharedManager().encryptPrivateKey(self.appDelegate.userId, directory: utilityFileSystem.directoryUserData, passphrase: e2ePassphrase, privateKey: &privateKeyString, iterationCount: 1024) else { - let error = NKError(errorCode: error.errorCode, errorDescription: "Serious internal error to create PrivateKey chiper") + guard let privateKeyCipher = NCEndToEndEncryption.sharedManager().encryptPrivateKey(self.appDelegate.userId, directory: utilityFileSystem.directoryUserData, passphrase: e2ePassphrase, privateKey: &privateKeyString, iterationCount: 1024) else { + let error = NKError(errorCode: error.errorCode, errorDescription: "Error creating private key cipher") NCContentPresenter().messageNotification("E2E privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) return } // privateKeyChiper - print(privateKeyChiper) + print(privateKeyCipher) - NextcloudKit.shared.storeE2EEPrivateKey(privateKey: privateKeyChiper) { account, _, _, error in + NextcloudKit.shared.storeE2EEPrivateKey(privateKey: privateKeyCipher) { account, _, _, error in if error == .success, account == self.appDelegate.account, let privateKey = privateKeyString { @@ -288,15 +288,15 @@ class NCEndToEndInitialize: NSObject { switch error.errorCode { case NCGlobal.shared.errorBadRequest: - let error = NKError(errorCode: error.errorCode, errorDescription: "bad request: unpredictable internal error") + let error = NKError(errorCode: error.errorCode, errorDescription: "Bad request: internal error") NCContentPresenter().messageNotification("E2E Server publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorResourceNotFound: - let error = NKError(errorCode: error.errorCode, errorDescription: "Server publickey doesn't exists") + let error = NKError(errorCode: error.errorCode, errorDescription: "Server public key doesn't exist") NCContentPresenter().messageNotification("E2E Server publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorConflict: - let error = NKError(errorCode: error.errorCode, errorDescription: "forbidden: the user can't access the Server publickey") + let error = NKError(errorCode: error.errorCode, errorDescription: "Forbidden: the user can't access the Server public key") NCContentPresenter().messageNotification("E2E Server publicKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) default: @@ -310,11 +310,11 @@ class NCEndToEndInitialize: NSObject { switch error.errorCode { case NCGlobal.shared.errorBadRequest: - let error = NKError(errorCode: error.errorCode, errorDescription: "bad request: unpredictable internal error") + let error = NKError(errorCode: error.errorCode, errorDescription: "Bad request: internal error") NCContentPresenter().messageNotification("E2E store privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) case NCGlobal.shared.errorConflict: - let error = NKError(errorCode: error.errorCode, errorDescription: "conflict: a private key for the user already exists") + let error = NKError(errorCode: error.errorCode, errorDescription: "Conflict: a private key for the user already exists") NCContentPresenter().messageNotification("E2E store privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max) default: diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 98b5c633da..ef01cfaed4 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -686,7 +686,7 @@ "_transfers_" = "Transfers"; "_activity_" = "Activity"; "_activity_file_not_present_" = "File no longer present"; -"_trash_file_not_found_" = "It seems that the file is not in the trash, go to the trash to update it and try again"; +"_trash_file_not_found_" = "It seems that the file is not in the trash. Go to the trash to update it and try again"; "_list_shares_" = "Shares"; "_list_shares_no_files_" = "No shares yet"; "_tutorial_list_shares_view_" = "Files and folders you share will show up here"; @@ -733,7 +733,7 @@ "_e2e_set_folder_encrypted_" = "Encrypt"; "_e2e_remove_folder_encrypted_" = "Decrypt"; "_e2e_goto_settings_for_enable_" = "This is an encrypted directory, go to \"Settings\" and enable end-to-end encryption"; -"_e2e_error_" = "Serious internal error end-to-end encryption"; +"_e2e_error_" = "An internal end-to-end encryption error occurred"; "_e2e_in_upload_" = "Upload in progress, please wait for all files to be transferred"; "_scans_document_" = "Scan document"; "_scanned_images_" = "Scanned images"; @@ -1077,10 +1077,10 @@ "_no_types_subtitle_" = "AI Providers need to be installed to use the Assistant"; // MARK: Client certificate -"_no_client_cert_found_" = "No client certificate was found"; -"_no_client_cert_found_desc_" = "Do you want to install a TLS client certificate? \n Note: Only .p12 created through OpenSSL with the -legacy flag can work on Apple devices."; +"_no_client_cert_found_" = "The server is requesting a client certificate"; +"_no_client_cert_found_desc_" = "Do you want to install a TLS client certificate? \n Note that only .p12 archives created through OpenSSL with the -legacy flag can work on Apple devices."; "_client_cert_enter_password_" = "Enter the password for the chosen certificate"; "_client_cert_wrong_password_" = "Sorry, you entered an invalid password"; // MARK: Login poll -"_poll_desc_" = "Please complete the log in process your browser"; +"_poll_desc_" = "Please complete the log in process in your browser"; From 7289bf1d4d5ef10a74f455c4564b2e39d9315a47 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 19 Jun 2024 13:29:53 +0200 Subject: [PATCH 29/31] cleanup Signed-off-by: Milen Pivchev --- iOSClient/AppDelegate.swift | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index d11b637230..fb48e8c6b8 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -152,8 +152,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD self.handleProcessingTask(task) } - NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive2(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) - return true } @@ -274,10 +272,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } - @objc private func applicationDidBecomeActive2(_ notification: NSNotification) { - pollLogin() - } - // MARK: - Background Networking Session func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { @@ -375,7 +369,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if NCBrandOptions.shared.use_AppConfig { if activeLogin?.view.window == nil { urlBase = NCBrandOptions.shared.loginBaseUrl - pollLogin() NextcloudKit.shared.getLoginFlowV2(serverUrl: urlBase) { token, endpoint, login, _, error in @@ -432,14 +425,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } - @objc func pollLogin() { - NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in - if error == .success, let server, let loginName, let appPassword { - self.createAccount(server: server, username: loginName, password: appPassword, completion: { error in }) - } - } - } - // MARK: - Error Networking @objc func startTimerErrorNetworking(scene: UIScene) { From d1be5532757971aee7803a1b11492f885f4b9d2c Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 24 Jun 2024 10:22:40 +0200 Subject: [PATCH 30/31] WIP Signed-off-by: Milen Pivchev --- iOSClient/Data/NCManageDatabase+Account.swift | 9 --------- iOSClient/Utility/PKCS12.swift | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index 32e3bd1ca3..6d2c7f4f31 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -90,15 +90,6 @@ extension NCManageDatabase { addObject.account = account -// // Brand -// if NCBrandOptions.shared.use_default_auto_upload { -// -// addObject.autoUpload = true -// addObject.autoUploadImage = true -// addObject.autoUploadVideo = true -// addObject.autoUploadWWAnVideo = true -// } - NCKeychain().setPassword(account: account, password: password) addObject.urlBase = urlBase diff --git a/iOSClient/Utility/PKCS12.swift b/iOSClient/Utility/PKCS12.swift index 919a11c836..36b8411acc 100644 --- a/iOSClient/Utility/PKCS12.swift +++ b/iOSClient/Utility/PKCS12.swift @@ -70,7 +70,7 @@ class PKCS12 { } } -extension Array where Element == [String: AnyObject] { +private extension Array where Element == [String: AnyObject] { func element(for key: CFString) -> T? { for dictElement in self { if let value = dictElement[key as String] as? T { From b3dd8ba9a6505b26c9f6364e417460e95f35aae4 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 24 Jun 2024 10:23:26 +0200 Subject: [PATCH 31/31] Remove UI test Signed-off-by: Milen Pivchev --- Nextcloud.xcodeproj/project.pbxproj | 4 -- Tests/NextcloudUITests/LoginUITests.swift | 75 ----------------------- 2 files changed, 79 deletions(-) delete mode 100644 Tests/NextcloudUITests/LoginUITests.swift diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 11e0fad851..2a38e6b153 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -65,7 +65,6 @@ AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; }; AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; }; AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; }; - C0046CDD2A17B98400D87C9D /* LoginUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0046CDC2A17B98400D87C9D /* LoginUITests.swift */; }; C04E2F232A17BB4D001BAD85 /* FilesIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */; }; D575039F27146F93008DC9DC /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; }; @@ -1106,7 +1105,6 @@ AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = ""; }; AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = ""; }; C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - C0046CDC2A17B98400D87C9D /* LoginUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginUITests.swift; sourceTree = ""; }; C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesIntegrationTests.swift; sourceTree = ""; }; D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = ""; }; @@ -1911,7 +1909,6 @@ C0046CDB2A17B98400D87C9D /* NextcloudUITests */ = { isa = PBXGroup; children = ( - C0046CDC2A17B98400D87C9D /* LoginUITests.swift */, F3A7AFC52A41AA82001FC89C /* BaseUIXCTestCase.swift */, ); path = NextcloudUITests; @@ -3835,7 +3832,6 @@ files = ( F3A7AFC62A41AA82001FC89C /* BaseUIXCTestCase.swift in Sources */, F37208822BAB597B006B5430 /* BaseXCTestCase.swift in Sources */, - C0046CDD2A17B98400D87C9D /* LoginUITests.swift in Sources */, F37208812BAB5979006B5430 /* TestConstants.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/NextcloudUITests/LoginUITests.swift b/Tests/NextcloudUITests/LoginUITests.swift deleted file mode 100644 index 8c0bcf8115..0000000000 --- a/Tests/NextcloudUITests/LoginUITests.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// NextcloudUITests.swift -// NextcloudUITests -// -// Created by Milen Pivchev on 5/19/23. -// Copyright © 2023 Marino Faggiana. All rights reserved. -// -// 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 XCTest -import NextcloudKit -@testable import Nextcloud - -final class LoginUITests: BaseUIXCTestCase { - let app = XCUIApplication() - - override func setUp() { - app.launchArguments += ["UI_TESTING"] - } - - func test_logIn_withProperParams_shouldLogInAndGoToHomeScreen() throws { - app.launch() - - let loginButton = app.buttons["Log in"] - XCTAssert(loginButton.waitForExistence(timeout: TestConstants.timeoutLong)) - loginButton.tap() - - let serverAddressHttpsTextField = app.textFields["Server address https:// …"] - serverAddressHttpsTextField.tap() - serverAddressHttpsTextField.typeText(TestConstants.server) - let button = app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .button).element(boundBy: 0) - button.tap() - - let webViewsQuery = app.webViews.webViews.webViews - let loginButton2 = webViewsQuery/*@START_MENU_TOKEN@*/.buttons["Log in"]/*[[".otherElements.matching(identifier: \"Nextcloud\")",".otherElements[\"main\"].buttons[\"Log in\"]",".buttons[\"Log in\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/ - XCTAssert(loginButton2.waitForExistence(timeout: TestConstants.timeoutLong)) - waitForEnabledAndHittable(object: loginButton2) - loginButton2.tap() - - let usernameTextField = webViewsQuery.textFields["Login with username or email"] - XCTAssert(usernameTextField.waitForExistence(timeout: TestConstants.timeoutLong)) - usernameTextField.tap() - usernameTextField.typeText(TestConstants.username) - - let passwordTextField = webViewsQuery/*@START_MENU_TOKEN@*/.secureTextFields["Password"]/*[[".otherElements[\"Login – Nextcloud\"]",".otherElements[\"main\"].secureTextFields[\"Password\"]",".secureTextFields[\"Password\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/ - XCTAssert(passwordTextField.waitForExistence(timeout: TestConstants.timeoutLong)) - passwordTextField.tap() - passwordTextField.typeText(TestConstants.username) - - let loginButton3 = webViewsQuery/*@START_MENU_TOKEN@*/.buttons["Log in"]/*[[".otherElements[\"Login – Nextcloud\"]",".otherElements[\"main\"].buttons[\"Log in\"]",".buttons[\"Log in\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/ - XCTAssert(loginButton3.waitForExistence(timeout: TestConstants.timeoutLong)) - loginButton3.tap() - - let grantAccessButton = webViewsQuery/*@START_MENU_TOKEN@*/.buttons["Grant access"]/*[[".otherElements.matching(identifier: \"Nextcloud\")",".otherElements[\"main\"].buttons[\"Grant access\"]",".buttons[\"Grant access\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/ - XCTAssert(grantAccessButton.waitForExistence(timeout: TestConstants.timeoutLong)) - waitForEnabledAndHittable(object: grantAccessButton) - grantAccessButton.tap() - - // Check if we are in the home screen - XCTAssert(app.navigationBars["Nextcloud"].waitForExistence(timeout: TestConstants.timeoutLong)) - XCTAssert(app.tabBars["Tab Bar"].waitForExistence(timeout: TestConstants.timeoutLong)) - } -}