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
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
}
}
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)
}
}
}
// 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)
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)
}
}
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)
}
}
}
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
- }
- }
}
if (command == QStringLiteral("FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY")) {
_accountState = accountStateFromFileProviderDomainIdentifier(argument);
- sendAccountKeychainEntryKey();
+ sendAccountDetails();
return;
}
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);
}
void parseReceivedLine(const QString &receivedLine);
void requestFileProviderDomainInfo() const;
- void sendAccountKeychainEntryKey() const;
+ void sendAccountDetails() const;
private:
static AccountStatePtr accountStateFromFileProviderDomainIdentifier(const QString &domainIdentifier);