Bläddra i källkod

Merge pull request #1740 from nextcloud/SSLImproved

SSL pinning (removed old code + improvements)
Marino Faggiana 3 år sedan
förälder
incheckning
5b5ce47503

+ 12 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -138,6 +138,12 @@
 		F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */; };
 		F7434B3820E2400600417916 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; };
 		F745B253222D88AE00346520 /* NCLoginQRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F745B252222D88AE00346520 /* NCLoginQRCode.swift */; };
+		F746EC4E273906B80052598D /* NCViewCertificateDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */; };
+		F746EC4F273906B90052598D /* NCViewCertificateDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */; };
+		F746EC50273906BA0052598D /* NCViewCertificateDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */; };
+		F746EC51273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */; };
+		F746EC52273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */; };
+		F746EC53273906C50052598D /* NCViewCertificateDetails.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */; };
 		F747BA1F22354D2000971601 /* NCCreateFormUploadVoiceNote.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F747BA1E22354D2000971601 /* NCCreateFormUploadVoiceNote.storyboard */; };
 		F749C10B23C4A5340027D966 /* NCIntroCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F749C10723C4A5330027D966 /* NCIntroCollectionViewCell.swift */; };
 		F749C10C23C4A5340027D966 /* NCIntroViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F749C10823C4A5330027D966 /* NCIntroViewController.swift */; };
@@ -1886,6 +1892,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				F746EC53273906C50052598D /* NCViewCertificateDetails.storyboard in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1900,6 +1907,7 @@
 				F7145A1A1D12E3B700CAFEEC /* Images.xcassets in Resources */,
 				F7148063262ED66200693E51 /* NCEmptyView.xib in Resources */,
 				F7145A231D12E3B700CAFEEC /* Localizable.strings in Resources */,
+				F746EC51273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */,
 				F79EC784263161BA004E59D6 /* NCRenameFile.storyboard in Resources */,
 				F714804F262ED4F900693E51 /* NCGridCell.xib in Resources */,
 				F714805E262ED52900693E51 /* NCSectionFooter.xib in Resources */,
@@ -1911,6 +1919,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				F746EC52273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -2024,6 +2033,7 @@
 				F785EEA52461A4CF00B3F945 /* CCUtility.m in Sources */,
 				2C1D5D7923E2DE9100334ABB /* NCBrand.swift in Sources */,
 				F770768A263A8A2500A1BA94 /* NCUtilityFileSystem.swift in Sources */,
+				F746EC50273906BA0052598D /* NCViewCertificateDetails.swift in Sources */,
 				F702F2D225EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F7707689263A896A00A1BA94 /* UIImage+Extensions.swift in Sources */,
 				2C1D5D7523E2DE3300334ABB /* NCDatabase.swift in Sources */,
@@ -2042,6 +2052,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				F746EC4E273906B80052598D /* NCViewCertificateDetails.swift in Sources */,
 				F73D5E48246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F7EDE4E5262D7BBE00414FE6 /* NCSectionHeaderFooter.swift in Sources */,
 				F79EC78926316AC4004E59D6 /* NCPopupViewController.swift in Sources */,
@@ -2085,6 +2096,7 @@
 				F702F2D125EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F7434B3820E2400600417916 /* NCBrand.swift in Sources */,
 				F785EE9E2461A09900B3F945 /* NCNetworking.swift in Sources */,
+				F746EC4F273906B90052598D /* NCViewCertificateDetails.swift in Sources */,
 				F771E3D320E2392D00AFB62D /* FileProviderExtension.swift in Sources */,
 				F73D5E49246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F771E3D520E2392D00AFB62D /* FileProviderItem.swift in Sources */,

+ 57 - 18
iOSClient/AppDelegate.swift

@@ -297,7 +297,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NCCommunicationCommon.shared.writeLog("initialize Main")
         
         // Clear error certificate
-        CCUtility.clearCertificateError(account)
+        NCNetworking.shared.certificatesError.removeAll()
         
         // Registeration push notification
         NCPushNotification.shared().pushNotification()
@@ -433,7 +433,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
     
     func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
-        NCPushNotification.shared().registerForRemoteNotifications(withDeviceToken: deviceToken)
+        NCNetworking.shared.checkPushNotificationServerProxyCertificateUntrusted(viewController: self.window?.rootViewController) { errorCode in
+            if errorCode == 0 {
+                NCPushNotification.shared().registerForRemoteNotifications(withDeviceToken: deviceToken)
+            }
+        }
     }
     
     func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
