electron-osx-sign
Advanced tools
Comparing version 0.2.0 to 0.3.0-beta
@@ -10,2 +10,2 @@ | ||
pkg Path to the output package. | ||
verbose Verbose flag, to display every action. | ||
verbose Verbose flag, to display logs. |
@@ -9,10 +9,4 @@ | ||
entitlements-inherit Path to child entitlements file for signing frameworks and bundles of Mac App Store application. | ||
helper-path Path to `Electron Helper.app`, which may be renamed. | ||
helper-executable-path Path to `Electron Helper`, which may be renamed, in `Electron Helper.app`. | ||
helper-eh-path Path to `Electron Helper EH.app`, which may be renamed. | ||
helper-eh-executable-path Path to `Electron Helper EH`, which may be renamed, in `Electron Helper EH.app`. | ||
helper-np-path Path to `Electron Helper NP.app`, which may be renamed. | ||
helper-np-executable-path Path to `Electron Helper NP`, which may be renamed, in `Electron Helper NP.app`. | ||
identity Name of certificate to use when signing. Default to retrieve from `login.keychain`. | ||
platform Build platform of Electron. Allowed values: `darwin`, `mas`. Default to auto detect from application package. | ||
verbose Verbose flag, to display every action. | ||
verbose Verbose flag, to display logs. |
214
index.js
@@ -19,11 +19,17 @@ var fs = require('fs') | ||
function findIdentity (opts, identity, cb) { | ||
child.exec('security find-identity', function (err, stdout, stderr) { | ||
// Only to look for valid identities, excluding those flagged with | ||
// CSSMERR_TP_CERT_EXPIRED or CSSMERR_TP_NOT_TRUSTED. Fix #9 | ||
child.exec([ | ||
'security', | ||
'find-identity', | ||
'-v' | ||
].join(' '), function (err, stdout, stderr) { | ||
if (err) return cb(new Error('Error in finding an identity.')) | ||
var lines = stdout.split('\n') | ||
var location | ||
for (var i = 0, l = lines.length; i < l && !opts.identity; i++) { | ||
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(location, line.length - 1) | ||
opts.identity = line.substring(location, line.lastIndexOf('"')) | ||
break | ||
@@ -60,107 +66,73 @@ } | ||
function generateAppBasename (opts) { | ||
return path.basename(opts.app, '.app') | ||
function generateAppContentsPath (opts) { | ||
return path.join(opts.app, 'Contents') | ||
} | ||
function generateAppFrameworksPath (opts) { | ||
return path.join(opts.app, 'Contents', 'Frameworks') | ||
return path.join(generateAppContentsPath(opts), 'Frameworks') | ||
} | ||
function generateHelperAppPath (opts, opt, suffix, callback) { | ||
if (opts[opt]) { | ||
// Use helper path if specified | ||
if (fs.existsSync(opts[opt])) return opts[opt] | ||
else return callback(new Error('Specified Electron Helper not found.')) | ||
} else { | ||
var appFrameworksPath = generateAppFrameworksPath(opts) | ||
var appBasename = generateAppBasename(opts) | ||
var helperPath | ||
if (fs.existsSync(helperPath = path.join(appFrameworksPath, appBasename + ' Helper' + (suffix || '') + '.app'))) { | ||
// Try to look for helper named after app (assume renamed) | ||
return helperPath | ||
} else if (fs.existsSync(helperPath = path.join(appFrameworksPath, | ||
'Electron Helper' + (suffix || '') + '.app'))) { | ||
// Try to look for helper by default | ||
return helperPath | ||
} else { | ||
// Helper not found | ||
callback(new Error('Electron Helper' + (suffix || '') + ' not found.')) | ||
return null | ||
} | ||
} | ||
} | ||
function generateHelperAppExecutablePath (opts, opt, helperPath, suffix, callback) { | ||
if (opts[opt]) { | ||
// Use helper executable path if specified | ||
if (fs.existsSync(opts[opt])) return opts[opt] | ||
else return callback(new Error('Specified Electron Helper executable not found.')) | ||
} else { | ||
var appBasename = generateAppBasename(opts) | ||
var helperExecutablePath | ||
if (fs.existsSync(helperExecutablePath = path.join(helperPath, 'Contents', 'MacOS', appBasename + ' Helper' + (suffix || '')))) { | ||
// Try to look for helper named after app (assume renamed) | ||
return helperExecutablePath | ||
} else if (fs.existsSync(helperExecutablePath = path.join(helperPath, 'Contents', 'MacOS', 'Electron Helper' + (suffix || '')))) { | ||
// Try to look for helper by default | ||
return helperExecutablePath | ||
} else { | ||
// Helper not found | ||
callback(new Error('Electron Helper' + (suffix || '') + ' executable not found.')) | ||
return null | ||
} | ||
} | ||
} | ||
function signApplication (opts, callback) { | ||
var operations = [] | ||
var appFrameworksPath = generateAppFrameworksPath(opts) | ||
var appContentsPath = generateAppContentsPath(opts) | ||
var childPaths | ||
if (opts.platform === 'mas') { | ||
childPaths = [ | ||
path.join(appFrameworksPath, 'Electron Framework.framework', 'Libraries', 'libnode.dylib'), | ||
path.join(appFrameworksPath, 'Electron Framework.framework', 'Versions', 'A', 'Electron Framework'), | ||
path.join(appFrameworksPath, 'Electron Framework.framework') | ||
] | ||
} else if (opts.platform === 'darwin') { | ||
childPaths = [ | ||
path.join(appFrameworksPath, 'Electron Framework.framework', 'Libraries', 'libnode.dylib'), | ||
path.join(appFrameworksPath, 'Electron Framework.framework', 'Versions', 'A', 'Electron Framework'), | ||
path.join(appFrameworksPath, 'Electron Framework.framework'), | ||
path.join(appFrameworksPath, 'Mantle.framework', 'Versions', 'A', 'Mantle'), | ||
path.join(appFrameworksPath, 'Mantle.framework'), | ||
path.join(appFrameworksPath, 'ReactiveCocoa.framework', 'Versions', 'A', 'ReactiveCocoa'), | ||
path.join(appFrameworksPath, 'ReactiveCocoa.framework'), | ||
path.join(appFrameworksPath, 'Squirrel.framework', 'Versions', 'A', 'Squirrel'), | ||
path.join(appFrameworksPath, 'Squirrel.framework') | ||
] | ||
function walkSync (dirPath) { | ||
fs.readdirSync(dirPath).forEach(function (name) { | ||
var filePath = path.join(dirPath, name) | ||
var stat = fs.lstatSync(filePath) | ||
if (stat.isFile()) { | ||
switch (path.extname(filePath)) { | ||
case '': // binary | ||
var baseName = path.basename(filePath) | ||
switch (baseName) { | ||
case 'PkgInfo': | ||
return // ignore files | ||
default: | ||
if (baseName[0] === '.') return // reject hidden files | ||
} | ||
childPaths.push(filePath) | ||
break | ||
case '.dylib': // dynamic library | ||
childPaths.push(filePath) | ||
break | ||
case '.cstemp': // temporary file generated from past codesign | ||
operations.push(function (cb) { | ||
fs.unlink(filePath, (err) => { | ||
if (err) return cb(err) | ||
cb() | ||
}) | ||
console.log('Removing...', filePath) | ||
}) | ||
break | ||
default: | ||
if (path.extname(filePath).includes(' ')) { | ||
// Still consider the file as binary if extension seems invalid | ||
childPaths.push(filePath) | ||
} | ||
} | ||
} else if (stat.isDirectory() && !stat.isSymbolicLink()) { | ||
switch (path.basename(filePath)) { | ||
case '_CodeSignature': | ||
case 'node_modules': | ||
return // ignore directories | ||
} | ||
walkSync(filePath) | ||
switch (path.extname(filePath)) { | ||
case '.app': // application | ||
case '.framework': // framework | ||
childPaths.push(filePath) | ||
break | ||
} | ||
} | ||
}) | ||
} | ||
var childPaths = [] | ||
walkSync(appContentsPath) | ||
if (opts.binaries) childPaths = childPaths.concat(opts.binaries) | ||
var helperPath = generateHelperAppPath(opts, 'helper-path', null, callback) | ||
if (helperPath) { | ||
var helperExecutablePath = generateHelperAppExecutablePath(opts, 'helper-executable-path', helperPath, null, callback) | ||
if (helperExecutablePath) childPaths.unshift(helperExecutablePath, helperPath) | ||
else return callback(new Error('Missing Electron Helper, stopped.')) | ||
} | ||
var helperEHPath = generateHelperAppPath(opts, 'helper-eh-path', ' EH', callback) | ||
if (helperEHPath) { | ||
var helperEHExecutablePath = generateHelperAppExecutablePath(opts, 'helper-eh-executable-path', helperEHPath, ' EH', callback) | ||
if (helperEHExecutablePath) childPaths.unshift(helperEHExecutablePath, helperEHPath) | ||
else return callback(new Error('Missing Electron Helper EH, stopped.')) | ||
} | ||
var helperNPPath = generateHelperAppPath(opts, 'helper-np-path', ' NP', callback) | ||
if (helperNPPath) { | ||
var helperNPExecutablePath = generateHelperAppExecutablePath(opts, 'helper-np-executable-path', helperNPPath, ' NP', callback) | ||
if (helperNPExecutablePath) childPaths.unshift(helperNPExecutablePath, helperNPPath) | ||
else return callback(new Error('Missing Electron Helper NP, stopped.')) | ||
} | ||
if (opts.entitlements) { | ||
if (opts.platform === 'mas') { | ||
// Sign with entitlements | ||
childPaths.forEach(function (path) { | ||
childPaths.forEach(function (filePath) { | ||
operations.push(function (cb) { | ||
@@ -172,5 +144,8 @@ child.exec([ | ||
'--entitlements', '"' + opts['entitlements-inherit'] + '"', | ||
'"' + path.replace(/"/g, '\\"') + '"' | ||
].join(' '), cb) | ||
if (opts.verbose) console.log('Signing...', path) | ||
'"' + filePath.replace(/"/g, '\\"') + '"' | ||
].join(' '), function (err, stdout, stderr) { | ||
if (err) return cb(err) | ||
cb() | ||
}) | ||
if (opts.verbose) console.log('Signing...', filePath) | ||
}) | ||
@@ -185,3 +160,6 @@ }) | ||
'"' + opts.app.replace(/"/g, '\\"') + '"' | ||
].join(' '), cb) | ||
].join(' '), function (err, stdout, stderr) { | ||
if (err) return cb(err) | ||
cb() | ||
}) | ||
if (opts.verbose) console.log('Signing...', opts.app) | ||
@@ -194,3 +172,3 @@ }) | ||
// Otherwise normally | ||
childPaths.forEach(function (path) { | ||
childPaths.forEach(function (filePath) { | ||
operations.push(function (cb) { | ||
@@ -201,5 +179,8 @@ child.exec([ | ||
'-fv', | ||
'"' + path.replace(/"/g, '\\"') + '"' | ||
].join(' '), cb) | ||
if (opts.verbose) console.log('Signing...', path) | ||
'"' + filePath.replace(/"/g, '\\"') + '"' | ||
].join(' '), function (err, stdout, stderr) { | ||
if (err) return cb(err) | ||
cb() | ||
}) | ||
if (opts.verbose) console.log('Signing...', filePath) | ||
}) | ||
@@ -213,3 +194,6 @@ }) | ||
'"' + opts.app.replace(/"/g, '\\"') + '"' | ||
].join(' '), cb) | ||
].join(' '), function (err, stdout, stderr) { | ||
if (err) return cb(err) | ||
cb() | ||
}) | ||
if (opts.verbose) console.log('Signing...', opts.app) | ||
@@ -273,3 +257,3 @@ }) | ||
if (!opts.platform) { | ||
if (opts.verbose) console.warn('No `--platform` passed in arguments, cheking Electron platform...') | ||
if (opts.verbose) console.warn('No `platform` passed in arguments, cheking Electron platform...') | ||
detectElectronPlatform(opts) | ||
@@ -285,8 +269,8 @@ } | ||
if (!opts.entitlements) { | ||
if (opts.verbose) console.warn('No `--entitlements` passed in arguments, will fallback to default settings.') | ||
opts.entitlements = path.join(__dirname, 'mas.default.plist') | ||
if (opts.verbose) console.warn('No `entitlements` passed in arguments, will fallback to default settings.') | ||
opts.entitlements = path.join(__dirname, 'mas.default.entitlements') | ||
} | ||
if (!opts['entitlements-inherit']) { | ||
if (opts.verbose) console.warn('No `--entitlements-inherit` passed in arguments, will fallback to default settings.') | ||
opts['entitlements-inherit'] = path.join(__dirname, 'mas.inherit.default.plist') | ||
if (opts.verbose) console.warn('No `entitlements-inherit` passed in arguments, will fallback to default settings.') | ||
opts['entitlements-inherit'] = path.join(__dirname, 'mas.inherit.default.entitlements') | ||
} | ||
@@ -306,3 +290,3 @@ } else if (opts.platform === 'darwin') { | ||
if (!opts.identity) { | ||
if (opts.verbose) console.warn('No `--identity` passed in arguments, matching identities...') | ||
if (opts.verbose) console.warn('No `identity` passed in arguments, discovering identities...') | ||
if (opts.platform === 'mas') { | ||
@@ -321,4 +305,4 @@ findIdentity(opts, '3rd Party Mac Developer Application', cb) | ||
console.log('> platform ', opts.platform) | ||
console.log('> entitlements ', opts.entitlements || false) | ||
console.log('> child-entitlements ', opts['entitlements-inherit'] || false) | ||
console.log('> entitlements ', opts.entitlements) | ||
console.log('> child-entitlements ', opts['entitlements-inherit']) | ||
console.log('> additional-binaries', opts.binaries) | ||
@@ -351,7 +335,7 @@ console.log('> identity ', opts.identity) | ||
if (!opts.pkg) { | ||
if (opts.verbose) console.warn('No `--pkg` passed in arguments, will fallback to default, inferred from the given application.') | ||
if (opts.verbose) console.warn('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 cb(new Error('Extension of output package must be `.pkg`.')) | ||
if (!opts.install) { | ||
if (opts.verbose) console.warn('No `--install` passed in arguments, will fallback to default `/Applications`.') | ||
if (opts.verbose) console.warn('No `install` passed in arguments, will fallback to default `/Applications`.') | ||
opts.install = '/Applications' | ||
@@ -363,5 +347,5 @@ } | ||
if (!opts.identity) { | ||
if (opts.verbose) console.warn('No `--identity` passed in arguments, matching identities...') | ||
if (opts.verbose) console.warn('No `identity` passed in arguments, discovering identities...') | ||
if (!opts.platform) { | ||
if (opts.verbose) console.warn('No `--platform` passed in arguments, cheking Electron platform...') | ||
if (opts.verbose) console.warn('No `platform` passed in arguments, cheking Electron platform...') | ||
detectElectronPlatform(opts) | ||
@@ -368,0 +352,0 @@ } else if (opts.platform !== 'mas' && opts.platform !== 'darwin') { |
{ | ||
"name": "electron-osx-sign", | ||
"version": "0.2.0", | ||
"version": "0.3.0-beta", | ||
"description": "Code-signing for Electron-packed OS X apps.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -5,4 +5,6 @@ # electron-osx-sign [![npm][npm_img]][npm_url] | ||
The signing procedure follows what described in [Mac App Store Submission Guide](https://github.com/atom/electron/blob/master/docs/tutorial/mac-app-store-submission-guide.md). | ||
Please visit our [Wiki](https://github.com/sethlu/electron-osx-sign/wiki) hosted here on GitHub for walk-throughs and notes from past projects shipped with `electron-packager` and `electron-osx-sign`. | ||
*Note: The signing procedure implemented in this package is based on what described in [Mac App Store Submission Guide](https://github.com/atom/electron/blob/master/docs/tutorial/mac-app-store-submission-guide.md).* | ||
## Installation | ||
@@ -12,10 +14,12 @@ | ||
# For use in npm scripts | ||
npm install electron-osx-sign --save-dev | ||
npm install electron-osx-sign --save | ||
``` | ||
```sh | ||
# For use from cli | ||
# For use from CLI | ||
npm install electron-osx-sign -g | ||
``` | ||
*Note: `electron-osx-sign` will become a dependency of `electron-packager` in a later release for signing apps on OS X. However, please install this package globally for more customization beyond specifying identity and entitlements.* | ||
## Usage | ||
@@ -37,3 +41,3 @@ | ||
For details on the optional flags, run `electron-osx-sign --help` or see [electron-osx-sign-usage.txt](https://github.com/sethlu/electron-sign/blob/master/bin/electron-osx-sign-usage.txt). | ||
For details on the optional flags, run `electron-osx-sign --help` or see [electron-osx-sign-usage.txt](https://github.com/sethlu/electron-osx-sign/blob/master/bin/electron-osx-sign-usage.txt). | ||
@@ -83,3 +87,3 @@ #### From the API | ||
Path to entitlements file for signing Mac App Store application. | ||
See [mas.default.plist](https://github.com/sethlu/electron-sign/blob/master/mas.default.plist) for default. | ||
See [mas.default.entitlements](https://github.com/sethlu/electron-osx-sign/blob/master/mas.default.entitlements) for default. | ||
@@ -89,36 +93,4 @@ `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 [mas.inherit.default.plist](https://github.com/sethlu/electron-sign/blob/master/mas.inherit.default.plist) for default. | ||
See [mas.inherit.default.entitlements](https://github.com/sethlu/electron-osx-sign/blob/master/mas.inherit.default.entitlements) for default. | ||
`helper-path` - *String* | ||
Path to `Electron Helper.app`, which may be renamed. | ||
Default to detect from application package. | ||
`helper-executable-path` - *String* | ||
Path to `Electron Helper`, which may be renamed, in `Electron Helper.app`. | ||
Default to detect from application package. | ||
`helper-eh-path` - *String* | ||
Path to `Electron Helper EH.app`, which may be renamed. | ||
Default to detect from application package. | ||
`helper-eh-executable-path` - *String* | ||
Path to `Electron Helper EH`, which may be renamed, in `Electron Helper EH.app`. | ||
Default to detect from application package. | ||
`helper-np-path` - *String* | ||
Path to `Electron Helper NP.app`, which may be renamed. | ||
Default to detect from application package. | ||
`helper-np-executable-path` - *String* | ||
Path to `Electron Helper NP`, which may be renamed, in `Electron Helper NP.app`. | ||
Default to detect from application package. | ||
*Note: `helper-path`, `helper-executable-path`, `helper-eh-path`, `helper-eh-executable-path`, `helper-np-path`, `helper-np-executable-path` needn't provided unless error thrown for not able to find any of them automatically.* | ||
`identity` - *String* | ||
@@ -139,3 +111,3 @@ | ||
Verbose flag, to display every action through `console.log()`. | ||
Verbose flag, to display logs. | ||
Allowed values: `true`, `false`. | ||
@@ -161,3 +133,3 @@ | ||
For details on the optional flags, run `electron-osx-flat --help` or see [electron-osx-flat-usage.txt](https://github.com/sethlu/electron-sign/blob/master/bin/electron-osx-flat-usage.txt). | ||
For details on the optional flags, run `electron-osx-flat --help` or see [electron-osx-flat-usage.txt](https://github.com/sethlu/electron-osx-sign/blob/master/bin/electron-osx-flat-usage.txt). | ||
@@ -217,7 +189,7 @@ #### From the API | ||
Path to the output flattened package. | ||
Needs file extension `.app`. | ||
Needs file extension `.pkg`. | ||
`verbose` - *String* | ||
Verbose flag, to display every action. | ||
Verbose flag, to display logs. | ||
@@ -228,24 +200,2 @@ ###### callback | ||
## Frequently Raised Issues | ||
If error persists with `A timestamp was expected but was not found.` or `The timestamp service is not available.`, please try code-sign the application later. The intermittent nature of the failures is a networking issue in communicating with the timestamp server. | ||
## Notes | ||
- Accidental halt of `codesign` may result in files with `.cstemp` extension created within the application. Please manually remove those files to avoid any issues that may occur during signing. | ||
- As `productbuild` is not yet incorporated into this code-signing module, please refer to [#5](https://github.com/sethlu/electron-osx-sign/issues/5) for packing signed applications for iTunes Connect submission. | ||
- In current version, binaries except built in within Electron will not be signed automatically. Please manually sign those before running this code-sign module. This issue may be resolved in future development, refer to [#6](https://github.com/sethlu/electron-osx-sign/issues/6). | ||
- The Mac App Store builds of Electron started from v0.34.0. | ||
- From v0.36.0 there was a bug preventing GPU process to start after the app being sandboxed, so it is recommended to use v0.35.x before this bug gets fixed. You can find more about this in issue [atom/electron#3871](https://github.com/atom/electron/issues/3871), refer to [Mac App Store Submission Guide](https://github.com/atom/electron/blob/master/docs/tutorial/mac-app-store-submission-guide.md). | ||
- To verify Gatekeeper acceptance of signed application package, currently not included in the automation, for distribution outside the Mac App Store (`darwin` only), enter the following command in Terminal: | ||
``` | ||
spctl --ignore-cache --no-cache -a -vvvv --type execute "path/to/my/app.app" | ||
``` | ||
For more details, please refer to [Distributing Apps Outside the Mac App Store]( https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/DistributingApplicationsOutside/DistributingApplicationsOutside.html). | ||
## Test | ||
@@ -268,3 +218,3 @@ | ||
> electron-osx-sign@0.2.0 test electron-osx-sign | ||
> electron-osx-sign@0.3.0-beta test electron-osx-sign | ||
> standard && tape test | ||
@@ -271,0 +221,0 @@ |
@@ -18,3 +18,3 @@ { | ||
], | ||
"verbose": false | ||
"verbose": true | ||
} |
Sorry, the diff of this file is not supported yet
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
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
0
28988
527
283