question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Notarize OSX / Hardened Runtime

See original GitHub issue

I’m trying to understand what needs to be done, so that I can notarize my NWjs application. I am using 33.3 as I have prebuilt binaries for that version and it seems to be nice and stable.

I can’t seem to find anything related to notarization and NWjs and I’m struggling to follow any steps due to terrible information from the notarization tool. I tried to notarize via command line:

xcrun altool --notarize-app --primary-bundle-id "space.devader.demo" --file "../DevaderSrc/nwjs-v0.33.3-osx-x64/devader.app" --output-format xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>os-version</key>
	<string>10.14.5</string>
	<key>product-errors</key>
	<array>
		<dict>
			<key>code</key>
			<integer>-1</integer>
			<key>message</key>
			<string>The operation couldn’t be completed. ( error -1.)</string>
		</dict>
	</array>
	<key>tool-path</key>
	<string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
	<key>tool-version</key>
	<string>1.1.1138</string>
</dict>
</plist>

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:24 (10 by maintainers)

github_iconTop GitHub Comments

7reactions
Zarelcommented, Mar 3, 2020

SUCCESS! After two days of struggle.

After a bunch of struggling with @gpetrov’s script (it kept on matching things it shouldn’t sign), I rewrote it in Node and hardcoded more paths.

@weiluenju, you might want this, too.

sign-mac-app or whatever else you want to call the shell script; remember to chmod 755.

#!/usr/bin/env node

const APP = "path/to/your/app.app";
const IDENTITY = "identity of Developer ID cert";

/****************************************************************************/

console.log("### finding things to sign");

const fs = require('fs');
const child_process = require('child_process');

const items = [];

const frameworksDir = `${APP}/Contents/Frameworks/nwjs Framework.framework`;

let currentVersionDir;
for (const dir of fs.readdirSync(`${frameworksDir}/Versions`)) {
    if (fs.statSync(`${frameworksDir}/Versions/${dir}`).isDirectory) {
        currentVersionDir = `${frameworksDir}/Versions/${dir}`;
        break;
    }
}
if (!currentVersionDir) {
    console.error(`couldn't find "${frameworksDir}/Versions/[version]"`);
    process.exit(1);
}
for (const file of fs.readdirSync(`${currentVersionDir}`)) {
    if (file.endsWith('.dylib')) {
        items.push(`${currentVersionDir}/${file}`);
    }
}
for (const file of fs.readdirSync(`${currentVersionDir}/Helpers`)) {
    if (/^[a-z0-9_]*$/.test(file) || file.endsWith('.app')) {
        items.push(`${currentVersionDir}/Helpers/${file}`);
    }
}
for (const file of fs.readdirSync(`${currentVersionDir}/Libraries`)) {
    if (file.endsWith('.dylib')) {
        items.push(`${currentVersionDir}/Libraries/${file}`);
    }
}
for (const file of fs.readdirSync(`${currentVersionDir}/XPCServices`)) {
    if (file.endsWith('.xpc')) {
        items.push(`${currentVersionDir}/XPCServices/${file}`);
    }
}
items.push(frameworksDir);

/****************************************************************************/

console.log("");
console.log("### signing");

function exec(cmd) {
    console.log(cmd);
    const result = child_process.spawnSync(cmd, {shell: true, stdio: 'inherit'});
    if (result.status !== 0) {
        console.log(`Command failed with status ${result.status}`);
        if (result.error) console.log(result.error);
        process.exit(1);
    }
}

for (const item of items) {
    exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements neededToRun.entitlements "${item}"`);
}

exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements neededToRun.entitlements "${APP}"`);

/****************************************************************************/

console.log("");
console.log("### verifying signature");

exec(`codesign --verify -vvvv "${APP}"`);

neededToRun.entitlements is still needed.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.automation.apple-events</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
  </dict>
</plist>
6reactions
gpetrovcommented, Aug 12, 2019

I was able to fully notarize our nwjs app and get it approved by Apple! Thanks to the mailing list topic above.

I do had to sign all of the included nwjs frameworks and dylibs of the different libraries, separately! Which was a huge list! So for the convenience I made a bash script that finds all the modules and sign them.

Script is called codesign.sh that does all that automatically:

dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
app="$dir/your_app.app"
identity="**Your Apple registered Identity (XXXX)**"

echo "### signing app"
ITEMS=""

FRAMEWORKS_DIR="$app/Contents"
if [ -d "$FRAMEWORKS_DIR" ] ; then
    FRAMEWORKS=$(find "${FRAMEWORKS_DIR}" -depth -type d -name "*.framework" -or -type d -name "*.app" -or -type d -name "*.xpc" -or -name "*.dylib" -or -name "*.bundle" -or -path "*/Helpers/*" | sed -e "s/\(.*\/\(.*\)\.framework\)$/\1\/Versions\/A\/\2/")
    #  
    RESULT=$?
    if [[ $RESULT != 0 ]] ; then
        exit 1
    fi

    ITEMS="${FRAMEWORKS}"
fi

echo "Found:"
echo "${ITEMS}"

# Change the Internal Field Separator (IFS) so that spaces in paths will not cause problems below.
SAVED_IFS=$IFS
IFS=$(echo -en "\n\b")

# Loop through all items.
for ITEM in $ITEMS;
do
    echo "Signing '${ITEM}'"
    codesign --verbose --force --deep --strict --options runtime --timestamp --sign "$identity" --entitlements neededToRun.entitlements "${ITEM}"
    RESULT=$?
    if [[ $RESULT != 0 ]] ; then
        echo "Failed to sign '${ITEM}'."
        IFS=$SAVED_IFS
        exit 1
    fi
done

# Restore $IFS.
IFS=$SAVED_IFS

codesign --verbose --force --deep --strict --options runtime --timestamp --sign "$identity" --entitlements neededToRun.entitlements "$app"

echo "### verifying signature"
codesign -vvv -d "$app"

also as neededToRun.entitlements file I have:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.automation.apple-events</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
  </dict>
</plist>

for the further upload and notarization by apple I used the commands described in: https://successfulsoftware.net/2018/11/16/how-to-notarize-your-software-on-macos/

and it all worked great.

Maybe this should be included in the docs @rogerwang ? As from the next MacOS release 10.15 now in September, notarization will be required and nwjs apps won’t be able to run if not notarized by Apple!

Important

Beginning in macOS 10.14.5, all new or updated kernel extensions and all software from developers new to distributing with Developer ID must be notarized in order to run. Beginning in macOS 10.15, notarization is required by default for all software.

https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution

Read more comments on GitHub >

github_iconTop Results From Across the Web

Hardened Runtime | Apple Developer Documentation
To upload a macOS app to be notarized, you must enable the Hardened Runtime capability. For more information about notarization, see Notarizing macOS...
Read more >
Notarization: the hardened runtime
Currently, the only method provided by macOS to discover whether an app uses the hardened runtime, and which entitlements it takes, ...
Read more >
macOS Hardened runtime, notarization, code signing: app ...
I was already signing with a "Developer ID" key, so I just added entitlements, gatekeeperAssesment and hardenedRuntime to package.json and the ...
Read more >
Dummies guide to notarizing your runtime | by George Adams
Apple has recently changed the requirements for applications to install on macOS 10.15 and above. The change requires developers to notarize the application ......
Read more >
Getting Ready for macOS's Hardened Runtime and Notary
“Beginning in macOS 10.14.5, all new or updated kernel extensions and all software from developers new to distributing with Developer ID ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found