summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2023-06-29 17:29:24 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2023-06-30 14:05:16 +0200
commit90345459fce8ae9ca58ca2279ea50129ad14e287 (patch)
tree7dc8e01c4acf91b8e54237183ff7f610c5e9a6e7 /src
parent8fbce6b4a04ba9712e45340afc9b52fe2966f125 (diff)
macOS: Avoid triggering TCC permission dialogs in file dialogs
In our NSOpenSavePanelDelegate we respond to panel:shouldEnableURL: by checking the file dialog's filter options. As part of this, we pulled out the file's attributes using [NSFileManager attributesOfItemAtPath:], but this API triggers the TCC (Transparency, Consent, and Control) machinery to ask the user for permission to access the path in question. We could replace the directory check with fileExistsAtPath:isDirectory:, but this would still leave the checks for writable/readable/executable. Luckily for us, the plumbing for QFileInfo uses lower level CoreFoundation APIs that don't have these issues (except for isBundle, which we should fix separately). This also means we can remove the custom isHiddenFileAtURL helper, as it was based on the same kCFURLIsHiddenKey as the QFileInfo plumbing. Fixes: QTBUG-114919 Pick-to: 6.5 6.6 Change-Id: I9ebefaeb1ef7bcc5bb9a1c5cd4b993ce230cf506 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm54
1 files changed, 19 insertions, 35 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index c67909f33a..b53235a0f1 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -194,19 +194,6 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
[m_panel close];
}
-- (BOOL)isHiddenFileAtURL:(NSURL *)url
-{
- BOOL hidden = NO;
- if (url) {
- CFBooleanRef isHiddenProperty;
- if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, nullptr)) {
- hidden = CFBooleanGetValue(isHiddenProperty);
- CFRelease(isHiddenProperty);
- }
- }
- return hidden;
-}
-
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url
{
Q_UNUSED(sender);
@@ -215,24 +202,21 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
if (!filename.length)
return NO;
- // Always accept directories regardless of their names (unless it is a bundle):
- NSFileManager *fm = NSFileManager.defaultManager;
- NSDictionary *fileAttrs = [fm attributesOfItemAtPath:filename error:nil];
- if (!fileAttrs)
- return NO; // Error accessing the file means 'no'.
- NSString *fileType = fileAttrs.fileType;
- bool isDir = [fileType isEqualToString:NSFileTypeDirectory];
- if (isDir) {
+ QFileInfo fileInfo(QString::fromNSString(filename));
+
+ // Always accept directories regardless of their names.
+ // This also includes symlinks and aliases to directories.
+ if (fileInfo.isDir()) {
+ // Unless it's a bundle, and we should treat bundles as files.
+ // FIXME: We'd like to use QFileInfo::isBundle() here, but the
+ // detection in QFileInfo goes deeper than NSWorkspace does
+ // (likely a bug), and as a result causes TCC permission
+ // dialogs to pop up when used.
bool treatBundlesAsFiles = !m_panel.treatsFilePackagesAsDirectories;
if (!(treatBundlesAsFiles && [NSWorkspace.sharedWorkspace isFilePackageAtPath:filename]))
return YES;
}
- // Treat symbolic links and aliases to directories like directories
- QFileInfo fileInfo(QString::fromNSString(filename));
- if (fileInfo.isSymLink() && QFileInfo(fileInfo.symLinkTarget()).isDir())
- return YES;
-
QString qtFileName = fileInfo.fileName();
// No filter means accept everything
bool nameMatches = m_selectedNameFilter->isEmpty();
@@ -245,22 +229,22 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
return NO;
QDir::Filters filter = m_options->filter();
- if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && isDir)
- || (!(filter & QDir::Files) && [fileType isEqualToString:NSFileTypeRegular])
- || ((filter & QDir::NoSymLinks) && [fileType isEqualToString:NSFileTypeSymbolicLink]))
+ if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && fileInfo.isDir())
+ || (!(filter & QDir::Files) && (fileInfo.isFile() && !fileInfo.isSymLink()))
+ || ((filter & QDir::NoSymLinks) && fileInfo.isSymLink()))
return NO;
bool filterPermissions = ((filter & QDir::PermissionMask)
&& (filter & QDir::PermissionMask) != QDir::PermissionMask);
if (filterPermissions) {
- if ((!(filter & QDir::Readable) && [fm isReadableFileAtPath:filename])
- || (!(filter & QDir::Writable) && [fm isWritableFileAtPath:filename])
- || (!(filter & QDir::Executable) && [fm isExecutableFileAtPath:filename]))
+ if ((!(filter & QDir::Readable) && fileInfo.isReadable())
+ || (!(filter & QDir::Writable) && fileInfo.isWritable())
+ || (!(filter & QDir::Executable) && fileInfo.isExecutable()))
return NO;
}
- if (!(filter & QDir::Hidden)
- && (qtFileName.startsWith(u'.') || [self isHiddenFileAtURL:url]))
- return NO;
+
+ if (!(filter & QDir::Hidden) && fileInfo.isHidden())
+ return NO;
return YES;
}