Merge pull request #6648 from nextcloud/bugfix/fp-sharing

Fix possible issues with item metadata acquisition required for macOS VFS file sharing
This commit is contained in:
Claudio Cambra 2024-04-18 13:13:03 +08:00 committed by GitHub
commit fcb5380437
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 77 additions and 42 deletions

View file

@ -34,7 +34,7 @@ class DocumentActionViewController: FPUIActionExtensionViewController {
override func prepare( override func prepare(
forAction actionIdentifier: String, itemIdentifiers: [NSFileProviderItemIdentifier] forAction actionIdentifier: String, itemIdentifiers: [NSFileProviderItemIdentifier]
) { ) {
Logger.actionViewController.info("Preparing for action: \(actionIdentifier)") Logger.actionViewController.info("Preparing action: \(actionIdentifier, privacy: .public)")
if actionIdentifier == "com.nextcloud.desktopclient.FileProviderUIExt.ShareAction" { if actionIdentifier == "com.nextcloud.desktopclient.FileProviderUIExt.ShareAction" {
prepare(childViewController: ShareViewController(itemIdentifiers)) prepare(childViewController: ShareViewController(itemIdentifiers))
@ -43,7 +43,11 @@ class DocumentActionViewController: FPUIActionExtensionViewController {
} }
override func prepare(forError error: Error) { override func prepare(forError error: Error) {
Logger.actionViewController.info("Preparing for error: \(error.localizedDescription)") Logger.actionViewController.info(
"""
Preparing for error: \(error.localizedDescription, privacy: .public)
"""
)
} }
override public func loadView() { override public func loadView() {

View file

@ -8,5 +8,9 @@
<array> <array>
<string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string> <string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
</array> </array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict> </dict>
</plist> </plist>

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -2,6 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleDisplayName</key>
<string>$(OC_APPLICATION_NAME) File Provider UI Extension</string>
<key>CFBundleIdentifier</key>
<string>$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME)</string>
<key>NSExtension</key> <key>NSExtension</key>
<dict> <dict>
<key>NSExtensionFileProviderActions</key> <key>NSExtensionFileProviderActions</key>
@ -15,10 +21,10 @@
<string>Share options</string> <string>Share options</string>
</dict> </dict>
</array> </array>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).DocumentActionViewController</string>
<key>NSExtensionPointIdentifier</key> <key>NSExtensionPointIdentifier</key>
<string>com.apple.fileprovider-actionsui</string> <string>com.apple.fileprovider-actionsui</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).DocumentActionViewController</string>
</dict> </dict>
</dict> </dict>
</plist> </plist>

View file

@ -42,14 +42,18 @@ class ShareController: ObservableObject {
) { account, share, data, error in ) { account, share, data, error in
defer { continuation.resume(returning: error) } defer { continuation.resume(returning: error) }
guard error == .success else { guard error == .success else {
Logger.shareController.error("Error creating link share: \(error)") Logger.shareController.error(
"""
Error creating link share: \(error.errorDescription, privacy: .public)
"""
)
return return
} }
} }
} else { } else {
guard let shareWith = shareWith else { guard let shareWith = shareWith else {
let errorString = "No recipient for share!" let errorString = "No recipient for share!"
Logger.shareController.error("\(errorString)") Logger.shareController.error("\(errorString, privacy: .public)")
let error = NKError(statusCode: 0, fallbackDescription: errorString) let error = NKError(statusCode: 0, fallbackDescription: errorString)
continuation.resume(returning: error) continuation.resume(returning: error)
return return
@ -66,7 +70,11 @@ class ShareController: ObservableObject {
) { account, share, data, error in ) { account, share, data, error in
defer { continuation.resume(returning: error) } defer { continuation.resume(returning: error) }
guard error == .success else { guard error == .success else {
Logger.shareController.error("Error creating share: \(error)") Logger.shareController.error(
"""
Error creating share: \(error.errorDescription, privacy: .public)
"""
)
return return
} }
} }
@ -90,7 +98,7 @@ class ShareController: ObservableObject {
attributes: String? = nil, attributes: String? = nil,
options: NKRequestOptions = NKRequestOptions() options: NKRequestOptions = NKRequestOptions()
) async -> NKError? { ) async -> NKError? {
Logger.shareController.info("Saving share: \(self.share.url)") Logger.shareController.info("Saving share: \(self.share.url, privacy: .public)")
return await withCheckedContinuation { continuation in return await withCheckedContinuation { continuation in
kit.updateShare( kit.updateShare(
idShare: share.idShare, idShare: share.idShare,
@ -104,10 +112,18 @@ class ShareController: ObservableObject {
attributes: attributes, attributes: attributes,
options: options options: options
) { account, share, data, error in ) { account, share, data, error in
Logger.shareController.info("Received update response: \(share?.url ?? "")") Logger.shareController.info(
"""
Received update response: \(share?.url ?? "", privacy: .public)
"""
)
defer { continuation.resume(returning: error) } defer { continuation.resume(returning: error) }
guard error == .success, let share = share else { guard error == .success, let share = share else {
Logger.shareController.error("Error updating save: \(error.errorDescription)") Logger.shareController.error(
"""
Error updating save: \(error.errorDescription, privacy: .public)
"""
)
return return
} }
self.share = share self.share = share
@ -116,13 +132,21 @@ class ShareController: ObservableObject {
} }
func delete() async -> NKError? { func delete() async -> NKError? {
Logger.shareController.info("Deleting share: \(self.share.url)") Logger.shareController.info("Deleting share: \(self.share.url, privacy: .public)")
return await withCheckedContinuation { continuation in return await withCheckedContinuation { continuation in
kit.deleteShare(idShare: share.idShare) { account, error in kit.deleteShare(idShare: share.idShare) { account, error in
Logger.shareController.info("Received delete response: \(self.share.url)") Logger.shareController.info(
"""
Received delete response: \(self.share.url, privacy: .public)
"""
)
defer { continuation.resume(returning: error) } defer { continuation.resume(returning: error) }
guard error == .success else { guard error == .success else {
Logger.shareController.error("Error deleting save: \(error.errorDescription)") Logger.shareController.error(
"""
Error deleting save: \(error.errorDescription, privacy: .public)
"""
)
return return
} }
} }

View file

@ -71,7 +71,7 @@ class ShareOptionsView: NSView {
} }
var createMode = false { var createMode = false {
didSet { didSet {
Logger.shareOptionsView.info("Create mode set: \(self.createMode)") Logger.shareOptionsView.info("Create mode set: \(self.createMode, privacy: .public)")
shareTypePicker.isHidden = !createMode shareTypePicker.isHidden = !createMode
shareRecipientTextField.isHidden = !createMode shareRecipientTextField.isHidden = !createMode
labelTextField.isHidden = createMode // Cannot set label on create API call labelTextField.isHidden = createMode // Cannot set label on create API call
@ -259,10 +259,10 @@ class ShareOptionsView: NSView {
let itemServerRelativePath = dataSource.itemServerRelativePath let itemServerRelativePath = dataSource.itemServerRelativePath
else { else {
Logger.shareOptionsView.error("Cannot create new share due to missing data.") Logger.shareOptionsView.error("Cannot create new share due to missing data.")
Logger.shareOptionsView.error("dataSource: \(self.dataSource)") Logger.shareOptionsView.error("dataSource: \(self.dataSource, privacy: .public)")
Logger.shareOptionsView.error("kit: \(self.kit)") Logger.shareOptionsView.error("kit: \(self.kit, privacy: .public)")
Logger.shareOptionsView.error( Logger.shareOptionsView.error(
"path: \(self.dataSource?.itemServerRelativePath ?? "")" "path: \(self.dataSource?.itemServerRelativePath ?? "", privacy: .public)"
) )
return return
} }

View file

@ -99,6 +99,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele
account = convertedAccount account = convertedAccount
await sharesTableView?.deselectAll(self) await sharesTableView?.deselectAll(self)
capabilities = await fetchCapabilities() capabilities = await fetchCapabilities()
guard capabilities != nil else { return }
guard capabilities?.filesSharing?.apiEnabled == true else { guard capabilities?.filesSharing?.apiEnabled == true else {
presentError("Server does not support shares.") presentError("Server does not support shares.")
return return

View file

@ -47,6 +47,13 @@ class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate {
return return
} }
Logger.shareViewController.info(
"""
Instantiated with itemIdentifiers:
\(itemIdentifiers.map { $0.rawValue }, privacy: .public)
"""
)
Task { Task {
await processItemIdentifier(firstItem) await processItemIdentifier(firstItem)
} }
@ -72,14 +79,19 @@ class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate {
do { do {
let itemUrl = try await manager.getUserVisibleURL(for: itemIdentifier) let itemUrl = try await manager.getUserVisibleURL(for: itemIdentifier)
guard itemUrl.startAccessingSecurityScopedResource() else {
Logger.shareViewController.error("Could not access scoped resource for item url!")
return
}
await updateDisplay(itemUrl: itemUrl) await updateDisplay(itemUrl: itemUrl)
shareDataSource.uiDelegate = self shareDataSource.uiDelegate = self
shareDataSource.sharesTableView = tableView shareDataSource.sharesTableView = tableView
shareDataSource.loadItem(url: itemUrl) shareDataSource.loadItem(url: itemUrl)
optionsView.dataSource = shareDataSource optionsView.dataSource = shareDataSource
itemUrl.stopAccessingSecurityScopedResource()
} catch let error { } catch let error {
let errorString = "Error processing item: \(error)" let errorString = "Error processing item: \(error)"
Logger.shareViewController.error("\(errorString)") Logger.shareViewController.error("\(errorString, privacy: .public)")
fileNameLabel.stringValue = "Unknown item" fileNameLabel.stringValue = "Unknown item"
descriptionLabel.stringValue = errorString descriptionLabel.stringValue = errorString
} }
@ -99,7 +111,11 @@ class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate {
let fileThumbnail = await withCheckedContinuation { continuation in let fileThumbnail = await withCheckedContinuation { continuation in
generator.generateRepresentations(for: request) { thumbnail, type, error in generator.generateRepresentations(for: request) { thumbnail, type, error in
if thumbnail == nil || error != nil { if thumbnail == nil || error != nil {
Logger.shareViewController.error("Could not get thumbnail: \(error)") Logger.shareViewController.error(
"""
Could not get thumbnail: \(error, privacy: .public)
"""
)
} }
continuation.resume(returning: thumbnail) continuation.resume(returning: thumbnail)
} }

View file

@ -157,7 +157,6 @@
536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderSocketLineProcessor.swift; sourceTree = "<group>"; }; 536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderSocketLineProcessor.swift; sourceTree = "<group>"; };
5374FD432B95EE1400C78D54 /* ShareController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareController.swift; sourceTree = "<group>"; }; 5374FD432B95EE1400C78D54 /* ShareController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareController.swift; sourceTree = "<group>"; };
5376307C2B85E2ED0026BFAB /* Logger+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Extensions.swift"; sourceTree = "<group>"; }; 5376307C2B85E2ED0026BFAB /* Logger+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Extensions.swift"; sourceTree = "<group>"; };
5376307E2B85E5650026BFAB /* FileProviderUIExt.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = FileProviderUIExt.entitlements; sourceTree = "<group>"; };
537630902B85F4980026BFAB /* ShareViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareViewController.xib; sourceTree = "<group>"; }; 537630902B85F4980026BFAB /* ShareViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareViewController.xib; sourceTree = "<group>"; };
537630922B85F4B00026BFAB /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; }; 537630922B85F4B00026BFAB /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
537630942B860D560026BFAB /* FPUIExtensionServiceSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUIExtensionServiceSource.swift; sourceTree = "<group>"; }; 537630942B860D560026BFAB /* FPUIExtensionServiceSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUIExtensionServiceSource.swift; sourceTree = "<group>"; };
@ -181,7 +180,7 @@
53D666602B70C9A70042C03D /* FileProviderConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderConfig.swift; sourceTree = "<group>"; }; 53D666602B70C9A70042C03D /* FileProviderConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderConfig.swift; sourceTree = "<group>"; };
53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+ClientInterface.swift"; sourceTree = "<group>"; }; 53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+ClientInterface.swift"; sourceTree = "<group>"; };
53FE144F2B8E0658006C4193 /* ShareTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareTableViewDataSource.swift; sourceTree = "<group>"; }; 53FE144F2B8E0658006C4193 /* ShareTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareTableViewDataSource.swift; sourceTree = "<group>"; };
53FE14572B8E3A7C006C4193 /* FileProviderUIExtRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FileProviderUIExtRelease.entitlements; sourceTree = "<group>"; }; 53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FileProviderUIExt.entitlements; sourceTree = "<group>"; };
53FE14582B8E3F6C006C4193 /* ShareTableItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareTableItemView.swift; sourceTree = "<group>"; }; 53FE14582B8E3F6C006C4193 /* ShareTableItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareTableItemView.swift; sourceTree = "<group>"; };
53FE145A2B8F1305006C4193 /* NKShare+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKShare+Extensions.swift"; sourceTree = "<group>"; }; 53FE145A2B8F1305006C4193 /* NKShare+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKShare+Extensions.swift"; sourceTree = "<group>"; };
53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewDataSourceUIDelegate.swift; sourceTree = "<group>"; }; 53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewDataSourceUIDelegate.swift; sourceTree = "<group>"; };
@ -329,8 +328,7 @@
537630922B85F4B00026BFAB /* ShareViewController.swift */, 537630922B85F4B00026BFAB /* ShareViewController.swift */,
537630902B85F4980026BFAB /* ShareViewController.xib */, 537630902B85F4980026BFAB /* ShareViewController.xib */,
53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */, 53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */,
5376307E2B85E5650026BFAB /* FileProviderUIExt.entitlements */, 53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */,
53FE14572B8E3A7C006C4193 /* FileProviderUIExtRelease.entitlements */,
53B979852B84C81F002DA742 /* Info.plist */, 53B979852B84C81F002DA742 /* Info.plist */,
); );
path = FileProviderUIExt; path = FileProviderUIExt;
@ -1023,7 +1021,6 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = FileProviderUIExt/Info.plist; INFOPLIST_FILE = FileProviderUIExt/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = FileProviderUIExt;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_OUTPUT_FORMAT = "same-as-input"; INFOPLIST_OUTPUT_FORMAT = "same-as-input";
INFOPLIST_PREPROCESS = NO; INFOPLIST_PREPROCESS = NO;
@ -1070,7 +1067,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = FileProviderUIExt/FileProviderUIExtRelease.entitlements; CODE_SIGN_ENTITLEMENTS = FileProviderUIExt/FileProviderUIExt.entitlements;
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO; CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
@ -1084,7 +1081,6 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = FileProviderUIExt/Info.plist; INFOPLIST_FILE = FileProviderUIExt/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = FileProviderUIExt;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_OUTPUT_FORMAT = "same-as-input"; INFOPLIST_OUTPUT_FORMAT = "same-as-input";
INFOPLIST_PREPROCESS = NO; INFOPLIST_PREPROCESS = NO;