Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix authentication issues for macOS File Provider Extension #7240

Merged
merged 7 commits into from
Oct 11, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import NextcloudKit
import NextcloudFileProviderKit
import OSLog

let AuthenticationTimeouts: [UInt64] = [ // Have progressively longer timeouts to not hammer server
3_000_000_000, 6_000_000_000, 30_000_000_000, 60_000_000_000, 120_000_000_000, 300_000_000_000
]

extension FileProviderExtension: NSFileProviderServicing, ChangeNotificationInterface {
/*
This FileProviderExtension extension contains everything needed to communicate with the client.
Expand Down Expand Up @@ -100,14 +104,57 @@ extension FileProviderExtension: NSFileProviderServicing, ChangeNotificationInte
}
}

@objc func setupDomainAccount(user: String, serverUrl: String, password: String) {
let newNcAccount = Account(user: user, serverUrl: serverUrl, password: password)
@objc func setupDomainAccount(
user: String, userId: String, serverUrl: String, password: String
) {
let semaphore = DispatchSemaphore(value: 0)
var authAttemptState = AuthenticationAttemptResultState.connectionError // default
Task {
let authTestNcKit = NextcloudKit()
authTestNcKit.setup(user: user, userId: userId, password: password, urlBase: serverUrl)

// Retry a few times if we have a connection issue
for authTimeout in AuthenticationTimeouts {
authAttemptState = await authTestNcKit.tryAuthenticationAttempt()
guard authAttemptState == .connectionError else { break }

Logger.fileProviderExtension.info(
"\(user, privacy: .public) authentication try timed out. Trying again soon."
)
try? await Task.sleep(nanoseconds: authTimeout)
}
semaphore.signal()
}
semaphore.wait()

switch (authAttemptState) {
case .authenticationError:
Logger.fileProviderExtension.info(
"\(user, privacy: .public) authentication failed due to bad creds, stopping"
)
return
case .connectionError:
// Despite multiple connection attempts we are still getting connection issues, so quit.
Logger.fileProviderExtension.info(
"\(user, privacy: .public) authentication try failed, no connection."
)
return
case .success:
Logger.fileProviderExtension.info(
"""
Authenticated! Nextcloud account set up in File Provider extension.
User: \(user, privacy: .public) at server: \(serverUrl, privacy: .public)
"""
)
}

let newNcAccount = Account(user: user, id: userId, serverUrl: serverUrl, password: password)
guard newNcAccount != ncAccount else { return }
ncAccount = newNcAccount
ncKit.setup(
account: newNcAccount.ncKitAccount,
user: newNcAccount.username,
userId: newNcAccount.username,
userId: newNcAccount.id,
password: newNcAccount.password,
urlBase: newNcAccount.serverUrl,
userAgent: "Nextcloud-macOS/FileProviderExt",
Expand All @@ -118,11 +165,6 @@ extension FileProviderExtension: NSFileProviderServicing, ChangeNotificationInte
remoteInterface: ncKit, changeNotificationInterface: self, domain: domain
)
ncKit.setup(delegate: changeObserver)

Logger.fileProviderExtension.info(
"Nextcloud account set up in File Provider extension for user: \(user, privacy: .public) at server: \(serverUrl, privacy: .public)"
)

signalEnumeratorAfterAccountSetup()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ class FileProviderSocketLineProcessor: NSObject, LineProcessor {
delegate.removeAccountConfig()
} else if command == "ACCOUNT_DETAILS" {
guard let accountDetailsSubsequence = splitLine.last else { return }
let splitAccountDetails = accountDetailsSubsequence.split(separator: "~", maxSplits: 2)
let splitAccountDetails = accountDetailsSubsequence.split(separator: "~", maxSplits: 3)

let user = String(splitAccountDetails[0])
let serverUrl = String(splitAccountDetails[1])
let password = String(splitAccountDetails[2])
let userId = String(splitAccountDetails[1])
let serverUrl = String(splitAccountDetails[2])
let password = String(splitAccountDetails[3])

delegate.setupDomainAccount(user: user, serverUrl: serverUrl, password: password)
delegate.setupDomainAccount(user: user, userId: userId, serverUrl: serverUrl, password: password)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
#ifndef ClientCommunicationProtocol_h
#define ClientCommunicationProtocol_h

#import <Foundation/Foundation.h>

Check failure on line 18 in shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h

View workflow job for this annotation

GitHub Actions / build

shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h:18:9 [clang-diagnostic-error]

'Foundation/Foundation.h' file not found

@protocol ClientCommunicationProtocol

- (void)getExtensionAccountIdWithCompletionHandler:(void(^)(NSString *extensionAccountId, NSError *error))completionHandler;
- (void)configureAccountWithUser:(NSString *)user
userId:(NSString *)userId
serverUrl:(NSString *)serverUrl
password:(NSString *)password;
- (void)removeAccountConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi
completionHandler(accountUserId, nil)
}

func configureAccount(withUser user: String,
func configureAccount(withUser user: String,
userId: String,
serverUrl: String,
password: String) {
Logger.desktopClientConnection.info("Received configure account information over client communication service")
self.fpExtension.setupDomainAccount(user: user,
userId: userId,
serverUrl: serverUrl,
password: password)
}
Expand Down
8 changes: 5 additions & 3 deletions src/gui/macOS/fileprovidersocketcontroller.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/macOS/fileprovidersocketcontroller.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/macOS/fileprovidersocketcontroller.cpp

File src/gui/macOS/fileprovidersocketcontroller.cpp does not conform to Custom style guidelines. (lines 224)
* Copyright (C) 2022 by Claudio Cambra <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -213,13 +213,15 @@

const auto credentials = account->credentials();
Q_ASSERT(credentials);
const auto accountUser = account->davUser();
const auto accountUrl = account->url().toString();
const auto accountPassword = credentials->password();
const auto accountUser = credentials->user(); // User-provided username/email
const auto accountUserId = account->davUser(); // Backing user id on server
const auto accountUrl = account->url().toString(); // Server base URL
const auto accountPassword = credentials->password(); // Account password

// We cannot use colons as separators here due to "https://" in the url
const auto message = QString(QStringLiteral("ACCOUNT_DETAILS:") +
accountUser + "~" +
accountUserId + "~" +
accountUrl + "~" +
accountPassword);
sendMessage(message);
Expand Down
2 changes: 2 additions & 0 deletions src/gui/macOS/fileproviderxpc_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@
const auto account = accountState->account();
const auto credentials = account->credentials();
NSString *const user = credentials->user().toNSString();
NSString *const userId = account->davUser().toNSString();
NSString *const serverUrl = account->url().toString().toNSString();
NSString *const password = credentials->password().toNSString();

const auto clientCommService = (NSObject<ClientCommunicationProtocol> *)_clientCommServices.value(extensionAccountId);
[clientCommService configureAccountWithUser:user
userId:userId
serverUrl:serverUrl
password:password];
}
Expand Down
Loading