Associate AIR app in OSX without breaking codesigning - macos

If an app is build in Flash/AIR and exported as Captive Runtime for OSX, how does one associate a filetype with that app without breaking codesigning?
In a more general sense, can one edit the Info.plist in any app without invalidating codesigning, or use some other signed installer to handle the associations (like one would do on windows) and then sign that?
The only way I've seen to associate the app with a filetype, so far, is via the guide at https://superuser.com/questions/178316/how-to-set-an-icon-for-a-file-type-on-mac
This, according to the comments there, does invalidate codesigning.

If an application is already codesigned with a valid signature and any changes are made to the signed contents of it's .app bundle it will come back as invalid. So to answer your question, changing one byte in a signed apps info.plist will invalidate the signature. Changing an .apps icon does not affect the codesignature nor does adding something else entirely into it's app bundle, strangely enough. Well, maybe not entirely strange — since those actions (presumably) won't be changing/manipulating the signed contents.
As for associating filetypes with your application, that is handled through LaunchServices. If you aren't able to specify the properties at build time (using an info.plist) then you can use a dynamic configuration instead.

Related

How to check if two macOS apps, one code signed and notarized, are otherwise identical?

Imagine following scenario:
Person A without a Mac developer account, e.g. someone building an open source app, wants to have this app properly code signing (and notarized, with stapling).
Person B offers to code sign and notarize the app for person A.
The challenge:
How can Person A make sure that the signed code from B is not otherwise modified?
For instance, can A remove code signature and notarization information from the app again, and then use diff to verify that the original app's contents are identical to B's? If so, which commands accomplish this?
Please also consider the possibility that the app is simply a standalone executable (or, alternatively, the app may contain such executables as helpers), meaning the executable includes the signature instead of having it attached to the bundle in Contents/_CodeSignature.
(Disclaimer: I haven't built anything for macOS or iOS since 2016, so I'm a bit behind - please edit my post for me if I'm half-right - but if this answer is incorrect please let me know in a comment and I'll delete it right-away)
Based on these articles:
https://blog.fleetsmith.com/macos-mojave-app-notarization/
https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution
https://scriptingosx.com/2019/09/notarize-a-command-line-tool/
https://www.publicspace.net/blog/mac/2019/07/26/some-things-i-wish-i-had-know-before-starting-to-automate-mac-developer-id-notarization/
My understanding of the process is that your redistributable executable/app package is not actually modified at all - instead Apple records a hash of the files in the package on their servers. Whenever a macOS user runs your program, macOS sends the hash of the application's files to Apple and Apple responds with the notarization information.
However, you can "staple" a notarization receipt to an redistributable executable - which does modify the package - and this allows other macOS users' computers to quickly verify the notarization without needing to contact Apple's servers (though they may still check for notarization revocation in cases where a signing-certificate was compromised).
How can Person A make sure that the signed code from B is not otherwise modified?
If the receipt isn't stapled to the application package, the hash of both package files should be identical.
For instance, can A remove code signature and notarization information from the app again, and then use diff to verify that the original app's contents are identical to B's? If so, which commands accomplish this?
Not diff, but shasum: http://osxdaily.com/2012/02/05/check-sha1-checksum-in-mac-os-x/
shasum ~/Desktop/DownloadedFile.dmg

Uninstalling items installed by an .app when user deletes it, including SMJobBless helpers

