Send account details over socket and simplify NextcloudAccount members, turn all...
authorClaudio Cambra <claudio.cambra@nextcloud.com>
Thu, 26 Jan 2023 22:01:31 +0000 (23:01 +0100)
committerClaudio Cambra <claudio.cambra@nextcloud.com>
Fri, 12 May 2023 05:21:15 +0000 (13:21 +0800)
Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderSocketLineProcessor.swift
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/NextcloudAccount.swift
src/gui/macOS/fileprovidersocketcontroller.cpp
src/gui/macOS/fileprovidersocketcontroller.h

index 128fab4baf5003f24d65cf769e40b6578a0bb836..9754380aa91426e3b6e1e240fe3dab83221880e8 100644 (file)
@@ -21,7 +21,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
     private let anchor = NSFileProviderSyncAnchor("an anchor".data(using: .utf8)!)
     private static let maxItemsPerFileProviderPage = 100
     var ncAccount: NextcloudAccount?
-    var serverUrl: URL?
+    var serverUrl: String?
     
     init(enumeratedItemIdentifier: NSFileProviderItemIdentifier, ncAccount: NextcloudAccount?) {
         self.enumeratedItemIdentifier = enumeratedItemIdentifier
@@ -34,7 +34,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
             if let itemMetadata = dbManager.itemMetadataFromFileProviderItemIdentifier(enumeratedItemIdentifier),
                let itemDirectoryMetadata = dbManager.parentDirectoryMetadataForItem(itemMetadata) {
 
-                self.serverUrl = URL(string: itemDirectoryMetadata.serverUrl + "/" + itemMetadata.fileName)
+                self.serverUrl = itemDirectoryMetadata.serverUrl + "/" + itemMetadata.fileName
             }
 
         }
@@ -133,33 +133,32 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
         completionHandler(metadatas)
     }
 
