Browse Source

add Swifter

Signed-off-by: Marino Faggiana <marino@marinofaggiana.com>
Marino Faggiana 2 years ago
parent
commit
6a5d879f9e

+ 1 - 0
.swiftlint.yml

@@ -113,6 +113,7 @@ excluded:
   - iOSClient/Networking/NCNetworkingProcessUpload.swift
   - iOSClient/Networking/NCOperationQueue.swift
   - iOSClient/Networking/NCService.swift
+  - iOSClient/Networking/NCConfigServer.swift
   - iOSClient/Notification/NCNotification.swift
   - iOSClient/Recent/NCRecent.swift
   - iOSClient/Rename file/NCRenameFile.swift

+ 21 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -318,6 +318,8 @@
 		F77BB746289984CA0090FC19 /* UIViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77BB745289984CA0090FC19 /* UIViewController+Extension.swift */; };
 		F77BB748289985270090FC19 /* UITabBarController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77BB747289985270090FC19 /* UITabBarController+Extension.swift */; };
 		F77BB74A2899857B0090FC19 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77BB7492899857B0090FC19 /* UINavigationController+Extension.swift */; };
+		F77BC3EB293E5268005F2B08 /* Swifter in Frameworks */ = {isa = PBXBuildFile; productRef = F77BC3EA293E5268005F2B08 /* Swifter */; };
+		F77BC3ED293E528A005F2B08 /* NCConfigServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77BC3EC293E528A005F2B08 /* NCConfigServer.swift */; };
 		F77ED59128C9CE9D00E24ED0 /* ToolbarData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59028C9CE9D00E24ED0 /* ToolbarData.swift */; };
 		F77ED59328C9CEA000E24ED0 /* ToolbarWidgetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59228C9CEA000E24ED0 /* ToolbarWidgetProvider.swift */; };
 		F77ED59528C9CEA400E24ED0 /* ToolbarWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59428C9CEA300E24ED0 /* ToolbarWidgetView.swift */; };
@@ -922,6 +924,7 @@
 		F77BB745289984CA0090FC19 /* UIViewController+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extension.swift"; sourceTree = "<group>"; };
 		F77BB747289985270090FC19 /* UITabBarController+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITabBarController+Extension.swift"; sourceTree = "<group>"; };
 		F77BB7492899857B0090FC19 /* UINavigationController+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extension.swift"; sourceTree = "<group>"; };
+		F77BC3EC293E528A005F2B08 /* NCConfigServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCConfigServer.swift; sourceTree = "<group>"; };
 		F77ED59028C9CE9D00E24ED0 /* ToolbarData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarData.swift; sourceTree = "<group>"; };
 		F77ED59228C9CEA000E24ED0 /* ToolbarWidgetProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarWidgetProvider.swift; sourceTree = "<group>"; };
 		F77ED59428C9CEA300E24ED0 /* ToolbarWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarWidgetView.swift; sourceTree = "<group>"; };
@@ -1238,6 +1241,7 @@
 				F76DA941277B75870082465B /* KTVHTTPCache.xcframework in Frameworks */,
 				F7ED547C25EEA65400956C55 /* QRCodeReader in Frameworks */,
 				F788ECC7263AAAFA00ADC67F /* MarkdownKit in Frameworks */,
+				F77BC3EB293E5268005F2B08 /* Swifter in Frameworks */,
 				F7BB7E4727A18C56009B9F29 /* Parchment in Frameworks */,
 				F734B06628E75C0100E180D5 /* TLPhotoPicker in Frameworks */,
 				F770768E263A8C3400A1BA94 /* FloatingPanel in Frameworks */,
@@ -1566,6 +1570,7 @@
 				F70D8D8024A4A9BF000A5756 /* NCNetworkingProcessUpload.swift */,
 				F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */,
 				F755BD9A20594AC7008C5FBB /* NCService.swift */,
+				F77BC3EC293E528A005F2B08 /* NCConfigServer.swift */,
 			);
 			path = Networking;
 			sourceTree = "<group>";
@@ -2446,6 +2451,7 @@
 				F72AD70C28C24B93006CB92D /* NextcloudKit */,
 				F734B06528E75C0100E180D5 /* TLPhotoPicker */,
 				F77333872927A72100466E35 /* OpenSSL */,
+				F77BC3EA293E5268005F2B08 /* Swifter */,
 			);
 			productName = "Crypto Cloud";
 			productReference = F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */;
@@ -2603,6 +2609,7 @@
 				F783034028B511D200B84583 /* XCRemoteSwiftPackageReference "NextcloudKit" */,
 				F734B06428E75C0100E180D5 /* XCRemoteSwiftPackageReference "TLPhotoPicker" */,
 				F77333862927A72100466E35 /* XCRemoteSwiftPackageReference "OpenSSL" */,