The short version: is it possible to delete helper tools which were set up by the app (SMJobBless() etc.) when the app is deleted? If so, how?
The long version:
The Mac app we are developing unfortunately requires admin privileges to perform an occasional operation, and it also requires a background task to be live for other apps' plugins to connect to even when the app itself isn't running (this one can be unprivileged). The app will be signed with a Developer ID certificate, and distributed only outside the App Store.
We'd like the app to be a "good citizen" as far as possible, also on uninstall.
For the background task, we're using a login item, created using SMLoginItemSetEnabled(). This isn't amazing, because XPC messaging doesn't seem to work (we're using CFMessagePort instead - alternative suggestions welcome), but if the user deletes the app, the login item at least doesn't get loaded anymore on next login. I suspect there's still a trace of it somewhere in the system, but the executable inside the .app bundle is used, and when that disappears, the login item no longer runs.
For the occasional operation requiring admin rights, we've got a privileged helper tool which our app installs using SMJobBless(), and which implements a named XPC service, so the task spins up on demand when it receives a message from the main app. This is what Apple recommends and describes in its Even Better Authorization Sample.
The helper executable is copied to /Library/PrivilegedHelperTools/ by SMJobBless(), and the embedded launchd.plist ends up in /Library/LaunchDaemons/. Even though the OS has the information on which app "owns" the helper, it doesn't seem to uninstall it when the user deletes the app. Apple's sample is silent on uninstalling, other than the uninstall.sh script which is apparently intended to be used during development only. We don't need this helper while the app isn't running, so installing it as a full-blown launch daemon is slightly overkill, but we'd also like to avoid repeatedly annoying the user with the password prompt too. Besides, Apple advises against other forms of running code with admin privileges than SMJobBless() these days - for example SMJobSubmit() is marked deprecated.
So how do we clean up after ourselves?
I've found SMJobRemove(), but (a) when would we call that in our case - you can't run code on .app bundle deletion, or can you? and (b) it doesn't actually seem to clean up.
The only 2 things I can think of are not terribly satisfying:
Some kind of uninstaller app or script. But that seems pretty ugly too.
Don't worry about it and just leave a mess behind when the user deletes our app.
Update:
There have been some changes in this area with macOS 13.0 Ventura; there's an introduction to the new mechanism in the WWDC22 session 'What’s new in privacy'. The new SMAppService APIs support automatic cleanup for daemons, agents and login items. Unfortunately you'll of course still have to find a workaround for any older macOS versions you support.
Original answer:
There has been a similar question on the Apple Developer Forums at https://forums.developer.apple.com/thread/66821 - the recommendation by Apple is a manual uninstall mechanism, and consuming as few resources as possible if the user does not do this.
Apple DTS staff further recommended implementing a self-uninstall mechanism in the privileged launch daemon, to be triggered from the app via XPC. This is what we're going with.
I think the only solution you have right now is to use the uninstall shell code that you mentioned in order to physically remove the privileged helper from disk or to build an uninstaller for it. Either way you will have to ask the user to enter his/her password. This what all installers / uninstallers that require privileged access to the system do, and for a very good reason. That's why I avoid like the plague to use privileged helpers, but I understand that sometimes you really have to. I don't think it is good that you leave such a helper in the user's system, because it will reload next time the user starts up the computer.
I just checked ServiceManagement.h header and they state that SMJobRemove will be replaced by an API that will be made available through libxpc in the future. (Sometimes you really need to go to the headers to get extra info that the documentation does not give you.) Hopefully this promised replacement will uninstall it for us. However, I'd file a bug report and ask for that enhancement.
One solution you could consider is to include an uninstaller script or program in your .app bundle.
You can then pass the path of this small tool to your helper tool (via IPC) and have the execute the the uninstaller, thereby deleting itself. You will have to be careful that components are removed in the right order but it can be made to work.
You're correct that Apple does not provide an API to uninstall a helper tool installed with SMJobBless nor do they do so automatically. As for why macOS doesn't automatically do an uninstall, my educated guess is because macOS fundamentally doesn't have a unified concept of "install". While it's convention for apps to be located in /Applications (and a few other locations), it's perfectly valid for apps to be located and run from anywhere on the system including external drives and network drives. For example should macOS uninstall helper tools when apps disappear because the drive they're on is disconnected?
In terms of how to uninstall, doing so requires root permission and so realistically have the helper tool itself do the uninstall is the easiest option. You can have your app via XPC tell the helper to uninstall itself. Here's an example in Swift of how to do this; it's part of SwiftAuthorizationSample. The basic idea is:
Use the launchctl command line tool to unload the helper tool
Delete the helper tool executable
Delete the helper tool launchd plist
But there's a bit of additional complexity involved because launchctl won't let you unload a running process.

