summaryrefslogtreecommitdiff
path: root/node_modules/electron-packager/src/mac.js
diff options
context:
space:
mode:
authorLinuxWizard42 <computerwizard@linuxmail.org>2022-10-12 22:54:37 +0300
committerLinuxWizard42 <computerwizard@linuxmail.org>2022-10-12 22:54:37 +0300
commit703e03aba33f234712206769f57717ba7d92d23d (patch)
tree0041f04ccb75bd5379c764e9fe42249fffe75fc3 /node_modules/electron-packager/src/mac.js
parentab6e257e6e9d9a483d7e86f220d8b209a2cd7753 (diff)
downloadFlashRunner-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.js444
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
+}