Document-scope, Security scoped bookmarks for file packages - macos

I'm trying to create document-scope security scoped bookmarks for file packages. That is, directories where NSURLIsPackageKey is YES. I know you're not normally supposed to be able to create document-scope bookmarks to directories, but I would have expected packages to be exempt from that (after all, I get access to them using an NSOpenPanel which isn't allowed to select directories, but there's no problem there).
I've got my entitlements set up with com.apple.security.files.bookmarks.document-scope = true, and I'm doing a basic bookmark creation call with a file URL that I've just received from an NSOpenPanel (so I have access):
NSError *bookmarkError = nil;
NSData *bookmark = [fileURL
bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:[self fileURL]
error:&bookmarkError];
After this call though, both bookmark and bookmarkError are nil.
Do I just need to give up on this and create app-scope bookmarks, even though I have a document-based app? That seems inappropriate, but I don't see another workaround.

I asked about this elsewhere and was told:
...we didn't implement support for it because it's complicated and there have been very few requests for it.
So that's that, you can't create this kind of bookmark because it's not implemented. I also filed a bug with Apple but the response just quoted the docs at me (i.e. telling me stuff I already knew and had mentioned in my report) before closing it. So, as of now and probably for the foreseeable future, this is not possible.

Related

OS X App Sandboxing and arbitrary files access - Update to Document-based?

My OS X app (currently not sandboxed) accesses files contained inside a directory set by the user (one chooses the path with a NSOpenPanel and a reference to this path is kept throughout execution). The list of files is generated via NSDirectoryEnumerator and I then read from and write to those files using AVAsset and taglib (in C++ with a bridging header) respectively.
As expected, enabling Sandboxing in Xcode rendered the app useless, the list of files given by NSDirectoryEnumerator is empty and even if it weren't, I would not be able to read from and write to the files. What are the steps I need to take to make my app sandbox-compliant?
Does my app need to be document based? Can my app really be "document-based" since I don't really have proper documents (as in: I don't have a window per file, it doesn't seem to comply to the standard document-based app model)? My app is basically just a table view with files references as rows.
Another important point: can I still use taglib to write to my files if my app is document-based ? I need to pass taglib the path to my file as a string pointer in order for it to work.
Thanks a lot, this topic is quite confusing at the moment.
You don't have to convert your app to be document-based to gain access to user selected files and security scoped bookmarks.
I can think of 2 reasons why your current code does not work in a sandboxed environment:
You don't have the "User Selected File Access" capability set (Xcode > target > Capabilities > App Sandbox > File Access)
You are using the path/NSString based API of the directory enumerator instead of the URL NSURL based one.
A vanilla Xcode project with Sandboxing enabled and the User selected files capabilities set, should enumerate any path obtained via NSOpenPanel:
NSOpenPanel* panel =[NSOpenPanel openPanel];
panel.canChooseDirectories = YES;
[panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) {
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL *directoryURL = panel.URL;
NSDirectoryEnumerator *enumerator = [fileManager
enumeratorAtURL:directoryURL
includingPropertiesForKeys:nil
options:0
errorHandler:nil];
for (NSURL *url in enumerator) {
NSLog(#"url:%#", url);
}
}];
If you want to store the ability to access specific folders from the sandbox across app launch/quit cycles, you will need to store a security scoped bookmark.
This post contains information persisting user selected file/directory access via app scoped bookmark:
Trouble creating Security-Scoped Bookmark
It sounds like the current functionality will convert to Sandboxing just fine.
The user selects the directory via NSOpenPanel (which will invoke something called Powerbox in the Sandboxed environment).
This directory is now writable, as the user has explicitly selected it.
You can even maintain write access to this directory by creating a Security Scoped Bookmark and storing it away between sessions.
This has got nothing at all to do with being Document based; that is an internal design that is unrelated to Sandboxing.

sandbox :get NSData using bookmarkDataWithOptions method of NSURL without NSOpenPanel

I enabled sandbox and I want to create data by bookmarkDataWithOptions.
If the URL is created by NSPanel that work very well. But, If I obtain URL without using NSOpenPanel, the bookmarkDataWithOptions method always return nil. why?
thank about If I want to set a special folder default can read/write without using NSOpenPanel.
How can i do?
Thanks
The main feature of the Sandbox is security. If an application could read/write an arbitrary folder without user permission, the security would be broken.
The App Sandbox Design Guide states clearly:
• Simulation of user input in Open and Save dialogs:
if your app depends on programmatically manipulating Open or Save dialogs to simulate or alter user input, your app is unsuitable for sandboxing.
The only way to achieve something similar, is to add a read/write entitlement to one of the preset directories (Documents, Pictures, Music, etc…). For further documentation, take a look at this guide.

Mac OS: Where to save NSData object with bookmark of file url?

I'm new to Mac OS development, so I have simple question. I have a NSURL object of a folder, I want to keep this URL and make it bulletproof to app quit/reboot/folder rename. So, I made a NSData bookmark. I'm a little confuse right now, where I must save this NSData object for future use.
It is better to save object to NSUserDefaults?
Or I must make a file in my bundle and store this object in it, if so, what must be an extension of that file, and is it "safe"?
Or I must save that file in Application Support Directory ?
After I write this question, I found another one, what if I will have more data to save like NSString objects or NSNumber or else, I must make another files with info, or could make a one file with all that necessary info?
NSUserDefaults is used to store user preference and other data that will be used by application in the next run. For your instance you can use it.
Application bundle usually not used for writing data. Specifically user may be standard user in that case he/she will have only read,execute permission to App bundle and attempt writing inside bundle will fail.
Application Support directory is used to save files and other big data that application needs in the next run .If data size is less then it is preferred to store in NSUserDefaults.
You can define your own keys to save other NSString, NSNumber etc objects to NSUserDefaults. Same keys is used to read from NSUserDefaults.

Saving CFPropertyLists To Users Folder

I'm trying to save a CFPropertyList to a location in the user's home folder. Using the code below I'm getting errorCode = -10 (unknown error).
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("~/testfile.txt"), kCFURLPOSIXPathStyle, false );
SInt32 errorCode;
Boolean status = CFURLWriteDataAndPropertiesToResource(fileURL, xmlData, NULL, &errorCode);
If I change the path to something like "/testfile.txt" without the '~' then everything works. How can one save a property list to the current user's home folder? Must one obtain the user's name first and include it in the path such as /users/toffler/testfile.txt?
With Foundation, you can call the NSHomeDirectory function to get the absolute path to the user's home directory. You can then use the path-manipulation methods of NSString or of NSURL, or the equivalent function for CFURL, to tack a sub-path onto that.
However, please don't put files into the top level of my Home folder unless I, as the user, tell you to.
If you want to save a file at the user's request, run a save panel, and then save it where the user told you to.
If you want to save a preferences file, you probably should be using NSUserDefaults or CFPreferences, instead of handling plists yourself.
If you have some other reason to save a user-specific file, it should generally go into either the chewable items folder, the Caches folder, or the Preferences folder. The two functions that I linked to are the easiest ways to access those two of those three folders; the harder way, and the only one that works on all three, is the FSFindFolder function. Unlike most of the Folder Manager, FSFindFolder is not deprecated and is available in 64-bit.
Updates from the year 2012
Nowadays, you should use URLs, not paths. NSFileManager has a method for getting a URL to a desired directory.
Stapling paths (or file URLs) together does not work in a sandboxed application, because you don't have authorization to access the path you just made up. You need to get the path (or URL) from a system API, whether it's NSFileManager, NSSavePanel, or something else.
For saving and restoring file references, use NSURL's security-scoped bookmarks feature.
NSUserDefaults and CFPreferences work as expected in a sandbox.
The Folder Manager is now fully deprecated as of 10.8.
Polluting the user's Home folder is still bad manners.
Automatic ~ expansion is a feature of the shell.
If you are using Cocoa/Foundation, you can use the NSString methods
- (NSString *)stringByAbbreviatingWithTildeInPath;
- (NSString *)stringByExpandingTildeInPath;
otherwise, you'll have to write some code yourself to do this. Getting the user's login name and constructing the path /Users/login-name/ is not the correct way to do this. (While most users will have their home directory here, some will not.)

App-Scoped vs. Document-Scoped Security-Scoped Bookmarks

Quick Question:
I'm working on a document based application in OS X. Can I use an App-Scope bookmark to gain access to a file, or must it be a document-scope bookmark?
I understand that any app can use both of these, but I wasn't sure if perhaps the app-scope bookmark can't be accessed by a specific document of that app.
I initially implemented an app-based scope bookmark and when I attempt to startAccessing it, it always returns FALSE.
Wondering if I will need to change this to a Document-scope to get it to work.
Here's a link to my other question which shows the actual code:
Security Scoped Bookmark - startAccessing always returns FALSE and Resolved URL doesn't work
Thanks!

Resources