electron-osx-sign
Advanced tools
Comparing version 0.4.0-beta4 to 0.4.0
Usage: electron-osx-flat <app> [--options...] | ||
NAME | ||
electron-osx-flat -- product building for Electron apps | ||
Options: | ||
SYNOPSIS | ||
electron-osx-flat app [options ...] | ||
identity Name of certificate to use when flattening. Default to retrieve from keychain specified, see below. | ||
install Path to install for the bundle. Default `/Applications`. | ||
keychain The keychain name. Default to system default keychain. | ||
platform Build platform of Electron. Allowed values: darwin, mas. Default to auto detect from application package. | ||
pkg Path to the output package. | ||
DESCRIPTION | ||
app | ||
Path to the application package. | ||
Needs file extension ``.app''. | ||
--help | ||
Flag to display all commands. | ||
--identity=identity | ||
Name of certificate to use when signing. | ||
Default to selected with respect to --platform from --keychain specified or keychain by system default. | ||
--install=install-path | ||
Path to install the bundle. | ||
Default to ``/Applications''. | ||
--keychain=keychain | ||
The keychain name. | ||
Default to system default keychain. | ||
--platform=platform | ||
Build platform of Electron. | ||
Allowed values: ``darwin'', ``mas''. | ||
Default to auto detect from application bundle. | ||
--pkg | ||
Path to the output the flattened package. | ||
Needs file extension ``.pkg''. | ||
--scripts | ||
Path to a directory containing pre and/or post install scripts. |
#!/usr/bin/env node | ||
var fs = require('fs') | ||
@@ -3,0 +4,0 @@ var path = require('path') |
Usage: electron-osx-sign <app> [additional-binaries...] [--options...] | ||
NAME | ||
electron-osx-sign -- code signing for Electron apps | ||
Options: | ||
SYNOPSIS | ||
electron-osx-sign app [embedded-binary ...] [options ...] | ||
binaries Path to additional binaries that will be signed along with built-ins of Electron, spaced. | ||
entitlements Path to entitlements file for signing Mac App Store application. | ||
entitlements-inherit Path to child entitlements file for signing frameworks and bundles of Mac App Store application. | ||
identity Name of certificate to use when signing. Default to retrieve from keychain specified, see below. | ||
keychain The keychain name. Default to system default keychain. | ||
ignore Regex that signals ignoring a file before signing. Default to undefined. | ||
no-pre-auto-entitlements Flag to disable automation of `com.apple.security.application-groups` in entitlements file and update `Info.plist` with `ElectronTeamID`. | ||
platform Build platform of Electron. Allowed values: `darwin`, `mas`. Default to auto detect from application package. | ||
version Build version of Electron. Values may be: `1.2.0`. | ||
DESCRIPTION | ||
app | ||
Path to the application package. | ||
Needs file extension ``.app''. | ||
embedded-binary ... | ||
Path to additional binaries that will be signed along with built-ins of Electron, spaced. | ||
--entitlements=file | ||
Path to entitlements file for signing the app. | ||
Default to built-in entitlements file, Sandbox enabled for Mac App Store platform. | ||
--entitlements-inherit=file | ||
Path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. | ||
This option only applies when signing with entitlements. | ||
--help | ||
Flag to display all commands. | ||
--identity=identity | ||
Name of certificate to use when signing. | ||
Default to selected with respect to --provisioning-profile and --platform from --keychain specified or keychain by system default. | ||
--ignore=regex | ||
Regex that signals ignoring a file before signing. | ||
--keychain=keychain | ||
The keychain name. | ||
Default to system default keychain. | ||
--platform=platform | ||
Build platform of Electron. | ||
Allowed values: ``darwin'', ``mas''. | ||
Default to auto detect from application bundle. | ||
--pre-auto-entitlements, --no-pre-auto-entitlements | ||
Flag to enable automation of entitlements file and Info.plist. | ||
--pre-embed-provisioning-profile, --no-pre-embed-provisioning-profile | ||
Flag to enable embedding of provisioning profile. | ||
--provisioning-profile | ||
Path to provisioning profile. | ||
--requirements=requirements | ||
Specify the criteria that you recommend to be used to evaluate the code signature. | ||
--type=type | ||
Specify whether to sign app for development or for distribution. | ||
Allowed values: ``development'', ``distribution''. | ||
Default to ``distribution''. | ||
--version=version | ||
Build version of Electron. | ||
Values may be: ``1.2.0''. | ||
Default to latest Electron version. |
#!/usr/bin/env node | ||
var fs = require('fs') | ||
@@ -7,10 +8,12 @@ var path = require('path') | ||
'help', | ||
'pre-auto-entitlements' | ||
'pre-auto-entitlements', | ||
'pre-embed-provisioning-profile' | ||
], | ||
'default': { | ||
'pre-auto-entitlements': true | ||
'pre-auto-entitlements': true, | ||
'pre-embed-provisioning-profile': true | ||
} | ||
}) | ||
var usage = fs.readFileSync(path.join(__dirname, 'electron-osx-sign-usage.txt')).toString() | ||
var sign = require('../') | ||
var sign = require('../').sign | ||
@@ -17,0 +20,0 @@ args.app = args._.shift() |
632
index.js
@@ -1,639 +0,47 @@ | ||
'use strict' | ||
var fs = require('fs') | ||
var path = require('path') | ||
var child = require('child_process') | ||
var Promise = require('bluebird') | ||
var isBinaryFileAsync = Promise.promisify(require('isbinaryfile')) | ||
var execFileAsync = Promise.promisify(child.execFile) | ||
var lstatAsync = Promise.promisify(fs.lstat) | ||
var compareVersion = require('compare-version') | ||
var plist = require('plist') | ||
var tempfile = require('tempfile') | ||
var debug = require('debug') | ||
var debuglog = debug('electron-osx-sign') | ||
debuglog.log = console.log.bind(console) | ||
var debugwarn = debug('electron-osx-sign:warn') | ||
debugwarn.log = console.warn.bind(console) | ||
var debugerror = debug('electron-osx-sign:error') | ||
debugerror.log = console.error.bind(console) | ||
/** | ||
* This function returns a promise with platform resolved. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise resolving platform. | ||
* @module electron-osx-sign | ||
*/ | ||
function detectElectronPlatformAsync (opts) { | ||
return new Promise(function (resolve) { | ||
var appFrameworksPath = getAppFrameworksPath(opts) | ||
// The presence of Squirrel.framework identifies a Mac App Store build as used in https://github.com/atom/electron/blob/master/docs/tutorial/mac-app-store-submission-guide.md | ||
return lstatAsync(path.join(appFrameworksPath, 'Squirrel.framework')) | ||
.then(function () { | ||
resolve('darwin') | ||
}) | ||
.catch(function () { | ||
resolve('mas') | ||
}) | ||
}) | ||
} | ||
/** | ||
* This function returns a promise checking the indentity proposed and updates the identity option to a exact finding from results. | ||
* @param {Object} opts - Options. | ||
* @param {string} identity - The proposed identity. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function findIdentityAsync (opts, identity) { | ||
return new Promise(function (resolve, reject) { | ||
// Only to look for valid identities, excluding those flagged with | ||
// CSSMERR_TP_CERT_EXPIRED or CSSMERR_TP_NOT_TRUSTED. Fixes #9 | ||
'use strict' | ||
var args = [ | ||
'find-identity', | ||
'-v' | ||
] | ||
if (opts.keychain) { | ||
args.push(opts.keychain) | ||
} | ||
const sign = require('./sign') | ||
const flat = require('./flat') | ||
execFileAsync('security', args) | ||
.then(function (result) { | ||
var lines = result.split('\n') | ||
var location | ||
for (var i = 0, l = lines.length; i < l; i++) { | ||
var line = lines[i] | ||
location = line.indexOf(identity) | ||
if (location >= 0) { | ||
opts.identity = line.substring(line.indexOf('"') + 1, line.lastIndexOf('"')) | ||
break | ||
} | ||
} | ||
if (!opts.identity) { | ||
reject(new Error('No identity found for signing.')) | ||
} else { | ||
resolve(null) | ||
} | ||
}) | ||
.catch(function (err) { | ||
debugerror(err) | ||
reject(new Error('Error in finding identity. See details in debug log. (electron-osx-sign:error)')) | ||
}) | ||
}) | ||
} | ||
/** | ||
* This function returns a promise flattening the application. | ||
* This function is a normal callback implementation. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise. | ||
* @param {RequestCallback} cb - Callback. | ||
*/ | ||
function flatApplicationAsync (opts) { | ||
var args = [ | ||
'--component', opts.app, opts.install, | ||
'--sign', opts.identity, | ||
opts.pkg | ||
] | ||
if (opts.keychain) { | ||
args.unshift('--keychain', opts.keychain) | ||
} | ||
module.exports = sign.sign // Aliasing | ||
debuglog('Flattening... ' + opts.app) | ||
return execFileAsync('productbuild', args) | ||
.thenReturn(null) | ||
} | ||
/** | ||
* This function returns the path to app contents. | ||
* This function is a normal callback implementation. | ||
* @function | ||
* @param {Object} opts - Options. | ||
* @returns {string} App contents path. | ||
* @param {RequestCallback} cb - Callback. | ||
*/ | ||
function getAppContentsPath (opts) { | ||
return path.join(opts.app, 'Contents') | ||
} | ||
module.exports.sign = sign.sign | ||
/** | ||
* This function returns the path to app frameworks within contents. | ||
* @param {Object} opts - Options. | ||
* @returns {string} App frameworks path. | ||
*/ | ||
function getAppFrameworksPath (opts) { | ||
return path.join(getAppContentsPath(opts), 'Frameworks') | ||
} | ||
/** | ||
* This function returns a promise resolving the file path if file binary. | ||
* @param {string} filePath - Path to file. | ||
* @returns {Promise} Promise resolving file path or null. | ||
*/ | ||
function getFilePathIfBinaryAsync (filePath) { | ||
return isBinaryFileAsync(filePath) | ||
.then(function (isBinary) { | ||
return isBinary ? filePath : null | ||
}) | ||
} | ||
/** | ||
* This function returns a promise completing the entitlements automation: The process includes checking in `Info.plist` for `ElectronTeamID` or setting parsed value from identity, and checking in entitlements file for `com.apple.security.application-groups` or inserting new into array. A temporary entitlements file may be created to replace the input for any changes introduced. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function preAutoEntitlementAppGroupAsync (opts) { | ||
// If entitlements file not provided, default will be used. Fixes #41 | ||
var readFileAsync = Promise.promisify(fs.readFile) | ||
var writeFileAsync = Promise.promisify(fs.writeFile) | ||
var appInfoPath = path.join(getAppContentsPath(opts), 'Info.plist') | ||
var appInfo | ||
var entitlementsPath = tempfile('.plist') | ||
var entitlements | ||
return readFileAsync(opts.entitlements, 'utf8') | ||
.then(function (result) { | ||
entitlements = plist.parse(result) | ||
if (!entitlements['com.apple.security.app-sandbox']) { | ||
// Only automate when app sandbox enabled | ||
return | ||
} | ||
return readFileAsync(appInfoPath, 'utf8') | ||
.then(function (result) { | ||
appInfo = plist.parse(result) | ||
// Use ElectronTeamID in Info.plist if already specified | ||
if (!appInfo.ElectronTeamID) { | ||
appInfo.ElectronTeamID = opts.identity.substring(opts.identity.indexOf('(') + 1, opts.identity.lastIndexOf(')')) | ||
debugwarn('`ElectronTeamID` not found in `Info.plist`, use parsed from signing identity: ' + appInfo.ElectronTeamID) | ||
return writeFileAsync(appInfoPath, plist.build(appInfo), 'utf8') | ||
} else { | ||
debuglog('`ElectronTeamID` found in `Info.plist`: ' + appInfo.ElectronTeamID) | ||
} | ||
}) | ||
.then(function () { | ||
// Init entitlements app group key to array | ||
if (!entitlements['com.apple.security.application-groups']) { | ||
entitlements['com.apple.security.application-groups'] = [] | ||
} | ||
// Insert app group if not exists | ||
var appGroup = appInfo.ElectronTeamID + '.' + appInfo.CFBundleIdentifier | ||
if (entitlements['com.apple.security.application-groups'].indexOf(appGroup) === -1) { | ||
debugwarn('`com.apple.security.application-groups` not found in entitlements file, new inserted: ' + appGroup) | ||
entitlements['com.apple.security.application-groups'].push(appGroup) | ||
opts.entitlements = entitlementsPath | ||
return writeFileAsync(entitlementsPath, plist.build(entitlements), 'utf8') | ||
} else { | ||
debuglog('`com.apple.security.application-groups` found in entitlements file: ' + appGroup) | ||
} | ||
}) | ||
.thenReturn(null) | ||
}) | ||
} | ||
/** | ||
* This function returns a promise validating opts.app, the application to be signed or flattened | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function validateOptsApplicationAsync (opts) { | ||
return new Promise(function (resolve, reject) { | ||
if (!opts.app) { | ||
reject(new Error('Path to aplication must be specified.')) | ||
return | ||
} | ||
if (path.extname(opts.app) !== '.app') { | ||
reject(new Error('Extension of application must be `.app`.')) | ||
return | ||
} | ||
return lstatAsync(opts.app) | ||
.then(function () { | ||
resolve(null) | ||
}) | ||
.catch(function (err) { | ||
debugerror(err) | ||
reject(new Error('Application not found. See details in debug log. (electron-osx-sign:error)')) | ||
}) | ||
}) | ||
} | ||
/** | ||
* This function returns a promise validating opts.binaries, the additional binaries to be signed along with the discovered enclosed components. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function validateOptsBinariesAsync (opts) { | ||
return new Promise(function (resolve, reject) { | ||
if (opts.binaries) { | ||
if (!Array.isArray(opts.binaries)) { | ||
reject(new Error('Additional binaries should be an Array.')) | ||
return | ||
} | ||
// TODO: Loop check every binary file for existence, reject promise if any not found | ||
} | ||
resolve(null) | ||
}) | ||
} | ||
/** | ||
* This function returns a promise validating opts.platform, the platform of Electron build. It allows auto-discovery if no opts.platform is specified. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function validateOptsPlatformAsync (opts) { | ||
return new Promise(function (resolve, reject) { | ||
if (opts.platform) { | ||
if (opts.platform === 'mas' || opts.platform === 'darwin') { | ||
resolve(null) | ||
return | ||
} else { | ||
debugwarn('`platform` passed in arguments not supported, checking Electron platform...') | ||
} | ||
} else { | ||
debugwarn('No `platform` passed in arguments, checking Electron platform...') | ||
} | ||
return detectElectronPlatformAsync(opts) | ||
.then(function (platform) { | ||
opts.platform = platform | ||
resolve(null) | ||
}) | ||
.catch(function (err) { | ||
// NB: This should logically not happen as detectElectronPlatformAsync should not give any rejections. However, it is put here just in case. | ||
debugerror(err) | ||
reject(new Error('Unable to decide Electron platform. See details in debug log. (electron-osx-sign:error)')) | ||
}) | ||
}) | ||
} | ||
/** | ||
* This function returns a promise verifying the code sign of application bundle. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise resolving output. | ||
*/ | ||
function verifySignApplicationAsync (opts) { | ||
// Custom promise is used here due to a strange behavior with codesign: Verbose logs are output into stderr so regular promisified execFile could not catch stderr while code execution finishes successfully. | ||
return new Promise(function (resolve, reject) { | ||
child.execFile('codesign', [ | ||
'--verify', | ||
'--deep', | ||
'--verbose=2', | ||
opts.app | ||
], function (err, stdout, stderr) { | ||
if (err) { | ||
debugerror(err) | ||
reject('Failed to verify application bundle. See details in debug log. (electron-osx-sign:error)') | ||
return | ||
} | ||
resolve(stderr) | ||
}) | ||
}) | ||
} | ||
/** | ||
* This function returns a promise resolving all child paths within the directory specified. | ||
* @param {string} dirPath - Path to directory. | ||
* @returns {Promise} Promise resolving child paths needing signing in order. | ||
*/ | ||
function walkAsync (dirPath) { | ||
var unlinkAsync = Promise.promisify(fs.unlink) | ||
var readdirAsync = Promise.promisify(fs.readdir) | ||
function _walkAsync (dirPath) { | ||
return readdirAsync(dirPath) | ||
.then(function (names) { | ||
return Promise.map(names, function (name) { | ||
var filePath = path.join(dirPath, name) | ||
return lstatAsync(filePath) | ||
.then(function (stat) { | ||
if (stat.isFile()) { | ||
switch (path.extname(filePath)) { | ||
case '': // Binary | ||
if (path.basename(filePath)[0] !== '.') { | ||
return getFilePathIfBinaryAsync(filePath) | ||
} // Else reject hidden file | ||
break | ||
case '.dylib': // Dynamic library | ||
case '.node': // Native node addon | ||
return filePath | ||
case '.cstemp': // Temporary file generated from past codesign | ||
debuglog('Removing... ' + filePath) | ||
return unlinkAsync(filePath) | ||
.thenReturn(null) | ||
default: | ||
if (path.extname(filePath).indexOf(' ') >= 0) { | ||
// Still consider the file as binary if extension seems invalid | ||
return getFilePathIfBinaryAsync(filePath) | ||
} | ||
} | ||
} else if (stat.isDirectory() && !stat.isSymbolicLink()) { | ||
return _walkAsync(filePath) | ||
.then(function (result) { | ||
switch (path.extname(filePath)) { | ||
case '.app': // Application | ||
case '.framework': // Framework | ||
result.push(filePath) | ||
} | ||
return result | ||
}) | ||
} | ||
return null | ||
}) | ||
}) | ||
}) | ||
} | ||
return _walkAsync(dirPath) | ||
.then(function (result) { | ||
function populateChildPaths (list) { | ||
if (!Array.isArray(list)) { | ||
childPaths.push(list) | ||
} else if (list.length > 0) { | ||
for (let item of list) { | ||
if (item != null) { | ||
populateChildPaths(item) | ||
} | ||
} | ||
} | ||
} | ||
var childPaths = [] | ||
populateChildPaths(result) | ||
return childPaths | ||
}) | ||
} | ||
/** | ||
* This function returns a promise codesigning only. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function signApplicationAsync (opts) { | ||
return walkAsync(getAppContentsPath(opts)) | ||
.then(function (childPaths) { | ||
if (opts.binaries) childPaths = childPaths.concat(opts.binaries) | ||
var args = [ | ||
'--sign', opts.identity, | ||
'--force' | ||
] | ||
if (opts.keychain) { | ||
args.push('--keychain', opts.keychain) | ||
} | ||
var promise | ||
if (opts.entitlements) { | ||
// Sign with entitlements | ||
promise = Promise.mapSeries(childPaths, function (filePath) { | ||
debuglog('Signing... ' + filePath) | ||
return execFileAsync('codesign', args.concat('--entitlements', opts['entitlements-inherit'], filePath)) | ||
}) | ||
.then(function () { | ||
debuglog('Signing... ' + opts.app) | ||
return execFileAsync('codesign', args.concat('--entitlements', opts.entitlements, opts.app)) | ||
}) | ||
} else { | ||
// Otherwise normally | ||
promise = Promise.mapSeries(childPaths, function (filePath) { | ||
debuglog('Signing... ' + filePath) | ||
return execFileAsync('codesign', args.concat(filePath)) | ||
}) | ||
.then(function () { | ||
debuglog('Signing... ' + opts.app) | ||
return execFileAsync('codesign', args.concat(opts.app)) | ||
}) | ||
} | ||
return promise | ||
.then(function () { | ||
// Verify code sign | ||
debuglog('Verifying code sign...') | ||
var promise = verifySignApplicationAsync(opts) | ||
.then(function (result) { | ||
debuglog('Verification displayed below:\n' + result) | ||
}) | ||
// Check entitlements if applicable | ||
if (opts.entitlements) { | ||
promise = promise | ||
.then(function () { | ||
debuglog('Displaying entitlements...') | ||
return execFileAsync('codesign', [ | ||
'--display', | ||
'--entitlements', | ||
'-', | ||
opts.app | ||
]) | ||
}) | ||
.then(function (result) { | ||
debuglog('Entitlements:\n' + result) | ||
}) | ||
} | ||
return promise | ||
}) | ||
}) | ||
.thenReturn(null) | ||
} | ||
/** | ||
* This function is exported and returns a promise signing the application. | ||
* This function returns a promise signing the application. | ||
* @function | ||
* @param {mixed} opts - Options. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function signAsync (opts) { | ||
if (opts.ignore) { | ||
if (typeof opts.ignore !== 'function' || typeof opts.ignore !== 'string') return Promise.reject(new Error('Ignore filter should be either a function or a string.')) | ||
} | ||
module.exports.signAsync = sign.signAsync | ||
return validateOptsApplicationAsync(opts) | ||
.then(function () { | ||
return validateOptsPlatformAsync(opts) | ||
}) | ||
.then(function () { | ||
if (opts.platform === 'mas') { | ||
// To sign apps for Mac App Store, an entitlements file is required, especially for app sandboxing (as well some other services). | ||
// Fallback entitlements for sandboxing by default: Note this may cause troubles while running an signed app due to missing keys special to the project. | ||
// Further reading: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html | ||
if (!opts.entitlements) { | ||
debugwarn('No `entitlements` passed in arguments, will fallback to default settings.') | ||
opts.entitlements = path.join(__dirname, 'default.entitlements.mas.plist') | ||
} | ||
if (!opts['entitlements-inherit']) { | ||
debugwarn('No `entitlements-inherit` passed in arguments, will fallback to default settings.') | ||
opts['entitlements-inherit'] = path.join(__dirname, 'default.entitlements.mas.inherit.plist') | ||
} | ||
} else if (opts.platform === 'darwin') { | ||
// Not necessary to have entitlements for non Mac App Store distribution | ||
if (!opts.entitlements) { | ||
debugwarn('No `entitlements` passed in arguments, will not sign with entitlements.') | ||
} else { | ||
// If entitlements is provided as a flag, fallback to default | ||
if (opts.entitlements === true) { | ||
debugwarn('`entitlements` not specified in arguments, will fallback to default settings.') | ||
opts.entitlements = path.join(__dirname, 'default.entitlements.darwin.plist') | ||
} | ||
if (!opts['entitlements-inherit']) { | ||
debugwarn('No `entitlements-inherit` passed in arguments, will fallback to default settings.') | ||
opts['entitlements-inherit'] = path.join(__dirname, 'default.entitlements.darwin.inherit.plist') | ||
} | ||
} | ||
} else { | ||
// NB: This should logically not happen. It is put here just in case. | ||
return Promise.reject(new Error('Unexpected Electron platform.')) | ||
} | ||
return validateOptsBinariesAsync(opts) | ||
}) | ||
.then(function () { | ||
if (opts.identity) { | ||
return findIdentityAsync(opts, opts.identity) | ||
} | ||
debugwarn('No `identity` passed in arguments, discovering identities...') | ||
if (opts.platform === 'mas') { | ||
return findIdentityAsync(opts, '3rd Party Mac Developer Application') | ||
} else if (opts.platform === 'darwin') { | ||
return findIdentityAsync(opts, 'Developer ID Application') | ||
} else { | ||
// NB: This should logically not happen. It is put here just in case. | ||
return Promise.reject(new Error('Unexpected Electron platform.')) | ||
} | ||
}) | ||
.then(function () { | ||
// Pre-sign operations | ||
if (opts.entitlements && (!opts.version || compareVersion(opts.version, '1.1.1') >= 0)) { | ||
// Enable Mac App Store sandboxing without using temporary-exception, introduced in Electron v1.1.1. Relates to electron#5601 | ||
if (opts['pre-auto-entitlements'] === false) { | ||
debugwarn('Pre-sign operation disabled for entitlements automation.') | ||
} else { | ||
debuglog('Pre-sign operation enabled for entitlements automation with versions >= `1.1.1`; disable by setting `pre-auto-entitlements` to `false`.') | ||
debuglog('Automating entitlement app group...') | ||
return preAutoEntitlementAppGroupAsync(opts) | ||
} | ||
} | ||
}) | ||
.then(function () { | ||
debuglog('Signing application...') | ||
debuglog('> application ' + opts.app) | ||
debuglog('> platform ' + opts.platform) | ||
debuglog('> entitlements ' + opts.entitlements) | ||
debuglog('> child-entitlements ' + opts['entitlements-inherit']) | ||
debuglog('> additional-binaries ' + opts.binaries) | ||
debuglog('> identity ' + opts.identity) | ||
return signApplicationAsync(opts) | ||
}) | ||
.then(function () { | ||
// Post-sign operations | ||
debuglog('Application signed.') | ||
}) | ||
} | ||
/** | ||
* This function is exported and returns a promise flattening the application. | ||
* @param {Object} opts - Options. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function flatAsync (opts) { | ||
if (!opts.pkg) { | ||
debugwarn('No `pkg` passed in arguments, will fallback to default, inferred from the given application.') | ||
opts.pkg = path.join(path.dirname(opts.app), path.basename(opts.app, '.app') + '.pkg') | ||
} else if (path.extname(opts.pkg) !== '.pkg') return Promise.reject(new Error('Extension of output package must be `.pkg`.')) | ||
if (!opts.install) { | ||
debugwarn('No `install` passed in arguments, will fallback to default `/Applications`.') | ||
opts.install = '/Applications' | ||
} | ||
return validateOptsApplicationAsync(opts) | ||
.then(function () { | ||
return validateOptsPlatformAsync(opts) | ||
}) | ||
.then(function () { | ||
if (opts.identity) { | ||
return findIdentityAsync(opts, opts.identity) | ||
} | ||
debugwarn('No `identity` passed in arguments, discovering identities...') | ||
if (opts.platform === 'mas') { | ||
return findIdentityAsync(opts, '3rd Party Mac Developer Installer') | ||
} else if (opts.platform === 'darwin') { | ||
return findIdentityAsync(opts, 'Developer ID Installer') | ||
} else { | ||
// NB: This should logically not happen. It is put here just in case. | ||
return Promise.reject(new Error('Unexpected Electron platform.')) | ||
} | ||
}) | ||
.then(function () { | ||
// Pre-flat operations | ||
}) | ||
.then(function () { | ||
debuglog('Flattening application...') | ||
debuglog('> application ' + opts.app) | ||
debuglog('> package-output ' + opts.pkg) | ||
debuglog('> install-path ' + opts.install) | ||
debuglog('> identity ' + opts.identity) | ||
return flatApplicationAsync(opts) | ||
}) | ||
.then(function () { | ||
// Post-flat operations | ||
debuglog('Application flattened.') | ||
}) | ||
} | ||
/** | ||
* This callback is used across signing and flattening. | ||
* @callback RequestCallback | ||
* @param {?Error} err | ||
*/ | ||
/** | ||
* This function is exported with normal callback implementation. | ||
* @function | ||
* @param {Object} opts - Options. | ||
* @param {RequestCallback} cb - Callback. | ||
* @returns {null} Nothing. | ||
*/ | ||
function sign (opts, cb) { | ||
// Default callback function if none provided | ||
if (!cb) { | ||
cb = function (err) { | ||
if (err) { | ||
debugerror('Sign failed:') | ||
if (err.message) debugerror(err.message) | ||
else if (err.stack) debugerror(err.stack) | ||
else debugerror(err) | ||
return | ||
} | ||
debuglog('Application signed: ' + opts.app) | ||
} | ||
} | ||
module.exports.flat = flat.flat | ||
signAsync(opts) | ||
.then(cb) | ||
.catch(cb) | ||
} | ||
/** | ||
* This function is exported with normal callback implementation. | ||
* This function is exported and returns a promise flattening the application. | ||
* @function | ||
* @param {Object} opts - Options. | ||
* @param {RequestCallback} cb - Callback. | ||
* @returns {null} Nothing. | ||
* @returns {Promise} Promise. | ||
*/ | ||
function flat (opts, cb) { | ||
// Default callback function if none provided | ||
if (!cb) { | ||
cb = function (err) { | ||
if (err) { | ||
debugerror('Flat failed:') | ||
if (err.message) debugerror(err.message) | ||
else if (err.stack) debugerror(err.stack) | ||
else debugerror(err) | ||
return | ||
} | ||
debuglog('Application flattened, saved to: ' + opts.app) | ||
} | ||
} | ||
flatAsync(opts) | ||
.then(cb) | ||
.catch(cb) | ||
} | ||
// Module exporting | ||
module.exports = sign // Aliasing | ||
module.exports.sign = sign | ||
module.exports.signAsync = signAsync | ||
module.exports.flat = flat | ||
module.exports.flatAsync = flatAsync | ||
module.exports.flatAsync = flat.flatAsync |
{ | ||
"name": "electron-osx-sign", | ||
"version": "0.4.0-beta4", | ||
"version": "0.4.0", | ||
"description": "Code-signing for Electron-packed OS X apps.", | ||
@@ -36,2 +36,3 @@ "main": "index.js", | ||
"rimraf": "^2.5.2", | ||
"run-series": "^1.1.4", | ||
"run-waterfall": "^1.1.3", | ||
@@ -38,0 +39,0 @@ "standard": "^7.0.1", |
133
README.md
# electron-osx-sign [![npm][npm_img]][npm_url] [![Build Status][travis_img]][travis_url] | ||
Code-signing for packaged Electron OS X apps. | ||
Codesign Electron macOS apps | ||
@@ -37,3 +37,3 @@ ## About | ||
*Note: `electron-osx-sign` is a dependency of `electron-packager` as of 6.0.0 for signing apps on OS X. However, feel free to install this package globally for more customization beyond specifying identity and entitlements.* | ||
*Note: `electron-osx-sign` is a dependency of `electron-packager` as of 6.0.0 for signing apps on macOS. However, feel free to install this package globally for more customization beyond specifying identity and entitlements.* | ||
@@ -47,3 +47,3 @@ ## Usage | ||
```sh | ||
electron-osx-sign <app> [additional-binaries...] [--options...] | ||
electron-osx-sign app [embedded-binary ...] [options ...] | ||
``` | ||
@@ -63,3 +63,3 @@ | ||
For details on the optional flags, run `electron-osx-sign --help` or see [electron-osx-sign-usage.txt](https://github.com/electron-userland/electron-osx-sign/blob/master/bin/electron-osx-sign-usage.txt). | ||
Run `electron-osx-sign --help` or see [electron-osx-sign-usage.txt](https://github.com/electron-userland/electron-osx-sign/blob/master/bin/electron-osx-sign-usage.txt) for CLI-specific options. | ||
@@ -93,4 +93,4 @@ #### From the API | ||
signAsync(opts) | ||
[.then(function () {}) | ||
[.catch(function (err) {})]] | ||
[.then(function () {})] | ||
[.catch(function (err) {})] | ||
``` | ||
@@ -127,3 +127,3 @@ | ||
Path to additional binaries that will be signed along with built-ins of Electron. | ||
Default to `null`. | ||
Default to `undefined`. | ||
@@ -133,8 +133,9 @@ `entitlements` - *String* | ||
Path to entitlements file for signing the app. | ||
See [default.entitlements.mas.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.mas.plist) or [default.entitlements.darwin.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.darwin.plist) for default. | ||
Default to built-in entitlements file, Sandbox enabled for Mac App Store platform. | ||
See [default.entitlements.mas.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.mas.plist) or [default.entitlements.darwin.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.darwin.plist) with respect to your platform. | ||
`entitlements-inherit` - *String* | ||
Path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. *This option only applies when signing with `entitlements` provided, or for a `mas` platform version.* | ||
See [default.entitlements.mas.inherit.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.mas.inherit.plist) or [default.entitlements.darwin.inherit.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.darwin.inherit.plist) for default. | ||
Path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. *This option only applies when signing with entitlements.* | ||
See [default.entitlements.mas.inherit.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.mas.inherit.plist) or [default.entitlements.darwin.inherit.plist](https://github.com/electron-userland/electron-osx-sign/blob/master/default.entitlements.darwin.inherit.plist) with respect to your platform. | ||
@@ -144,3 +145,3 @@ `identity` - *String* | ||
Name of certificate to use when signing. | ||
Default to retrieve from `keychain` (see below) or system default keychain. | ||
Default to be selected with respect to `provisioning-profile` and `platform` from `keychain` or keychain by system default. | ||
@@ -157,3 +158,3 @@ Signing platform `mas` will look for `3rd Party Mac Developer Application: * (*)`, and platform `darwin` will look for `Developer ID Application: * (*)` by default. | ||
Regex or function that signals ignoring a file before signing. | ||
Default to undefined. | ||
Default to `undefined`. | ||
@@ -172,2 +173,24 @@ `platform` - *String* | ||
`pre-embed-provisioning-profile` - *Boolean* | ||
Flag to enable embedding of provisioning profile in the current working directory. | ||
Allowed values: `true`, `false`. | ||
Default to `true`. | ||
`provisioning-profile` - *String* | ||
Path to provisioning profile. | ||
`requirements` - *String* | ||
Specify the criteria that you recommend to be used to evaluate the code signature. | ||
See more info from https://developer.apple.com/library/mac/documentation/Security/Conceptual/CodeSigningGuide/RequirementLang/RequirementLang.html | ||
Default to `undefined`. | ||
`type` - *String* | ||
Specify whether to sign app for development or for distribution. | ||
Allowed values: `development`, `distribution`. | ||
Default to `distribution`. | ||
`version` - *String* | ||
@@ -190,3 +213,3 @@ | ||
```sh | ||
electron-osx-flat <app> [--options...] | ||
electron-osx-flat app [options ...] | ||
``` | ||
@@ -200,3 +223,3 @@ | ||
For details on the optional flags, run `electron-osx-flat --help` or see [electron-osx-flat-usage.txt](https://github.com/electron-userland/electron-osx-sign/blob/master/bin/electron-osx-flat-usage.txt). | ||
Run `electron-osx-flat --help` or see [electron-osx-flat-usage.txt](https://github.com/electron-userland/electron-osx-sign/blob/master/bin/electron-osx-flat-usage.txt) for CLI-specific options. | ||
@@ -230,4 +253,4 @@ #### From the API | ||
flatAsync(opts) | ||
[.then(function () {}) | ||
[.catch(function (err) {})]] | ||
[.then(function () {})] | ||
[.catch(function (err) {})] | ||
``` | ||
@@ -263,4 +286,4 @@ | ||
Name of certificate to use when flattening. | ||
Default to retrieve from `keychain`(see below) or system default keychain. | ||
Name of certificate to use when signing. | ||
Default to be selected with respect to `platform` from `keychain` or keychain by system default. | ||
@@ -271,3 +294,3 @@ Flattening platform `mas` will look for `3rd Party Mac Developer Installer: * (*)`, and platform `darwin` will look for `Developer ID Installer: * (*)` by default. | ||
Path to install for the bundle. | ||
Path to install the bundle. | ||
Default to `/Applications`. | ||
@@ -287,5 +310,8 @@ | ||
Path to the output flattened package. | ||
Path to the output the flattened package. | ||
Needs file extension `.pkg`. | ||
`scripts` - *String* | ||
Path to a directory containing pre and/or post install scripts. | ||
###### cb - Callback | ||
@@ -301,3 +327,3 @@ | ||
As developer certificates are required for `codesign` in OS X, this module may not be tested via online build services. If you wish to test out this module, enter: | ||
As developer certificates are required for `codesign` on macOS, this module is difficult to be tested via online build services. If you wish to test out this module, enter: | ||
@@ -310,3 +336,3 @@ ``` | ||
When this command is fun for the first time: `electron-download` will download all major releases of Electron available for OS X from 0.24.0, and save to `~/.electron/`, which might take up less than 1GB of disk space. | ||
When this command is fun for the first time: `electron-download` will download all major releases of Electron available for macOS from 0.24.0, and save to `~/.electron/`, which might take up less than 1GB of disk space. | ||
@@ -318,6 +344,6 @@ A successful testing should look something like: | ||
> electron-osx-sign@0.4.0-beta4 pretest electron-osx-sign | ||
> electron-osx-sign@0.4.0 pretest electron-osx-sign | ||
> rimraf test/work | ||
> electron-osx-sign@0.4.0-beta4 test electron-osx-sign | ||
> electron-osx-sign@0.4.0 test electron-osx-sign | ||
> standard && tape test | ||
@@ -329,79 +355,76 @@ | ||
# setup | ||
# defaults-test:v0.24.0-darwin-x64 | ||
# defaults-test:v0.29.2-darwin-x64 | ||
ok 1 app signed | ||
ok 2 app flattened | ||
# defaults-test:v0.25.3-darwin-x64 | ||
# defaults-test:v0.30.8-darwin-x64 | ||
ok 3 app signed | ||
ok 4 app flattened | ||
# defaults-test:v0.26.1-darwin-x64 | ||
# defaults-test:v0.31.2-darwin-x64 | ||
ok 5 app signed | ||
ok 6 app flattened | ||
# defaults-test:v0.27.3-darwin-x64 | ||
# defaults-test:v0.32.3-darwin-x64 | ||
ok 7 app signed | ||
ok 8 app flattened | ||
# defaults-test:v0.28.3-darwin-x64 | ||
# defaults-test:v0.33.9-darwin-x64 | ||
ok 9 app signed | ||
ok 10 app flattened | ||
# defaults-test:v0.29.2-darwin-x64 | ||
# defaults-test:v0.34.5-darwin-x64 | ||
ok 11 app signed | ||
ok 12 app flattened | ||
# defaults-test:v0.30.8-darwin-x64 | ||
# defaults-test:v0.34.5-mas-x64 | ||
ok 13 app signed | ||
ok 14 app flattened | ||
# defaults-test:v0.31.2-darwin-x64 | ||
# defaults-test:v0.35.6-darwin-x64 | ||
ok 15 app signed | ||
ok 16 app flattened | ||
# defaults-test:v0.32.3-darwin-x64 | ||
# defaults-test:v0.35.6-mas-x64 | ||
ok 17 app signed | ||
ok 18 app flattened | ||
# defaults-test:v0.33.9-darwin-x64 | ||
# defaults-test:v0.36.12-darwin-x64 | ||
ok 19 app signed | ||
ok 20 app flattened | ||
# defaults-test:v0.34.5-darwin-x64 | ||
# defaults-test:v0.36.12-mas-x64 | ||
ok 21 app signed | ||
ok 22 app flattened | ||
# defaults-test:v0.34.5-mas-x64 | ||
# defaults-test:v0.37.8-darwin-x64 | ||
ok 23 app signed | ||
ok 24 app flattened | ||
# defaults-test:v0.35.6-darwin-x64 | ||
# defaults-test:v0.37.8-mas-x64 | ||
ok 25 app signed | ||
ok 26 app flattened | ||
# defaults-test:v0.35.6-mas-x64 | ||
# defaults-test:v1.0.2-darwin-x64 | ||
ok 27 app signed | ||
ok 28 app flattened | ||
# defaults-test:v0.36.12-darwin-x64 | ||
# defaults-test:v1.0.2-mas-x64 | ||
ok 29 app signed | ||
ok 30 app flattened | ||
# defaults-test:v0.36.12-mas-x64 | ||
# defaults-test:v1.1.3-darwin-x64 | ||
ok 31 app signed | ||
ok 32 app flattened | ||
# defaults-test:v0.37.8-darwin-x64 | ||
# defaults-test:v1.1.3-mas-x64 | ||
ok 33 app signed | ||
ok 34 app flattened | ||
# defaults-test:v0.37.8-mas-x64 | ||
# defaults-test:v1.2.8-darwin-x64 | ||
ok 35 app signed | ||
ok 36 app flattened | ||
# defaults-test:v1.0.2-darwin-x64 | ||
# defaults-test:v1.2.8-mas-x64 | ||
ok 37 app signed | ||
ok 38 app flattened | ||
# defaults-test:v1.0.2-mas-x64 | ||
# defaults-test:v1.3.7-darwin-x64 | ||
ok 39 app signed | ||
ok 40 app flattened | ||
# defaults-test:v1.1.3-darwin-x64 | ||
# defaults-test:v1.3.7-mas-x64 | ||
ok 41 app signed | ||
ok 42 app flattened | ||
# defaults-test:v1.1.3-mas-x64 | ||
# defaults-test:v1.4.2-darwin-x64 | ||
ok 43 app signed | ||
ok 44 app flattened | ||
# defaults-test:v1.2.0-darwin-x64 | ||
# defaults-test:v1.4.4-mas-x64 | ||
ok 45 app signed | ||
ok 46 app flattened | ||
# defaults-test:v1.2.0-mas-x64 | ||
ok 47 app signed | ||
ok 48 app flattened | ||
# teardown | ||
1..48 | ||
# tests 48 | ||
# pass 48 | ||
1..46 | ||
# tests 46 | ||
# pass 46 | ||
@@ -413,4 +436,4 @@ # ok | ||
- [electron-packager] - Package your electron app in OS executables (.app, .exe, etc) via JS or CLI. | ||
- [electron-builder] - Complete solution to build ready for distribution and "auto update" installers of your app for OS X, Windows and Linux. | ||
- [electron-packager] - Package your electron app in OS executables (.app, .exe, etc) via JS or CLI | ||
- [electron-builder] - A complete solution to package and build a ready for distribution Electron app with “auto update” support out of the box | ||
@@ -417,0 +440,0 @@ [Bluebird]: https://github.com/petkaantonov/bluebird |
@@ -5,7 +5,2 @@ { | ||
"versions": [ | ||
"0.24.0", | ||
"0.25.3", | ||
"0.26.1", | ||
"0.27.3", | ||
"0.28.3", | ||
"0.29.2", | ||
@@ -22,4 +17,6 @@ "0.30.8", | ||
"1.1.3", | ||
"1.2.0" | ||
"1.2.8", | ||
"1.3.7", | ||
"1.4.4" | ||
] | ||
} |
@@ -59,5 +59,8 @@ var path = require('path') | ||
mkdirp(WORK_CWD, function (err) { | ||
if (err) t.end(err) | ||
process.chdir(WORK_CWD) | ||
t.end() | ||
if (err) { | ||
t.end(err) | ||
} else { | ||
process.chdir(WORK_CWD) | ||
t.end() | ||
} | ||
}) | ||
@@ -64,0 +67,0 @@ }) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
72668
27
1566
429
10
1
4