diff --git a/Package.resolved b/Package.resolved index bff4ffdc..cfe19b9c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Alamofire/Alamofire", "state" : { - "revision" : "f455c2975872ccd2d9c81594c658af65716e9b9a", - "version" : "5.9.1" + "revision" : "513364f870f6bfc468f9d2ff0a95caccc10044c5", + "version" : "5.10.2" } }, { @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/WeTransfer/Mocker.git", "state" : { - "revision" : "5d86f27a8f80d4ba388bc1a379a3c2289a1f3d18", - "version" : "2.6.0" + "revision" : "95fa785c751f6bc40c49e112d433c3acf8417a97", + "version" : "3.0.2" } }, { diff --git a/Package.swift b/Package.swift index 05616674..f38c574d 100644 --- a/Package.swift +++ b/Package.swift @@ -22,10 +22,10 @@ let package = Package( targets: ["NextcloudKit"]), ], dependencies: [ - .package(url: "https://github.com/WeTransfer/Mocker.git", .upToNextMajor(from: "2.3.0")), - .package(url: "https://github.com/Alamofire/Alamofire", .upToNextMajor(from: "5.9.1")), - .package(url: "https://github.com/SwiftyJSON/SwiftyJSON", .upToNextMajor(from: "5.0.0")), - .package(url: "https://github.com/yahoojapan/SwiftyXMLParser", .upToNextMajor(from: "5.3.0")), + .package(url: "https://github.com/WeTransfer/Mocker.git", .upToNextMajor(from: "3.0.2")), + .package(url: "https://github.com/Alamofire/Alamofire", .upToNextMajor(from: "5.10.2")), + .package(url: "https://github.com/SwiftyJSON/SwiftyJSON", .upToNextMajor(from: "5.0.2")), + .package(url: "https://github.com/yahoojapan/SwiftyXMLParser", .upToNextMajor(from: "5.6.0")), ], targets: [ .target( diff --git a/Sources/NextcloudKit/Extensions/NSLock+Extension.swift b/Sources/NextcloudKit/Extensions/NSLock+Extension.swift new file mode 100644 index 00000000..9cb023ac --- /dev/null +++ b/Sources/NextcloudKit/Extensions/NSLock+Extension.swift @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Claudio Cambra +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation + +extension NSLock { + @discardableResult + func perform(_ block: () throws -> T) rethrows -> T { + lock() + defer { unlock() } + return try block() + } +} diff --git a/Sources/NextcloudKit/Models/NKDownloadLimit.swift b/Sources/NextcloudKit/Models/NKDownloadLimit.swift index b3722a4c..adb5d54b 100644 --- a/Sources/NextcloudKit/Models/NKDownloadLimit.swift +++ b/Sources/NextcloudKit/Models/NKDownloadLimit.swift @@ -9,7 +9,7 @@ import Foundation /// /// Each relates to a share of a file and is optionally provided by the [Files Download Limit](https://github.com/nextcloud/files_downloadlimit) app for Nextcloud server. /// -public class NKDownloadLimit: NSObject { +public struct NKDownloadLimit: Sendable { /// /// The number of downloads which already happened. /// diff --git a/Sources/NextcloudKit/Models/NKFile.swift b/Sources/NextcloudKit/Models/NKFile.swift index 422b1477..a44e273d 100644 --- a/Sources/NextcloudKit/Models/NKFile.swift +++ b/Sources/NextcloudKit/Models/NKFile.swift @@ -5,7 +5,7 @@ import Foundation -public class NKFile: NSObject { +public struct NKFile: Sendable { public var account = "" public var classFile = "" public var commentsUnread: Bool = false diff --git a/Sources/NextcloudKit/Models/NKFileProperty.swift b/Sources/NextcloudKit/Models/NKFileProperty.swift index 1da8f4d5..1df5e71e 100644 --- a/Sources/NextcloudKit/Models/NKFileProperty.swift +++ b/Sources/NextcloudKit/Models/NKFileProperty.swift @@ -5,9 +5,18 @@ import Foundation +#if swift(<6.0) public class NKFileProperty: NSObject { public var classFile: String = "" public var iconName: String = "" public var name: String = "" public var ext: String = "" } +#else +public struct NKFileProperty: Sendable { + public var classFile: String = "" + public var iconName: String = "" + public var name: String = "" + public var ext: String = "" +} +#endif diff --git a/Sources/NextcloudKit/Models/NKTermsOfService.swift b/Sources/NextcloudKit/Models/NKTermsOfService.swift index 5d8b41ff..61c17d77 100644 --- a/Sources/NextcloudKit/Models/NKTermsOfService.swift +++ b/Sources/NextcloudKit/Models/NKTermsOfService.swift @@ -19,7 +19,7 @@ public class NKTermsOfService: NSObject { self.data = decodedResponse.ocs.data return true } catch { - print("decode error:", error) + debugPrint("[DEBUG] decode error:", error) return false } } diff --git a/Sources/NextcloudKit/NKCommon.swift b/Sources/NextcloudKit/NKCommon.swift index 87107a2d..0b51b1b8 100644 --- a/Sources/NextcloudKit/NKCommon.swift +++ b/Sources/NextcloudKit/NKCommon.swift @@ -12,7 +12,7 @@ import MobileCoreServices import CoreServices #endif -public protocol NextcloudKitDelegate { +public protocol NextcloudKitDelegate: AnyObject, Sendable { func authenticationChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) @@ -25,13 +25,12 @@ public protocol NextcloudKitDelegate { func downloadComplete(fileName: String, serverUrl: String, etag: String?, date: Date?, dateLastModified: Date?, length: Int64, task: URLSessionTask, error: NKError) func uploadComplete(fileName: String, serverUrl: String, ocId: String?, etag: String?, date: Date?, size: Int64, task: URLSessionTask, error: NKError) - - func request(_ request: DataRequest, didParseResponse response: AFDataResponse) } -public class NKCommon: NSObject { +public struct NKCommon: Sendable { public var nksessions = ThreadSafeArray() public var delegate: NextcloudKitDelegate? + public var groupIdentifier: String? public let identifierSessionDownload: String = "com.nextcloud.nextcloudkit.session.download" public let identifierSessionUpload: String = "com.nextcloud.nextcloudkit.session.upload" @@ -82,7 +81,7 @@ public class NKCommon: NSObject { case xls = "xls" } - public struct UTTypeConformsToServer { + public struct UTTypeConformsToServer: Sendable { var typeIdentifier: String var classFile: String var editor: String @@ -91,9 +90,15 @@ public class NKCommon: NSObject { var account: String } +#if swift(<6.0) internal var utiCache = NSCache() internal var mimeTypeCache = NSCache() internal var filePropertiesCache = NSCache() +#else + internal var utiCache = [String: String]() + internal var mimeTypeCache = [String: String]() + internal var filePropertiesCache = [String: NKFileProperty]() +#endif internal var internalTypeIdentifiers = ThreadSafeArray() public var filenamePathLog: String = "" @@ -133,56 +138,77 @@ public class NKCommon: NSObject { // MARK: - Init - override init() { - super.init() - + init() { filenamePathLog = internalPathLog + "/" + internalFilenameLog } // MARK: - Type Identifier - public func clearInternalTypeIdentifier(account: String) { + mutating public func clearInternalTypeIdentifier(account: String) { internalTypeIdentifiers = internalTypeIdentifiers.filter({ $0.account != account }) } - public func addInternalTypeIdentifier(typeIdentifier: String, classFile: String, editor: String, iconName: String, name: String, account: String) { + mutating public func addInternalTypeIdentifier(typeIdentifier: String, classFile: String, editor: String, iconName: String, name: String, account: String) { if !internalTypeIdentifiers.contains(where: { $0.typeIdentifier == typeIdentifier && $0.editor == editor && $0.account == account}) { let newUTI = UTTypeConformsToServer(typeIdentifier: typeIdentifier, classFile: classFile, editor: editor, iconName: iconName, name: name, account: account) internalTypeIdentifiers.append(newUTI) } } - public func getInternalType(fileName: String, mimeType: String, directory: Bool, account: String) -> (mimeType: String, classFile: String, iconName: String, typeIdentifier: String, fileNameWithoutExt: String, ext: String) { + mutating public func getInternalType(fileName: String, mimeType: String, directory: Bool, account: String) -> (mimeType: String, classFile: String, iconName: String, typeIdentifier: String, fileNameWithoutExt: String, ext: String) { var ext = (fileName as NSString).pathExtension.lowercased() var mimeType = mimeType var classFile = "", iconName = "", typeIdentifier = "", fileNameWithoutExt = "" var inUTI: CFString? +#if swift(<6.0) if let cachedUTI = utiCache.object(forKey: ext as NSString) { inUTI = cachedUTI - } else { + } +#else + if let cachedUTI = utiCache[ext] { + inUTI = cachedUTI as CFString + } +#endif + if inUTI == nil { if let unmanagedFileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext as CFString, nil) { inUTI = unmanagedFileUTI.takeRetainedValue() if let inUTI { +#if swift(<6.0) utiCache.setObject(inUTI, forKey: ext as NSString) +#else + utiCache[ext] = inUTI as String +#endif } } } - if let inUTI = inUTI { + if let inUTI { typeIdentifier = inUTI as String fileNameWithoutExt = (fileName as NSString).deletingPathExtension // contentType detect if mimeType.isEmpty { +#if swift(<6.0) if let cachedMimeUTI = mimeTypeCache.object(forKey: inUTI) { mimeType = cachedMimeUTI as String - } else { + } +#else + if let cachedMimeUTI = mimeTypeCache[inUTI as String] { + mimeType = cachedMimeUTI + } +#endif + + if mimeType.isEmpty { if let mimeUTI = UTTypeCopyPreferredTagWithClass(inUTI, kUTTagClassMIMEType) { let mimeUTIString = mimeUTI.takeRetainedValue() as String mimeType = mimeUTIString +#if swift(<6.0) mimeTypeCache.setObject(mimeUTIString as NSString, forKey: inUTI) +#else + mimeTypeCache[inUTI as String] = mimeUTIString as String +#endif } } } @@ -197,12 +223,21 @@ public class NKCommon: NSObject { } else { var fileProperties: NKFileProperty +#if swift(<6.0) if let cachedFileProperties = filePropertiesCache.object(forKey: inUTI) { fileProperties = cachedFileProperties } else { fileProperties = getFileProperties(inUTI: inUTI) filePropertiesCache.setObject(fileProperties, forKey: inUTI) } +#else + if let cachedFileProperties = filePropertiesCache[inUTI as String] { + fileProperties = cachedFileProperties + } else { + fileProperties = getFileProperties(inUTI: inUTI) + filePropertiesCache[inUTI as String] = fileProperties + } +#endif classFile = fileProperties.classFile iconName = fileProperties.iconName @@ -335,7 +370,7 @@ public class NKCommon: NSObject { writer = nil chunk = 0 counterChunk(counter) - print("Counter: \(counter)") + debugPrint("[DEBUG] Counter: \(counter)") counter += 1 } @@ -390,7 +425,7 @@ public class NKCommon: NSObject { return session } - public func getStandardHeaders(account: String, options: NKRequestOptions? = nil) -> HTTPHeaders? { + public func getStandardHeaders(account: String, checkUnauthorized: Bool? = nil, options: NKRequestOptions? = nil) -> HTTPHeaders? { guard let session = nksessions.filter({ $0.account == account }).first else { return nil} var headers: HTTPHeaders = [] @@ -411,6 +446,10 @@ public class NKCommon: NSObject { for (key, value) in options?.customHeader ?? [:] { headers.update(name: key, value: value) } + headers.update(name: "X-NC-Account", value: account) + if let checkUnauthorized { + headers.update(name: "X-NC-CheckUnauthorized", value: checkUnauthorized.description) + } // Paginate if let options { if options.paginate { @@ -493,7 +532,7 @@ public class NKCommon: NSObject { let attributes = try FileManager.default.attributesOfItem(atPath: filePath) return attributes[FileAttributeKey.size] as? Int64 ?? 0 } catch { - print(error) + debugPrint(error) } return 0 } diff --git a/Sources/NextcloudKit/NKDataFileXML.swift b/Sources/NextcloudKit/NKDataFileXML.swift index eef09d65..268b3d20 100644 --- a/Sources/NextcloudKit/NKDataFileXML.swift +++ b/Sources/NextcloudKit/NKDataFileXML.swift @@ -7,7 +7,7 @@ import Foundation import SwiftyXMLParser class NKDataFileXML: NSObject { - let nkCommonInstance: NKCommon + var nkCommonInstance: NKCommon let requestBodyComments = """ @@ -147,64 +147,6 @@ class NKDataFileXML: NSObject { } func getRequestBodySearchMedia(createProperties: [NKProperties]?, removeProperties: [NKProperties] = []) -> String { - let request = """ - - - - - - """ + NKProperties.properties(createProperties: createProperties, removeProperties: removeProperties) + """ - - - - - %@ - infinity - - - - - <%@> - - - - - - - - - - - - - image/%% - - - - video/%% - - - - - - <%@> - %@ - - - <%@> - %@ - - - - - - - - """ - return request - } - - func getRequestBodySearchMediaWithLimit(createProperties: [NKProperties]?, removeProperties: [NKProperties] = []) -> String { let request = """ @@ -307,7 +249,7 @@ class NKDataFileXML: NSObject { let elements = xml["d:multistatus", "d:response"] for element in elements { - let file = NKFile() + var file = NKFile() if let href = element["d:href"].text { var fileNamePath = href if href.last == "/" { diff --git a/Sources/NextcloudKit/NKError.swift b/Sources/NextcloudKit/NKError.swift index f162a261..5d4db76d 100644 --- a/Sources/NextcloudKit/NKError.swift +++ b/Sources/NextcloudKit/NKError.swift @@ -32,7 +32,7 @@ extension OCSPath { static var ocsXMLMsg: Self { ["d:error", "s:message"] } } -public class NKError: NSObject { +public struct NKError: Sendable, Equatable { static let internalError = -9999 // Chunk error public static let chunkNoEnoughMemory = -9998 @@ -159,7 +159,7 @@ public class NKError: NSObject { self.responseData = responseData } - convenience init(httpResponse: HTTPURLResponse) { + init(httpResponse: HTTPURLResponse) { self.init(statusCode: httpResponse.statusCode, fallbackDescription: httpResponse.description) } @@ -181,7 +181,7 @@ public class NKError: NSObject { self.error = NSError(domain: NSCocoaErrorDomain, code: self.errorCode, userInfo: [NSLocalizedDescriptionKey: self.errorDescription]) } - public convenience init(error: AFError?, afResponse: T, responseData: Data? = nil) { + public init(error: AFError?, afResponse: T, responseData: Data? = nil) { if let errorCode = afResponse.response?.statusCode { guard let dataResponse = afResponse as? Alamofire.DataResponse, let errorData = dataResponse.data @@ -216,9 +216,13 @@ public class NKError: NSObject { } } - public override func isEqual(_ object: Any?) -> Bool { - if let object = object as? NKError { - return self.errorCode == object.errorCode && self.errorDescription == object.errorDescription + public static func == (lhs: NKError, rhs: NKError) -> Bool { + return lhs.errorCode == rhs.errorCode && lhs.errorDescription == rhs.errorDescription + } + + public static func == (lhs: NKError, rhs: NKError?) -> Bool { + if let rhs { + return lhs == rhs; } return false } diff --git a/Sources/NextcloudKit/NKInterceptor.swift b/Sources/NextcloudKit/NKInterceptor.swift new file mode 100644 index 00000000..795c23cb --- /dev/null +++ b/Sources/NextcloudKit/NKInterceptor.swift @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation +import Alamofire + +final class NKInterceptor: RequestInterceptor, Sendable { + let nkCommonInstance: NKCommon + + init(nkCommonInstance: NKCommon) { + self.nkCommonInstance = nkCommonInstance + } + + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { + // + // Detect if exists in the groupDefaults Unauthorized array the account + // + if let url: String = urlRequest.url?.absoluteString, + self.nkCommonInstance.levelLog > 0 { + debugPrint("[DEBUG] Interceptor request url: " + url) + } + + if let checkUnauthorized = urlRequest.value(forHTTPHeaderField: "X-NC-CheckUnauthorized"), + checkUnauthorized == "false" { + return completion(.success(urlRequest)) + } else if let account = urlRequest.value(forHTTPHeaderField: "X-NC-Account"), + let groupDefaults = UserDefaults(suiteName: NextcloudKit.shared.nkCommonInstance.groupIdentifier), + let unauthorizedArray = groupDefaults.array(forKey: "Unauthorized") as? [String], + unauthorizedArray.contains(account) { + self.nkCommonInstance.writeLog("[DEBUG] Unauthorized for account: \(account)") + let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 401)) + return completion(.failure(error)) + } + + completion(.success(urlRequest)) + } +} diff --git a/Sources/NextcloudKit/NKLogger.swift b/Sources/NextcloudKit/NKMonitor.swift similarity index 51% rename from Sources/NextcloudKit/NKLogger.swift rename to Sources/NextcloudKit/NKMonitor.swift index 5b85215b..8e83e13c 100644 --- a/Sources/NextcloudKit/NKLogger.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -5,7 +5,7 @@ import Foundation import Alamofire -final class NKLogger: EventMonitor { +final class NKMonitor: EventMonitor, Sendable { let nkCommonInstance: NKCommon init(nkCommonInstance: NKCommon) { @@ -26,8 +26,49 @@ final class NKLogger: EventMonitor { } func request(_ request: DataRequest, didParseResponse response: AFDataResponse) { - self.nkCommonInstance.delegate?.request(request, didParseResponse: response) + if let statusCode = response.response?.statusCode { + // + // Unauthorized, append the account in groupDefaults unauthorized array + // + if statusCode == 401, + let headerValue = request.request?.allHTTPHeaderFields?["X-NC-CheckUnauthorized"], + headerValue.lowercased() == "true", + let account = request.request?.allHTTPHeaderFields?["X-NC-Account"] as? String, + let groupDefaults = UserDefaults(suiteName: NextcloudKit.shared.nkCommonInstance.groupIdentifier) { + + var unauthorizedArray = groupDefaults.array(forKey: "Unauthorized") as? [String] ?? [] + if !unauthorizedArray.contains(account) { + unauthorizedArray.append(account) + groupDefaults.set(unauthorizedArray, forKey: "Unauthorized") + groupDefaults.synchronize() + } + + // + // Unavailable, append the account in groupDefaults unavailable array + // + } else if statusCode == 503, + let account = request.request?.allHTTPHeaderFields?["X-NC-Account"] as? String, + let groupDefaults = UserDefaults(suiteName: NextcloudKit.shared.nkCommonInstance.groupIdentifier) { + + var unavailableArray = groupDefaults.array(forKey: "Unavailable") as? [String] ?? [] + if !unavailableArray.contains(account) { + unavailableArray.append(account) + groupDefaults.set(unavailableArray, forKey: "Unavailable") + groupDefaults.synchronize() + } + } + + if let url = request.request?.url?.absoluteString, + let account = request.request?.allHTTPHeaderFields?["X-NC-Account"] as? String, + self.nkCommonInstance.levelLog > 0 { + debugPrint("[DEBUG] Monitor request url: \(url), status code \(statusCode), account: \(account)") + } + } + + // + // LOG + // guard let date = self.nkCommonInstance.convertDate(Date(), format: "yyyy-MM-dd' 'HH:mm:ss") else { return } let responseResultString = String("\(response.result)") let responseDebugDescription = String("\(response.debugDescription)") diff --git a/Sources/NextcloudKit/NKRequestOptions.swift b/Sources/NextcloudKit/NKRequestOptions.swift index 4b586a86..2c2baa68 100644 --- a/Sources/NextcloudKit/NKRequestOptions.swift +++ b/Sources/NextcloudKit/NKRequestOptions.swift @@ -16,6 +16,7 @@ public class NKRequestOptions: NSObject { var taskDescription: String? var createProperties: [NKProperties]? var removeProperties: [NKProperties] + var checkUnauthorized: Bool? var paginate: Bool var paginateToken: String? var paginateOffset: Int? @@ -32,6 +33,7 @@ public class NKRequestOptions: NSObject { taskDescription: String? = nil, createProperties: [NKProperties]? = nil, removeProperties: [NKProperties] = [], + checkUnauthorized: Bool? = nil, paginate: Bool = false, paginateToken: String? = nil, paginateOffset: Int? = nil, @@ -48,6 +50,7 @@ public class NKRequestOptions: NSObject { self.taskDescription = taskDescription self.createProperties = createProperties self.removeProperties = removeProperties + self.checkUnauthorized = checkUnauthorized self.paginate = paginate self.paginateToken = paginateToken self.paginateOffset = paginateOffset diff --git a/Sources/NextcloudKit/NKSession.swift b/Sources/NextcloudKit/NKSession.swift index ba019afc..018ecbd1 100644 --- a/Sources/NextcloudKit/NKSession.swift +++ b/Sources/NextcloudKit/NKSession.swift @@ -3,9 +3,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later import Foundation -import Alamofire +@preconcurrency import Alamofire -public class NKSession { +public struct NKSession: Sendable { public var urlBase: String public var user: String public var userId: String @@ -26,7 +26,8 @@ public class NKSession { public let sessionUploadBackgroundWWan: URLSession public let sessionUploadBackgroundExt: URLSession - init(urlBase: String, + init(nkCommonInstance: NKCommon, + urlBase: String, user: String, userId: String, password: String, @@ -51,7 +52,7 @@ public class NKSession { self.httpMaximumConnectionsPerHostInUpload = httpMaximumConnectionsPerHostInUpload self.requestCachePolicy = requestCachePolicy - let backgroundSessionDelegate = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance) + let backgroundSessionDelegate = NKBackground(nkCommonInstance: nkCommonInstance) /// Strange but works ?!?! let sharedCookieStorage = user + "@" + urlBase @@ -66,11 +67,11 @@ public class NKSession { configuration.httpCookieStorage = HTTPCookieStorage.sharedCookieStorage(forGroupContainerIdentifier: sharedCookieStorage) sessionData = Alamofire.Session(configuration: configuration, - delegate: NextcloudKitSessionDelegate(nkCommonInstance: NextcloudKit.shared.nkCommonInstance), - rootQueue: NextcloudKit.shared.nkCommonInstance.rootQueue, - requestQueue: NextcloudKit.shared.nkCommonInstance.requestQueue, - serializationQueue: NextcloudKit.shared.nkCommonInstance.serializationQueue, - eventMonitors: [NKLogger(nkCommonInstance: NextcloudKit.shared.nkCommonInstance)]) + delegate: NextcloudKitSessionDelegate(nkCommonInstance: nkCommonInstance), + rootQueue: nkCommonInstance.rootQueue, + requestQueue: nkCommonInstance.requestQueue, + serializationQueue: nkCommonInstance.serializationQueue, + eventMonitors: [NKMonitor(nkCommonInstance: nkCommonInstance)]) /// Session Download Background let configurationDownloadBackground = URLSessionConfiguration.background(withIdentifier: NKCommon().identifierSessionDownloadBackground) diff --git a/Sources/NextcloudKit/NextcloudKit+API.swift b/Sources/NextcloudKit/NextcloudKit+API.swift index a9ad6158..42b209d0 100644 --- a/Sources/NextcloudKit/NextcloudKit+API.swift +++ b/Sources/NextcloudKit/NextcloudKit+API.swift @@ -39,7 +39,7 @@ public extension NextcloudKit { return options.queue.async { completion(nil, .urlError) } } - internalSession.request(url, method: .head, parameters: nil, encoding: URLEncoding.default, headers: nil, interceptor: nil).onURLSessionTaskCreation { task in + unauthorizedSession.request(url, method: .head, encoding: URLEncoding.default).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -64,14 +64,18 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } let method = HTTPMethod(rawValue: method.uppercased()) - nkSession.sessionData.request(url, method: method, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: method, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -96,13 +100,17 @@ public extension NextcloudKit { completion: @escaping (_ account: String, _ externalFiles: [NKExternalSite], _ responseData: AFDataResponse?, _ error: NKError) -> Void) { var externalSites: [NKExternalSite] = [] let endpoint = "ocs/v2.php/apps/external/api/v1" + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, externalSites, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -164,7 +172,7 @@ public extension NextcloudKit { headers = [HTTPHeader.userAgent(userAgent)] } - internalSession.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + unauthorizedSession.request(url, method: .get, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -213,8 +221,12 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let nkSession = nkCommonInstance.getSession(account: account), - var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + var headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } if var etag = etag { @@ -222,7 +234,7 @@ public extension NextcloudKit { headers.update(name: "If-None-Match", value: etag) } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -252,10 +264,14 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ width: Int, _ height: Int, _ etag: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "index.php/core/preview?fileId=\(fileId)&x=\(width)&y=\(height)&a=\(crop)&mode=\(cropMode)&forceIcon=\(forceIcon)&mimeFallback=\(mimeFallback)" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + var headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, width, height, nil, nil, .urlError) } } @@ -264,7 +280,7 @@ public extension NextcloudKit { headers.update(name: "If-None-Match", value: etag) } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -293,15 +309,19 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ width: Int, _ height: Int, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "index.php/apps/files_trashbin/preview?fileId=\(fileId)&x=\(width)&y=\(height)&a=\(crop)&mode=\(cropMode)&forceIcon=\(forceIcon)&mimeFallback=\(mimeFallback)" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, width, height, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -327,10 +347,14 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ imageAvatar: UIImage?, _ imageOriginal: UIImage?, _ etag: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "index.php/avatar/\(user)/\(sizeImage)" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + var headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, nil, nil, .urlError) } } @@ -339,7 +363,7 @@ public extension NextcloudKit { headers.update(name: "If-None-Match", value: etag) } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -379,7 +403,19 @@ public extension NextcloudKit { #else #if os(iOS) - let screenScale = UIScreen.main.scale + var screenScale = 1.0 + if #available(iOS 13.0, *) { + let semaphore = DispatchSemaphore(value: 0) + Task { + screenScale = await UIScreen.main.scale + semaphore.signal() + } + semaphore.wait() + } else { + #if swift(<6.0) + screenScale = UIScreen.main.scale + #endif + } #else let screenScale = 1.0 #endif @@ -415,13 +451,17 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let url = serverUrl.asUrl, let nkSession = nkCommonInstance.getSession(account: account), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -444,14 +484,18 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ userProfile: NKUserProfile?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v2.php/cloud/user" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -513,14 +557,18 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v1.php/cloud/capabilities" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -550,13 +598,15 @@ public extension NextcloudKit { /// options.contentType = "application/json" /// - guard let nkSession = nkCommonInstance.getSession(account: account), - let url = nkCommonInstance.createStandardUrl(serverUrl: serverUrl, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + guard let url = nkCommonInstance.createStandardUrl(serverUrl: serverUrl, endpoint: endpoint, options: options) else { return options.queue.async { completion(account, false, nil, .urlError) } } + var headers: HTTPHeaders? + if let userAgent = options.customUserAgent { + headers = [HTTPHeader.userAgent(userAgent)] + } - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + unauthorizedSession.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -586,13 +636,15 @@ public extension NextcloudKit { /// options.contentType = "application/json" /// - guard let nkSession = nkCommonInstance.getSession(account: account), - let url = nkCommonInstance.createStandardUrl(serverUrl: serverUrl, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + guard let url = nkCommonInstance.createStandardUrl(serverUrl: serverUrl, endpoint: endpoint, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } + var headers: HTTPHeaders? + if let userAgent = options.customUserAgent { + headers = [HTTPHeader.userAgent(userAgent)] + } - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + unauthorizedSession.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -620,6 +672,10 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ activities: [NKActivity], _ activityFirstKnown: Int, _ activityLastGiven: Int, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } var activities: [NKActivity] = [] var activityFirstKnown = 0 var activityLastGiven = 0 @@ -644,11 +700,11 @@ public extension NextcloudKit { guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, activities, activityFirstKnown, activityLastGiven, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -717,14 +773,18 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ notifications: [NKNotifications]?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v2.php/apps/notifications/api/v2/notifications" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -791,8 +851,12 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let nkSession = nkCommonInstance.getSession(account: account), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } var url: URLConvertible? @@ -807,7 +871,7 @@ public extension NextcloudKit { } let method = HTTPMethod(rawValue: method) - nkSession.sessionData.request(urlRequest, method: method, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, method: method, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -831,6 +895,10 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ url: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v2.php/apps/dav/api/v1/direct" let parameters: [String: Any] = [ "fileId": fileId, @@ -838,11 +906,11 @@ public extension NextcloudKit { ] guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -869,13 +937,17 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v2.php/apps/security_guard/diagnostics" /// options.contentType = "application/json" /// guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } var urlRequest: URLRequest @@ -886,7 +958,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Assistant.swift b/Sources/NextcloudKit/NextcloudKit+Assistant.swift index 1b558de2..992e870d 100644 --- a/Sources/NextcloudKit/NextcloudKit+Assistant.swift +++ b/Sources/NextcloudKit/NextcloudKit+Assistant.swift @@ -18,7 +18,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -59,7 +59,7 @@ public extension NextcloudKit { } let parameters: [String: Any] = ["input": input, "type": typeId, "appId": appId, "identifier": identifier] - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -96,7 +96,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -133,7 +133,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -170,7 +170,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Comments.swift b/Sources/NextcloudKit/NextcloudKit+Comments.swift index 818bd325..65149708 100644 --- a/Sources/NextcloudKit/NextcloudKit+Comments.swift +++ b/Sources/NextcloudKit/NextcloudKit+Comments.swift @@ -32,7 +32,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -82,7 +82,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -129,7 +129,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -162,7 +162,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -207,7 +207,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Dashboard.swift b/Sources/NextcloudKit/NextcloudKit+Dashboard.swift index 160b0122..516a6bd5 100644 --- a/Sources/NextcloudKit/NextcloudKit+Dashboard.swift +++ b/Sources/NextcloudKit/NextcloudKit+Dashboard.swift @@ -19,7 +19,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - let dashboardRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + let dashboardRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -58,7 +58,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - let dashboardRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + let dashboardRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Download.swift b/Sources/NextcloudKit/NextcloudKit+Download.swift index 16081acb..ae08bc5a 100644 --- a/Sources/NextcloudKit/NextcloudKit+Download.swift +++ b/Sources/NextcloudKit/NextcloudKit+Download.swift @@ -33,7 +33,7 @@ public extension NextcloudKit { } destination = destinationFile - let request = nkSession.sessionData.download(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil, to: destination).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + let request = nkSession.sessionData.download(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance), to: destination).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription options.queue.async { taskHandler(task) } } .downloadProgress { progress in diff --git a/Sources/NextcloudKit/NextcloudKit+E2EE.swift b/Sources/NextcloudKit/NextcloudKit+E2EE.swift index 38f6af7d..7644a8db 100644 --- a/Sources/NextcloudKit/NextcloudKit+E2EE.swift +++ b/Sources/NextcloudKit/NextcloudKit+E2EE.swift @@ -25,7 +25,7 @@ public extension NextcloudKit { } let method: HTTPMethod = delete ? .delete : .put - nkSession.sessionData.request(url, method: method, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: method, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -77,7 +77,7 @@ public extension NextcloudKit { headers.update(name: "X-NC-E2EE-COUNTER", value: e2eCounter) } - nkSession.sessionData.request(url, method: method, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: method, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -122,7 +122,7 @@ public extension NextcloudKit { parameters["e2e-token"] = e2eToken } - nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -177,7 +177,7 @@ public extension NextcloudKit { headers.update(name: "X-NC-E2EE-SIGNATURE", value: signature) } - nkSession.sessionData.request(url, method: method, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: method, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -228,7 +228,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -272,7 +272,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -311,7 +311,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -352,7 +352,7 @@ public extension NextcloudKit { } let parameters = ["csr": certificate] - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -394,7 +394,7 @@ public extension NextcloudKit { } let parameters = ["privateKey": privateKey] - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -432,7 +432,7 @@ public extension NextcloudKit { let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -464,7 +464,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+FilesLock.swift b/Sources/NextcloudKit/NextcloudKit+FilesLock.swift index c9d5678e..54d2d493 100644 --- a/Sources/NextcloudKit/NextcloudKit+FilesLock.swift +++ b/Sources/NextcloudKit/NextcloudKit+FilesLock.swift @@ -24,7 +24,7 @@ public extension NextcloudKit { } headers.update(name: "X-User-Lock", value: "1") - nkSession.sessionData.request(url, method: method, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: method, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift b/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift index 80413c3d..8641ad10 100644 --- a/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift +++ b/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift @@ -19,7 +19,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Hovercard.swift b/Sources/NextcloudKit/NextcloudKit+Hovercard.swift index b5ba2dd6..2e192c91 100644 --- a/Sources/NextcloudKit/NextcloudKit+Hovercard.swift +++ b/Sources/NextcloudKit/NextcloudKit+Hovercard.swift @@ -19,7 +19,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Livephoto.swift b/Sources/NextcloudKit/NextcloudKit+Livephoto.swift index 5c49ad86..1e84cd70 100644 --- a/Sources/NextcloudKit/NextcloudKit+Livephoto.swift +++ b/Sources/NextcloudKit/NextcloudKit+Livephoto.swift @@ -32,7 +32,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Login.swift b/Sources/NextcloudKit/NextcloudKit+Login.swift index df5ce0d7..251a0a56 100644 --- a/Sources/NextcloudKit/NextcloudKit+Login.swift +++ b/Sources/NextcloudKit/NextcloudKit+Login.swift @@ -32,7 +32,7 @@ public extension NextcloudKit { return options.queue.async { completion(nil, nil, NKError(error: error)) } } - internalSession.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + unauthorizedSession.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -112,7 +112,7 @@ public extension NextcloudKit { headers = [HTTPHeader.userAgent(userAgent)] } - internalSession.request(url, method: .post, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + unauthorizedSession.request(url, method: .post, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -149,7 +149,7 @@ public extension NextcloudKit { headers = [HTTPHeader.userAgent(userAgent)] } - internalSession.request(url, method: .post, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + unauthorizedSession.request(url, method: .post, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+NCText.swift b/Sources/NextcloudKit/NextcloudKit+NCText.swift index 9d2fb097..c5f1661e 100644 --- a/Sources/NextcloudKit/NextcloudKit+NCText.swift +++ b/Sources/NextcloudKit/NextcloudKit+NCText.swift @@ -20,7 +20,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, editors, creators, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -90,7 +90,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .post, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -121,7 +121,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -174,7 +174,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .post, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+PushNotification.swift b/Sources/NextcloudKit/NextcloudKit+PushNotification.swift index 847093d9..18d29faa 100644 --- a/Sources/NextcloudKit/NextcloudKit+PushNotification.swift +++ b/Sources/NextcloudKit/NextcloudKit+PushNotification.swift @@ -15,10 +15,14 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ deviceIdentifier: String?, _ signature: String?, _ publicKey: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v2.php/apps/notifications/api/v2/push" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, nil, nil, .urlError) } } let parameters = [ @@ -27,7 +31,7 @@ public extension NextcloudKit { "proxyServer": proxyServerUrl ] - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -58,14 +62,18 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v2.php/apps/notifications/api/v2/push" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -105,7 +113,7 @@ public extension NextcloudKit { ] let headers = HTTPHeaders(arrayLiteral: .userAgent(userAgent)) - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -143,7 +151,7 @@ public extension NextcloudKit { ] let headers = HTTPHeaders(arrayLiteral: .userAgent(userAgent)) - nkSession.sessionData.request(url, method: .delete, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift b/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift index 172fb58c..55d5e587 100644 --- a/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift +++ b/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift @@ -12,17 +12,21 @@ public extension NextcloudKit { request: @escaping (DataRequest?) -> Void = { _ in }, taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ recommendations: [NKRecommendation]?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } let endpoint = "ocs/v2.php/apps/recommendations/api/v1/recommendations" /// options.contentType = "application/xml" /// guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } - let tosRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + let tosRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift b/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift index e6e25894..eb73e694 100644 --- a/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift +++ b/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift @@ -20,7 +20,7 @@ public extension NextcloudKit { } let parameters: [String: Any] = ["fileId": fileID] - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -55,7 +55,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -104,7 +104,7 @@ public extension NextcloudKit { } let parameters: [String: Any] = ["path": path, "template": templateId] - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -140,7 +140,7 @@ public extension NextcloudKit { } let parameters: [String: Any] = ["path": path] - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Search.swift b/Sources/NextcloudKit/NextcloudKit+Search.swift index 82fecb02..64b8e8df 100644 --- a/Sources/NextcloudKit/NextcloudKit+Search.swift +++ b/Sources/NextcloudKit/NextcloudKit+Search.swift @@ -40,7 +40,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, .urlError) } } - let requestUnifiedSearch = nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + let requestUnifiedSearch = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -131,7 +131,7 @@ public extension NextcloudKit { return nil } - let requestSearchProvider = nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + let requestSearchProvider = nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Share.swift b/Sources/NextcloudKit/NextcloudKit+Share.swift index 1b64ddbf..3ca60e91 100644 --- a/Sources/NextcloudKit/NextcloudKit+Share.swift +++ b/Sources/NextcloudKit/NextcloudKit+Share.swift @@ -67,7 +67,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: parameters.queryParameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, parameters: parameters.queryParameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -130,7 +130,7 @@ public extension NextcloudKit { "lookup": lookupString ] - nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -300,7 +300,7 @@ public extension NextcloudKit { parameters["attributes"] = attributes } - nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -385,7 +385,7 @@ public extension NextcloudKit { parameters["attributes"] = "[]" } - nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -423,7 +423,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift index 316c540b..1aaa19ab 100644 --- a/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift +++ b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift @@ -25,7 +25,7 @@ public extension NextcloudKit { nkSession .sessionData - .request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil) + .request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in if self.nkCommonInstance.levelLog > 0 { @@ -94,7 +94,7 @@ public extension NextcloudKit { nkSession .sessionData - .request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil) + .request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) .response(queue: self.nkCommonInstance.backgroundQueue) { response in if self.nkCommonInstance.levelLog > 0 { @@ -136,7 +136,7 @@ public extension NextcloudKit { nkSession .sessionData - .request(urlRequest) + .request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) .response(queue: self.nkCommonInstance.backgroundQueue) { response in if self.nkCommonInstance.levelLog > 0 { diff --git a/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift b/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift index 1ea602e3..862e5c00 100644 --- a/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift +++ b/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift @@ -19,7 +19,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - let tosRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + let tosRequest = nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -70,7 +70,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index 6438f082..3d3e2f69 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -43,7 +43,7 @@ public extension NextcloudKit { headers.update(name: "Overwrite", value: "true") } - let request = nkSession.sessionData.upload(fileNameLocalPathUrl, to: url, method: .put, headers: headers, interceptor: nil, fileManager: .default).validate(statusCode: 200..<300).onURLSessionTaskCreation(perform: { task in + let request = nkSession.sessionData.upload(fileNameLocalPathUrl, to: url, method: .put, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance), fileManager: .default).validate(statusCode: 200..<300).onURLSessionTaskCreation(perform: { task in task.taskDescription = options.taskDescription options.queue.async { taskHandler(task) } }) .uploadProgress { progress in @@ -161,7 +161,7 @@ public extension NextcloudKit { if error == .success { completion(NKError()) } else if error.errorCode == 404 { - NextcloudKit.shared.createFolder(serverUrlFileName: serverUrlChunkFolder, account: account, options: options) { _, _, _, _, error in + self.createFolder(serverUrlFileName: serverUrlChunkFolder, account: account, options: options) { _, _, _, _, error in completion(error) } } else { diff --git a/Sources/NextcloudKit/NextcloudKit+UserStatus.swift b/Sources/NextcloudKit/NextcloudKit+UserStatus.swift index 72260b4f..13ac6e39 100644 --- a/Sources/NextcloudKit/NextcloudKit+UserStatus.swift +++ b/Sources/NextcloudKit/NextcloudKit+UserStatus.swift @@ -22,7 +22,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, nil, nil, false, nil, false, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -73,7 +73,7 @@ public extension NextcloudKit { "statusType": String(status) ] - nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -115,7 +115,7 @@ public extension NextcloudKit { parameters["clearAt"] = String(clearAt) } - nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -162,7 +162,7 @@ public extension NextcloudKit { parameters["clearAt"] = String(clearAt) } - nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .put, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -197,7 +197,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, .urlError) } } - nkSession.sessionData.request(url, method: .delete, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -232,7 +232,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } - nkSession.sessionData.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -289,7 +289,7 @@ public extension NextcloudKit { "offset": String(offset) ] - nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: nil).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift index b29c461a..2948973a 100644 --- a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift +++ b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift @@ -12,9 +12,13 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ ocId: String?, _ date: Date?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let url = serverUrlFileName.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, nil, .urlError) } } let method = HTTPMethod(rawValue: "MKCOL") @@ -26,7 +30,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -57,9 +61,13 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let url = serverUrlFileName.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } var urlRequest: URLRequest @@ -70,7 +78,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -94,9 +102,13 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let url = serverUrlFileNameSource.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), - var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + var headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } let method = HTTPMethod(rawValue: "MOVE") @@ -114,7 +126,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -138,9 +150,13 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } guard let url = serverUrlFileNameSource.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), - var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + var headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } let method = HTTPMethod(rawValue: "COPY") @@ -159,7 +175,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -185,6 +201,10 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ files: [NKFile]?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } var files: [NKFile] = [] var serverUrlFileName = serverUrlFileName /// @@ -192,7 +212,7 @@ public extension NextcloudKit { /// guard let nkSession = nkCommonInstance.getSession(account: account), let url = serverUrlFileName.encodedToUrl, - var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + var headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } if depth == "0", serverUrlFileName.last == "/" { @@ -216,7 +236,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, files, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -313,8 +333,6 @@ public extension NextcloudKit { greaterDate: Any, elementDate: String, limit: Int, - showHiddenFiles: Bool, - includeHiddenFiles: [String] = [], account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, @@ -323,6 +341,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, nil, .urlError) } } let files: [NKFile] = [] + let elementDate = elementDate + "/" var greaterDateString: String?, lessDateString: String? let href = "/files/" + nkSession.userId + path if let lessDate = lessDate as? Date { @@ -335,25 +354,17 @@ public extension NextcloudKit { } else if let greaterDate = greaterDate as? Int { greaterDateString = String(greaterDate) } - if lessDateString == nil || greaterDateString == nil { + guard let lessDateString, let greaterDateString else { return options.queue.async { completion(account, files, nil, .invalidDate) } } - var requestBody = "" - - if let lessDateString, let greaterDateString { - if limit > 0 { - requestBody = String(format: NKDataFileXML(nkCommonInstance: self.nkCommonInstance).getRequestBodySearchMediaWithLimit(createProperties: options.createProperties, removeProperties: options.removeProperties), href, elementDate, elementDate, lessDateString, elementDate, greaterDateString, String(limit)) - } else { - requestBody = String(format: NKDataFileXML(nkCommonInstance: self.nkCommonInstance).getRequestBodySearchMedia(createProperties: options.createProperties, removeProperties: options.removeProperties), href, elementDate, elementDate, lessDateString, elementDate, greaterDateString) - } + guard let httpBody = String(format: NKDataFileXML(nkCommonInstance: self.nkCommonInstance).getRequestBodySearchMedia(createProperties: options.createProperties, removeProperties: options.removeProperties), href, elementDate, elementDate, lessDateString, elementDate, greaterDateString, String(limit)).data(using: .utf8) else { + return options.queue.async { completion(account, files, nil, .invalidData) } } - if let httpBody = requestBody.data(using: .utf8) { - search(serverUrl: nkSession.urlBase, httpBody: httpBody, showHiddenFiles: showHiddenFiles, includeHiddenFiles: includeHiddenFiles, account: account, options: options) { task in - taskHandler(task) - } completion: { account, files, responseData, error in - options.queue.async { completion(account, files, responseData, error) } - } + search(serverUrl: nkSession.urlBase, httpBody: httpBody, showHiddenFiles: false, includeHiddenFiles: [], account: account, options: options) { task in + taskHandler(task) + } completion: { account, files, responseData, error in + options.queue.async { completion(account, files, responseData, error) } } } @@ -365,11 +376,15 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ files: [NKFile]?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } /// options.contentType = "application/xml" /// guard let nkSession = nkCommonInstance.getSession(account: account), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } var files: [NKFile] = [] @@ -386,7 +401,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, files, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -414,11 +429,15 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } /// options.contentType = "application/xml" /// guard let nkSession = nkCommonInstance.getSession(account: account), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, .urlError) } } let serverUrlFileName = nkSession.urlBase + "/" + nkSession.dav + "/files/" + nkSession.userId + "/" + fileName @@ -437,7 +456,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -460,11 +479,15 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ files: [NKFile]?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } /// options.contentType = "application/xml" /// guard let nkSession = nkCommonInstance.getSession(account: account), - let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + let headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } let serverUrlFileName = nkSession.urlBase + "/" + nkSession.dav + "/files/" + nkSession.userId @@ -483,7 +506,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, files, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in @@ -511,11 +534,15 @@ public extension NextcloudKit { options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, completion: @escaping (_ account: String, _ items: [NKTrash]?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + var checkUnauthorized = true + if let optionsCheckUnauthorized = options.checkUnauthorized { + checkUnauthorized = optionsCheckUnauthorized + } /// options.contentType = "application/xml" /// guard let nkSession = nkCommonInstance.getSession(account: account), - var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { + var headers = nkCommonInstance.getStandardHeaders(account: account, checkUnauthorized: checkUnauthorized, options: options) else { return options.queue.async { completion(account, nil, nil, .urlError) } } var serverUrlFileName = nkSession.urlBase + "/" + nkSession.dav + "/trashbin/" + nkSession.userId + "/trash/" @@ -538,7 +565,7 @@ public extension NextcloudKit { return options.queue.async { completion(account, items, nil, NKError(error: error)) } } - nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in + nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in diff --git a/Sources/NextcloudKit/NextcloudKit.swift b/Sources/NextcloudKit/NextcloudKit.swift index ce7b8402..3c73daf6 100644 --- a/Sources/NextcloudKit/NextcloudKit.swift +++ b/Sources/NextcloudKit/NextcloudKit.swift @@ -11,25 +11,35 @@ import Alamofire import SwiftyJSON open class NextcloudKit { +#if swift(<6.0) public static let shared: NextcloudKit = { let instance = NextcloudKit() return instance }() +#endif #if !os(watchOS) private let reachabilityManager = Alamofire.NetworkReachabilityManager() #endif - public let nkCommonInstance = NKCommon() - internal lazy var internalSession: Alamofire.Session = { + public var nkCommonInstance = NKCommon() + internal lazy var unauthorizedSession: Alamofire.Session = { return Alamofire.Session(configuration: URLSessionConfiguration.af.default, delegate: NextcloudKitSessionDelegate(nkCommonInstance: nkCommonInstance), - eventMonitors: [NKLogger(nkCommonInstance: self.nkCommonInstance)]) + eventMonitors: [NKMonitor(nkCommonInstance: self.nkCommonInstance)]) }() +#if swift(<6.0) init() { #if !os(watchOS) startNetworkReachabilityObserver() #endif } +#else + public init() { +#if !os(watchOS) + startNetworkReachabilityObserver() +#endif + } +#endif deinit { #if !os(watchOS) @@ -39,8 +49,13 @@ open class NextcloudKit { // MARK: - Session setup - public func setup(delegate: NextcloudKitDelegate?, memoryCapacity: Int = 30, diskCapacity: Int = 500, removeAllCachedResponses: Bool = false) { + public func setup(groupIdentifier: String? = nil, + delegate: NextcloudKitDelegate? = nil, + memoryCapacity: Int = 30, + diskCapacity: Int = 500, + removeAllCachedResponses: Bool = false) { self.nkCommonInstance.delegate = delegate + self.nkCommonInstance.groupIdentifier = groupIdentifier /// Cache URLSession /// @@ -54,6 +69,14 @@ open class NextcloudKit { } } + public func setupLog(pathLog: String, + levelLog: Int, + copyLogToDocumentDirectory: Bool) { + self.nkCommonInstance.pathLog = pathLog + self.nkCommonInstance.levelLog = levelLog + self.nkCommonInstance.copyLogToDocumentDirectory = copyLogToDocumentDirectory + } + public func appendSession(account: String, urlBase: String, user: String, @@ -70,6 +93,7 @@ open class NextcloudKit { } let nkSession = NKSession( + nkCommonInstance: nkCommonInstance, urlBase: urlBase, user: user, userId: userId, @@ -94,7 +118,7 @@ open class NextcloudKit { userAgent: String? = nil, nextcloudVersion: Int? = nil, replaceWithAccount: String? = nil) { - guard let nkSession = nkCommonInstance.nksessions.filter({ $0.account == account }).first else { return } + guard var nkSession = nkCommonInstance.nksessions.filter({ $0.account == account }).first else { return } if let urlBase { nkSession.urlBase = urlBase } diff --git a/Sources/NextcloudKit/NextcloudKitBackground.swift b/Sources/NextcloudKit/NextcloudKitBackground.swift index 8b7da1ec..2a80b817 100644 --- a/Sources/NextcloudKit/NextcloudKitBackground.swift +++ b/Sources/NextcloudKit/NextcloudKitBackground.swift @@ -4,7 +4,7 @@ import Foundation -public class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDelegate, URLSessionDownloadDelegate { +public final class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDelegate, URLSessionDownloadDelegate { let nkCommonInstance: NKCommon public init(nkCommonInstance: NKCommon) { @@ -19,18 +19,29 @@ public class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDelegate, taskDescription: String? = nil, account: String) -> URLSessionDownloadTask? { var url: URL? + let groupDefaults = UserDefaults(suiteName: NextcloudKit.shared.nkCommonInstance.groupIdentifier) + if serverUrlFileName is URL { url = serverUrlFileName as? URL } else if serverUrlFileName is String || serverUrlFileName is NSString { url = (serverUrlFileName as? String)?.encodedToUrl as? URL } - guard let nkSession = nkCommonInstance.getSession(account: account) else { + + if let unauthorizedArray = groupDefaults?.array(forKey: "Unauthorized") as? [String], + unauthorizedArray.contains(account) { + return nil + } + + guard let nkSession = nkCommonInstance.getSession(account: account), + let urlForRequest = url + else { return nil } - guard let urlForRequest = url else { return nil } var request = URLRequest(url: urlForRequest) let loginString = "\(nkSession.user):\(nkSession.password)" - guard let loginData = loginString.data(using: String.Encoding.utf8) else { + + guard let loginData = loginString.data(using: String.Encoding.utf8) + else { return nil } let base64LoginString = loginData.base64EncodedString() @@ -58,15 +69,25 @@ public class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDelegate, sessionIdentifier: String) -> URLSessionUploadTask? { var url: URL? var uploadSession: URLSession? - guard let nkSession = nkCommonInstance.getSession(account: account) else { return nil } + let groupDefaults = UserDefaults(suiteName: NextcloudKit.shared.nkCommonInstance.groupIdentifier) + if serverUrlFileName is URL { url = serverUrlFileName as? URL } else if serverUrlFileName is String || serverUrlFileName is NSString { url = (serverUrlFileName as? String)?.encodedToUrl as? URL } - guard let urlForRequest = url else { + + if let unauthorizedArray = groupDefaults?.array(forKey: "Unauthorized") as? [String], + unauthorizedArray.contains(account) { + return nil + } + + guard let nkSession = nkCommonInstance.getSession(account: account), + let urlForRequest = url + else { return nil } + var request = URLRequest(url: urlForRequest) let loginString = "\(nkSession.user):\(nkSession.password)" guard let loginData = loginString.data(using: String.Encoding.utf8) else { @@ -139,13 +160,13 @@ public class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDelegate, } var nkError: NKError = .success - if let httpResponse = (task.response as? HTTPURLResponse) { - if httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 { + if let response = (task.response as? HTTPURLResponse) { + if response.statusCode >= 200 && response.statusCode < 300 { if let error = error { nkError = NKError(error: error) } } else { - nkError = NKError(httpResponse: httpResponse) + nkError = NKError(httpResponse: response) } } else { if let error = error { diff --git a/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift b/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift index c8b42707..9d9c65ce 100644 --- a/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift +++ b/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift @@ -14,15 +14,11 @@ import Alamofire import SwiftyJSON final class NextcloudKitSessionDelegate: SessionDelegate { - public var nkCommonInstance: NKCommon? + public let nkCommonInstance: NKCommon? - override public init(fileManager: FileManager = .default) { - super.init(fileManager: fileManager) - } - - convenience init(nkCommonInstance: NKCommon?) { - self.init() + public init(fileManager: FileManager = .default, nkCommonInstance: NKCommon? = nil) { self.nkCommonInstance = nkCommonInstance + super.init(fileManager: fileManager) } public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { diff --git a/Sources/NextcloudKit/Utils/FileAutoRenamer.swift b/Sources/NextcloudKit/Utils/FileAutoRenamer.swift index ca0d508a..632475ca 100644 --- a/Sources/NextcloudKit/Utils/FileAutoRenamer.swift +++ b/Sources/NextcloudKit/Utils/FileAutoRenamer.swift @@ -12,47 +12,38 @@ import Foundation // Copyright © 2024 Marino Faggiana. All rights reserved. // -public class FileAutoRenamer { - public static let shared: FileAutoRenamer = { - let instance = FileAutoRenamer() - return instance - }() - - private var forbiddenFileNameCharacters: [String] = [] - - private var forbiddenFileNameExtensions: [String] = [] { - didSet { - forbiddenFileNameExtensions = forbiddenFileNameExtensions.map({$0.lowercased()}) - } - } +public final class FileAutoRenamer: Sendable { + private let forbiddenFileNameCharacters: [String] + private let forbiddenFileNameExtensions: [String] private let replacement = "_" - public func setup(forbiddenFileNameCharacters: [String], forbiddenFileNameExtensions: [String]) { + public init(forbiddenFileNameCharacters: [String] = [], forbiddenFileNameExtensions: [String] = []) { self.forbiddenFileNameCharacters = forbiddenFileNameCharacters - self.forbiddenFileNameExtensions = forbiddenFileNameExtensions + self.forbiddenFileNameExtensions = forbiddenFileNameExtensions.map { $0.lowercased() } } public func rename(filename: String, isFolderPath: Bool = false) -> String { var pathSegments = filename.split(separator: "/", omittingEmptySubsequences: false).map { String($0) } + var mutableForbiddenFileNameCharacters = self.forbiddenFileNameCharacters if isFolderPath { - forbiddenFileNameCharacters.removeAll { $0 == "/" } + mutableForbiddenFileNameCharacters.removeAll { $0 == "/" } } pathSegments = pathSegments.map { segment in var modifiedSegment = segment - forbiddenFileNameCharacters.forEach { forbiddenChar in + if mutableForbiddenFileNameCharacters.contains(" ") { + modifiedSegment = modifiedSegment.trimmingCharacters(in: .whitespaces) + } + + mutableForbiddenFileNameCharacters.forEach { forbiddenChar in if modifiedSegment.contains(forbiddenChar) { modifiedSegment = modifiedSegment.replacingOccurrences(of: forbiddenChar, with: replacement, options: .caseInsensitive) } } - if forbiddenFileNameExtensions.contains(" ") { - modifiedSegment = modifiedSegment.trimmingCharacters(in: .whitespaces) - } - // Replace forbidden extension, if any (ex. .part -> _part) forbiddenFileNameExtensions.forEach { forbiddenExtension in if modifiedSegment.lowercased().hasSuffix(forbiddenExtension) && isFullExtension(forbiddenExtension) { @@ -77,6 +68,11 @@ public class FileAutoRenamer { modifiedSegment.append(".\(fileExtension.lowercased())") } + if modifiedSegment.hasPrefix(".") { + modifiedSegment.remove(at: modifiedSegment.startIndex) + modifiedSegment = replacement + modifiedSegment + } + return modifiedSegment } @@ -101,7 +97,7 @@ public class FileAutoRenamer { let range = NSRange(location: 0, length: filename.utf16.count) return regex.stringByReplacingMatches(in: filename, options: [], range: range, withTemplate: "") } catch { - print("Could not remove printable unicode characters.") + debugPrint("[DEBUG] Could not remove printable unicode characters.") return filename } } diff --git a/Sources/NextcloudKit/Utils/FileNameValidator.swift b/Sources/NextcloudKit/Utils/FileNameValidator.swift index 52dc05c1..12320712 100644 --- a/Sources/NextcloudKit/Utils/FileNameValidator.swift +++ b/Sources/NextcloudKit/Utils/FileNameValidator.swift @@ -4,61 +4,39 @@ import Foundation -public class FileNameValidator { - public static let shared: FileNameValidator = { - let instance = FileNameValidator() - return instance - }() - - private var forbiddenFileNames: [String] = [] { - didSet { - forbiddenFileNames = forbiddenFileNames.map({$0.uppercased()}) - } - } - - private var forbiddenFileNameBasenames: [String] = [] { - didSet { - forbiddenFileNameBasenames = forbiddenFileNameBasenames.map({$0.uppercased()}) - } - } - - private var forbiddenFileNameCharacters: [String] = [] - - private var forbiddenFileNameExtensions: [String] = [] { - didSet { - forbiddenFileNameExtensions = forbiddenFileNameExtensions.map({$0.uppercased()}) - } +public final class FileNameValidator: Sendable { + private let forbiddenFileNames: [String] + private let forbiddenFileNameBasenames: [String] + private let forbiddenFileNameCharacters: [String] + private let forbiddenFileNameExtensions: [String] + + public func fileWithSpaceError() -> NKError { + NKError(errorCode: NSURLErrorCannotCreateFile, errorDescription: NSLocalizedString("_file_name_validator_error_space_", value: "Name must not contain spaces at the beginning or end.", comment: "")) } - public let fileWithSpaceError = NKError(errorCode: NSURLErrorCannotCreateFile, errorDescription: NSLocalizedString("_file_name_validator_error_space_", value: "Name must not contain spaces at the beginning or end.", comment: "")) - - public var fileReservedNameError: NKError { + public func fileReservedNameError(templateString: String) -> NKError { let errorMessageTemplate = NSLocalizedString("_file_name_validator_error_reserved_name_", value: "\"%@\" is a forbidden name.", comment: "") let errorMessage = String(format: errorMessageTemplate, templateString) return NKError(errorCode: NSURLErrorCannotCreateFile, errorDescription: errorMessage) } - public var fileForbiddenFileExtensionError: NKError { - let errorMessageTemplate = NSLocalizedString("_file_name_validator_error_forbidden_file_extension_", value: "\".%@\" is a forbidden file extension.", comment: "") + public func fileForbiddenFileExtensionError(templateString: String) -> NKError { + let errorMessageTemplate = NSLocalizedString("_file_name_validator_error_forbidden_file_extension_", value: ".\"%@\" is a forbidden file extension.", comment: "") let errorMessage = String(format: errorMessageTemplate, templateString) return NKError(errorCode: NSURLErrorCannotCreateFile, errorDescription: errorMessage) } - public var fileInvalidCharacterError: NKError { + public func fileInvalidCharacterError(templateString: String) -> NKError { let errorMessageTemplate = NSLocalizedString("_file_name_validator_error_invalid_character_", value: "Name contains an invalid character: \"%@\".", comment: "") let errorMessage = String(format: errorMessageTemplate, templateString) return NKError(errorCode: NSURLErrorCannotCreateFile, errorDescription: errorMessage) } - private var templateString = "" - - private init() {} - - public func setup(forbiddenFileNames: [String], forbiddenFileNameBasenames: [String], forbiddenFileNameCharacters: [String], forbiddenFileNameExtensions: [String]) { - self.forbiddenFileNames = forbiddenFileNames - self.forbiddenFileNameBasenames = forbiddenFileNameBasenames + public init(forbiddenFileNames: [String], forbiddenFileNameBasenames: [String], forbiddenFileNameCharacters: [String], forbiddenFileNameExtensions: [String]) { + self.forbiddenFileNames = forbiddenFileNames.map { $0.uppercased() } + self.forbiddenFileNameBasenames = forbiddenFileNameBasenames.map { $0.uppercased() } self.forbiddenFileNameCharacters = forbiddenFileNameCharacters - self.forbiddenFileNameExtensions = forbiddenFileNameExtensions + self.forbiddenFileNameExtensions = forbiddenFileNameExtensions.map { $0.uppercased() } } public func checkFileName(_ filename: String) -> NKError? { @@ -68,23 +46,20 @@ public class FileNameValidator { if forbiddenFileNames.contains(filename.uppercased()) || forbiddenFileNames.contains(filename.withRemovedFileExtension.uppercased()) || forbiddenFileNameBasenames.contains(filename.uppercased()) || forbiddenFileNameBasenames.contains(filename.withRemovedFileExtension.uppercased()) { - templateString = filename - return fileReservedNameError + return fileReservedNameError(templateString: filename) } for fileNameExtension in forbiddenFileNameExtensions { if fileNameExtension == " " { if filename.uppercased().hasSuffix(fileNameExtension) || filename.uppercased().hasPrefix(fileNameExtension) { - return fileWithSpaceError + return fileWithSpaceError() } } else if filename.uppercased().hasSuffix(fileNameExtension.uppercased()) { if fileNameExtension == " " { - return fileWithSpaceError + return fileWithSpaceError() } - templateString = filename.fileExtension - - return fileForbiddenFileExtensionError + return fileForbiddenFileExtensionError(templateString: filename.fileExtension) } } @@ -96,7 +71,7 @@ public class FileNameValidator { .allSatisfy { checkFileName(String($0)) == nil } } - public func isFileHidden(_ name: String) -> Bool { + public static func isFileHidden(_ name: String) -> Bool { return !name.isEmpty && name.first == "." } @@ -106,8 +81,7 @@ public class FileNameValidator { let range = NSRange(location: 0, length: charAsString.utf16.count) if regex.firstMatch(in: charAsString, options: [], range: range) != nil { - templateString = charAsString - return fileInvalidCharacterError + return fileInvalidCharacterError(templateString: charAsString) } } return nil diff --git a/Sources/NextcloudKit/Utils/ThreadSafeArray.swift b/Sources/NextcloudKit/Utils/ThreadSafeArray.swift index 1dec61d1..fae38414 100644 --- a/Sources/NextcloudKit/Utils/ThreadSafeArray.swift +++ b/Sources/NextcloudKit/Utils/ThreadSafeArray.swift @@ -7,14 +7,13 @@ import Foundation /// A thread-safe array. -public class ThreadSafeArray { +public struct ThreadSafeArray: Sendable { private var array = [Element]() - private let queue = DispatchQueue(label: "com.nextcloud.ThreadSafeArray", attributes: .concurrent) public init() { } - public convenience init(_ array: [Element]) { + public init(_ array: [Element]) { self.init() self.array = array } @@ -26,37 +25,27 @@ public extension ThreadSafeArray { /// The first element of the collection. var first: Element? { - var result: Element? - queue.sync { result = self.array.first } - return result + NSLock().perform { self.array.first } } /// The last element of the collection. var last: Element? { - var result: Element? - queue.sync { result = self.array.last } - return result + NSLock().perform { self.array.last } } /// The number of elements in the array. var count: Int { - var result = 0 - queue.sync { result = self.array.count } - return result + NSLock().perform { self.array.count } } /// A Boolean value indicating whether the collection is empty. var isEmpty: Bool { - var result = false - queue.sync { result = self.array.isEmpty } - return result + NSLock().perform { self.array.isEmpty } } /// A textual representation of the array and its elements. var description: String { - var result = "" - queue.sync { result = self.array.description } - return result + NSLock().perform { self.array.description } } } @@ -69,9 +58,7 @@ public extension ThreadSafeArray { /// - Parameter predicate: A closure that takes an element of the sequence as its argument and returns a Boolean value indicating whether the element is a match. /// - Returns: The first element of the sequence that satisfies predicate, or nil if there is no element that satisfies predicate. func first(where predicate: (Element) -> Bool) -> Element? { - var result: Element? - queue.sync { result = self.array.first(where: predicate) } - return result + NSLock().perform { self.array.first(where: predicate) } } /// Returns the last element of the sequence that satisfies the given predicate. @@ -79,9 +66,7 @@ public extension ThreadSafeArray { /// - Parameter predicate: A closure that takes an element of the sequence as its argument and returns a Boolean value indicating whether the element is a match. /// - Returns: The last element of the sequence that satisfies predicate, or nil if there is no element that satisfies predicate. func last(where predicate: (Element) -> Bool) -> Element? { - var result: Element? - queue.sync { result = self.array.last(where: predicate) } - return result + NSLock().perform { self.array.last(where: predicate) } } /// Returns an array containing, in order, the elements of the sequence that satisfy the given predicate. @@ -89,9 +74,7 @@ public extension ThreadSafeArray { /// - Parameter isIncluded: A closure that takes an element of the sequence as its argument and returns a Boolean value indicating whether the element should be included in the returned array. /// - Returns: An array of the elements that includeElement allowed. func filter(_ isIncluded: @escaping (Element) -> Bool) -> ThreadSafeArray { - var result: ThreadSafeArray? - queue.sync { result = ThreadSafeArray(self.array.filter(isIncluded)) } - return result! + NSLock().perform { ThreadSafeArray(self.array.filter(isIncluded)) } } /// Returns the first index in which an element of the collection satisfies the given predicate. @@ -99,9 +82,7 @@ public extension ThreadSafeArray { /// - Parameter predicate: A closure that takes an element as its argument and returns a Boolean value that indicates whether the passed element represents a match. /// - Returns: The index of the first element for which predicate returns true. If no elements in the collection satisfy the given predicate, returns nil. func index(where predicate: (Element) -> Bool) -> Int? { - var result: Int? - queue.sync { result = self.array.firstIndex(where: predicate) } - return result + NSLock().perform { self.array.firstIndex(where: predicate) } } /// Returns the elements of the collection, sorted using the given predicate as the comparison between elements. @@ -109,9 +90,7 @@ public extension ThreadSafeArray { /// - Parameter areInIncreasingOrder: A predicate that returns true if its first argument should be ordered before its second argument; otherwise, false. /// - Returns: A sorted array of the collection’s elements. func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> ThreadSafeArray { - var result: ThreadSafeArray? - queue.sync { result = ThreadSafeArray(self.array.sorted(by: areInIncreasingOrder)) } - return result! + NSLock().perform { ThreadSafeArray(self.array.sorted(by: areInIncreasingOrder)) } } /// Returns an array containing the results of mapping the given closure over the sequence’s elements. @@ -119,9 +98,7 @@ public extension ThreadSafeArray { /// - Parameter transform: A closure that accepts an element of this sequence as its argument and returns an optional value. /// - Returns: An array of the non-nil results of calling transform with each element of the sequence. func map(_ transform: @escaping (Element) -> ElementOfResult) -> [ElementOfResult] { - var result = [ElementOfResult]() - queue.sync { result = self.array.map(transform) } - return result + NSLock().perform { self.array.map(transform) } } /// Returns an array containing the non-nil results of calling the given transformation with each element of this sequence. @@ -129,9 +106,7 @@ public extension ThreadSafeArray { /// - Parameter transform: A closure that accepts an element of this sequence as its argument and returns an optional value. /// - Returns: An array of the non-nil results of calling transform with each element of the sequence. func compactMap(_ transform: (Element) -> ElementOfResult?) -> [ElementOfResult] { - var result = [ElementOfResult]() - queue.sync { result = self.array.compactMap(transform) } - return result + NSLock().perform { self.array.compactMap(transform) } } /// Returns the result of combining the elements of the sequence using the given closure. @@ -141,9 +116,7 @@ public extension ThreadSafeArray { /// - nextPartialResult: A closure that combines an accumulating value and an element of the sequence into a new accumulating value, to be used in the next call of the nextPartialResult closure or returned to the caller. /// - Returns: The final accumulated value. If the sequence has no elements, the result is initialResult. func reduce(_ initialResult: ElementOfResult, _ nextPartialResult: @escaping (ElementOfResult, Element) -> ElementOfResult) -> ElementOfResult { - var result: ElementOfResult? - queue.sync { result = self.array.reduce(initialResult, nextPartialResult) } - return result ?? initialResult + NSLock().perform { self.array.reduce(initialResult, nextPartialResult) } } /// Returns the result of combining the elements of the sequence using the given closure. @@ -153,16 +126,14 @@ public extension ThreadSafeArray { /// - updateAccumulatingResult: A closure that updates the accumulating value with an element of the sequence. /// - Returns: The final accumulated value. If the sequence has no elements, the result is initialResult. func reduce(into initialResult: ElementOfResult, _ updateAccumulatingResult: @escaping (inout ElementOfResult, Element) -> Void) -> ElementOfResult { - var result: ElementOfResult? - queue.sync { result = self.array.reduce(into: initialResult, updateAccumulatingResult) } - return result ?? initialResult + NSLock().perform { self.array.reduce(into: initialResult, updateAccumulatingResult) } } /// Calls the given closure on each element in the sequence in the same order as a for-in loop. /// /// - Parameter body: A closure that takes an element of the sequence as a parameter. func forEach(_ body: (Element) -> Void) { - queue.sync { self.array.forEach(body) } + NSLock().perform { self.array.forEach(body) } } /// Returns a Boolean value indicating whether the sequence contains an element that satisfies the given predicate. @@ -170,9 +141,7 @@ public extension ThreadSafeArray { /// - Parameter predicate: A closure that takes an element of the sequence as its argument and returns a Boolean value that indicates whether the passed element represents a match. /// - Returns: true if the sequence contains an element that satisfies predicate; otherwise, false. func contains(where predicate: (Element) -> Bool) -> Bool { - var result = false - queue.sync { result = self.array.contains(where: predicate) } - return result + NSLock().perform { self.array.contains(where: predicate) } } /// Returns a Boolean value indicating whether every element of a sequence satisfies a given predicate. @@ -180,18 +149,14 @@ public extension ThreadSafeArray { /// - Parameter predicate: A closure that takes an element of the sequence as its argument and returns a Boolean value that indicates whether the passed element satisfies a condition. /// - Returns: true if the sequence contains only elements that satisfy predicate; otherwise, false. func allSatisfy(_ predicate: (Element) -> Bool) -> Bool { - var result = false - queue.sync { result = self.array.allSatisfy(predicate) } - return result + NSLock().perform { self.array.allSatisfy(predicate) } } /// Returns the array /// /// - Returns: the array part. func getArray() -> [Element]? { - var results: [Element]? - queue.sync { results = self.array } - return results + NSLock().perform { self.array } } } @@ -202,19 +167,15 @@ public extension ThreadSafeArray { /// Adds a new element at the end of the array. /// /// - Parameter element: The element to append to the array. - func append(_ element: Element) { - queue.async(flags: .barrier) { - self.array.append(element) - } + mutating func append(_ element: Element) { + NSLock().perform { self.array.append(element) } } /// Adds new elements at the end of the array. /// /// - Parameter element: The elements to append to the array. - func append(_ elements: [Element]) { - queue.async(flags: .barrier) { - self.array += elements - } + mutating func append(_ elements: [Element]) { + NSLock().perform { self.array += elements } } /// Inserts a new element at the specified position. @@ -222,10 +183,8 @@ public extension ThreadSafeArray { /// - Parameters: /// - element: The new element to insert into the array. /// - index: The position at which to insert the new element. - func insert(_ element: Element, at index: Int) { - queue.async(flags: .barrier) { - self.array.insert(element, at: index) - } + mutating func insert(_ element: Element, at index: Int) { + NSLock().perform { self.array.insert(element, at: index) } } /// Removes and returns the element at the specified position. @@ -233,11 +192,8 @@ public extension ThreadSafeArray { /// - Parameters: /// - index: The position of the element to remove. /// - completion: The handler with the removed element. - func remove(at index: Int, completion: ((Element) -> Void)? = nil) { - queue.async(flags: .barrier) { - let element = self.array.remove(at: index) - DispatchQueue.main.async { completion?(element) } - } + mutating func remove(at index: Int, completion: ((Element) -> Void)? = nil) { + NSLock().perform { self.array.remove(at: index) } } /// Removes and returns the elements that meet the criteria. @@ -245,27 +201,21 @@ public extension ThreadSafeArray { /// - Parameters: /// - predicate: A closure that takes an element of the sequence as its argument and returns a Boolean value indicating whether the element is a match. /// - completion: The handler with the removed elements. - func remove(where predicate: @escaping (Element) -> Bool, completion: (([Element]) -> Void)? = nil) { - queue.async(flags: .barrier) { + mutating func remove(where predicate: @escaping (Element) -> Bool) -> [Element] { + return NSLock().perform { var elements = [Element]() - while let index = self.array.firstIndex(where: predicate) { elements.append(self.array.remove(at: index)) } - - DispatchQueue.main.async { completion?(elements) } + return elements } } /// Removes all elements from the array. /// - /// - Parameter completion: The handler with the removed elements. - func removeAll(completion: (([Element]) -> Void)? = nil) { - queue.async(flags: .barrier) { - let elements = self.array - self.array.removeAll() - DispatchQueue.main.async { completion?(elements) } - } + /// - Parameter keepingCapacity: Pass true to keep the existing capacity of the array after removing its elements. The default value is false. + mutating func removeAll(keepingCapacity: Bool = false) { + NSLock().perform { self.array.removeAll(keepingCapacity: keepingCapacity) } } } @@ -277,21 +227,14 @@ public extension ThreadSafeArray { /// - Returns: optional element if it exists. subscript(index: Int) -> Element? { get { - var result: Element? - - queue.sync { - guard self.array.startIndex.. Bool { - var result = false - queue.sync { result = self.array.contains(element) } - return result + NSLock().perform { self.array.contains(element) } } } diff --git a/Tests/NextcloudKitIntegrationTests/Common/BaseXCTestCase.swift b/Tests/NextcloudKitIntegrationTests/Common/BaseXCTestCase.swift index 393d2e78..158b3720 100644 --- a/Tests/NextcloudKitIntegrationTests/Common/BaseXCTestCase.swift +++ b/Tests/NextcloudKitIntegrationTests/Common/BaseXCTestCase.swift @@ -10,11 +10,17 @@ import NextcloudKit class BaseXCTestCase: XCTestCase { var appToken = "" + var ncKit: NextcloudKit! - func setupAppToken() { + func setupAppToken() async { let expectation = expectation(description: "Should get app token") +#if swift(<6.0) + ncKit = NextcloudKit.shared +#else + ncKit = NextcloudKit() +#endif - NextcloudKit.shared.getAppPassword(url: TestConstants.server, user: TestConstants.username, password: TestConstants.password) { token, _, error in + ncKit.getAppPassword(url: TestConstants.server, user: TestConstants.username, password: TestConstants.password) { token, _, error in XCTAssertEqual(error.errorCode, 0) XCTAssertNotNil(token) @@ -23,11 +29,11 @@ class BaseXCTestCase: XCTestCase { self.appToken = token expectation.fulfill() } - - waitForExpectations(timeout: TestConstants.timeoutLong) + + await fulfillment(of: [expectation], timeout: TestConstants.timeoutLong) } - override func setUpWithError() throws { - setupAppToken() + override func setUp() async throws { + await setupAppToken() } } diff --git a/Tests/NextcloudKitUnitTests/FileAutoRenamerUnitTests.swift b/Tests/NextcloudKitUnitTests/FileAutoRenamerUnitTests.swift index d82ae672..814dc262 100644 --- a/Tests/NextcloudKitUnitTests/FileAutoRenamerUnitTests.swift +++ b/Tests/NextcloudKitUnitTests/FileAutoRenamerUnitTests.swift @@ -6,17 +6,15 @@ import Testing @testable import NextcloudKit @Suite(.serialized) struct FileAutoRenamerUnitTests { - let fileAutoRenamer = FileAutoRenamer.shared - let forbiddenFilenameCharacter = ">" let forbiddenFilenameExtension = "." let characterArrays = [ - ["\\\\", "*", ">", "&", "/", "|", ":", "<", "?"], - [">", ":", "?", "&", "*", "\\\\", "|", "<", "/"], - ["<", "|", "?", ":", "&", "*", "\\\\", "/", ">"], - ["?", "/", ":", "&", "<", "|", ">", "\\\\", "*"], - ["&", "<", "|", "*", "/", "?", ">", ":", "\\\\"] + ["\\\\", "*", ">", "&", "/", "|", ":", "<", "?", " "], + [">", ":", "?", " ", "&", "*", "\\\\", "|", "<", "/"], + ["<", "|", "?", ":", "&", "*", "\\\\", " ", "/", ">"], + ["?", "/", " ", ":", "&", "<", "|", ">", "\\\\", "*"], + ["&", "<", "|", "*", "/", "?", ">", " ", ":", "\\\\"] ] let extensionArrays = [ @@ -35,7 +33,7 @@ import Testing @Test func testInvalidChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -49,7 +47,7 @@ import Testing @Test func testInvalidExtension() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -63,7 +61,7 @@ import Testing @Test func testMultipleInvalidChars() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -77,7 +75,7 @@ import Testing @Test func testStartEndInvalidExtensions() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -91,7 +89,7 @@ import Testing @Test func testStartInvalidExtension() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -105,7 +103,7 @@ import Testing @Test func testEndInvalidExtension() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -119,7 +117,7 @@ import Testing @Test func testHiddenFile() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -133,7 +131,7 @@ import Testing @Test func testUppercaseExtension() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -147,7 +145,7 @@ import Testing @Test func testMiddleNonPrintableChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -161,7 +159,7 @@ import Testing @Test func testStartNonPrintableChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -175,7 +173,7 @@ import Testing @Test func testEndNonPrintableChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -189,7 +187,7 @@ import Testing @Test func testExtensionNonPrintableChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -203,7 +201,7 @@ import Testing @Test func testMiddleInvalidFolderChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -217,7 +215,7 @@ import Testing @Test func testEndInvalidFolderChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -231,7 +229,7 @@ import Testing @Test func testStartInvalidFolderChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -245,7 +243,7 @@ import Testing @Test func testMixedInvalidChar() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -259,7 +257,7 @@ import Testing @Test func testStartsWithPathSeparator() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) @@ -273,7 +271,7 @@ import Testing @Test func testStartsWithPathSeparatorAndValidFilepath() { for (characterArray, extensionArray) in combinedTuples { - fileAutoRenamer.setup( + let fileAutoRenamer = FileAutoRenamer( forbiddenFileNameCharacters: characterArray, forbiddenFileNameExtensions: extensionArray ) diff --git a/Tests/NextcloudKitUnitTests/FileNameValidatorUnitTests.swift b/Tests/NextcloudKitUnitTests/FileNameValidatorUnitTests.swift index fab4d2ed..7828c27a 100644 --- a/Tests/NextcloudKitUnitTests/FileNameValidatorUnitTests.swift +++ b/Tests/NextcloudKitUnitTests/FileNameValidatorUnitTests.swift @@ -6,10 +6,10 @@ import XCTest @testable import NextcloudKit class FileNameValidatorUnitTests: XCTestCase { - let fileNameValidator = FileNameValidator.shared + var fileNameValidator: FileNameValidator! override func setUp() { - fileNameValidator.setup( + fileNameValidator = FileNameValidator( forbiddenFileNames: [".htaccess",".htaccess"], forbiddenFileNameBasenames: ["con", "prn", "aux", "nul", "com0", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "com¹", "com²", "com³", @@ -23,31 +23,31 @@ class FileNameValidatorUnitTests: XCTestCase { func testInvalidCharacter() { let result = fileNameValidator.checkFileName("file