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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ import Foundation
import NextcloudCapabilitiesKit
import NextcloudKit

func chunkedUploadRemotePathComponents(from remotePath: String) -> (serverUrl: String, destinationFileName: String)? {
guard let separatorIndex = remotePath.lastIndex(of: "/") else {
return nil
}

let destinationFileNameIndex = remotePath.index(after: separatorIndex)
guard destinationFileNameIndex < remotePath.endIndex else {
return nil
}

return (
serverUrl: String(remotePath[..<separatorIndex]),
destinationFileName: String(remotePath[destinationFileNameIndex...])
)
}

extension NextcloudKit: RemoteInterface {
public func setDelegate(_ delegate: any NextcloudKitDelegate) {
setup(delegate: delegate)
Expand Down Expand Up @@ -111,7 +127,7 @@ extension NextcloudKit: RemoteInterface {
) async -> (account: String, file: NKFile?, nkError: NKError) {
let logger = FileProviderLogger(category: "NextcloudKit+RemoteInterface", log: log)

guard let remoteUrl = URL(string: remotePath) else {
guard let remotePathComponents = chunkedUploadRemotePathComponents(from: remotePath) else {
return ("", nil, .urlError)
}
let localUrl = URL(fileURLWithPath: localPath)
Expand All @@ -136,17 +152,8 @@ extension NextcloudKit: RemoteInterface {
}
let fileChunksOutputDirectory = chunksOutputDirectoryUrl.path
let fileName = localUrl.lastPathComponent
let destinationFileName = remoteUrl.lastPathComponent
guard let serverUrl = remoteUrl
.deletingLastPathComponent()
.absoluteString
.removingPercentEncoding
else {
logger.error(
"NCKit ext: Could not get server url from \(remotePath)"
)
return ("", nil, .urlError)
}
let destinationFileName = remotePathComponents.destinationFileName
let serverUrl = remotePathComponents.serverUrl
let fileChunks = remainingChunks.toNcKitChunks()

logger.info(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,27 @@ struct RemoteInterfaceExtensionTests {
let testAccount = Account(user: "a1", id: "1", serverUrl: "example.com", password: "pass")
let otherAccount = Account(user: "a2", id: "2", serverUrl: "example.com", password: "word")

@Test func chunkedUploadRemotePathComponentsPreserveFilenameCharacters() throws {
let serverUrl = "https://cloud.example.com/remote.php/dav/files/user/comics"
let fileNames = [
"The Nightly News #001 (2011).cbz",
"Question?.txt",
"Literal%23Name.txt"
]

for fileName in fileNames {
let components = try #require(chunkedUploadRemotePathComponents(from: "\(serverUrl)/\(fileName)"))

#expect(components.serverUrl == serverUrl)
#expect(components.destinationFileName == fileName)
}
}

@Test func chunkedUploadRemotePathComponentsRejectInvalidPaths() {
#expect(chunkedUploadRemotePathComponents(from: "filename.txt") == nil)
#expect(chunkedUploadRemotePathComponents(from: "https://cloud.example.com/") == nil)
}

func capabilitiesFromMockJSON(jsonString: String = mockCapabilities) -> (Capabilities, Data) {
let data = jsonString.data(using: .utf8)!
let caps = Capabilities(data: data)!
Expand Down
Loading