The Wayback Machine - https://web.archive.org/web/20200225153153/https://github.com/nwjs/nw.js/issues/6338
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

MAS code signing and distribution guide request #6338

Open
tankakatan opened this issue Dec 16, 2017 · 31 comments
Open

MAS code signing and distribution guide request #6338

tankakatan opened this issue Dec 16, 2017 · 31 comments
Labels

Comments

@tankakatan
Copy link

@tankakatan tankakatan commented Dec 16, 2017

Hello!

Thank you very much for nw.js!

Me and my colleagues are currently trying to prepare our nwjs app for Mac App Store distribution. But there is a lack of information on how to do it properly.

We use NWJS 0.27.1 on Mac OS 10.13.2. The documentation suggests to use MAS helper script, but it seems to be designed for nwjs 0.19.5, whereas our project uses latest nwjs features such as importNWBin.

Still, we've tried to sign our app with that script with entitlements relevant to our app features. Unfortunately the application signed with build_mas.py silently crashes upon start regardless of signing identity set in the configuration file. Here is a crash log that was captured via OS X Console app:
app-signed-via-build_mas-crash-log.txt

We have tested build_mas.py with these kinds of identity:

  • 3rd Party Mac Developer Application
  • Developer ID Application
  • Mac Developer

All the necessary certificates and provision profiles were properly installed on the system that has been used for a code signing.

We have also tried signing our product with the following self-made script:

#!/bin/sh

APP_IDENTITY="Mac Developer: Our Identity (...)"
ENTITLEMENTS_CHILD="entitlements-child.plist"
ENTITLEMENTS_PARENT="entitlements-parent.plist"
APP="Our App Name.app"

sign () {
    OBJECT=$1
    ENTITLEMENTS=$2

    codesign --force --verbose --verify --sign "$APP_IDENTITY" --entitlements "$ENTITLEMENTS" --deep "$OBJECT"
    codesign --verify --deep --strict --verbose=2 "$OBJECT"
}

sign "$APP/Contents/Versions/63.0.3239.84/nwjs Framework.framework/libnode.dylib" "$ENTITLEMENTS_CHILD"
sign "$APP/Contents/Versions/63.0.3239.84/nwjs Framework.framework/Helpers/crashpad_handler" "$ENTITLEMENTS_CHILD"
sign "$APP/Contents/Versions/63.0.3239.84/nwjs Framework.framework/XPCServices/AlertNotificationService.xpc" "$ENTITLEMENTS_CHILD"
sign "$APP/Contents/Versions/63.0.3239.84/nwjs Framework.framework/nwjs Framework" "$ENTITLEMENTS_CHILD"
# sign "$APP/Contents/Versions/63.0.3239.84/nwjs Framework.framework" "$ENTITLEMENTS_CHILD"

sign "$APP/Contents/Versions/63.0.3239.84/nwjs Helper.app" "$ENTITLEMENTS_CHILD"
sign "$APP/Contents/Versions/63.0.3239.84/libffmpeg.dylib" "$ENTITLEMENTS_CHILD"

sign "$APP" "$ENTITLEMENTS_PARENT"

The instructions listed above work correctly and the codesign validation shows valid on disk / satisfies its Designated Requirement status for every resource it is applied to (except nwjs Framework.framework that will be mentioned further). However the application signed with this script crashes in the same way as described earlier. This time the crash log differs from the one attached above, but it also has a lot in common:
app-signed-for-development-crash-log.txt

It is also worth to note that both of the above scripts (build_mas.py and the one we created ourselves) have displayed a following error after the attempt to sign nwjs Framework.framework

Our App Name.app/Contents/Versions/63.0.3239.84/nwjs Framework.framework: unsealed contents present in the root directory of an embedded framework

I suppose that the reason of this error is that the nwjs Framework.framework itself consists of a large number of resources each of which should be signed on it's own as described in the apple documentation https://developer.apple.com/library/content/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html.