-    private static func readServerUrl(_ serverUrl: URL, ncAccount: NextcloudAccount, completionHandler: @escaping (_ metadatas: [NextcloudItemMetadataTable]?) -> Void) {
+    private static func readServerUrl(_ serverUrl: String, ncAccount: NextcloudAccount, completionHandler: @escaping (_ metadatas: [NextcloudItemMetadataTable]?) -> Void) {
         let dbManager = NextcloudFilesDatabaseManager.shared
-        let serverUrlPath = serverUrl.path
-        let ncKitAccount = ncAccount.ncKitAccount!
+        let ncKitAccount = ncAccount.ncKitAccount
         var directoryEtag: String?
 
-        if let directoryMetadata = dbManager.directoryMetadata(account: ncKitAccount, serverUrl: serverUrl.path) {
+        if let directoryMetadata = dbManager.directoryMetadata(account: ncKitAccount, serverUrl: serverUrl) {
             directoryEtag = directoryMetadata.etag
         }
 
-        NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlPath, depth: "0", showHiddenFiles: true) { account, files, _, error in
+        NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: true) { account, files, _, error in
             guard directoryEtag != files.first?.etag else {
-                finishReadServerUrl(serverUrlPath, ncKitAccount: ncKitAccount, completionHandler: completionHandler)
+                finishReadServerUrl(serverUrl, ncKitAccount: ncKitAccount, completionHandler: completionHandler)
                 return
             }
 
-            NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlPath, depth: "1", showHiddenFiles: true) { account, files, _, error in
+            NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: true) { account, files, _, error in
                 guard error == .success else {
-                    finishReadServerUrl(serverUrlPath, ncKitAccount: ncKitAccount, completionHandler: completionHandler)
+                    finishReadServerUrl(serverUrl, ncKitAccount: ncKitAccount, completionHandler: completionHandler)
                     return
                 }
 
                 DispatchQueue.global().async {
                     dbManager.convertNKFilesToItemMetadatas(files, account: ncKitAccount) { _, childDirectoriesMetadata, metadatas in
-                        dbManager.updateItemMetadatas(account: ncKitAccount, serverUrl: serverUrlPath, updatedMetadatas: metadatas)
-                        dbManager.updateDirectoryMetadatasFromItemMetadatas(account: ncKitAccount, parentDirectoryServerUrl: serverUrlPath, updatedDirectoryItemMetadatas: childDirectoriesMetadata)
-                        finishReadServerUrl(serverUrlPath, ncKitAccount: ncKitAccount, completionHandler: completionHandler)
+                        dbManager.updateItemMetadatas(account: ncKitAccount, serverUrl: serverUrl, updatedMetadatas: metadatas)
+                        dbManager.updateDirectoryMetadatasFromItemMetadatas(account: ncKitAccount, parentDirectoryServerUrl: serverUrl, updatedDirectoryItemMetadatas: childDirectoriesMetadata)
+                        finishReadServerUrl(serverUrl, ncKitAccount: ncKitAccount, completionHandler: completionHandler)
                     }
                 }
             }
index e8ad2becb90480209bed7632059e7f132f7f2162..b7891c2bfbe2e956f1174c50a232d195b872c91e 100644 (file)
@@ -66,19 +66,19 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension {
         // resolve the given identifier to a record in the model
         
         if identifier == .rootContainer {
-            guard let ncAccount = ncAccount, let ncKitAccount = ncAccount.ncKitAccount, let serverUrl = ncAccount.serverUrl else {
+            guard let ncAccount = ncAccount else {
                 completionHandler(nil, NSFileProviderError(.notAuthenticated))
                 return Progress()
             }
 
             let metadata = NextcloudItemMetadataTable()
 
-            metadata.account = ncKitAccount
+            metadata.account = ncAccount.ncKitAccount
             metadata.directory = true
             metadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue
             metadata.fileName = "root"
             metadata.fileNameView = "root"
-            metadata.serverUrl = serverUrl.path
+            metadata.serverUrl = ncAccount.serverUrl
             metadata.classFile = NKCommon.typeClassFile.directory.rawValue
 
             completionHandler(FileProviderItem(metadata: metadata, parentItemIdentifier: NSFileProviderItemIdentifier.rootContainer), nil)
@@ -136,7 +136,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension {
         socketClient?.sendMessage(message)
     }
 
-    func setupDomainAccount(keychainAccount:String) {
-        ncAccount = NextcloudAccount(withKeychainAccount:keychainAccount)
+    func setupDomainAccount(user: String, serverUrl: String, password: String) {
+        ncAccount = NextcloudAccount(user: user, serverUrl: serverUrl, password: password)
     }
 }
index 5589e101e70725b4ec649e2a420f7528980390c0..08aad6b3d38121a71a6933905624df2ad25fbab7 100644 (file)
@@ -35,10 +35,15 @@ class FileProviderSocketLineProcessor: NSObject, LineProcessor {
         NSLog("Received command: %@", command)
         if (command == "SEND_FILE_PROVIDER_DOMAIN_IDENTIFIER") {
             delegate.sendFileProviderDomainIdentifier()
-        } else if (command == "ACCOUNT_KEYCHAIN_NAME") {
-            guard let keychainAccountSubsequence = splitLine.last else { return }
-            let keychainAccountString = String(keychainAccountSubsequence)
-            delegate.setupDomainAccount(keychainAccount:keychainAccountString)
+        } else if (command == "ACCOUNT_DETAILS") {
+            guard let accountDetailsSubsequence = splitLine.last else { return }
+            let splitAccountDetails = accountDetailsSubsequence.split(separator: ":", maxSplits: 2)
+
+            let user = String(splitAccountDetails[0])
+            let serverUrl = String(splitAccountDetails[1])
+            let password = String(splitAccountDetails[2])
+
+            delegate.setupDomainAccount(user: user, serverUrl: serverUrl, password: password)
         }
     }
 }
index b8b000dc493af7ad14df33b5afe55093273bcf13..6af7046ad1189f02460108a986f2f0c02158a5f4 100644 (file)
@@ -17,63 +17,16 @@ import FileProvider
 
 class NextcloudAccount: NSObject {
     let webDavFilesUrlSuffix: String = "/remote.php/dav/files/"
-    let username, password, ncKitAccount: String?
-    let serverUrl, davFilesUrl: URL?
+    let username, password, ncKitAccount, serverUrl, davFilesUrl: String
 
-    var isNull: Bool {
-        return username?.isEmpty ?? false || serverUrl?.absoluteString.isEmpty ?? false
-    }
-
-    init?(withKeychainAccount account:String) {
-        // The client sets the account field in the keychain entry as a colon-separated string consisting of
-        // an account's username, its homeserver url, and the id of the account
-        guard let passwordData = NextcloudAccount.getUserPasswordFromKeychain(accountString: account),
-              let passwordString = String(data: passwordData, encoding: .utf8) else {
-
-            return nil
-        }
-
-        let keychainAccountSplit = account.split(separator: ":")
-        let usernameSubstring = keychainAccountSplit[0]
-        let serverUrlSubstring = keychainAccountSplit[1]
-        let clientAccountIdSubstring = keychainAccountSplit[2]
-
-        let usernameString = String(usernameSubstring)
-        let serverUrlString = String(serverUrlSubstring)
-        let clientAccountIdString = String(clientAccountIdSubstring)
-
-        guard let serverUrlUrl = URL(string: String(serverUrlString)) else {
-            return nil
-        }
-
-        let davFilesUrlUrl = serverUrlUrl.appendingPathComponent(webDavFilesUrlSuffix + usernameString)
-
-        username = usernameString
-        password = passwordString
-        ncKitAccount = usernameString + " " + serverUrlString
-        serverUrl = serverUrlUrl
-        davFilesUrl = davFilesUrlUrl
+    init(user: String, serverUrl: String, password: String) {
+        self.username = user
+        self.password = password
+        self.ncKitAccount = user + " " + serverUrl
+        self.serverUrl = serverUrl
+        self.davFilesUrl = serverUrl + webDavFilesUrlSuffix
 
         super.init()
     }
-
-    private static func getUserPasswordFromKeychain(accountString:String) -> Data? {
-        let query = [
-            kSecClass as String       : kSecClassGenericPassword,
-            kSecAttrAccount as String : accountString,
-            kSecReturnData as String  : kCFBooleanTrue!,
-            kSecMatchLimit as String  : kSecMatchLimitOne
-        ] as [String : Any]
-
-        var dataTypeRef: AnyObject? = nil
-
-        let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
-
-        if status == noErr {
-            return dataTypeRef as! Data?
-        } else {
-            return nil
-        }
-    }
 }
 
index a473b55814da679a3d8dd83b4fcc0ff914399f21..7dc1d4f92a26751c42fc08fda68a04b6991ab17a 100644 (file)
@@ -81,7 +81,7 @@ void FileProviderSocketController::parseReceivedLine(const QString &receivedLine
 
     if (command == QStringLiteral("FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY")) {
         _accountState = accountStateFromFileProviderDomainIdentifier(argument);
-        sendAccountKeychainEntryKey();
+        sendAccountDetails();
         return;
     }
 
@@ -135,19 +135,21 @@ void FileProviderSocketController::requestFileProviderDomainInfo() const
     sendMessage(requestMessage);
 }
 
-void FileProviderSocketController::sendAccountKeychainEntryKey() const
+void FileProviderSocketController::sendAccountDetails() const
 {
     Q_ASSERT(_accountState);
     const auto account = _accountState->account();
     Q_ASSERT(account);
     const auto credentials = account->credentials();
     Q_ASSERT(credentials);
+    const auto accountUser = credentials->user();
     const auto accountUrl = account->url().toString();
-    const auto accountUser = account->credentials()->user();
-    const auto accountId = account->id();
-    const auto accountKey = credentials->keychainKey(accountUrl, accountUser, accountId);
+    const auto accountPassword = credentials->password();
 
-    const auto message = QString(QStringLiteral("ACCOUNT_KEYCHAIN_NAME:") + accountKey);
+    const auto message = QString(QStringLiteral("ACCOUNT_DETAILS:") +
+                                 accountUser + ":" +
+                                 accountUrl + ":" +
+                                 accountPassword);
     sendMessage(message);
 }
 
index 67a4ebfd2fa0499076aa265517d0ae9a2de8e55c..e5142a057cb9f9f4a636ede0728b094c04136e32 100644 (file)
@@ -45,7 +45,7 @@ private slots:
 
     void parseReceivedLine(const QString &receivedLine);
     void requestFileProviderDomainInfo() const;
-    void sendAccountKeychainEntryKey() const;
+    void sendAccountDetails() const;
 
 private:
     static AccountStatePtr accountStateFromFileProviderDomainIdentifier(const QString &domainIdentifier);