AppleScript App entitlement for access-group identifier="*" - xcode

I am developing a Mac app that makes use of App Scripting. The is Sandboxed and thus needs the proper entitlements in order to get permissions to send AppleScript events to other apps. I have gotten this working properly for apps (like Mail and spotify) which specify access-group identifiers like this:
<access-group identifier="com.apple.mail.compose" access="rw"/>
<access-group identifier="com.spotify.playback"/>
However, a few other of the Apple made apps (like Xcode) specify their identifiers like this:
<access-group identifier="*"/>
I have tried to configure my entitlement file like this:
<key>com.apple.security.scripting-targets</key>
<dict>
<key>com.apple.dt.Xcode</key>
<array>
<string>*</string>
</array>
</dict>
, but when doing this it does not work and I get this error message in the console:
AppleEvents/sandbox: Returning errAEPrivilegeError/-10004 and denying dispatch of event xcod/buld from process '-------'/0x0-0x1a05a04, pid=82514, because it is not entitled to send an AppleEvent to this process.
Does anyone know how to properly configure this?

Actually I found the answer myself. In the sdef Man pages it states:
An identifier of "*" means the element is usable by any application,
without an explicit entitlement.
This means that you do not have to add the identifiers in your entitlements file and it should work regardless. The reason why I got the error was because I accidentally used commands that were not included in those particular access-groups.

Related

How can I know what entitlement items should be added for Mac sandbox app?

In Apple's document about App Sandbox, I found something about Temporary Exception, and the value of Global Mach Service Temporary Exception is an array, but I do know what items can this array contains.
Actually, I hope there is place where I can check what entitlement items should be added for a specific function in sandbox app. For example, for a certain function, maybe I should add some com.apple.security.temporary-exception.mach-lookup.global-name and com.apple.security.temporary-exception.files.absolute-path.read-write, but the problem is what they are.
For now, when the function is unable to work in sandbox, I can find error message in system log, but still do not know what entitlements are needed.
documentation of sandbox is pretty inconsistent. what it suggests is to just use whatever you want to do, run the app and check console to see which functions fail. https://developer.apple.com/library/mac/documentation/Security/Conceptual/AppSandboxDesignGuide/DesigningYourSandbox/DesigningYourSandbox.html#//apple_ref/doc/uid/TP40011183-CH4-SW1
EDIT: if you're using temporary exceptions you'll need to add them in iTunes connect and explain each one in detail.

How can I pass the name of the file that was changed in launchd?

I am trying to watch a directory for changes via launchd. My plist
file looks like this:
<key>ProgramArguments</key>
<array>
<string>/Users/myname/bin/boink</string>
<string>path modified</string>
</array>
All this works OK, but I would like to pass the name of the file that
was changed as an argument to the script /Users/myname/bin/boink
Is that possible? the man page isn't very helpful, nor did googling help a lot.
Thanks.
The short answer is: no. launchd(8) uses Kqueue (http://en.wikipedia.org/wiki/Kqueue) to receive this kind of notification. Unfortunately kqueue(2) does not return which item has triggered the event.
You may want to use the launchd(8) key QueueDirectories instead. It works essentially the same way WatchPaths works, but it assumes that the processing agent/daemon is moving the processed items from the directory being monitored to another one. So whenever an event is triggered your job can process every file in the monitored directory. Just make sure you move them after processing.

How to register a Cocoa-Applescript application as a URL handler? (equivalent of "on open location" in Applescript Studio)

Should be relatively straightforward, but I can't seem to find anything on this - I'm trying to add a URL handler to a Cocoa-Applescript application, as described here:
http://www.macosxautomation.com/applescript/linktrigger/index.html
Except that example doesn't seem to work in an Xcode/Cocoa-Applescript application.
In my AppDelegate.applescript, after applicationDidFinishLaunching_ I've got:
on open location this_URL
tell me to log "this_URL: " & this_URL
end open location
And I've added all the CFBundleURLTypes/CFBundleURLschemes stuff in info.plist.
The latter seems to be working, as my app activates when I click a myAppScheme:// link.
But the log statement doesn't fire.
I also tried stuff like on handleGetURLEvent_(this_URL) but I'm kind of just guessing at this point :)
Any help much appreciated..
Solved! (The 'magic number' below is due to a bug in ASObjc stuff).
on applicationDidFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
-- Register the URL Handler stuff
tell current application's NSAppleEventManager's sharedAppleEventManager() to setEventHandler_andSelector_forEventClass_andEventID_(me, "handleGetURLEvent:", current application's kInternetEventClass, current application's kAEGetURL)
-- all your other application startup stuff..
end applicationDidFinishLaunching_
-- handler that runs when the URL is clicked
on handleGetURLEvent_(ev)
set urlString to (ev's paramDescriptorForKeyword_(7.57935405E+8)) as string
tell me to log "urlString: " & urlString
-- do stuff with 'Set AppleScript's text item delimiters to "foo="', and then "&" etc, to parse your parameters out of the URL String
end handleGetURLEvent_
And your info.plist needs to be in the form:
<key>CFBundleIdentifier</key>
<string>com.myappname</string>
...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>My App Name Helper</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myappscheme</string>
</array>
</dict>
</array>
Which allows your app to take input from URLs in the form:
myappscheme://com.myappname/?foo=stuff&bar=otherstuff
The whole URL is passed in and and ends up in your 'urlString' variable, so you can parse it however you like. Which means you don't even necessarily have to follow the standard URL conventions like I have above, but you might find it convenient to do so, so that potentially you can support parsing let's say Facebook or Google Maps URLs in your app with a simple change of http:// to myappscheme://
Enjoy/Hope that helps.. :)
I don't use ApplescriptObjC, however in a normal cocoa application see this post which explains how to do it. I'd assume you need to do it like that.
I may be running into something similar. I have an Applescript URL handler that launches but doesn't process the passed URL (just as you've described).
What I found was when another program sends a link, everything functions properly.
When I try to manually send a link via the terminal "open" command, the "on run" handler triggers rather than "on open location" - which unfortunately means I can't get the passed URL.

Non in-place saving in OS X sandbox

I'm developing a sandboxed app for Mac OS X 10.7 and I'm trying to implement file saving in a way similar to NSDocument:
Rewrite the file's new contents to a temporary file
Overwrite the original file with the temporary file
The issue I'm having is that the sandbox is denying step 2. I see the following line in Console:
sandboxd: XXXX deny file-write-create /Volumes/Home/sbooth/Test Files/Test
I already have this file open for reading and writing, and I have the File System Read/Write Access entitlement enabled. I know NSDocument does this with no special entitlements so I'm trying to figure out what I've missed.
Here is how I'm doing things now (this portion of the app is in C++, not Objective-C/C++):
FSRef tempFileFSRef;
if(noErr != FSPathMakeRef((const UInt8 *)tempFileName, &tempFileFSRef, NULL))
; // Handle it
CFURLRef destinationDirURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mURL);
FSRef destinationDirFSRef;
if(!CFURLGetFSRef(destinationDirURL, &destinationDirFSRef))
; // Handle it
CFRelease(destinationDirURL), destinationDirURL = NULL;
CFStringRef destinationName = CFURLCopyLastPathComponent(mURL);
FSRef target;
OSStatus result = FSCopyObjectSync(&tempFileFSRef, &destinationDirFSRef, destinationName, &target, kFSFileOperationOverwrite | kFSFileOperationSkipSourcePermissionErrors);
if(noErr != result)
; // Handle it
The code works correctly if I disable sandboxing.
Edit: Additional information was requested by Femi. I open the file using C stdio:
FILE *f = fopen(reinterpret_cast<const char *>(buf), "r");
and it closed using fclose before the temp file is created.
My entitlements are:
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.music.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
It's also worth noting that Apple says in their App Sandbox Design Guide that:
If you are managing documents using any technology other than the
NSDocument class, you must convert to using this class. The NSDocument
class automatically works with Powerbox. NSDocument also provides
support for keeping documents within your sandbox if the user moves
them using Finder.
The sandbox only allows you to read and write from your application's container. If you have the read/write entitlement enabled, then you only have access to the files that are opened via the OpenSavePanel (or some method like dragging an icon to the dock where the user has specifically opened the file). This will severely limit how the application works with files on the file system.
So, as long as your application has permission to write over the document in question, you can write your temporary file to your applications container and then retrieve the temp file contents to then save to the original location. However, this assumes that you app maintains permissions to the original file throughout the process.
So, my suggestion is to make sure any writing you do is done in the application container and then verify that you app still has permission to write to the real file location before calling the save function.
I recently wrote a similar question where my app lost access to files that were open because another (non-sandboxed) app saved to the same file. The sandbox then gave that app access to my doc and removed permissions from the app.

Creating an OS X Service

I'm trying to create an OS X Service. I found Providing System Services in Apple's documentation, however I'm finding it less than clear on what exactly I need to do. I'm currently using an application to register my service (thinking that would be more straight forward - eventually I'd like to create a .service), however even after a logout/login my service still doesn't appear in the list of services in the menu.
Is there some step missing from the linked document that I'm missing? I feel like there is some registration step so that the OS knows about my service (in addition to what is listed in that doc), but I'm not able to find anything.
Thanks in advance. :)
Edit: Here is my NSServices dictionary from my Info.plist file:
<key>NSServices</key>
<array>
<dict>
<key>NSPortName</key>
<string>POPrlTest</string>
<key>NSMessage</key>
<string>shortenUrlService</string>
<key>NSSendTypes</key>
<string>NSStringPboardType</string>
<key>NSReturnTypes</key>
<string>NSStringPboardType</string>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Shorten URL</string>
</dict>
</dict>
</array>
Make sure your NSServices dictionary has everything it needs. If you're not sure, please post it so we can tell you.
Make sure you are launching your app first to get the system to see the Service.
Make sure you are registering the services handler in your app using
- setServicesProvider:
Also, check the Console log as that might give you some useful error info.
You might want to look at some commercial products to help you with this. See this posting on Fun Script.

Resources