Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 55 additions & 13 deletions iOSClient/Account/NCAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import NextcloudKit

@MainActor
class NCAccount: NSObject {
private static var accountsCheckingRemoteUser: Set<String> = []
let database = NCManageDatabase.shared
let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
let global = NCGlobal.shared
Expand Down Expand Up @@ -89,20 +90,10 @@ class NCAccount: NSObject {

func changeAccount(_ account: String, userProfile: NKUserProfile?, controller: NCMainTabBarController?) async {
if let tblAccount = await database.setAccountActiveAsync(account) {
// Set account
controller?.account = account
// Set User Profile
if let userProfile {
await database.setAccountUserProfileAsync(account: account, userProfile: userProfile)
}
// Networking Certificate
NCNetworking.shared.activeAccountCertificate(account: account)
// Subscribing Push Notification
await NCPushNotification.shared.subscribingNextcloudServerPushNotification(account: tblAccount.account, urlBase: tblAccount.urlBase)
// Start the service
Task(priority: .utility) {
await NCService().startRequestServicesServer(account: account, controller: controller)
}
// Capabilities
if let capabilities = await self.database.getCapabilities(account: account) {
// set theming color
Expand All @@ -111,13 +102,24 @@ class NCAccount: NSObject {
// Networking Process
await NCNetworkingProcess.shared.setCurrentAccount(account)

// Update the account and the file context together, before starting network requests.
controller?.account = account
NCNetworking.shared.activeAccountCertificate(account: account)

// Color
NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeTheming, userInfo: ["account": account])
// Notification
if let controller {
NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeUser, userInfo: ["account": account, "controller": controller])
NotificationCenter.default.post(name: Notification.Name(self.global.notificationCenterChangeUser), object: nil, userInfo: ["account": account, "controller": controller])
} else {
NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeUser, userInfo: ["account": account])
NotificationCenter.default.post(name: Notification.Name(self.global.notificationCenterChangeUser), object: nil, userInfo: ["account": account])
}

// Subscribing Push Notification
await NCPushNotification.shared.subscribingNextcloudServerPushNotification(account: tblAccount.account, urlBase: tblAccount.urlBase)
// Start the service
Task(priority: .utility) {
await NCService().startRequestServicesServer(account: account, controller: controller)
}
}
}
Expand Down Expand Up @@ -189,10 +191,35 @@ class NCAccount: NSObject {
}

func checkRemoteUser(account: String, controller: NCMainTabBarController?) async {
guard Self.accountsCheckingRemoteUser.insert(account).inserted else {
return
}
defer { Self.accountsCheckingRemoteUser.remove(account) }

let token = NCPreferences().getPassword(account: account)
guard let tblAccount = await NCManageDatabase.shared.getTableAccountAsync(predicate: NSPredicate(format: "account == %@", account)) else {
return
}
guard let session = NextcloudKit.shared.nkCommonInstance.nksessions.session(forAccount: account),
session.password == token else {
return
}

// A stored 401 may belong to an inconsistent or outdated request. Verify with the server.
let result = await NextcloudKit.shared.getUserProfileAsync(account: account, options: NKRequestOptions(checkInterceptor: false))
guard !Task.isCancelled,
remoteUserCredentialsMatch(session, token: token) else {
return
}
if result.error == .success, result.userProfile?.userId == session.userId {
NCNetworking.shared.removeUnauthorizedAccount(account)
return
}
guard result.responseData?.response?.statusCode == NCGlobal.shared.errorUnauthorized else {
// Network failures and other responses do not confirm invalid credentials.
return
}

let windowScene = SceneManager.shared.getWindowScene(controller: controller)
await showErrorBanner(windowScene: windowScene, text: String(format: NSLocalizedString("_account_unauthorized_", comment: ""), account), errorCode: NCGlobal.shared.errorUnauthorized)

Expand All @@ -206,6 +233,10 @@ class NCAccount: NSObject {
}

// REMOVE ACCOUNT
guard !Task.isCancelled,
remoteUserCredentialsMatch(session, token: token) else {
return
}
await NCAccount().deleteAccount(account, wipe: resultsWipe.wipe)
if resultsWipe.wipe {
let resultsSetWipe = await NextcloudKit.shared.setRemoteWipeCompletitionAsync(serverUrl: tblAccount.urlBase, token: token, account: tblAccount.account) { task in
Expand All @@ -219,11 +250,22 @@ class NCAccount: NSObject {
nkLog(debug: "Set Remote Wipe Completition error code: \(resultsSetWipe.error.errorCode)")
}

if account.count > 0 {
if !account.isEmpty, controller == nil || controller?.account == account {
await switchToFirstAvailableAccount(controller: controller)
}
}

private func remoteUserCredentialsMatch(_ session: NKSession, token: String) -> Bool {
guard let currentSession = NextcloudKit.shared.nkCommonInstance.nksessions.session(forAccount: session.account) else {
return false
}
return currentSession.urlBase == session.urlBase
&& currentSession.user == session.user
&& currentSession.userId == session.userId
&& currentSession.password == session.password
&& NCPreferences().getPassword(account: session.account) == token
}

/// Presents the login (or intro) screen if no account remains.
func switchToFirstAvailableAccount(controller: NCMainTabBarController?) async {
let accounts = await NCManageDatabase.shared.getAccountsAsync()
Expand Down
16 changes: 9 additions & 7 deletions iOSClient/Files/NCFiles.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class NCFiles: NCCollectionViewCommon {
self.serverUrl = utilityFileSystem.getHomeServer(session: session)
self.titleCurrentFolder = getNavigationTitle()

NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { notification in
Task { @MainActor in
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: .main) { notification in
MainActor.assumeIsolated {
guard let userInfo = notification.userInfo,
let account = userInfo["account"] as? String,
self.controller?.account == account else {
Expand All @@ -69,8 +69,8 @@ class NCFiles: NCCollectionViewCommon {
self.mainNavigationController?.menuPlusButton.menu = nil
self.mainNavigationController?.menuPlusButton.isEnabled = false

self.navigationController?.popToRootViewController(animated: false)
self.serverUrl = self.utilityFileSystem.getHomeServer(session: session)
self.navigationController?.popToRootViewController(animated: false)
self.isSearchingMode = false
self.isEditMode = false
self.fileSelect.removeAll()
Expand All @@ -87,10 +87,12 @@ class NCFiles: NCCollectionViewCommon {
self.titleCurrentFolder = self.getNavigationTitle()
self.navigationItem.title = self.titleCurrentFolder

await self.mainNavigationController?.menuPlus?.create(session: session)
await (self.navigationController as? NCMainNavigationController)?.setNavigationLeftItems()
await self.reloadDataSource()
await self.getServerData()
Task { @MainActor in
await self.mainNavigationController?.menuPlus?.create(session: session)
await (self.navigationController as? NCMainNavigationController)?.setNavigationLeftItems()
await self.reloadDataSource()
await self.getServerData()
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions iOSClient/Networking/NCNetworking+ServerError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ extension NCNetworking {
return true
}

func removeUnauthorizedAccount(_ account: String) {
guard let groupDefaults = UserDefaults(suiteName: NCBrandOptions.shared.capabilitiesGroup) else {
return
}
var accounts = groupDefaults.array(forKey: nkComm.groupDefaultsUnauthorized) as? [String] ?? []
accounts.removeAll { $0 == account }
groupDefaults.set(accounts, forKey: nkComm.groupDefaultsUnauthorized)
}

func removeServerErrorAccount(_ account: String) {
guard let groupDefaults = UserDefaults(suiteName: NCBrandOptions.shared.capabilitiesGroup) else {
return
Expand Down
Loading