Skip to content

Commit

Permalink
Merge pull request #7240 from nextcloud/bugfix/mac-vfs-login-loop
Browse files Browse the repository at this point in the history
  • Loading branch information
claucambra authored Oct 11, 2024
2 parents 7b826d5 + 690303f commit b68da20
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 16 deletions.
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 @@ -21,6 +21,7 @@

- (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
Expand Up @@ -213,13 +213,15 @@ void FileProviderSocketController::sendAccountDetails() const

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

0 comments on commit b68da20

Please sign in to comment.