@@ -543,36 +547,71 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
     
     @objc private func checkErrorNetworking() {
-        
+                
         if account == "" { return }
-        
+        guard let currentHost = URL(string: self.urlBase)?.host else { return }
+        guard let pushNotificationServerProxyHost = URL(string: NCBrandOptions.shared.pushNotificationServerProxy)?.host else { return }
+                
         // check unauthorized server (401/403)
         if CCUtility.getPassword(account)!.count == 0 {
             openLogin(viewController: window?.rootViewController, selector: NCGlobal.shared.introLogin, openLoginWeb: true)
         }
         
-        // check certificate untrusted (-1202)
-        if CCUtility.getCertificateError(account) {
+        // check certificate untrusted (-1202)        
+        if NCNetworking.shared.certificatesError.contains(currentHost) || NCNetworking.shared.certificatesError.contains(pushNotificationServerProxyHost) {
+            
+            let directoryCertificate = CCUtility.getDirectoryCerificates()!
+            let certificateHostSavedPath = directoryCertificate + "/" + currentHost + ".der"
+            let certificatePushNotificationServerProxySavedPath = directoryCertificate + "/" + pushNotificationServerProxyHost + ".der"
+            var title = NSLocalizedString("_ssl_certificate_changed_", comment: "")
+            
+            if (NCNetworking.shared.certificatesError.contains(currentHost) && !FileManager.default.fileExists(atPath: certificateHostSavedPath)) || (NCNetworking.shared.certificatesError.contains(pushNotificationServerProxyHost) && !FileManager.default.fileExists(atPath: certificatePushNotificationServerProxySavedPath)) {
+                
+                title = NSLocalizedString("_connect_server_anyway_", comment: "")
+            }
+            
+            let alertController = UIAlertController(title: title, message: NSLocalizedString("_server_is_trusted_", comment: ""), preferredStyle: .alert)
             
-            let alertController = UIAlertController(title: NSLocalizedString("_ssl_certificate_changed_", comment: ""), message: NSLocalizedString("_server_is_trusted_", comment: ""), preferredStyle: .alert)
-                        
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in
-                NCNetworking.shared.writeCertificate(url: self.urlBase)
-                CCUtility.clearCertificateError(self.account)
+                
+                if NCNetworking.shared.certificatesError.contains(currentHost) {
+                    NCNetworking.shared.writeCertificate(host: currentHost)
+                }
+                if NCNetworking.shared.certificatesError.contains(pushNotificationServerProxyHost) {
+                    NCNetworking.shared.writeCertificate(host: pushNotificationServerProxyHost)
+                }
+                
+                NCNetworking.shared.certificatesError.removeAll()
                 self.startTimerErrorNetworking()
             }))
             
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in
+                
+                NCNetworking.shared.certificatesError.removeAll()
                 self.startTimerErrorNetworking()
             }))
             
-            alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in
-                if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController {
-                    let viewController = navigationController.topViewController as! NCViewCertificateDetails
-                    viewController.delegate = self
-                    self.window?.rootViewController?.present(navigationController, animated: true)
-                }
-            }))
+            if NCNetworking.shared.certificatesError.contains(currentHost) {
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in
+                    if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController {
+                        let viewController = navigationController.topViewController as! NCViewCertificateDetails
+                        viewController.delegate = self
+                        viewController.host = currentHost
+                        self.window?.rootViewController?.present(navigationController, animated: true)
+                    }
+                }))
+            }
+            
+            if NCNetworking.shared.certificatesError.contains(pushNotificationServerProxyHost) {
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_pn_details_", comment: ""), style: .default, handler: { action in
+                    if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController {
+                        let viewController = navigationController.topViewController as! NCViewCertificateDetails
+                        viewController.delegate = self
+                        viewController.host = pushNotificationServerProxyHost
+                        self.window?.rootViewController?.present(navigationController, animated: true)
+                    }
+                }))
+            }
             
             window?.rootViewController?.present(alertController, animated: true, completion: {
                 self.timerErrorNetworking?.invalidate()
@@ -612,9 +651,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         }
         NCManageDatabase.shared.clearDatabase(account: account, removeAccount: true)
         
+        NCNetworking.shared.certificatesError.removeAll()
         CCUtility.clearAllKeysEnd(toEnd: account)
         CCUtility.clearAllKeysPushNotification(account)
-        CCUtility.clearCertificateError(account)
         CCUtility.setPassword(account, password: nil)
         
         if wipe {

+ 2 - 2
iOSClient/Login/NCLogin.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>

+ 77 - 110
iOSClient/Login/NCLogin.swift

@@ -205,44 +205,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
     
     @IBAction func actionCertificate(_ sender: Any) {
         
-        let pathsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
-        let fileNameCertificate = pathsDirectory.appendingPathComponent(NCGlobal.shared.certificate).path
-        let directoryCertificate = CCUtility.getDirectoryCerificates()!
-        
-        var host = "cloud.nextcloud.com"
-        if let url = URL(string: NCBrandOptions.shared.loginBaseUrl) {
-            let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
-            if let hostComponets = urlComponents?.host {
-                host = hostComponets
-            }
-        }
-            
-        if FileManager.default.fileExists(atPath: fileNameCertificate) {
-            
-            let certificateToPath = directoryCertificate + "/" + host + ".der"
-        
-            if NCUtilityFileSystem.shared.moveFile(atPath: fileNameCertificate, toPath: certificateToPath) {
-                
-                let message = String(format: NSLocalizedString("_certificate_installed_", comment: ""), NCGlobal.shared.certificate)
-                let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
-                alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in }))
-                self.present(alertController, animated: true, completion: { })
-                
-            } else {
-                
-                let message = String(format: NSLocalizedString("_copy_failed_", comment: ""), NCGlobal.shared.certificate)
-                let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: message, preferredStyle: .alert)
-                alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in }))
-                self.present(alertController, animated: true, completion: { })
-            }
-            
-        } else {
-            
-            let message = String(format: NSLocalizedString("_certificate_not_found_", comment: ""), NCGlobal.shared.certificate)
-            let alertController = UIAlertController(title: NSLocalizedString("_file_not_found_", comment: ""), message: message, preferredStyle: .alert)
-            alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in }))
-            self.present(alertController, animated: true, completion: { })
-        }
     }
     
     // MARK: - Login
