Platypus icon indicating copy to clipboard operation
Platypus copied to clipboard

Notarization

Open hohno-panopto opened this issue 4 years ago • 14 comments

This is not an issue, but I wanted to share my experience with Platypus users.

I was able to get Apple's notarization to my application which was generated by Platypus. As the result, I was able to put my app on the public website and let people download and run. Without notarization, macOS 10.15 rejects the execution of downloaded app and there is no way to override it.

I referred this article as a starting point. Thank you, @dpid

Prerequisite

  • Xcode is installed on your machine.
  • You understand signing application and notarization. I do not explain about them.
  • You have Apple ID which is registered to Apple developer program, and you have already generated and downloaded Developer ID Application certificate.

Steps

All of them are done from command line (Terminal). Please read this document for more details about notarization from command line tools.

Let's assume your app is generated as ./Example.app and bundle name is com.example.app. Also assume the name of Developer ID Application certificate as "Developer ID Application: Example Company (A1BC234DEF)".

  1. Sign your application.
chmod -R a+xr ./Example.app
codesign --deep --force --verify --verbose --timestamp --options runtime --sign "Developer ID Application: Example Company (A1BC234DEF)" ./Example.app
  1. Create archive ZIP for notarization. This is different from the final product.
ditto -c -k --keepParent ./Example.app ./Example.archive.zip
  1. Submitting notarization. You might need --asc-provider option if your Apple ID is associated to two or more teams.
xcrun altool --notarize-app -f ./Example.archive.zip --primary-bundle-id "com.example.app" -u [email protected] -p PassWordForAppleId
  1. You should see RequestUUID as the result of previous step. Note that UUID. We assume 12345678-1234-5678-90ab-cdef12345678 here. Type the command periodically until the Status becomes 'success'.
xcrun altool --notarization-info 12345678-1234-5678-90ab-cdef12345678 -u [email protected]  -p PassWordForAppleId
  1. After notarization succeeds, staple the ticket to the package.
xcrun stapler staple ./Example.app
  1. Zip the app as final product. This Example.zip may be put on the public web server, and people may download and run it.
zip -r ./Example.zip ./Example.app

Notes

  • This is the info as of May 10, 2020.
  • My app is with zsh script, using Text Window UI, and requiring admin privilege. I guess those do not matter for notarization, but I did not verify other variations.
  • Since my app does not use Mac App Store, I cannot say whether this would mean good for Mac App Store or not.
  • Sveinbjorn, Platypus is awesome. This made my script as a real app with very little effort! Thank you, thank you, thank you.

hohno-panopto avatar May 10 '20 21:05 hohno-panopto

This is great, thank you very much.

sveinbjornt avatar Aug 07 '20 01:08 sveinbjornt

I only have a free Apple Development certificate which is not suitable for distribution, but I still give my Platypus apps a valid code signature with my own third-party certificate.

In those Platypus apps meant for distribution, the script has a test for path randomization (app translocation).

You could also have your app open an info text file or an info webpage on your domain which then explains how to remove the quarantine extended attribute to the user, instead of just displaying a generic prompt & quitting.

uiprocess="app_name"
process="process_name"
mypath="$0"
myname=$(basename "$mypath")
[[ $myname == "script" ]] && myname="$process"	
scr_parent=$(dirname "$mypath") # Resources (in Contents)

_quit-app () {
	printf "QUITAPP\n"
}

_error () {
	afplay "$scr_parent/error.aif" &>/dev/null
}

_syswarning () {
	_error &
	osascript &>/dev/null << EOT
display alert "$1" message "$2" as critical buttons {"Quit"} default button "Quit" giving up after 180
EOT
	_quit-app
	exit 1
}

if echo "$mypath" | grep -q "/AppTranslocation/" &>/dev/null ; then
	echo "ERROR[04]: application $uiprocess ($myname) has been translocated"
	_syswarning "Internal error [04]: AppTranslocation" "Please quit $uiprocess ($myname), dequarantine the app, and try again!"
fi

JayBrown avatar Aug 28 '20 09:08 JayBrown

This looks great. However, I got this issue when trying to validate the notarization

>$ spctl -vvv --assess --type exec "$TFILE"
lol.app: rejected (the code is valid but does not seem to be an app)
origin=Developer ID Application: XXXXXX

Looks like the Gatekeeper still fails the app even though it's properly signed?

I found this thread, not sure if it's relevant

dipterix avatar Nov 21 '20 08:11 dipterix

For some reason, the correct command is spctl -vvv --assess --type install <filepath> or short-form spctl -vvv -a -t install <filepath>, even though an app is not an installer.

EDIT 1: you should also check the app and its nested code with codesign --verify --deep --strict --verbose=4 <filepath>

EDIT 2: and another check, only for the stapled notarization ticket: xcrun stapler validate <filepath>

JayBrown avatar Nov 21 '20 08:11 JayBrown

Uh, I see... Then it looks everything got passed. But my apps still cannot execute on other machines once I upload them to Github (dmg, zipped or not zipped).

Began to doubt my life as I only got problems but don't know where it went wrong...

dipterix avatar Nov 21 '20 09:11 dipterix

That's weird. If your app is notarized, it should run just fine.

JayBrown avatar Nov 21 '20 23:11 JayBrown

Yup, that's what I was struggling about. I got green lights all the way to staple and verified each step, but still unable to download from another computer.

dipterix avatar Nov 22 '20 04:11 dipterix

Three questions:

(1) Does the main script at ./Contents/Resources/script have the executable bit set? You can check with e.g. stat -x script. It should read something like rwxr-xr-x. You can also safely change those even after code-signing with the usual chmod +x script command. (I'm asking, because maybe some x-bits got flipped by Apple's notarization service.)

(2) Are you using any additional nested code or scripts besides ./Contents/MacOS/<Executable> and ./Contents/Resources/script? Other executables would probably need to be notarized/stapled too. (Not scripts, though.)

(3) EDIT: did you use macOS' built-in /bin/zsh as the script's interpreter in the shebang?

JayBrown avatar Nov 22 '20 07:11 JayBrown

PS: maybe there's another problem… if you use additional code/scripts, it should be in one of the default directories assigned by Apple for signing nested code:

./Contents/Frameworks
./Contents/SharedFrameworks
./Contents/PlugIns
./Contents/Plug-ins
./Contents/XPCServices
./Contents/Helpers
./Contents/MacOS
./Contents/Library/Automator
./Contents/Library/Spotlight
./Contents/Library/LoginItems

…and maybe that's also causing the problem with the main script.

Many developers tend to nest code in irregular subpaths like ./Contents/Resources, which can lead to problems. I also asked the Platypus dev to change this, i.e. move script from ./Contents/Resources/script to e.g. ./Contents/Helpers/bin/script or ./Contents/MacOS/script.

So you could maybe try to move your script into one of the default directories, e.g. Helpers or MacOS, and then recreate ./Contents/Resources/script as a symbolic link to the new location. (Would need to be a relative path symlink, e.g. ../Helpers/script.)

JayBrown avatar Nov 22 '20 07:11 JayBrown

If you are not notarized, e.g. demoing w/out a cert the solution is the user must have admin access from https://apple.stackexchange.com/a/253943/222813.

running sudo xattr -r -d com.apple.quarantine /Applications/Some.app will unquarantine the app

lastlink avatar Dec 15 '20 18:12 lastlink

You normally don't need sudo. If the app is a drag & drop installation, the installing user has ownership & control, at the very least in ~/Applications, so privilege escalation isn't necessary a lot of the time.

JayBrown avatar Dec 15 '20 23:12 JayBrown

Thank you all for the info, I followed it, however I have an issue when I try to sign the app. Here's what I'm doing: I have an .app created by pyinstaller that doesn't work on its own, I need a shell script to launch it.

So, with platypus, I create an .app from the shell script, and put the pyinstaller created .app in the ressources folder. This launches with no issues.

However, platypus converts my shell script to a file named "script" without extension, in the Resources folder. This causes codesign to give me this error:

"resource fork, Finder information, or similar detritus not allowed"

This is caused by that file that doesn't have an extension. If I remove the "script" file of the bundle, I can sign with no issue... but of course, the app then doesn't find the script, and crashes. Did anybody find a solution to this? I don't see how you can sign an app if platypus created a file with no extension.

Thank you

AdrienLF avatar Mar 06 '21 23:03 AdrienLF

Always run xattr -cr /Applications/<yourPlatypus>.app before codesigning. And always codesign at the very end, after you have finished modifying the bundle. If you have another bundle nested within your Platypus app, you have to sign that first, and then the main bundle at the end.

Additionally, try not to use Finder when navigating the nested contents of a bundle including app bundles. Finder is a catastrophe in these scenarios.

PS: executing code should not be in ./Contents/Resources. Only non-Mach-O scripts go there. I don't know what kind of an executable the pyinstaller app has… if it's a script, it's fine in Resources… otherwise put it e.g. in ./Contents/MacOS or /Contents/Helpers

See e.g. here s.v. "Nested Code": https://developer.apple.com/library/archive/technotes/tn2206/_index.html

JayBrown avatar Mar 07 '21 00:03 JayBrown

Thanks @hohno-panopto for this great share. The PassWordForAppleId should be App specific password I guess, as normal password of Apple ID didn't worked for me. Then I created App specific password at https://appleid.apple.com/account/home which worked.

Mudasir441 avatar Feb 20 '24 12:02 Mudasir441