Additionally we have tried to manually sync our app's bundle identifier and display name with PlistBuddy utility but it doesn't seem to solve our problem as well.

BUNDLE_ID="our.app.bundle.id"
APP_NAME="Our App Name"

sed -i '' "s#(CFBundleDisplayName[^\"]\")[^\"](\")#\1$APP_NAME\2#g" "$APP/Contents/Resources/en.lproj/InfoPlist.strings"

/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$APP/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $APP_NAME" "$APP/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID.helper" "$NWJS_HELPER/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $APP_NAME Helper" "$NWJS_HELPER/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :com.apple.security.application-groups $BUNDLE_ID" "$ENTITLEMENTS_PARENT"

Is there a way to make it work? We would really appreciate if someone shared some experience or advice on how to do MAS code signing properly. We will be happy for any help. Thanks in advance!

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Dec 16, 2017

Good news everyone!

The reason of the crash was the usage of the apple sandbox entitlement. If it is set to false app starts normally.

However it would be nice to find out the problem that leads our app to crash while running in the sandbox. The log attached to the issue says much about sandbox errors. So any ideas on how to solve them are welcome!

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Dec 23, 2017

This issue is obviously related to #6041

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Dec 23, 2017

Ok, I've found a fix to the unsealed contents error. It is caused by a libnode.dylib placed in the root folder of nwjs.app/Contents/Versions/63.0.3239.108/nwjs Framework.framework/.

According to Apple documentation:

...if a bundle has a Contents or Versions directory at its top level, there may be no other files or directories alongside them. The one exception is that alongside Versions, there may be symlinks to files in Versions/Current.

So the way to fix the problem is to move libnode.dylib to a nwjs.app/Contents/Versions/63.0.3239.108/nwjs Framework.framework/Versions/A/ folder and make a symbolic link to it in nwjs Framework.framework so its content will look like this:

drwxr-xr-x@ 8 user  group  256 Dec 23 20:36 .
drwxr-xr-x@ 5 user  group  160 Dec 23 20:36 ..
lrwxr-xr-x  1 user  group   24 Dec 16 20:47 Helpers -> Versions/Current/Helpers
lrwxr-xr-x  1 user  group   26 Dec 16 20:47 Resources -> Versions/Current/Resources
drwxr-xr-x@ 4 user  group  128 Dec 16 20:47 Versions
lrwxr-xr-x  1 user  group   28 Dec 16 20:47 XPCServices -> Versions/Current/XPCServices
lrwxr-xr-x  1 user  group   24 Dec 23 20:36 libnode.dylib -> Versions/A/libnode.dylib
lrwxr-xr-x  1 user  group   31 Dec 16 20:47 nwjs Framework -> Versions/Current/nwjs Framework

This fix helps to sign the application for a MAS distribution properly that can be proved via spctl utility:

spctl --assess --type execute Your app name.app
spctl --assess --verbose=4 Your app name.app

But unfortunately the application still can not be submitted to Mac App Store because the spctl will reject it whenever you replace an app bundle id with your own (keeping in mind that Info.plist can be edited strictly before the app will be signed).

Also the solution described above doesn't help to add the app sandbox capability. The application keeps crashing on start every time the sandbox option appears in entitlements.plist.

Looking forward for any help or advice.

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Dec 24, 2017

Yesterday I have finally gained success with getting spctl accepted status for our application. Here's a very useful application that helped me to discover some more unsealed contents in the Resources folder inside the application.

But the final fix was to add our team id to the application bundle id in the app entitlements.

BTW the entitlements-parent.plist file distributed with build_mas.py has a little bit incorrect format. According to apple docs the com.apple.security.application-groups key should have a value of type array of strings even if there is only one string.

The value for this key must be of type array, and must contain one or more string values, each of which must consist of your development team ID, followed by a period, followed by an arbitrary name chosen by your development team.