Mac App Store app rejected because of accessing file system - 2.30

After developing my first Mac app I've decided to submit it to the Mac App Store but it got rejected. Basically my app uses NSOpenPanel for reading Xcode project file and NSSavePanel for saving file after it finishes it's work.
Reviewer pointed out that app is violating 2.30 rule - Apps that do not comply with the Mac OS X File System documentation will be rejected, but I'm unclear why.
When you look at app's workspace you can see it uses CocoaPods for handling dependencies which shouldn't be a problem. Next it has JBLocalizer.framework which is being linked as an embedded library to JBLocalizerApp. JBLocalizerApp is final target sent to the review.
Here is what reviewer pointed out as a problem:
2.30
The application accesses the following location(s):
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBString.gcda'
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBPostProcessStringsOperation.gcda'
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBOperation.gcda'
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBLoadStringsInFileOperation.gcda'
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBLoadSourceFilesOperation.gcda'
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBLoadRootFilesOperation.gcda'
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBFileController.gcda'
'/Users/josipbernat/Library/Developer/Xcode/DerivedData/Build/Intermediates/ArchiveIntermediates/JBLocalizerApp/IntermediateBuildFilesPath/JBLocalizer.build/Release/JBLocalizer.build/Objects-normal/x86_64/JBFile.gcda'
The majority of developers encountering this issue are opening files
in Read/Write mode instead of Read-Only mode, in which case it should
be changed to Read-Only.
Other common reasons for this issue include:
creating or writing files in the above location(s), which are not valid locations for files to be written as stated in documentation
writing to the above location(s) without using a valid app-id as a container for the written files
Please review the "File-System Usage Requirements for the App Store"
of Submitting to the Mac App Store for the locations apps are allowed
to write and for further guidance.
I'm really not sure how can my app violate access to the library which is being linked to. Any suggestions?
You've got Code Coverage turned on in your project settings.
See QA1514 on how it's turned on, which should help you turn it off.

Mac Sandboxing: Can it really be this easy?

I'm just trying to get some confirmation on Sandboxing. I understand exactly why it's been put in place and the principle behind it.
As I start to near the release of my first Mac App I kept putting off sandboxing as it sounded rather complicated and thought I'll worry about it nearer the time. I watched a couple of the Apple videos and read up on some of the documentation (not all) and thought I'd try and add it to my app!
I turned on sandboxing in Xcode, didn't specify any entitlements as they didn't really relate to my app and the entitlements certificate popped up on the left and ran my app....that was it, all ran fine without issues.
That's where I got confused...surely it can't be that simple?! My app saves data in the background, no user input to save, it just happens seamlessly. Anyway I checked /Users/whoever/Library/Containers and there was my app named container folder and the relevant data was saved there (although of course that wasn't the exact path I specified as the save location in my app). I closed my app, reopened it and sure enough the saved data was still there.
IS THAT IT? Does that now mean my app is sandboxed or am I missing something here?
Yes, that's it. If your app really doesn't need any entitlements, not even the ability to open/save files specified by the user, then it's trivial to sandbox.

How to Suppress the keychain prompt when the app modified?

Hi Im using Mac 10.5.8 . In my app im using my own keychain(created by me), but my actual question is when I modify my code in the app every time a prompt is appearing, saying that the present app is modified do you want to allow or not.Can any one tell how to supress this prompt(allow by default when ever I change the app).I couldn't find the solution in the documentation.
The Keychain has a list of trusted applications, and this list includes a hash digest for the application. When the application changes, it becomes untrusted again. This also happens with "big" applications like Camino.
There are two special measures to reduce this: When a shared library gets updated, the system will keep track of this and accept the application even after the update. Also, when Software Update updates an app, it will fix the digests as well (which is why Apple's own apps can get away without re-confirmation).
Update: If you sign your code, Keychain will also accept updated applications (signed with the same certificate).

Resources