Pick out additional fixes, functionality to SecurityBookmarkFileAccess

Match the state of this class with the current state of the macOS sandbox PR

Signed-off-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com>
This commit is contained in:
Kenneth Chew
2025-04-10 17:25:59 -04:00
parent efe1d71d35
commit d937563ead
2 changed files with 59 additions and 19 deletions

View File

@@ -39,9 +39,12 @@ class SecurityBookmarkFileAccess {
/// Contains URLs that are currently being accessed.
NSMutableSet* m_activeURLs;
bool m_readOnly;
NSURL* securityScopedBookmarkToNSURL(QByteArray& bookmark, bool& isStale);
public:
SecurityBookmarkFileAccess();
/// \param readOnly A boolean indicating whether the bookmark should be read-only.
SecurityBookmarkFileAccess(bool readOnly = false);
~SecurityBookmarkFileAccess();
/// Get a security scoped bookmark from a URL.
@@ -78,6 +81,9 @@ public:
/// \return A boolean indicating whether the bookmark was successfully accessed.
bool startUsingSecurityScopedBookmark(QByteArray& bookmark, bool& isStale);
void stopUsingSecurityScopedBookmark(QByteArray& bookmark);
/// Returns true if access to the `path` is currently being maintained by this object.
bool isAccessingPath(const QString& path);
};
#endif //FILEACCESS_H

View File

@@ -29,25 +29,41 @@ QByteArray SecurityBookmarkFileAccess::urlToSecurityScopedBookmark(const QUrl& u
NSError* error = nil;
NSURL* nsurl = [url.toNSURL() absoluteURL];
NSData* bookmark;
if ([m_paths objectForKey:[nsurl path]]) {
return QByteArray::fromNSData(m_paths[[nsurl path]]);
bookmark = m_paths[[nsurl path]];
} else {
bookmark = [nsurl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope |
(m_readOnly ? NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess : 0)
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
}
[m_activeURLs addObject:nsurl];
NSData* bookmark = [nsurl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
if (error) {
return {};
}
// remove/reapply access to ensure that write access is immediately cut off for read-only bookmarks
// sometimes you need to call this twice to actually stop access (extra calls aren't harmful)
[nsurl stopAccessingSecurityScopedResource];
[nsurl stopAccessingSecurityScopedResource];
nsurl = [NSURL URLByResolvingBookmarkData:bookmark
options:NSURLBookmarkResolutionWithSecurityScope |
(m_readOnly ? NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess : 0)
relativeToURL:nil
bookmarkDataIsStale:nil
error:&error];
m_paths[[nsurl path]] = bookmark;
m_bookmarks[bookmark] = nsurl;
[m_activeURLs addObject:nsurl];
return QByteArray::fromNSData(bookmark);
QByteArray qBookmark = QByteArray::fromNSData(bookmark);
bool isStale = false;
startUsingSecurityScopedBookmark(qBookmark, isStale);
return qBookmark;
}
SecurityBookmarkFileAccess::SecurityBookmarkFileAccess()
SecurityBookmarkFileAccess::SecurityBookmarkFileAccess(bool readOnly) : m_readOnly(readOnly)
{
m_bookmarks = [NSMutableDictionary new];
m_paths = [NSMutableDictionary new];
@@ -59,9 +75,6 @@ SecurityBookmarkFileAccess::~SecurityBookmarkFileAccess()
for (NSURL* url : m_activeURLs) {
[url stopAccessingSecurityScopedResource];
}
[m_bookmarks release];
[m_paths release];
[m_activeURLs release];
}
QByteArray SecurityBookmarkFileAccess::pathToSecurityScopedBookmark(const QString& path)
@@ -74,7 +87,8 @@ NSURL* SecurityBookmarkFileAccess::securityScopedBookmarkToNSURL(QByteArray& boo
NSError* error = nil;
BOOL localStale = NO;
NSURL* nsurl = [NSURL URLByResolvingBookmarkData:bookmark.toNSData()
options:NSURLBookmarkResolutionWithSecurityScope
options:NSURLBookmarkResolutionWithSecurityScope |
(m_readOnly ? NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess : 0)
relativeToURL:nil
bookmarkDataIsStale:&localStale
error:&error];
@@ -83,18 +97,21 @@ NSURL* SecurityBookmarkFileAccess::securityScopedBookmarkToNSURL(QByteArray& boo
}
isStale = localStale;
if (isStale) {
NSData* nsBookmark = [nsurl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
NSData* nsBookmark = [nsurl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope |
(m_readOnly ? NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess : 0)
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
if (error) {
return nil;
}
m_paths[[nsurl path]] = nsBookmark;
m_bookmarks[nsBookmark] = nsurl;
bookmark = QByteArray::fromNSData(nsBookmark);
}
NSData* nsBookmark = bookmark.toNSData();
m_paths[[nsurl path]] = nsBookmark;
m_bookmarks[nsBookmark] = nsurl;
return nsurl;
}
@@ -112,10 +129,12 @@ QUrl SecurityBookmarkFileAccess::securityScopedBookmarkToURL(QByteArray& bookmar
bool SecurityBookmarkFileAccess::startUsingSecurityScopedBookmark(QByteArray& bookmark, bool& isStale)
{
NSURL* url = [m_bookmarks objectForKey:bookmark.toNSData()] ? m_bookmarks[bookmark.toNSData()] : securityScopedBookmarkToNSURL(bookmark, isStale);
NSURL* url = [m_bookmarks objectForKey:bookmark.toNSData()] ? m_bookmarks[bookmark.toNSData()]
: securityScopedBookmarkToNSURL(bookmark, isStale);
if ([m_activeURLs containsObject:url])
return false;
[url stopAccessingSecurityScopedResource];
if ([url startAccessingSecurityScopedResource]) {
[m_activeURLs addObject:url];
return true;
@@ -131,8 +150,23 @@ void SecurityBookmarkFileAccess::stopUsingSecurityScopedBookmark(QByteArray& boo
if ([m_activeURLs containsObject:url]) {
[url stopAccessingSecurityScopedResource];
[url stopAccessingSecurityScopedResource];
[m_activeURLs removeObject:url];
[m_bookmarks removeObjectForKey:bookmark.toNSData()];
[m_paths removeObjectForKey:[url path]];
[m_bookmarks removeObjectForKey:bookmark.toNSData()];
}
}
bool SecurityBookmarkFileAccess::isAccessingPath(const QString& path)
{
NSData* bookmark = [m_paths objectForKey:path.toNSString()];
if (!bookmark && path.endsWith('/')) {
bookmark = [m_paths objectForKey:path.left(path.length() - 1).toNSString()];
}
if (!bookmark) {
return false;
}
NSURL* url = [m_bookmarks objectForKey:bookmark];
return [m_activeURLs containsObject:url];
}