Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notarization #169

Open
hohno-panopto opened this issue May 10, 2020 · 14 comments
Open

Notarization #169

hohno-panopto opened this issue May 10, 2020 · 14 comments

Comments

@hohno-panopto
Copy link

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.
@sveinbjornt
Copy link
Owner

This is great, thank you very much.

@JayBrown
Copy link

JayBrown commented Aug 28, 2020

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

@dipterix
Copy link

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

@JayBrown
Copy link

JayBrown commented Nov 21, 2020

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>

@dipterix
Copy link

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...

@JayBrown
Copy link

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

@dipterix
Copy link

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.

@JayBrown
Copy link

JayBrown commented Nov 22, 2020

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
Copy link

JayBrown commented Nov 22, 2020

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.)

@lastlink
Copy link

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

@JayBrown
Copy link

JayBrown commented Dec 15, 2020

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.

@AdrienLF
Copy link

AdrienLF commented Mar 6, 2021

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

@JayBrown
Copy link

JayBrown commented Mar 7, 2021

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

@Mudasir441
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants