123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- /**
- * @module util
- */
- 'use strict'
- const child = require('child_process')
- const fs = require('fs')
- const path = require('path')
- const Promise = require('bluebird')
- const debug = require('debug')
- /**
- * This callback is used across signing and flattening.
- * @callback RequestCallback
- * @param {?Error} err
- */
- /** @function */
- const debuglog = module.exports.debuglog = debug('electron-osx-sign')
- debuglog.log = console.log.bind(console)
- /** @function */
- const debugwarn = module.exports.debugwarn = debug('electron-osx-sign:warn')
- debugwarn.log = console.warn.bind(console)
- /** @function */
- const isBinaryFileAsync = module.exports.isBinaryFileAsync = Promise.promisify(require('isbinaryfile'))
- /** @function */
- const removePassword = function (input) {
- return input.replace(/(-P |pass:|\/p|-pass )([^ ]+)/, function (match, p1, p2) {
- return `${p1}***`
- })
- }
- /** @function */
- module.exports.execFileAsync = function (file, args, options) {
- if (debuglog.enabled) {
- debuglog('Executing...', file, args && Array.isArray(args) ? removePassword(args.join(' ')) : '')
- }
- return new Promise(function (resolve, reject) {
- child.execFile(file, args, options, function (err, stdout, stderr) {
- if (err) {
- debuglog('Error executing file:', '\n',
- '> Stdout:', stdout, '\n',
- '> Stderr:', stderr)
- reject(err)
- return
- }
- resolve(stdout)
- })
- })
- }
- /** @function */
- const lstatAsync = module.exports.lstatAsync = Promise.promisify(fs.lstat)
- /** @function */
- const readdirAsync = module.exports.readdirAsync = Promise.promisify(fs.readdir)
- /** @function */
- module.exports.readFileAsync = Promise.promisify(fs.readFile)
- /** @function */
- module.exports.writeFileAsync = Promise.promisify(fs.writeFile)
- /**
- * This function returns a flattened list of elements from an array of lists.
- * @function
- * @param {*} list - List.
- * @returns Flattened list.
- */
- var flatList = module.exports.flatList = function (list) {
- function populateResult (list) {
- if (!Array.isArray(list)) {
- result.push(list)
- } else if (list.length > 0) {
- for (let item of list) if (item) populateResult(item)
- }
- }
- var result = []
- populateResult(list)
- return result
- }
- /**
- * This function returns the path to app contents.
- * @function
- * @param {Object} opts - Options.
- * @returns {string} App contents path.
- */
- var getAppContentsPath = module.exports.getAppContentsPath = function (opts) {
- return path.join(opts.app, 'Contents')
- }
- /**
- * This function returns the path to app frameworks within contents.
- * @function
- * @param {Object} opts - Options.
- * @returns {string} App frameworks path.
- */
- var getAppFrameworksPath = module.exports.getAppFrameworksPath = function (opts) {
- return path.join(getAppContentsPath(opts), 'Frameworks')
- }
- /**
- * This function returns a promise copying a file from the source to the target.
- * @function
- * @param {string} source - Source path.
- * @param {string} target - Target path.
- * @returns {Promise} Promise.
- */
- module.exports.copyFileAsync = function (source, target) {
- debuglog('Copying file...', '\n',
- '> Source:', source, '\n',
- '> Target:', target)
- return new Promise(function (resolve, reject) {
- var readStream = fs.createReadStream(source)
- readStream.on('error', reject)
- var writeStream = fs.createWriteStream(target)
- writeStream.on('error', reject)
- writeStream.on('close', resolve)
- readStream.pipe(writeStream)
- })
- }
- /**
- * This function returns a promise with platform resolved.
- * @function
- * @param {Object} opts - Options.
- * @returns {Promise} Promise resolving platform.
- */
- var detectElectronPlatformAsync = module.exports.detectElectronPlatformAsync = function (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 resolving the file path if file binary.
- * @function
- * @param {string} filePath - Path to file.
- * @returns {Promise} Promise resolving file path or undefined.
- */
- var getFilePathIfBinaryAsync = module.exports.getFilePathIfBinaryAsync = function (filePath) {
- return isBinaryFileAsync(filePath)
- .then(function (isBinary) {
- return isBinary ? filePath : undefined
- })
- }
- /**
- * This function returns a promise validating opts.app, the application to be signed or flattened.
- * @function
- * @param {Object} opts - Options.
- * @returns {Promise} Promise.
- */
- module.exports.validateOptsAppAsync = function (opts) {
- if (!opts.app) {
- return Promise.reject(new Error('Path to aplication must be specified.'))
- }
- if (path.extname(opts.app) !== '.app') {
- return Promise.reject(new Error('Extension of application must be `.app`.'))
- }
- return lstatAsync(opts.app)
- .thenReturn()
- }
- /**
- * This function returns a promise validating opts.platform, the platform of Electron build. It allows auto-discovery if no opts.platform is specified.
- * @function
- * @param {Object} opts - Options.
- * @returns {Promise} Promise.
- */
- module.exports.validateOptsPlatformAsync = function (opts) {
- if (opts.platform) {
- if (opts.platform === 'mas' || opts.platform === 'darwin') {
- return Promise.resolve()
- } 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
- })
- }
- /**
- * This function returns a promise resolving all child paths within the directory specified.
- * @function
- * @param {string} dirPath - Path to directory.
- * @returns {Promise} Promise resolving child paths needing signing in order.
- */
- module.exports.walkAsync = function (dirPath) {
- debuglog('Walking... ' + dirPath)
- var unlinkAsync = Promise.promisify(fs.unlink)
- 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(undefined)
- 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 _walkAsync(dirPath)
- .then(flatList)
- }
|