So the correct format for this entitlement is

	<key>com.apple.security.application-groups</key>
	<array>
		<string>TEAM_ID.your.app.bundle.id</string>
	</array>

Unfortunately the issue with app sandboxed mode still remains unsolved. Still waiting for any help or feedback on this subject.

Thanks everyone for the attention. Merry xmas and sorry for my awful english.

@Arti3DPlayer

This comment has been minimized.

Copy link

@Arti3DPlayer Arti3DPlayer commented Jan 18, 2018

@tankakatan thank you, I will try your solution. Spent a lot of hours with unsealed contents. Could you add commands that you do to fix problem. It will be nice

Also, did you build app with nw-builder?

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Jan 21, 2018

@Arti3DPlayer here's my script for that:

# Set PATH_TO_YOUR_APP variable first
VERSION_NUMBER=`ls "${PATH_TO_YOUR_APP}/Contents/Versions/"`
NWJS_FRAMEWORK="$PATH_TO_YOUR_APP/Contents/Versions/$VERSION_NUMBER/nwjs Framework.framework"
LIBNODE_DYLIB="libnode.dylib"
LIBNODE_LINK_TO="Versions/A/$LIBNODE_DYLIB"

echo fixing nwjs Framework unsealed content
pushd "$NWJS_FRAMEWORK"
mv "$LIBNODE_DYLIB" "$LIBNODE_LINK_TO"
ln -s "$LIBNODE_LINK_TO"
popd

To synchronise bundle ids you can use PlistBuddy – a very handy tool for that. So my script is something like this:

# Set BUNDLE_ID variable with your app bundle id
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$PATH_TO_YOUR_APP/Contents/Info.plist"

# Set PATH_TO_ENTITLEMENTS_PARENT_PLIST variable
# Set TEAM_ID variable with your team id
/usr/libexec/PlistBuddy -c "Set :com.apple.security.application-groups:0 $TEAM_ID.$BUNDLE_ID" "$PATH_TO_ENTITLEMENTS_PARENT_PLIST"

Also i suggest you to update CFBundleIdentifier in all Info.plist files you will find inside your app's package. Add the corresponding postfix to the bundle id of each resource. For example, use $BUNDLE_ID.helper in Info.plist of nwjs Helper.app.

@Arti3DPlayer

This comment has been minimized.

Copy link

@Arti3DPlayer Arti3DPlayer commented Jan 24, 2018

@tankakatan thanks, it works! But Users still get message that app from Unknown developer. i used mas.py script

And yes still crashing problem with Sandbox=Yes that makes impossible to upload app to Appstore

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Jan 24, 2018

@Arti3DPlayer it is ok to see the unknown developer warning until your users do not have to manually allow gatekeeper to run your app. It means that as long as you need to go to the system security settings to open your application its code signature is incorrect.

Sadly i haven't found a solution to the sandbox issue yet. The apple console shows a number of different errors refer to crashpad_handler and nwjs Framework itself. Сurrently i'm trying to build nwjs from the sources to try to fix all that errors one by one.

@Arti3DPlayer

This comment has been minimized.

Copy link

@Arti3DPlayer Arti3DPlayer commented Jan 24, 2018

@tankakatan I fixed my problem by set the full name of certificate in build.cfg file:

## [REQUIRED] Your Application Certificate Identity
ApplicationIdentity = Developer ID Application: MyComapny Name (TT666666)

And its weird because when I used only code from brackets in this line(TT666666) it used 3rd Party Mac Developer Application that needed for appstore, but doesn't work for outside app. For now after download my app gatekeeper only warn user that

App was downloaded from internet, do you want to open it?

I didn't test this with auto update yet. Hope I will be able to swap apps programmatically

Found a lot of useful info from electron documentation:
https://www.electron.build/code-signing

@gpetrov

This comment has been minimized.

Copy link

@gpetrov gpetrov commented Apr 8, 2018

@tankakatan, @Arti3DPlayer and @rogerwang - does this all means that we can finally upload the latest NWJS to the MAS - or is still a special build needed?

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Apr 8, 2018

@gpetrov nope, i have not succeed with MAS distribution so far. I also tried to build nwjs from the sources, but alas, failed to do so.

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Apr 13, 2018

@Arti3DPlayer Have you successfully uploaded your app to MAS?

@denigada

This comment has been minimized.

Copy link

@denigada denigada commented May 31, 2018

@tankakatan I have tried everything and getting this problem when trying to sign my app:

Warning: unable to build chain to self-signed root for signer

Have you found a solution to sign the app? I can't even sign the app for outside MAS use. I sign it with Developer ID and it gives unidentified developer warning, I sign with 3rd Party Mac Developer certificate and I get the above warning and the app crashes on launch.

@Arti3DPlayer

This comment has been minimized.

Copy link

@Arti3DPlayer Arti3DPlayer commented May 31, 2018

Yes, I'm not able to upload to MAS too, but sign app works fine even with autoupdates, so I don't require mas for now

@denigada try to use https://itunes.apple.com/us/app/rb-app-checker-lite/id519421117?mt=12 to identify what problems do you have. You can open and compare some popular apps and yours. I did this with "docker" app to make sure that I have all the same certificates

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Jun 1, 2018

@denigada @Arti3DPlayer i have built nwjs from the sources to find out the details of the sandboxed app crash and discovered that the reason of the problem is in the chromium itself. Here's the the google groups discussion where i have described it. Unfortunately i haven't got any feedback yet. Probably we should communicate with electron devs to ask them to share their experience.

@gretel

This comment has been minimized.

Copy link

@gretel gretel commented Oct 28, 2019

@tankakatan thanks for all your effort!
reflecting your work on my code still gives me

./Contents/Versions/72.0.3626.121/nwjs Framework.framework: unsealed contents present in the root directory of an embedded framework

any chance you can post your script as a whole?

here is mine:
https://gist.github.com/gretel/99bc84729c9b5298c277dad326d578c6

thank you!

@tankakatan

This comment has been minimized.

Copy link
Author

@tankakatan tankakatan commented Nov 2, 2019

@gretel i haven't been working with nw.js since my last comment here or so, therefore i believe my script is completely outdated and useless now. But the idea of solving your issue is pretty simple. That is to find all the unsigned items in the contents of your app. RB App Checker will help you to accomplish that (it seems being distributed outside of MAS now, but still available for download). This extremely useful tool will show you every unsealed item of your app's content, and you'll be able to sign them all just the same way as you do with other resources. You can find an example of signing script in the initial post of this thread.

@gretel

This comment has been minimized.

Copy link

@gretel gretel commented Nov 2, 2019

@tankakatan thanks for getting back to me!

i have been using the tool you mentioned prior to asking.. it does show only one "red" issue:

image

leaving me confused, still.

@gretel

This comment has been minimized.

Copy link

@gretel gretel commented Nov 3, 2019

@tankakatan updating to nwjs 0.42.2 and applying https://gist.github.com/gretel/99bc84729c9b5298c277dad326d578c6 does get rid of the unsealed contents present warning - still "rejected" - but does open using the ctrl trick. thanks again.

@zkrige

This comment has been minimized.

Copy link

@zkrige zkrige commented Jan 16, 2020

I able to distribute my app manually and have managed to get signing working. However, now I want to distribute via MAS and I'm hitting a bunch of interesting issues

ERROR ITMS-90511: "CFBundleIdentifier Collision. The Info.plist CFBundleIdentifier value 'io.nwjs.nwjs.framework.AlertNotificationService' of 'MYAPP.app/Contents/Frameworks/nwjs Framework.framework/Versions/78.0.3904.108/XPCServices/AlertNotificationService.xpc' is already in use by another application."
ERROR ITMS-90511: "CFBundleIdentifier Collision. The Info.plist CFBundleIdentifier value 'io.nwjs.nwjs.helper' of 'MYAPP.app/Contents/Frameworks/nwjs Framework.framework/Versions/78.0.3904.108/Helpers/nwjs Helper (GPU).app' is already in use by another application."
ERROR ITMS-90511: "CFBundleIdentifier Collision. The Info.plist CFBundleIdentifier value 'io.nwjs.nwjs.helper' of 'MYAPP.app/Contents/Frameworks/nwjs Framework.framework/Versions/78.0.3904.108/Helpers/nwjs Helper.app' is already in use by another application."

any suggestions on how to avoid the bundleid collisions?

@zkrige

This comment has been minimized.

Copy link

@zkrige zkrige commented Feb 3, 2020

@rogerwang is there any documentation available on getting an NWJS app into MAS? Theres some comments spread across multiple GitHub issues, but nothing definitive. Also, the comments seem relative to disparate versions of NWJS, so its difficult to tell how to get the latest version into MAS (if even possible)

@rogerwang

This comment has been minimized.

Copy link
Member

@rogerwang rogerwang commented Feb 3, 2020

I don't think the latest version supports MAS because Chromium upstream doesn't support MAS. The latest version is mentioned in https://nwjs.readthedocs.io/en/latest/For%20Users/Advanced/Support%20for%20Mac%20App%20Store/

@zkrige

This comment has been minimized.

Copy link

@zkrige zkrige commented Feb 3, 2020

Thank you for the update

@zkrige

This comment has been minimized.

Copy link

@zkrige zkrige commented Feb 13, 2020

After much wrangling I can get past everything EXCEPT the sandbox flag.

As soon as you turn the sandbox flag on, MAS is satisfied, but the app won't actually run - it crashes on startup

@jssuttles

This comment has been minimized.

Copy link

@jssuttles jssuttles commented Feb 13, 2020

@zkrige To fix the collision, I followed the Mac instructions in https://nwjs.readthedocs.io/en/nw28/For%20Users/Package%20and%20Distribute/#platform-specific-steps
(They are out of date. The helpers are now in a Helpers directory.)
So, I renamed CFBundleDisplayName and CFBundleExecutable in each plist file and while I was there I parsed the name and got the part in the parenthesis and added it to the CFBundleIdentifier.
For example: io.nwjs.nwjs.helper for nwjs Helper.app and io.nwjs.nwjs.helper.gui for nwjs Helper (GUI).app
Seems to have fixed the collision for me

@jssuttles

This comment has been minimized.

Copy link

@jssuttles jssuttles commented Feb 13, 2020

Using a lot from #7117 (comment):

const { exec, execSync } = require('child_process');
const { createWriteStream, readdirSync, statSync, move, readFile, writeFile } = require('fs-extra');
const path = require('path');
const plist = require('simple-plist');
const log = require('fancy-log');
const DEFAULT_ENTITLEMENTS_PATH = 'app entitlements file path';
const INTERNAL_ENTITLEMENTS_PATH = 'internal entitlements file path';
const IDENTITY = 'your signing identity here';
/**
 * Code sign .app or .dmg
 * @param {String} filePath  path to .app or .dmg
 * @param {String} [entitlementsFilePath=DEFAULT_ENTITLEMENTS_PATH] path to entitlements file
 */
function codesign(filePath, entitlementsFilePath=DEFAULT_ENTITLEMENTS_PATH) {
  log(`Signing ${filePath}...`);
  execSync(`codesign -s "${IDENTITY}" --timestamp --options runtime --entitlements ${entitlementsFilePath} --force --deep "${filePath}"`);
  log('Signed');
}

/**
 * NWJS helper apps can be renamed with app name
 * We need to fix colliding CFBundleIdentifier
 * @param {String} file
 * @param {String} appName
 * @param {String} currentVersionDir
 * @return {Promise<String>}
 * @private
 */