+				F77BC3E9293E5268005F2B08 /* XCRemoteSwiftPackageReference "swifter" */,
 			);
 			productRefGroup = F7F67B9F1A24D27800EE80DA;
 			projectDirPath = "";
@@ -3124,6 +3131,7 @@
 				F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */,
 				F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */,
 				AF93471B27E2361E002537EE /* NCShareAdvancePermission.swift in Sources */,
+				F77BC3ED293E528A005F2B08 /* NCConfigServer.swift in Sources */,
 				F70753EB2542A99800972D44 /* NCViewerMediaPage.swift in Sources */,
 				F7FAFD3A28BFA948000777FE /* NCNotification+Menu.swift in Sources */,
 				F74C0436253F1CDC009762AB /* NCShares.swift in Sources */,
@@ -3989,6 +3997,14 @@
 				minimumVersion = 1.0.0;
 			};
 		};
+		F77BC3E9293E5268005F2B08 /* XCRemoteSwiftPackageReference "swifter" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/httpswift/swifter.git";
+			requirement = {
+				branch = stable;
+				kind = branch;
+			};
+		};
 		F783034028B511D200B84583 /* XCRemoteSwiftPackageReference "NextcloudKit" */ = {
 			isa = XCRemoteSwiftPackageReference;
 			repositoryURL = "https://github.com/nextcloud/NextcloudKit";
@@ -4204,6 +4220,11 @@
 			package = F77333862927A72100466E35 /* XCRemoteSwiftPackageReference "OpenSSL" */;
 			productName = OpenSSL;
 		};
+		F77BC3EA293E5268005F2B08 /* Swifter */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F77BC3E9293E5268005F2B08 /* XCRemoteSwiftPackageReference "swifter" */;
+			productName = Swifter;
+		};
 		F783030428B4C50600B84583 /* SVGKit */ = {
 			isa = XCSwiftPackageProductDependency;
 			package = F75E57A725BF0D61002B72C2 /* XCRemoteSwiftPackageReference "SVGKit" */;

+ 186 - 0
iOSClient/Networking/NCConfigServer.swift

@@ -0,0 +1,186 @@
+//
+//  NCConfigServer.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 05/12/22.
+//  Copyright © 2022 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+import Swifter
+import NextcloudKit
+
+@objc class NCConfigServer: NSObject, UIActionSheetDelegate {
+
+    // MARK: Singleton
+
+    @objc static let shared = NCConfigServer()
+
+    fileprivate override init() {
+
+    }
+
+    // Start service
+    @objc func startService(url: URL) {
+
+        let defaultSessionConfiguration = URLSessionConfiguration.default
+        let defaultSession = URLSession(configuration: defaultSessionConfiguration)
+
+        var urlRequest = URLRequest(url: url)
+        urlRequest.headers = NKCommon.shared.getStandardHeaders(nil, customUserAgent: nil)
+
+        let dataTask = defaultSession.dataTask(with: urlRequest) { (data, response, error) in
+            if let data = data {
+                DispatchQueue.main.async { self.start(data: data) }
+            }
+        }
+        dataTask.resume()
+    }
+
+    private enum ConfigState: Int {
+        case Stopped, Ready, InstalledConfig, BackToApp
+    }
+
+    internal let listeningPort: in_port_t = 8080
+    internal var configName: String = "Profile install"
+    private var localServer: HttpServer!
+    private var returnURL: String = ""
+    private var configData: Data!
+
+    private var serverState: ConfigState = .Stopped
+    private var startTime: NSDate!
+    private var registeredForNotifications = false
+    private var backgroundTask = UIBackgroundTaskIdentifier.invalid
+
+    deinit {
+        unregisterFromNotifications()
+    }
+
+    // MARK:- Control functions
+
+    internal func start(data: Data) {
+        self.configData = data
+        self.localServer = HttpServer()
+        self.setupHandlers()
+
+        let page = self.baseURL(pathComponent: "install/")
+        let url = URL(string: page)!
+        if UIApplication.shared.canOpenURL(url as URL) {
+            do {
+                try localServer.start(listeningPort, forceIPv4: false, priority: .default)
+
+                startTime = NSDate()
+                serverState = .Ready
+                registerForNotifications()
+                UIApplication.shared.openURL(url)
+            } catch let error as NSError {
+                self.stop()
+            }
+        }
+    }
+
+    internal func stop() {
+        if serverState != .Stopped {
+            serverState = .Stopped
+            unregisterFromNotifications()
+        }
+    }
+
+    // MARK:- Private functions
+
+    private func setupHandlers() {
+        localServer["/install"] = { request in
+            switch self.serverState {
+            case .Stopped:
+                return .notFound()
+            case .Ready:
+                self.serverState = .InstalledConfig
+                return HttpResponse.raw(200, "OK", ["Content-Type": "application/x-apple-aspen-config"], { writer in
+                    do {
+                        try writer.write(self.configData)
+                    } catch {
+                        print("Failed to write response data")
+                    }
+                })
+            case .InstalledConfig:
+                return .movedPermanently(self.returnURL)
+            case .BackToApp:
+                let page = self.basePage(pathComponent: nil)
+                return .ok(.html(page))
+            }
+        }
+    }
+
+    private func baseURL(pathComponent: String?) -> String {
+        var page = "http://localhost:\(listeningPort)"
+        if let component = pathComponent {
+            page += "/\(component)"
+        }
+        return page
+    }
+
+    private func basePage(pathComponent: String?) -> String {
+        var page = "<!doctype html><html>" + "<head><meta charset='utf-8'><title>\(self.configName)</title></head>"
+        if let component = pathComponent {
+            let script = "function load() {  window.location.href='\(self.baseURL(pathComponent: component))'; }window.setInterval(load, 800);"
+
+            page += "<script>\(script)</script>"
+        }
+        page += "<body></body></html>"
+        return page
+    }
+
+    private func returnedToApp() {
+        if serverState != .Stopped {
+            serverState = .BackToApp
+            localServer.stop()
+        }
+    }
+
+    private func registerForNotifications() {
+        if !registeredForNotifications {
+            let notificationCenter = NotificationCenter.default
+            notificationCenter.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
+            notificationCenter.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
+            registeredForNotifications = true
+        }
+    }
+
+    private func unregisterFromNotifications() {
+        if registeredForNotifications {
+            let notificationCenter = NotificationCenter.default
+            notificationCenter.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)
+            notificationCenter.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
+            registeredForNotifications = false
+        }
+    }
+
+    @objc internal func didEnterBackground(notification: NSNotification) {
+        if serverState != .Stopped {
+            startBackgroundTask()
+        }
+    }
+
+    @objc internal func willEnterForeground(notification: NSNotification) {
+        if backgroundTask != UIBackgroundTaskIdentifier.invalid {
+            stopBackgroundTask()
+            returnedToApp()
+        }
+    }
+
+    private func startBackgroundTask() {
+        let application = UIApplication.shared
+        backgroundTask = application.beginBackgroundTask(expirationHandler: {
+            DispatchQueue.main.async {
+                self.stopBackgroundTask()
+            }
+        })
+    }
+
+    private func stopBackgroundTask() {
+        if backgroundTask != UIBackgroundTaskIdentifier.invalid {
+            UIApplication.shared.endBackgroundTask(self.backgroundTask)
+            backgroundTask = UIBackgroundTaskIdentifier.invalid
+        }
+    }
+}

+ 24 - 1
iOSClient/Settings/NCSettings.m

@@ -99,7 +99,21 @@
     [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
     [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
     [section addFormRow:row];
-    
+
+    // Section : CARDAV --------------------------------------------------------------
+
+    section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_cardav_", nil)];
+    [form addFormSection:section];
+
+    row = [XLFormRowDescriptor formRowDescriptorWithTag:@"cardav" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_cardav_", nil)];
+    row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
+    [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
+    [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"];
+    [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
+    [row.cellConfig setObject:[[UIImage imageNamed:@"shield.checkerboard"] imageWithColor:NCBrandColor.shared.gray size:25] forKey:@"imageView.image"];
+    row.action.formSelector = @selector(CalDAVCardDAV:);
+    [section addFormRow:row];
+
     // Section : E2EEncryption --------------------------------------------------------------
 
     BOOL isE2EEEnabled = [[NCManageDatabase shared] getCapabilitiesServerBoolWithAccount:appDelegate.account elements:NCElementsJSON.shared.capabilitiesE2EEEnabled exists:false];
@@ -331,6 +345,15 @@
     [self presentViewController:browserWebVC animated:YES completion:nil];
 }
 
+- (void)CalDAVCardDAV:(XLFormRowDescriptor *)sender
+{
+    [self deselectFormRow:sender];
+
+    NSString *url = [appDelegate.urlBase stringByAppendingString:@"/remote.php/dav/provisioning/apple-provisioning.mobileconfig"];
+    [[NCConfigServer shared] startServiceWithUrl:[NSURL URLWithString: url]];
+}
+
+
 #pragma mark - Passcode
 
 - (void)didPerformBiometricValidationRequestInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController