diff options
author | LinuxWizard42 <computerwizard@linuxmail.org> | 2022-10-12 22:54:37 +0300 |
---|---|---|
committer | LinuxWizard42 <computerwizard@linuxmail.org> | 2022-10-12 22:54:37 +0300 |
commit | 703e03aba33f234712206769f57717ba7d92d23d (patch) | |
tree | 0041f04ccb75bd5379c764e9fe42249fffe75fc3 /node_modules/electron-packager/src/mac.js | |
parent | ab6e257e6e9d9a483d7e86f220d8b209a2cd7753 (diff) | |
download | FlashRunner-703e03aba33f234712206769f57717ba7d92d23d.tar.gz FlashRunner-703e03aba33f234712206769f57717ba7d92d23d.tar.zst |
Added export_allowed file to make repository visible in cgit
Diffstat (limited to 'node_modules/electron-packager/src/mac.js')
-rw-r--r-- | node_modules/electron-packager/src/mac.js | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/node_modules/electron-packager/src/mac.js b/node_modules/electron-packager/src/mac.js new file mode 100644 index 0000000..2d6e769 --- /dev/null +++ b/node_modules/electron-packager/src/mac.js @@ -0,0 +1,444 @@ +'use strict' + +const App = require('./platform') +const common = require('./common') +const debug = require('debug')('electron-packager') +const fs = require('fs-extra') +const path = require('path') +const plist = require('plist') +const { notarize } = require('electron-notarize') +const { signAsync } = require('electron-osx-sign') + +class MacApp extends App { + constructor (opts, templatePath) { + super(opts, templatePath) + + this.appName = opts.name + } + + get appCategoryType () { + return this.opts.appCategoryType + } + + get appCopyright () { + return this.opts.appCopyright + } + + get appVersion () { + return this.opts.appVersion + } + + get buildVersion () { + return this.opts.buildVersion + } + + get enableDarkMode () { + return this.opts.darwinDarkModeSupport + } + + get usageDescription () { + return this.opts.usageDescription + } + + get protocols () { + return this.opts.protocols.map((protocol) => { + return { + CFBundleURLName: protocol.name, + CFBundleURLSchemes: [].concat(protocol.schemes) + } + }) + } + + get dotAppName () { + return `${common.sanitizeAppName(this.appName)}.app` + } + + get defaultBundleName () { + return `com.electron.${common.sanitizeAppName(this.appName).toLowerCase()}` + } + + get bundleName () { + return filterCFBundleIdentifier(this.opts.appBundleId || this.defaultBundleName) + } + + get originalResourcesDir () { + return path.join(this.contentsPath, 'Resources') + } + + get resourcesDir () { + return path.join(this.dotAppName, 'Contents', 'Resources') + } + + get electronBinaryDir () { + return path.join(this.contentsPath, 'MacOS') + } + + get originalElectronName () { + return 'Electron' + } + + get newElectronName () { + return this.appPlist.CFBundleExecutable + } + + get renamedAppPath () { + return path.join(this.stagingPath, this.dotAppName) + } + + get electronAppPath () { + return path.join(this.stagingPath, `${this.originalElectronName}.app`) + } + + get contentsPath () { + return path.join(this.electronAppPath, 'Contents') + } + + get frameworksPath () { + return path.join(this.contentsPath, 'Frameworks') + } + + get loginItemsPath () { + return path.join(this.contentsPath, 'Library', 'LoginItems') + } + + get loginHelperPath () { + return path.join(this.loginItemsPath, 'Electron Login Helper.app') + } + + updatePlist (basePlist, displayName, identifier, name) { + return Object.assign(basePlist, { + CFBundleDisplayName: displayName, + CFBundleExecutable: common.sanitizeAppName(displayName), + CFBundleIdentifier: identifier, + CFBundleName: common.sanitizeAppName(name) + }) + } + + updateHelperPlist (basePlist, suffix, identifierIgnoresSuffix) { + let helperSuffix, identifier, name + if (suffix) { + helperSuffix = `Helper ${suffix}` + if (identifierIgnoresSuffix) { + identifier = this.helperBundleIdentifier + } else { + identifier = `${this.helperBundleIdentifier}.${suffix}` + } + name = `${this.appName} ${helperSuffix}` + } else { + helperSuffix = 'Helper' + identifier = this.helperBundleIdentifier + name = this.appName + } + return this.updatePlist(basePlist, `${this.appName} ${helperSuffix}`, identifier, name) + } + + async extendPlist (basePlist, propsOrFilename) { + if (!propsOrFilename) { + return Promise.resolve() + } + + if (typeof propsOrFilename === 'string') { + const plist = await this.loadPlist(propsOrFilename) + return Object.assign(basePlist, plist) + } else { + return Object.assign(basePlist, propsOrFilename) + } + } + + async loadPlist (filename, propName) { + const loadedPlist = plist.parse((await fs.readFile(filename)).toString()) + if (propName) { + this[propName] = loadedPlist + } + return loadedPlist + } + + ehPlistFilename (helper) { + return this.helperPlistFilename(path.join(this.frameworksPath, helper)) + } + + helperPlistFilename (helperApp) { + return path.join(helperApp, 'Contents', 'Info.plist') + } + + async determinePlistFilesToUpdate () { + const appPlistFilename = path.join(this.contentsPath, 'Info.plist') + + const plists = [ + [appPlistFilename, 'appPlist'], + [this.ehPlistFilename('Electron Helper.app'), 'helperPlist'] + ] + + const possiblePlists = [ + [this.ehPlistFilename('Electron Helper (Renderer).app'), 'helperRendererPlist'], + [this.ehPlistFilename('Electron Helper (Plugin).app'), 'helperPluginPlist'], + [this.ehPlistFilename('Electron Helper (GPU).app'), 'helperGPUPlist'], + [this.ehPlistFilename('Electron Helper EH.app'), 'helperEHPlist'], + [this.ehPlistFilename('Electron Helper NP.app'), 'helperNPPlist'], + [this.helperPlistFilename(this.loginHelperPath), 'loginHelperPlist'] + ] + + const optional = await Promise.all(possiblePlists.map(async item => + (await fs.pathExists(item[0])) ? item : null)) + return plists.concat(optional.filter(item => item)) + } + + appRelativePath (p) { + return path.relative(this.contentsPath, p) + } + + async updatePlistFiles () { + const appBundleIdentifier = this.bundleName + this.helperBundleIdentifier = filterCFBundleIdentifier(this.opts.helperBundleId || `${appBundleIdentifier}.helper`) + + const plists = await this.determinePlistFilesToUpdate() + await Promise.all(plists.map(plistArgs => this.loadPlist(...plistArgs))) + await this.extendPlist(this.appPlist, this.opts.extendInfo) + if (this.asarIntegrity) { + await this.extendPlist(this.appPlist, { + ElectronAsarIntegrity: this.asarIntegrity + }) + } + this.appPlist = this.updatePlist(this.appPlist, this.executableName, appBundleIdentifier, this.appName) + + const updateIfExists = [ + ['helperRendererPlist', '(Renderer)', true], + ['helperPluginPlist', '(Plugin)', true], + ['helperGPUPlist', '(GPU)', true], + ['helperEHPlist', 'EH'], + ['helperNPPlist', 'NP'] + ] + + for (const [plistKey] of [...updateIfExists, ['helperPlist']]) { + if (!this[plistKey]) continue + await this.extendPlist(this[plistKey], this.opts.extendHelperInfo) + } + + this.helperPlist = this.updateHelperPlist(this.helperPlist) + for (const [plistKey, ...suffixArgs] of updateIfExists) { + if (!this[plistKey]) continue + this[plistKey] = this.updateHelperPlist(this[plistKey], ...suffixArgs) + } + + // Some properties need to go on all helpers as well, version, usage info, etc. + const plistsToUpdate = updateIfExists + .filter(([key]) => !!this[key]) + .map(([key]) => key) + .concat(['appPlist', 'helperPlist']) + + if (this.loginHelperPlist) { + const loginHelperName = common.sanitizeAppName(`${this.appName} Login Helper`) + this.loginHelperPlist.CFBundleExecutable = loginHelperName + this.loginHelperPlist.CFBundleIdentifier = `${appBundleIdentifier}.loginhelper` + this.loginHelperPlist.CFBundleName = loginHelperName + } + + if (this.appVersion) { + const appVersionString = '' + this.appVersion + for (const plistKey of plistsToUpdate) { + this[plistKey].CFBundleShortVersionString = this[plistKey].CFBundleVersion = appVersionString + } + } + + if (this.buildVersion) { + const buildVersionString = '' + this.buildVersion + for (const plistKey of plistsToUpdate) { + this[plistKey].CFBundleVersion = buildVersionString + } + } + + if (this.opts.protocols && this.opts.protocols.length) { + this.appPlist.CFBundleURLTypes = this.protocols + } + + if (this.appCategoryType) { + this.appPlist.LSApplicationCategoryType = this.appCategoryType + } + + if (this.appCopyright) { + this.appPlist.NSHumanReadableCopyright = this.appCopyright + } + + if (this.enableDarkMode) { + this.appPlist.NSRequiresAquaSystemAppearance = false + } + + if (this.usageDescription) { + for (const [type, description] of Object.entries(this.usageDescription)) { + const usageTypeKey = `NS${type}UsageDescription` + for (const plistKey of plistsToUpdate) { + this[plistKey][usageTypeKey] = description + } + this.appPlist[usageTypeKey] = description + } + } + + await Promise.all(plists.map(([filename, varName]) => + fs.writeFile(filename, plist.build(this[varName])))) + } + + async moveHelpers () { + const helpers = [' Helper', ' Helper EH', ' Helper NP', ' Helper (Renderer)', ' Helper (Plugin)', ' Helper (GPU)'] + await Promise.all(helpers.map(suffix => this.moveHelper(this.frameworksPath, suffix))) + if (await fs.pathExists(this.loginItemsPath)) { + await this.moveHelper(this.loginItemsPath, ' Login Helper') + } + } + + async moveHelper (helperDirectory, suffix) { + const originalBasename = `Electron${suffix}` + + if (await fs.pathExists(path.join(helperDirectory, `${originalBasename}.app`))) { + return this.renameHelperAndExecutable( + helperDirectory, + originalBasename, + `${common.sanitizeAppName(this.appName)}${suffix}` + ) + } else { + return Promise.resolve() + } + } + + async renameHelperAndExecutable (helperDirectory, originalBasename, newBasename) { + const originalAppname = `${originalBasename}.app` + const executableBasePath = path.join(helperDirectory, originalAppname, 'Contents', 'MacOS') + await this.relativeRename(executableBasePath, originalBasename, newBasename) + await this.relativeRename(helperDirectory, originalAppname, `${newBasename}.app`) + } + + async copyIcon () { + if (!this.opts.icon) { + return Promise.resolve() + } + + let icon + + try { + icon = await this.normalizeIconExtension('.icns') + } catch { + // Ignore error if icon doesn't exist, in case it's only available for other OSes + /* istanbul ignore next */ + return Promise.resolve() + } + if (icon) { + debug(`Copying icon "${icon}" to app's Resources as "${this.appPlist.CFBundleIconFile}"`) + await fs.copy(icon, path.join(this.originalResourcesDir, this.appPlist.CFBundleIconFile)) + } + } + + async renameAppAndHelpers () { + await this.moveHelpers() + await fs.rename(this.electronAppPath, this.renamedAppPath) + } + + async signAppIfSpecified () { + const osxSignOpt = this.opts.osxSign + const platform = this.opts.platform + const version = this.opts.electronVersion + + if ((platform === 'all' || platform === 'mas') && + osxSignOpt === undefined) { + common.warning('signing is required for mas builds. Provide the osx-sign option, ' + + 'or manually sign the app later.') + } + + if (osxSignOpt) { + const signOpts = createSignOpts(osxSignOpt, platform, this.renamedAppPath, version, this.opts.osxNotarize, this.opts.quiet) + debug(`Running electron-osx-sign with the options ${JSON.stringify(signOpts)}`) + try { + await signAsync(signOpts) + } catch (err) { + // Although not signed successfully, the application is packed. + common.warning(`Code sign failed; please retry manually. ${err}`) + } + } + } + + async notarizeAppIfSpecified () { + const osxNotarizeOpt = this.opts.osxNotarize + + /* istanbul ignore if */ + if (osxNotarizeOpt) { + const notarizeOpts = createNotarizeOpts( + osxNotarizeOpt, + this.bundleName, + this.renamedAppPath, + this.opts.quiet + ) + if (notarizeOpts) { + return notarize(notarizeOpts) + } + } + } + + async create () { + await this.initialize() + await this.updatePlistFiles() + await this.copyIcon() + await this.renameElectron() + await this.renameAppAndHelpers() + await this.copyExtraResources() + await this.signAppIfSpecified() + await this.notarizeAppIfSpecified() + return this.move() + } +} + +/** + * Remove special characters and allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.) + * Apple documentation: + * https://developer.apple.com/library/mac/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-102070 + */ +function filterCFBundleIdentifier (identifier) { + return identifier.replace(/ /g, '-').replace(/[^a-zA-Z0-9.-]/g, '') +} + +function createSignOpts (properties, platform, app, version, notarize, quiet) { + // use default sign opts if osx-sign is true, otherwise clone osx-sign object + const signOpts = properties === true ? { identity: null } : { ...properties } + + // osx-sign options are handed off to sign module, but + // with a few additions from the main options + // user may think they can pass platform, app, or version, but they will be ignored + common.subOptionWarning(signOpts, 'osx-sign', 'platform', platform, quiet) + common.subOptionWarning(signOpts, 'osx-sign', 'app', app, quiet) + common.subOptionWarning(signOpts, 'osx-sign', 'version', version, quiet) + + if (signOpts.binaries) { + common.warning('osx-sign.binaries is not an allowed sub-option. Not passing to electron-osx-sign.') + delete signOpts.binaries + } + + // Take argument osx-sign as signing identity: + // if opts.osxSign is true (bool), fallback to identity=null for + // autodiscovery. Otherwise, provide signing certificate info. + if (signOpts.identity === true) { + signOpts.identity = null + } + + if (notarize && !signOpts.hardenedRuntime && !signOpts['hardened-runtime']) { + common.warning('notarization is enabled but hardenedRuntime was not enabled in the signing ' + + 'options. It has been enabled for you but you should enable it in your config.') + signOpts.hardenedRuntime = true + } + + return signOpts +} + +function createNotarizeOpts (properties, appBundleId, appPath, quiet) { + // osxNotarize options are handed off to the electron-notarize module, but with a few + // additions from the main options. The user may think they can pass bundle ID or appPath, + // but they will be ignored. + if (properties.tool !== 'notarytool') { + common.subOptionWarning(properties, 'osxNotarize', 'appBundleId', appBundleId, quiet) + } + common.subOptionWarning(properties, 'osxNotarize', 'appPath', appPath, quiet) + return properties +} + +module.exports = { + App: MacApp, + createNotarizeOpts: createNotarizeOpts, + createSignOpts: createSignOpts, + filterCFBundleIdentifier: filterCFBundleIdentifier +} |