@@ -250,42 +212,50 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
     func isUrlValid(url: String) {
             
         loginButton.isEnabled = false
-        //activity.startAnimating()
         
         NCCommunication.shared.getServerStatus(serverUrl: url) { (serverProductName, serverVersion, versionMajor, versionMinor, versionMicro, extendedSupport, errorCode ,errorDescription) in
             
             if errorCode == 0 {
                 
-                NCNetworking.shared.writeCertificate(url: url)
+                if let host = URL(string: url)?.host {
+                    NCNetworking.shared.writeCertificate(host: host)
+                }
                 
                 NCCommunication.shared.getLoginFlowV2(serverUrl: url) { (token, endpoint, login, errorCode, errorDescription) in
                     
                     self.loginButton.isEnabled = true
-                    //self.activity.stopAnimating()
                                         
                     // Login Flow V2
                     if errorCode == 0 && NCBrandOptions.shared.use_loginflowv2 && token != nil && endpoint != nil && login != nil {
                         
-                        if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb {
-                            
-                            loginWeb.urlBase = url
-                            loginWeb.loginFlowV2Available = true
-                            loginWeb.loginFlowV2Token = token!
-                            loginWeb.loginFlowV2Endpoint = endpoint!
-                            loginWeb.loginFlowV2Login = login!
-                            
-                            self.navigationController?.pushViewController(loginWeb, animated: true)
-                        }
+                        NCNetworking.shared.checkPushNotificationServerProxyCertificateUntrusted(viewController: self, completion: { errorCode in
+                            if errorCode == 0 {
+                                if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb {
+                                    
+                                    loginWeb.urlBase = url
+                                    loginWeb.loginFlowV2Available = true
+                                    loginWeb.loginFlowV2Token = token!
+                                    loginWeb.loginFlowV2Endpoint = endpoint!
+                                    loginWeb.loginFlowV2Login = login!
+                                    
+                                    self.navigationController?.pushViewController(loginWeb, animated: true)
+                                }
+                            }
+                        })
                         
                     // Login Flow
                     } else if versionMajor >= NCGlobal.shared.nextcloudVersion12 {
                         
-                        if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb {
-                            
-                            loginWeb.urlBase = url
+                        NCNetworking.shared.checkPushNotificationServerProxyCertificateUntrusted(viewController: self, completion: { errorCode in
+                            if errorCode == 0 {
+                                if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb {
+                                    
+                                    loginWeb.urlBase = url
 
-                            self.navigationController?.pushViewController(loginWeb, animated: true)
-                        }
+                                    self.navigationController?.pushViewController(loginWeb, animated: true)
+                                }
+                            }
+                        })
                         
                     // NO Login flow available
                     } else if versionMajor < NCGlobal.shared.nextcloudVersion12 {
@@ -301,20 +271,18 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             } else {
                
                 self.loginButton.isEnabled = true
-                //self.activity.stopAnimating()
                 
                 if errorCode == NSURLErrorServerCertificateUntrusted {
                     
                     let alertController = UIAlertController(title: NSLocalizedString("_ssl_certificate_untrusted_", comment: ""), message: NSLocalizedString("_connect_server_anyway_", comment: ""), preferredStyle: .alert)
                                 
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in
-                        NCNetworking.shared.writeCertificate(url: url)
-                        self.appDelegate.startTimerErrorNetworking()
+                        if let host = URL(string: url)?.host {
+                            NCNetworking.shared.writeCertificate(host: host)
+                        }
                     }))
                     
-                    alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in
-                        self.appDelegate.startTimerErrorNetworking()
-                    }))
+                    alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in }))
                     
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in
                         if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() {
@@ -322,9 +290,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                         }
                     }))
                     
-                    self.present(alertController, animated: true, completion: {
-                        self.appDelegate.timerErrorNetworking?.invalidate()
-                    })
+                    self.present(alertController, animated: true)
                     
                 } else {
                     
@@ -338,19 +304,57 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
         }
     }
     
+    // MARK: - QRCode
+
+    func dismissQRCode(_ value: String?, metadataType: String?) {
+        
+        guard var value = value else { return }
+        
+        let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/"
+        
+        if value.hasPrefix(protocolLogin) && value.contains("user:") && value.contains("password:") && value.contains("server:") {
+            
+            value = value.replacingOccurrences(of: protocolLogin, with: "")
+            let valueArray = value.components(separatedBy: "&")
+            if valueArray.count == 3 {
+                
+                let user = valueArray[0].replacingOccurrences(of: "user:", with: "")
+                let password = valueArray[1].replacingOccurrences(of: "password:", with: "")
+                let urlBase = valueArray[2].replacingOccurrences(of: "server:", with: "")
+                let webDAV = NCUtilityFileSystem.shared.getWebDAV(account: appDelegate.account)
+                let serverUrl = urlBase + "/" + webDAV
+                
+                loginButton.isEnabled = false
+                
+                NCCommunication.shared.checkServer(serverUrl: serverUrl) { (errorCode, errorDescription) in
+                
+                    NCNetworking.shared.checkPushNotificationServerProxyCertificateUntrusted(viewController: self, completion: { errorCode in
+                        if errorCode == 0 {
+                            self.loginButton.isEnabled = true
+                            self.standardLogin(url: urlBase, user: user, password: password, errorCode: errorCode, errorDescription: errorDescription)
+                        }
+                    })
+                }
+            }
+        }
+    }
+    
     func standardLogin(url: String, user: String, password: String, errorCode: Int, errorDescription: String) {
         
         if errorCode == 0 {
             
-            NCNetworking.shared.writeCertificate(url: url)
+            if let host = URL(string: url)?.host {
+                NCNetworking.shared.writeCertificate(host: host)
+            }
             
             let account = user + " " + url
             
             if NCManageDatabase.shared.getAccounts() == nil {
                 NCUtility.shared.removeAllSettings()
             }
-            
-            CCUtility.clearCertificateError(account)
+               
+            // Clear certificate error
+            NCNetworking.shared.certificatesError.removeAll()
             
             NCManageDatabase.shared.deleteAccount(account)
             NCManageDatabase.shared.addAccount(account, urlBase: url, user: user, password: password)
@@ -388,13 +392,12 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             let alertController = UIAlertController(title: NSLocalizedString("_ssl_certificate_untrusted_", comment: ""), message: NSLocalizedString("_connect_server_anyway_", comment: ""), preferredStyle: .alert)
                         
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in
-                NCNetworking.shared.writeCertificate(url: url)
-                self.appDelegate.startTimerErrorNetworking()
+                if let host = URL(string: url)?.host {
+                    NCNetworking.shared.writeCertificate(host: host)
+                }
             }))
             
-            alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in
-                self.appDelegate.startTimerErrorNetworking()
-            }))
+            alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in }))
             
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in
                 if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() {
@@ -402,9 +405,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                 }
             }))
             
-            self.present(alertController, animated: true, completion: {
-                self.appDelegate.timerErrorNetworking?.invalidate()
-            })
+            self.present(alertController, animated: true)
             
         } else {
             
@@ -416,38 +417,4 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             self.present(alertController, animated: true, completion: { })
         }
     }
-    
-    // MARK: - QRCode
-
-    func dismissQRCode(_ value: String?, metadataType: String?) {
-        
-        guard var value = value else { return }
-        
-        let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/"
-        
-        if value.hasPrefix(protocolLogin) && value.contains("user:") && value.contains("password:") && value.contains("server:") {
-            
-            value = value.replacingOccurrences(of: protocolLogin, with: "")
-            let valueArray = value.components(separatedBy: "&")
-            if valueArray.count == 3 {
-                
-                let user = valueArray[0].replacingOccurrences(of: "user:", with: "")
-                let password = valueArray[1].replacingOccurrences(of: "password:", with: "")
-                let urlBase = valueArray[2].replacingOccurrences(of: "server:", with: "")
-                let webDAV = NCUtilityFileSystem.shared.getWebDAV(account: appDelegate.account)
-                let serverUrl = urlBase + "/" + webDAV
-                
-                loginButton.isEnabled = false
-                //activity.startAnimating()
-                
-                NCCommunication.shared.checkServer(serverUrl: serverUrl) { (errorCode, errorDescription) in
-                
-                    //self.activity.stopAnimating()
-                    self.loginButton.isEnabled = true
-                    
-                    self.standardLogin(url: urlBase, user: user, password: password, errorCode: errorCode, errorDescription: errorDescription)
-                }
-            }
-        }
-    }
 }

+ 2 - 2
iOSClient/Login/NCLoginWeb.swift

@@ -270,8 +270,8 @@ extension NCLoginWeb: WKNavigationDelegate {
             NCUtility.shared.removeAllSettings()
         }
         
-        // Clear certificate error 
-        CCUtility.clearCertificateError(account)
+        // Clear certificate error
+        NCNetworking.shared.certificatesError.removeAll()
 
         // Add new account
         NCManageDatabase.shared.deleteAccount(account)

+ 0 - 6
iOSClient/NCGlobal.swift

@@ -196,12 +196,6 @@ class NCGlobal: NSObject {
     //
     let fileNameRichWorkspace                       = "Readme.md"
     
-    // Certificate pinning
-    //
-    let certificate                                 = "certificate.der"
-    let certificateTmp                              = "tmp.der"
-    let certificateTmpV2                            = "certificatetmp.der"
-    
     // Extension
     @objc let extensionPreview                      = "ico"
     

+ 83 - 81
iOSClient/Networking/NCNetworking.swift

@@ -47,6 +47,8 @@ import Queuer
     var downloadRequest: [String: DownloadRequest] = [:]
     var uploadRequest: [String: UploadRequest] = [:]
     var uploadMetadataInBackground: [String: tableMetadata] = [:]
+    
+    var certificatesError: [String] = []
 
     @objc public let sessionMaximumConnectionsPerHost = 5
     @objc public let sessionIdentifierBackground: String = "com.nextcloud.session.upload.background"
@@ -158,97 +160,56 @@ import Queuer
     
     private func checkTrustedChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) -> Bool {
         
-        var trusted = false
-        var trustedV2 = false
         let protectionSpace: URLProtectionSpace = challenge.protectionSpace
         let directoryCertificate = CCUtility.getDirectoryCerificates()!
-        let directoryCertificateUrl = URL.init(fileURLWithPath: directoryCertificate)
         let host = challenge.protectionSpace.host
-    
+            
+        print("SSL host: \(host)")
+        
         if let serverTrust: SecTrust = protectionSpace.serverTrust {
             
-            saveX509Certificate(serverTrust, certName: NCGlobal.shared.certificateTmp, directoryCertificate: directoryCertificate)
+            saveX509Certificate(serverTrust, host: host, directoryCertificate: directoryCertificate)
             
-            // OLD
-            do {
-                let directoryContents = try FileManager.default.contentsOfDirectory(at: directoryCertificateUrl, includingPropertiesForKeys: nil)
-                let certTmpPath = directoryCertificate + "/" + NCGlobal.shared.certificateTmp
-                for file in directoryContents {
-                    let certPath = file.path
-                    if certPath == certTmpPath { continue }
-                    if FileManager.default.contentsEqual(atPath:certTmpPath, andPath: certPath) {
-                        trusted = true
-                        break
-                    }
-                }
-            } catch {
-                print(error)
-            }
-            
-            // V2
             var secresult = SecTrustResultType.invalid
             let status = SecTrustEvaluate(serverTrust, &secresult)
-            if (errSecSuccess == status) {
-                if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
-                    
-                    let serverCertificateData = SecCertificateCopyData(serverCertificate)
-                    let data = CFDataGetBytePtr(serverCertificateData);
-                    let size = CFDataGetLength(serverCertificateData);
-                    let certificate = NSData(bytes: data, length: size)
-                    
-                    // write certificate tmp to disk
-                    let certificatePath = directoryCertificate + "/" + NCGlobal.shared.certificateTmpV2
-                    certificate.write(toFile: certificatePath, atomically: true)
-                    
-                    let certificateSavedPath = directoryCertificate + "/" + host + ".der"
-                    if let certificateSaved = NSData(contentsOfFile: certificateSavedPath) {
-                        if certificate.isEqual(to: certificateSaved as Data) {
-                            trustedV2 = true
-                        }
-                    }
+            if errSecSuccess == status, let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
                     
-                    if !trusted && !trustedV2 {
-                        #if !EXTENSION
-                        DispatchQueue.main.async {
-                            CCUtility.setCertificateError((UIApplication.shared.delegate as! AppDelegate).account)
-                        }
-                        #endif
-                    }
+                let serverCertificateData = SecCertificateCopyData(serverCertificate)
+                let data = CFDataGetBytePtr(serverCertificateData);
+                let size = CFDataGetLength(serverCertificateData);
+                let certificate = NSData(bytes: data, length: size)
+                
+                // write certificate tmp to disk
+                certificate.write(toFile: directoryCertificate + "/" + host + ".tmp", atomically: true)
+                
+                // verify
+                let certificateSavedPath = directoryCertificate + "/" + host + ".der"
+                if let certificateSaved = NSData(contentsOfFile: certificateSavedPath), certificate.isEqual(to: certificateSaved as Data) {
+                    return true
                 }
             }
         }
         
-        if trusted || trustedV2 {
-            return true
-        } else {
-            return false
-        }
+        NCNetworking.shared.certificatesError.append(host)
+        return false
     }
     
-    func writeCertificate(url: String) {
+    func writeCertificate(host: String) {
         
         let directoryCertificate = CCUtility.getDirectoryCerificates()!
-
-        if let url = URL(string: url) {
-            let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
-            if let host = urlComponents?.host {
-            
-                let certificateAtPath = directoryCertificate + "/" + NCGlobal.shared.certificateTmpV2
-                let certificateToPath = directoryCertificate + "/" + host + ".der"
-            
-                if !NCUtilityFileSystem.shared.moveFile(atPath: certificateAtPath, toPath: certificateToPath) {
-                    NCContentPresenter.shared.messageNotification("_error_", description: "_error_creation_file_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorCreationFile, forced: true)
-                }
-            }
+        let certificateAtPath = directoryCertificate + "/" + host + ".tmp"
+        let certificateToPath = directoryCertificate + "/" + host + ".der"
+    
+        if !NCUtilityFileSystem.shared.moveFile(atPath: certificateAtPath, toPath: certificateToPath) {
+            NCContentPresenter.shared.messageNotification("_error_", description: "_error_creation_file_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorCreationFile, forced: true)
         }
     }
     
-    private func saveX509Certificate(_ serverTrust: SecTrust, certName: String, directoryCertificate: String) {
+    private func saveX509Certificate(_ serverTrust: SecTrust, host: String, directoryCertificate: String) {
         
         if let currentServerCert = SecTrustGetCertificateAtIndex(serverTrust, 0) {
             
-            let certNamePath = directoryCertificate + "/" + certName
-            let certificateDetailsNamePath = directoryCertificate + "/" + NCGlobal.shared.certificateTmpV2 + ".txt"
+            let certNamePathTXT = directoryCertificate + "/" + host + ".txt"
             let data: CFData = SecCertificateCopyData(currentServerCert)
             let mem = BIO_new_mem_buf(CFDataGetBytePtr(data), Int32(CFDataGetLength(data)))
             let x509cert = d2i_X509_bio(mem, nil)
@@ -258,24 +219,24 @@ import Queuer
             } else {
                 
                 // save certificate
-                if FileManager.default.fileExists(atPath: certNamePath) {
-                    do {
-                        try FileManager.default.removeItem(atPath: certNamePath)
-                    } catch { }
-                }
-                let fileCert = fopen(certNamePath, "w")
-                if fileCert != nil {
-                    PEM_write_X509(fileCert, x509cert)
-                }
-                fclose(fileCert)
+//                if FileManager.default.fileExists(atPath: certNamePath) {
+//                    do {
+//                        try FileManager.default.removeItem(atPath: certNamePath)
+//                    } catch { }
+//                }
+//                let fileCert = fopen(certNamePath, "w")
+//                if fileCert != nil {
+//                    PEM_write_X509(fileCert, x509cert)
+//                }
+//                fclose(fileCert)
                 
                 // save details
-                if FileManager.default.fileExists(atPath: certificateDetailsNamePath) {
+                if FileManager.default.fileExists(atPath: certNamePathTXT) {
                     do {
-                        try FileManager.default.removeItem(atPath: certificateDetailsNamePath)
+                        try FileManager.default.removeItem(atPath: certNamePathTXT)
                     } catch { }
                 }
-                let fileCertInfo = fopen(certificateDetailsNamePath, "w")
+                let fileCertInfo = fopen(certNamePathTXT, "w")
                 if fileCertInfo != nil {
                     let output = BIO_new_fp(fileCertInfo, BIO_NOCLOSE)
                     X509_print_ex(output, x509cert, UInt(XN_FLAG_COMPAT), UInt(X509_FLAG_COMPAT))
@@ -290,6 +251,47 @@ import Queuer
         }
     }
     
+    func checkPushNotificationServerProxyCertificateUntrusted(viewController: UIViewController?, completion: @escaping (_ errorCode: Int)->()) {
+                
+        guard let host = URL(string: NCBrandOptions.shared.pushNotificationServerProxy)?.host else { return }
+        
+        NCCommunication.shared.checkServer(serverUrl: NCBrandOptions.shared.pushNotificationServerProxy) { (errorCode, errorDescription) in
+            
+            if errorCode == 0 {
+                
+                NCNetworking.shared.writeCertificate(host: host)
+                completion(errorCode)
+                
+            } else if errorCode == NSURLErrorServerCertificateUntrusted {
+                
+                let alertController = UIAlertController(title: NSLocalizedString("_ssl_certificate_untrusted_", comment: ""), message: NSLocalizedString("_connect_server_anyway_", comment: ""), preferredStyle: .alert)
+                            
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in
+                    NCNetworking.shared.writeCertificate(host: host)
+                    completion(0)
+                }))
+                
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in
+                    completion(errorCode)
+                }))
+                
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in
+                    if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController {
+                        let vcCertificateDetails = navigationController.topViewController as! NCViewCertificateDetails
+                        vcCertificateDetails.host = host
+                        viewController?.present(navigationController, animated: true)
+                    }
+                }))
+                
+                viewController?.present(alertController, animated: true)
+                
+            } else {
+                
+                completion(0)
+            }
+        }
+    }
+    
     //MARK: - Utility
     
     func cancelTaskWithUrl(_ url: URL) {

+ 3 - 1
iOSClient/Networking/NCNetworkingE2EE.swift

@@ -327,7 +327,9 @@ import Alamofire
                             
                             } else if errorCode == Int(CFNetworkErrors.cfurlErrorServerCertificateUntrusted.rawValue) {
                             
-                                CCUtility.setCertificateError(metadata.account)
+                                if let host = URL(string: metadata.urlBase)?.host {
+                                    NCNetworking.shared.certificatesError.append(host)
+                                }
                                 NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError)
                                                     
                             } else {

+ 3 - 3
iOSClient/Security/NCViewCertificateDetails.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="N7y-68-uFW">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="N7y-68-uFW">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -11,7 +11,7 @@
         <!--View Certificate Details-->
         <scene sceneID="tne-QT-ifu">
             <objects>
-                <viewController id="BYZ-38-t0r" customClass="NCViewCertificateDetails" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
+                <viewController id="BYZ-38-t0r" customClass="NCViewCertificateDetails" customModule="File_Provider_Extension" customModuleProvider="target" sceneMemberID="viewController">
                     <layoutGuides>
                         <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                         <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>

+ 6 - 6
iOSClient/Security/NCViewCertificateDetails.swift

@@ -38,22 +38,22 @@ class NCViewCertificateDetails: UIViewController  {
     @IBOutlet weak var scrollView: UIScrollView!
     @IBOutlet weak var textView: UITextView!
 
+    private let directoryCertificate = CCUtility.getDirectoryCerificates()!
     public var delegate: NCViewCertificateDetailsDelegate?
+    @objc public var host: String = ""
 
     // MARK: - View Life Cycle
 
     override func viewDidLoad() {
         super.viewDidLoad()
-        
+
         self.navigationItem.title = NSLocalizedString("_certificate_details_", comment: "")
-        
         buttonCancel.title = NSLocalizedString("_close_", comment: "")
         
-        let directoryCertificate = CCUtility.getDirectoryCerificates()!
-        let certificatePath = directoryCertificate + "/" + NCGlobal.shared.certificateTmpV2 + ".txt"
-        if FileManager.default.fileExists(atPath: certificatePath) {
+        let certNamePathTXT = directoryCertificate + "/" + host + ".txt"
+        if FileManager.default.fileExists(atPath: certNamePathTXT) {
             do {
-                let text = try String(contentsOfFile: certificatePath, encoding: .utf8)
+                let text = try String(contentsOfFile: certNamePathTXT, encoding: .utf8)
                 let font = UIFont.systemFont(ofSize: 13)
                 let attributes = [NSAttributedString.Key.font: font] as [NSAttributedString.Key : Any]
                 var contentRect = NSString(string: text).boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: 0), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil)

+ 26 - 0
iOSClient/Settings/CCManageAccount.m

@@ -149,6 +149,15 @@
         [row.cellConfig setObject:NCBrandColor.shared.label forKey:@"textLabel.textColor"];
         row.action.formSelector = @selector(certificateDetails:);
         [section addFormRow:row];
+        
+        row = [XLFormRowDescriptor formRowDescriptorWithTag:@"certificatePNDetails" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_certificate_pn_details_", nil)];
+        row.cellConfigAtConfigure[@"backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground;
+        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
+        [row.cellConfig setObject:[[UIImage imageNamed:@"lock-question"] imageWithColor:NCBrandColor.shared.gray size:25] forKey:@"imageView.image"];
+        [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"];
+        [row.cellConfig setObject:NCBrandColor.shared.label forKey:@"textLabel.textColor"];
+        row.action.formSelector = @selector(certificatePNDetails:);
+        [section addFormRow:row];
     }
     
     // Section : USER INFORMATION -------------------------------------------
@@ -501,8 +510,25 @@
     [self deselectFormRow:sender];
     
     UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCViewCertificateDetails" bundle:nil] instantiateInitialViewController];
+    NCViewCertificateDetails *viewController = (NCViewCertificateDetails *)navigationController.topViewController;
+
+    NSURL *url = [NSURL URLWithString:appDelegate.urlBase];
+    viewController.host = [url host];
         
     [self presentViewController:navigationController animated:YES completion:nil];
 }
 
+- (void)certificatePNDetails:(XLFormRowDescriptor *)sender
+{
+    [self deselectFormRow:sender];
+    
+    UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCViewCertificateDetails" bundle:nil] instantiateInitialViewController];
+    NCViewCertificateDetails *viewController = (NCViewCertificateDetails *)navigationController.topViewController;
+        
+    NSURL *url = [NSURL URLWithString: NCBrandOptions.shared.pushNotificationServerProxy];
+    viewController.host = [url host];
+
+    [self presentViewController:navigationController animated:YES completion:nil];
+}
+
 @end

+ 2 - 1
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -787,7 +787,8 @@
 "Passcodes didn't match. Try again." = "Passcodes didn't match. Try again.";
 "Delete"                    = "Delete";
 "Cancel"                    = "Cancel";
-"_certificate_details_"     = "Certificate details";
+"_certificate_details_"     = "Certificate Server details";
+"_certificate_pn_details_"  = "Certificate Push Notification details";
 "_save_as_scan_"            = "Save as scan";
 "_modify_"                  = "Modify";
 "_overwrite_original_"      = "Overwrite original";

+ 0 - 4
iOSClient/Utility/CCUtility.h

@@ -146,10 +146,6 @@
 
 + (NSData *)getDatabaseEncryptionKey;
 
-+ (BOOL)getCertificateError:(NSString *)account;
-+ (void)setCertificateError:(NSString *)account;
-+ (void)clearCertificateError:(NSString *)account;
-
 + (BOOL)getDisableLocalCacheAfterUpload;
 + (void)setDisableLocalCacheAfterUpload:(BOOL)disable;
 

+ 0 - 35
iOSClient/Utility/CCUtility.m

@@ -550,41 +550,6 @@
     [UICKeyChainStore setData:data forKey:@"databaseEncryptionKey" service:NCGlobal.shared.serviceShareKeyChain];
 }
 
-+ (BOOL)getCertificateError:(NSString *)account
-{
-    NSString *key = [@"certificateError" stringByAppendingString:account];
-    NSString *error = [UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain];
-    
-    if (error == nil) {
-        return false;
-    }
-    
-    return true;
-}
-
-+ (void)setCertificateError:(NSString *)account
-{
-    // In background do not write the error
-#if !defined(EXTENSION)
-    UIApplicationState state = [[UIApplication sharedApplication] applicationState];
-    if (state == UIApplicationStateBackground || state == UIApplicationStateInactive) {
-        return;
-    }
-    NSString *key = [@"certificateError" stringByAppendingString:account];
-    
-    [UICKeyChainStore setString:@"true" forKey:key service:NCGlobal.shared.serviceShareKeyChain];
-#else
-    return;
-#endif
-}
-
-+ (void)clearCertificateError:(NSString *)account
-{
-    NSString *key = [@"certificateError" stringByAppendingString:account];
-    
-    [UICKeyChainStore setString:nil forKey:key service:NCGlobal.shared.serviceShareKeyChain];
-}
-
 + (BOOL)getDisableLocalCacheAfterUpload
 {
     return [[UICKeyChainStore stringForKey:@"disableLocalCacheAfterUpload" service:NCGlobal.shared.serviceShareKeyChain] boolValue];