async function _fixNWJSHelperApp(file, appName, currentVersionDir) {
  let newFileName = file.replace('nwjs', appName);
  log(`Working on ${file}`);
  for (const helperFile of readdirSync(`${currentVersionDir}/Helpers/${file}/Contents/MacOS`)) {
    let newHelperFileName = helperFile.replace('nwjs', appName);
    let plistFile = `${currentVersionDir}/Helpers/${file}/Contents/info.plist`;
    let plistString = await readFile(plistFile);
    let plistObject = plist.parse(plistString);
    plistObject.CFBundleDisplayName = newHelperFileName;
    plistObject.CFBundleExecutable = newHelperFileName;
    plistObject.CFBundleIdentifier = 'io.nwjs.nwjs.helper';
    if (/\([A-Za-z]*\)/.test(newHelperFileName)) {
      plistObject.CFBundleIdentifier += `.${newHelperFileName.match(/\(([A-Za-z]*)\)/)[1].toLowerCase()}`;
    }
    await writeFile(plistFile, plist.stringify(plistObject));
    await move(`${currentVersionDir}/Helpers/${file}/Contents/MacOS/${helperFile}`, `${currentVersionDir}/Helpers/${file}/Contents/MacOS/${newHelperFileName}`);
  }
  await move(`${currentVersionDir}/Helpers/${file}`, `${currentVersionDir}/Helpers/${newFileName}`);
  return newFileName;
}

/**
 * Code sign .app
 * @param {String} appPath
 */
async function codesignNWJSApp(appPath) {
  log(`Signing NWJS App ${appPath}...`);
  const items = [];

  let appName = path.basename(appPath, path.extname(appPath));
  const frameworksDir = `${appPath}/Contents/Frameworks/nwjs Framework.framework`;

  // find current version in frameworks
  let currentVersionDir;
  for (const dir of readdirSync(`${frameworksDir}/Versions`)) {
    if (statSync(`${frameworksDir}/Versions/${dir}`).isDirectory()) {
      currentVersionDir = `${frameworksDir}/Versions/${dir}`;
      break;
    }
  }
  if (!currentVersionDir) {
    log(`couldn't find "${frameworksDir}/Versions/[version]"`);
    throw new Error('No current version found');
  }

  // add files in frameworks to code sign
  for (const file of readdirSync(`${currentVersionDir}`)) {
    if (file.endsWith('.dylib')) {
      items.push(`${currentVersionDir}/${file}`);
    }
  }
  for (let file of readdirSync(`${currentVersionDir}/Helpers`)) {
    if (/^[a-z0-9_]*$/.test(file) || file.endsWith('.app')) {
      if (file.endsWith('.app')) {
        file = await _fixNWJSHelperApp(file, appName, currentVersionDir);
      }

      items.push(`${currentVersionDir}/Helpers/${file}`);
    }
  }
  for (const file of readdirSync(`${currentVersionDir}/Libraries`)) {
    if (file.endsWith('.dylib')) {
      items.push(`${currentVersionDir}/Libraries/${file}`);
    }
  }
  for (const file of readdirSync(`${currentVersionDir}/XPCServices`)) {
    if (file.endsWith('.xpc')) {
      items.push(`${currentVersionDir}/XPCServices/${file}`);
    }
  }
  items.push(frameworksDir);
  // code sign each executable in NWJS
  for (const itemPath of items) {
    codesign(itemPath, INTERNAL_ENTITLEMENTS_PATH);
  }
  // code sign the application
  codesign(appPath);
}
@zkrige

This comment has been minimized.

Copy link

@zkrige zkrige commented Feb 14, 2020

@zkrige To fix the collision, I followed the Mac instructions in https://nwjs.readthedocs.io/en/nw28/For%20Users/Package%20and%20Distribute/#platform-specific-steps
(They are out of date. The helpers are now in a Helpers directory.)
So, I renamed CFBundleDisplayName and CFBundleExecutable in each plist file and while I was there I parsed the name and got the part in the parenthesis and added it to the CFBundleIdentifier.
For example: io.nwjs.nwjs.helper for nwjs Helper.app and io.nwjs.nwjs.helper.gui for nwjs Helper (GUI).app
Seems to have fixed the collision for me

