From 5e3fd3ebd40518d7e2b368af3d6cd1406e22ecdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Garci=CC=81a=20Hierro?= Date: Tue, 25 Feb 2020 21:09:35 +0000 Subject: [PATCH] [macOS] Use macapptool for signing and notarizing macOS binaries nw-builder has been producing invalid frameworks at least since 2017, at it seems there's no progress in fixing it (see https://github.com/nwjs/nw.js/issues/6338). To workaround this problem, we use macapptool to proper seal all the framework resources so it can be signed and passes the validations required for notarization. Since we're introducing this dependency, we can also use macapptool to simplify signing and notarization. To create a signed macOS build, pass the --codesign flag. --codesign-identity can be used to use a non-default identity ("Developer ID") To notarize a signed bundle, use the --notarize flag. There are also flags provided to specify the username/password for the notarization service. --- entitlements.plist | 16 +++++++++++ gulpfile.js | 66 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 entitlements.plist diff --git a/entitlements.plist b/entitlements.plist new file mode 100644 index 00000000..4f6cca68 --- /dev/null +++ b/entitlements.plist @@ -0,0 +1,16 @@ + + + + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.disable-library-validation + + + diff --git a/gulpfile.js b/gulpfile.js index 159340bd..279c0a42 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -161,18 +161,31 @@ function get_task_name(key) { return 'build-' + key.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();}); } +function getArguments() { + return minimist(process.argv.slice(2)); +} + function getPlatforms() { - var defaultPlatforms = ['win32', 'win64', 'osx64', 'linux32', 'linux64']; - var argv = minimist(process.argv.slice(2)); - if (argv.platform) { - if (defaultPlatforms.indexOf(argv.platform) < 0) { - throw "Invalid platform '" + argv.platform + "'. Available ones are: " + defaultPlatforms; + const defaultPlatforms = ['win32', 'win64', 'osx64', 'linux32', 'linux64']; + const platform = getArguments().platform; + if (platform) { + if (defaultPlatforms.indexOf(platform) < 0) { + throw new Error(`Invalid platform "${platform}". Available ones are: ${defaultPlatforms}`) } - return [argv.platform]; + return [platform]; } return defaultPlatforms; } +function execSync() { + const cmd = arguments[0]; + const args = Array.prototype.slice.call(arguments, 1); + const result = child_process.spawnSync(cmd, args, {stdio: 'inherit'}); + if (result.error) { + throw result.error; + } +} + // Define build tasks dynamically based on the sources // and output variables. var buildCssTasks = []; @@ -289,15 +302,28 @@ gulp.task('release-win64', function() { return archive.finalize(); }); -gulp.task('release-osx64', function() { +gulp.task('release-osx64', function(done) { var pkg = require('./package.json'); var src = path.join(appsDir, pkg.name, 'osx64', pkg.name + '.app'); // Check if we want to sign the .app bundle - if (process.env.CODESIGN_IDENTITY) { - var sign_cmd = 'codesign --verbose --force --sign "' + process.env.CODESIGN_IDENTITY + '" ' + src; - child_process.execSync(sign_cmd); + if (getArguments().codesign) { + // macapptool can be downloaded from + // https://github.com/fiam/macapptool + // + // Make sure the bundle is well formed + execSync('macapptool', '-v', '1', 'fix', src); + // Sign + const codesignArgs = ['macapptool', '-v', '1', 'sign']; + const codesignIdentity = getArguments()['codesign-identity']; + if (codesignIdentity) { + codesignArgs.push('-i', codesignIdentity); + } + codesignArgs.push('-e', 'entitlements.plist'); + codesignArgs.push(src) + execSync.apply(this, codesignArgs); } - var output = fs.createWriteStream(path.join(appsDir, get_release_filename('macOS', 'zip'))); + const zipFilename = path.join(appsDir, get_release_filename('macOS', 'zip')); + var output = fs.createWriteStream(zipFilename); var archive = archiver('zip', { zlib: { level: 9 } }); @@ -305,7 +331,23 @@ gulp.task('release-osx64', function() { archive.on('error', function(err) { throw err; }); archive.pipe(output); archive.directory(src, 'INAV Configurator.app'); - return archive.finalize(); + output.on('close', function() { + if (getArguments().notarize) { + const notarizeArgs = ['macapptool', '-v', '1', 'notarize']; + const notarizationUsername = getArguments()['notarization-username']; + if (notarizationUsername) { + notarizeArgs.push('-u', notarizationUsername) + } + const notarizationPassword = getArguments()['notarization-password']; + if (notarizationPassword) { + notarizeArgs.push('-p', notarizationPassword) + } + notarizeArgs.push(zipFilename) + execSync.apply(this, notarizeArgs); + } + done(); + }); + archive.finalize(); }); function releaseLinux(bits) {