Thank You - I figured this out and managed to do the same. The only problem remaining is the sandbox issue

@gpetrov

This comment has been minimized.

Copy link

@gpetrov gpetrov commented Feb 14, 2020

well done @jssuttles ! Just a small note if you are having also native node modules included you have to sign them as well - so all *.node files.

@zkrige

This comment has been minimized.

Copy link

@zkrige zkrige commented Feb 14, 2020

I've built a bash script that does more or less what @jssuttles script does, but it also signs .node files

echo "==UPDATING PLIST ENTRIES=="
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID.helper" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper.app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $NAME Helper" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper.app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID.helper.gpu" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (GPU).app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $NAME Helper (GPU)" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (GPU).app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID.helper.plugin" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Plugin).app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $NAME Helper (PLUGIN)" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Plugin).app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID.helper.renderer" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Renderer).app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $NAME Helper (RENDERER)" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/Helpers/nwjs Helper (Renderer).app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID.framework.AlertNotificationService" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/XPCServices/AlertNotificationService.xpc/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $NAME AlertNotificationService" "${OUTDIRECTORY}/${NAME}.app/Contents/Frameworks/nwjs Framework.framework/XPCServices/AlertNotificationService.xpc/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :com.apple.security.application-groups:0 ${TEAM_ID}.${BUNDLE_ID}" "./installer/mac/entitlements_parent.plist"
echo ""

ITEMS=""
FRAMEWORKS_DIR="${OUTDIRECTORY}/${NAME}.app/Contents"
if [[ -d "$FRAMEWORKS_DIR" ]] ; then
    FRAMEWORKS=$(find "${FRAMEWORKS_DIR}" -depth -type d -name "*.framework" -or -name "*.dylib" -or -name "*.bundle" -or -name "*.node")
    RESULT=$?
    if [[ ${RESULT} != 0 ]] ; then
        exit 1
    fi
    ITEMS="${FRAMEWORKS}"
fi

ITEMS="${ITEMS}"$'\n'"$OUTDIRECTORY/$NAME.app"

IFS=$'\n'
for ITEM in ${ITEMS};
do
    echo "==Signing child '$ITEM'=="
    codesign --deep --verify --force --options runtime --timestamp --entitlements "./installer/mac/entitlements_child.plist" -s "$APP_CERT" "${ITEM}"
    RESULT=$?
    if [[ ${RESULT} != 0 ]] ; then
        echo "Failed to sign '${ITEM}'."
         unset IFS
        exit 1
    fi
done
unset IFS
echo "==Signing '$OUTDIRECTORY/$NAME.app'=="
codesign --deep --verify --force --options runtime --timestamp --entitlements "./installer/mac/entitlements_parent.plist" -s "$APP_CERT" "$OUTDIRECTORY/$NAME.app"
echo ""

echo "==Validating code signature and subsequent resources=="
spctl --assess -v "$OUTDIRECTORY/$NAME.app"
echo ""

echo "==Building Package $PACKAGE_NAME =="
productbuild --component "$OUTDIRECTORY/$NAME.app" /Applications --sign "$INSTALLER_CERT" "$OUTDIRECTORY/$PACKAGE_NAME"
echo ""

@gpetrov

This comment has been minimized.

Copy link

@gpetrov gpetrov commented Feb 17, 2020

@zkrige I see your are adjusting the plists with the new helper names - but you don't have the rename itself included?

@zkrige

This comment has been minimized.

Copy link

@zkrige zkrige commented Feb 17, 2020

I'm using https://github.com/evshiron/nwjs-builder-phoenix which handles the app rename, icon and a few other things

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
9 participants
You can’t perform that action at this time.