summaryrefslogtreecommitdiff
path: root/desktop/node_modules/electron-packager/src
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/node_modules/electron-packager/src')
-rw-r--r--desktop/node_modules/electron-packager/src/cli.js143
-rw-r--r--desktop/node_modules/electron-packager/src/common.js128
-rw-r--r--desktop/node_modules/electron-packager/src/copy-filter.js110
-rw-r--r--desktop/node_modules/electron-packager/src/download.js37
-rw-r--r--desktop/node_modules/electron-packager/src/hooks.js24
-rw-r--r--desktop/node_modules/electron-packager/src/index.d.ts607
-rw-r--r--desktop/node_modules/electron-packager/src/index.js207
-rw-r--r--desktop/node_modules/electron-packager/src/infer.js178
-rw-r--r--desktop/node_modules/electron-packager/src/linux.js25
-rw-r--r--desktop/node_modules/electron-packager/src/mac.js440
-rw-r--r--desktop/node_modules/electron-packager/src/platform.js277
-rw-r--r--desktop/node_modules/electron-packager/src/prune.js70
-rw-r--r--desktop/node_modules/electron-packager/src/targets.js149
-rw-r--r--desktop/node_modules/electron-packager/src/universal.js80
-rw-r--r--desktop/node_modules/electron-packager/src/unzip.js7
-rw-r--r--desktop/node_modules/electron-packager/src/win32.js113
16 files changed, 2595 insertions, 0 deletions
diff --git a/desktop/node_modules/electron-packager/src/cli.js b/desktop/node_modules/electron-packager/src/cli.js
new file mode 100644
index 0000000..29f911d
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/cli.js
@@ -0,0 +1,143 @@
+'use strict'
+
+const { info, hostInfo, warning } = require('./common')
+const fs = require('fs-extra')
+const { initializeProxy } = require('@electron/get')
+const packager = require('..')
+const path = require('path')
+const yargs = require('yargs-parser')
+
+/* istanbul ignore next */
+async function printUsageAndExit (isError) {
+ const usage = (await fs.readFile(path.resolve(__dirname, '..', 'usage.txt'))).toString()
+ const print = isError ? console.error : console.log
+ print(usage)
+ process.exit(isError ? 1 : 0)
+}
+
+module.exports = {
+ parseArgs: function parseArgs (argv) {
+ const args = yargs(argv, {
+ boolean: [
+ 'all',
+ 'deref-symlinks',
+ 'download.rejectUnauthorized',
+ 'junk',
+ 'overwrite',
+ 'prune',
+ 'quiet'
+ ],
+ default: {
+ 'deref-symlinks': true,
+ 'download.rejectUnauthorized': true,
+ junk: true,
+ prune: true
+ },
+ string: [
+ 'electron-version',
+ 'out'
+ ]
+ })
+
+ args.dir = args._[0]
+ args.name = args._[1]
+
+ const protocolSchemes = [].concat(args.protocol || [])
+ const protocolNames = [].concat(args.protocolName || [])
+
+ if (protocolSchemes && protocolNames && protocolNames.length === protocolSchemes.length) {
+ args.protocols = protocolSchemes.map(function (scheme, i) {
+ return { schemes: [scheme], name: protocolNames[i] }
+ })
+ }
+
+ if (args.out === '') {
+ warning('Specifying --out= without a value is the same as the default value', args.quiet)
+ args.out = null
+ }
+
+ // Overrides for multi-typed arguments, because minimist doesn't support it
+
+ // asar: `Object` or `true`
+ if (args.asar === 'true' || args.asar instanceof Array) {
+ warning('--asar does not take any arguments, it only has sub-properties (see --help)', args.quiet)
+ args.asar = true
+ }
+
+ // osx-sign: `Object` or `true`
+ if (args.osxSign === 'true') {
+ warning('--osx-sign does not take any arguments, it only has sub-properties (see --help)', args.quiet)
+ args.osxSign = true
+ } else if (typeof args['osx-sign'] === 'object') {
+ if (Array.isArray(args['osx-sign'])) {
+ warning('Remove --osx-sign (the bare flag) from the command line, only specify sub-properties (see --help)', args.quiet)
+ } else {
+ // Keep kebab case of sub properties
+ args.osxSign = args['osx-sign']
+ }
+ }
+
+ if (args.osxNotarize) {
+ let notarize = true
+ if (typeof args.osxNotarize !== 'object' || Array.isArray(args.osxNotarize)) {
+ warning('--osx-notarize does not take any arguments, it only has sub-properties (see --help)', args.quiet)
+ notarize = false
+ } else if (!args.osxSign) {
+ warning('Notarization was enabled but macOS code signing was not, code signing is a requirement for notarization, notarize will not run', args.quiet)
+ notarize = false
+ }
+
+ if (!notarize) {
+ args.osxNotarize = null
+ }
+ }
+
+ // tmpdir: `String` or `false`
+ if (args.tmpdir === 'false') {
+ warning('--tmpdir=false is deprecated, use --no-tmpdir instead', args.quiet)
+ args.tmpdir = false
+ }
+
+ return args
+ },
+ run: /* istanbul ignore next */ async function run (argv) {
+ const args = module.exports.parseArgs(argv)
+
+ // temporary fix for https://github.com/nodejs/node/issues/6456
+ for (const stdioWriter of [process.stdout, process.stderr]) {
+ if (stdioWriter._handle && stdioWriter._handle.setBlocking) {
+ stdioWriter._handle.setBlocking(true)
+ }
+ }
+
+ if (args.help) {
+ await printUsageAndExit(false)
+ } else if (args.version) {
+ if (typeof args.version !== 'boolean') {
+ console.error('--version does not take an argument. Perhaps you meant --app-version or --electron-version?\n')
+ }
+ console.log(hostInfo())
+ process.exit(0)
+ } else if (!args.dir) {
+ await printUsageAndExit(true)
+ }
+
+ initializeProxy()
+
+ try {
+ const appPaths = await packager(args)
+ if (appPaths.length > 1) {
+ info(`Wrote new apps to:\n${appPaths.join('\n')}`, args.quiet)
+ } else if (appPaths.length === 1) {
+ info(`Wrote new app to: ${appPaths[0]}`, args.quiet)
+ }
+ } catch (err) {
+ if (err.message) {
+ console.error(err.message)
+ } else {
+ console.error(err, err.stack)
+ }
+ process.exit(1)
+ }
+ }
+}
diff --git a/desktop/node_modules/electron-packager/src/common.js b/desktop/node_modules/electron-packager/src/common.js
new file mode 100644
index 0000000..1f6111f
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/common.js
@@ -0,0 +1,128 @@
+'use strict'
+
+const debug = require('debug')('electron-packager')
+const filenamify = require('filenamify')
+const fs = require('fs-extra')
+const metadata = require('../package.json')
+const os = require('os')
+const path = require('path')
+
+function sanitizeAppName (name) {
+ return filenamify(name, { replacement: '-' })
+}
+
+function generateFinalBasename (opts) {
+ return `${sanitizeAppName(opts.name)}-${opts.platform}-${opts.arch}`
+}
+
+function generateFinalPath (opts) {
+ return path.join(opts.out || process.cwd(), generateFinalBasename(opts))
+}
+
+function info (message, quiet) {
+ if (!quiet) {
+ console.error(message)
+ }
+}
+
+function warning (message, quiet) {
+ if (!quiet) {
+ console.warn(`WARNING: ${message}`)
+ }
+}
+
+function subOptionWarning (properties, optionName, parameter, value, quiet) {
+ if (Object.prototype.hasOwnProperty.call(properties, parameter)) {
+ warning(`${optionName}.${parameter} will be inferred from the main options`, quiet)
+ }
+ properties[parameter] = value
+}
+
+function createAsarOpts (opts) {
+ let asarOptions
+ if (opts.asar === true) {
+ asarOptions = {}
+ } else if (typeof opts.asar === 'object') {
+ asarOptions = opts.asar
+ } else if (opts.asar === false || opts.asar === undefined) {
+ return false
+ } else {
+ warning(`asar parameter set to an invalid value (${opts.asar}), ignoring and disabling asar`, opts.quiet)
+ return false
+ }
+
+ return asarOptions
+}
+
+module.exports = {
+ ensureArray: function ensureArray (value) {
+ return Array.isArray(value) ? value : [value]
+ },
+ isPlatformMac: function isPlatformMac (platform) {
+ return platform === 'darwin' || platform === 'mas'
+ },
+
+ createAsarOpts: createAsarOpts,
+
+ deprecatedParameter: function deprecatedParameter (properties, oldName, newName, newCLIName, quiet) {
+ if (Object.prototype.hasOwnProperty.call(properties, oldName)) {
+ warning(`The ${oldName} parameter is deprecated, use ${newName} (or --${newCLIName} in the CLI) instead`, quiet)
+ if (!Object.prototype.hasOwnProperty.call(properties, newName)) {
+ properties[newName] = properties[oldName]
+ }
+ delete properties[oldName]
+ }
+ },
+ subOptionWarning: subOptionWarning,
+
+ baseTempDir: function baseTempDir (opts) {
+ return path.join(opts.tmpdir || os.tmpdir(), 'electron-packager')
+ },
+ generateFinalBasename: generateFinalBasename,
+ generateFinalPath: generateFinalPath,
+ sanitizeAppName,
+ /**
+ * Convert slashes to UNIX-format separators.
+ */
+ normalizePath: function normalizePath (pathToNormalize) {
+ return pathToNormalize.replace(/\\/g, '/')
+ },
+ /**
+ * Validates that the application directory contains a package.json file, and that there exists an
+ * appropriate main entry point file, per the rules of the "main" field in package.json.
+ *
+ * See: https://docs.npmjs.com/cli/v6/configuring-npm/package-json#main
+ *
+ * @param appDir - the directory specified by the user
+ * @param bundledAppDir - the directory where the appDir is copied to in the bundled Electron app
+ */
+ validateElectronApp: async function validateElectronApp (appDir, bundledAppDir) {
+ debug('Validating bundled Electron app')
+ debug('Checking for a package.json file')
+
+ const bundledPackageJSONPath = path.join(bundledAppDir, 'package.json')
+ if (!(await fs.pathExists(bundledPackageJSONPath))) {
+ const originalPackageJSONPath = path.join(appDir, 'package.json')
+ throw new Error(`Application manifest was not found. Make sure "${originalPackageJSONPath}" exists and does not get ignored by your ignore option`)
+ }
+
+ debug('Checking for the main entry point file')
+ const packageJSON = await fs.readJson(bundledPackageJSONPath)
+ const mainScriptBasename = packageJSON.main || 'index.js'
+ const mainScript = path.resolve(bundledAppDir, mainScriptBasename)
+ if (!(await fs.pathExists(mainScript))) {
+ const originalMainScript = path.join(appDir, mainScriptBasename)
+ throw new Error(`The main entry point to your app was not found. Make sure "${originalMainScript}" exists and does not get ignored by your ignore option`)
+ }
+
+ debug('Validation complete')
+ },
+
+ hostInfo: function hostInfo () {
+ return `Electron Packager ${metadata.version}\n` +
+ `Node ${process.version}\n` +
+ `Host Operating system: ${process.platform} ${os.release()} (${process.arch})`
+ },
+ info: info,
+ warning: warning
+}
diff --git a/desktop/node_modules/electron-packager/src/copy-filter.js b/desktop/node_modules/electron-packager/src/copy-filter.js
new file mode 100644
index 0000000..ddfc608
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/copy-filter.js
@@ -0,0 +1,110 @@
+'use strict'
+
+const common = require('./common')
+const debug = require('debug')('electron-packager')
+const junk = require('junk')
+const path = require('path')
+const prune = require('./prune')
+const targets = require('./targets')
+
+const DEFAULT_IGNORES = [
+ '/package-lock\\.json$',
+ '/yarn\\.lock$',
+ '/\\.git($|/)',
+ '/node_modules/\\.bin($|/)',
+ '\\.o(bj)?$',
+ '/node_gyp_bins($|/)'
+]
+
+function populateIgnoredPaths (opts) {
+ opts.originalIgnore = opts.ignore
+ if (typeof (opts.ignore) !== 'function') {
+ if (opts.ignore) {
+ opts.ignore = common.ensureArray(opts.ignore).concat(DEFAULT_IGNORES)
+ } else {
+ opts.ignore = [].concat(DEFAULT_IGNORES)
+ }
+ if (process.platform === 'linux') {
+ opts.ignore.push(common.baseTempDir(opts))
+ }
+
+ debug('Ignored path regular expressions:', opts.ignore)
+ }
+}
+
+function generateIgnoredOutDirs (opts) {
+ const normalizedOut = opts.out ? path.resolve(opts.out) : null
+ const ignoredOutDirs = []
+ if (normalizedOut === null || normalizedOut === process.cwd()) {
+ for (const [platform, archs] of Object.entries(targets.officialPlatformArchCombos)) {
+ for (const arch of archs) {
+ const basenameOpts = {
+ arch: arch,
+ name: opts.name,
+ platform: platform
+ }
+ ignoredOutDirs.push(path.join(process.cwd(), common.generateFinalBasename(basenameOpts)))
+ }
+ }
+ } else {
+ ignoredOutDirs.push(normalizedOut)
+ }
+
+ debug('Ignored paths based on the out param:', ignoredOutDirs)
+
+ return ignoredOutDirs
+}
+
+function generateFilterFunction (ignore) {
+ if (typeof (ignore) === 'function') {
+ return file => !ignore(file)
+ } else {
+ const ignoredRegexes = common.ensureArray(ignore)
+
+ return function filterByRegexes (file) {
+ return !ignoredRegexes.some(regex => file.match(regex))
+ }
+ }
+}
+
+function userPathFilter (opts) {
+ const filterFunc = generateFilterFunction(opts.ignore || [])
+ const ignoredOutDirs = generateIgnoredOutDirs(opts)
+ const pruner = opts.prune ? new prune.Pruner(opts.dir, opts.quiet) : null
+
+ return async function filter (file) {
+ const fullPath = path.resolve(file)
+
+ if (ignoredOutDirs.includes(fullPath)) {
+ return false
+ }
+
+ if (opts.junk !== false) { // defaults to true
+ if (junk.is(path.basename(fullPath))) {
+ return false
+ }
+ }
+
+ let name = fullPath.split(path.resolve(opts.dir))[1]
+
+ if (path.sep === '\\') {
+ name = common.normalizePath(name)
+ }
+
+ if (pruner && name.startsWith('/node_modules/')) {
+ if (await prune.isModule(file)) {
+ return pruner.pruneModule(name)
+ } else {
+ return filterFunc(name)
+ }
+ }
+
+ return filterFunc(name)
+ }
+}
+
+module.exports = {
+ populateIgnoredPaths,
+ generateIgnoredOutDirs,
+ userPathFilter
+}
diff --git a/desktop/node_modules/electron-packager/src/download.js b/desktop/node_modules/electron-packager/src/download.js
new file mode 100644
index 0000000..9c104a0
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/download.js
@@ -0,0 +1,37 @@
+'use strict'
+
+const common = require('./common')
+const debug = require('debug')('electron-packager')
+const { downloadArtifact } = require('@electron/get')
+const semver = require('semver')
+const targets = require('./targets')
+
+function createDownloadOpts (opts, platform, arch) {
+ const downloadOpts = { ...opts.download }
+
+ common.subOptionWarning(downloadOpts, 'download', 'platform', platform, opts.quiet)
+ common.subOptionWarning(downloadOpts, 'download', 'arch', arch, opts.quiet)
+ common.subOptionWarning(downloadOpts, 'download', 'version', opts.electronVersion, opts.quiet)
+ common.subOptionWarning(downloadOpts, 'download', 'artifactName', 'electron', opts.quiet)
+
+ return downloadOpts
+}
+
+module.exports = {
+ createDownloadCombos: function createDownloadCombos (opts, selectedPlatforms, selectedArchs, ignoreFunc) {
+ return targets.createPlatformArchPairs(opts, selectedPlatforms, selectedArchs, ignoreFunc).map(([platform, arch]) => {
+ return createDownloadOpts(opts, platform, arch)
+ })
+ },
+ createDownloadOpts: createDownloadOpts,
+ downloadElectronZip: async function downloadElectronZip (downloadOpts) {
+ // armv7l builds have only been backfilled for Electron >= 1.0.0.
+ // See: https://github.com/electron/electron/pull/6986
+ /* istanbul ignore if */
+ if (downloadOpts.arch === 'armv7l' && semver.lt(downloadOpts.version, '1.0.0')) {
+ downloadOpts.arch = 'arm'
+ }
+ debug(`Downloading Electron with options ${JSON.stringify(downloadOpts)}`)
+ return downloadArtifact(downloadOpts)
+ }
+}
diff --git a/desktop/node_modules/electron-packager/src/hooks.js b/desktop/node_modules/electron-packager/src/hooks.js
new file mode 100644
index 0000000..a16426a
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/hooks.js
@@ -0,0 +1,24 @@
+'use strict'
+
+const { promisify } = require('util')
+
+module.exports = {
+ promisifyHooks: async function promisifyHooks (hooks, args) {
+ if (!hooks || !Array.isArray(hooks)) {
+ return Promise.resolve()
+ }
+
+ await Promise.all(hooks.map(hookFn => promisify(hookFn).apply(this, args)))
+ },
+ serialHooks: function serialHooks (hooks) {
+ return async function () {
+ const args = Array.prototype.splice.call(arguments, 0, arguments.length - 1)
+ const done = arguments[arguments.length - 1]
+ for (const hook of hooks) {
+ await hook.apply(this, args)
+ }
+
+ return done() // eslint-disable-line promise/no-callback-in-promise
+ }
+ }
+}
diff --git a/desktop/node_modules/electron-packager/src/index.d.ts b/desktop/node_modules/electron-packager/src/index.d.ts
new file mode 100644
index 0000000..5a2b63e
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/index.d.ts
@@ -0,0 +1,607 @@
+// Originally based on the type definitions for electron-packager 14.0
+// Project: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/electron-packager
+// Original Authors:
+// * Maxime LUCE <https://github.com/SomaticIT>
+// * Juan Jimenez-Anca <https://github.com/cortopy>
+// * John Kleinschmidt <https://github.com/jkleinsc>
+// * Brendan Forster <https://github.com/shiftkey>
+// * Mark Lee <https://github.com/malept>
+// * Florian Keller <https://github.com/ffflorian>
+
+import { CreateOptions as AsarOptions } from '@electron/asar';
+import { ElectronDownloadRequestOptions as ElectronDownloadOptions } from '@electron/get';
+import {
+ LegacyNotarizeCredentials,
+ NotaryToolCredentials,
+ TransporterOptions
+} from '@electron/notarize/lib/types';
+import { SignOptions } from '@electron/osx-sign/dist/esm/types';
+import type { makeUniversalApp } from '@electron/universal';
+
+type MakeUniversalOpts = Parameters<typeof makeUniversalApp>[0]
+
+type NotarizeLegacyOptions = LegacyNotarizeCredentials & TransporterOptions;
+
+/**
+ * Bundles Electron-based application source code with a renamed/customized Electron executable and
+ * its supporting files into folders ready for distribution.
+ *
+ * Briefly, this function:
+ * - finds or downloads the correct release of Electron
+ * - uses that version of Electron to create a app in `<out>/<appname>-<platform>-<arch>`
+ *
+ * Short example:
+ *
+ * ```javascript
+ * const packager = require('electron-packager')
+ *
+ * async function bundleElectronApp(options) {
+ * const appPaths = await packager(options)
+ * console.log(`Electron app bundles created:\n${appPaths.join("\n")}`)
+ * }
+ * ```
+ *
+ * @param opts - Options to configure packaging.
+ *
+ * @returns A Promise containing the paths to the newly created application bundles.
+ */
+declare function electronPackager(opts: electronPackager.Options): Promise<string[]>;
+
+declare namespace electronPackager {
+ /**
+ * Architectures that have been supported by the official Electron prebuilt binaries, past
+ * and present.
+ */
+ type OfficialArch = 'ia32' | 'x64' | 'armv7l' | 'arm64' | 'mips64el' | 'universal';
+ /**
+ * Platforms that have been supported by the official Electron prebuilt binaries, past and present.
+ */
+ type OfficialPlatform = 'linux' | 'win32' | 'darwin' | 'mas';
+ type TargetArch = OfficialArch | string;
+ type TargetPlatform = OfficialPlatform | string;
+ type ArchOption = TargetArch | 'all';
+ type PlatformOption = TargetPlatform | 'all';
+
+ /**
+ * A predicate function that, given an absolute file `path`, returns `true` if the file should be
+ * ignored, or `false` if the file should be kept. *This does not use any of the default ignored
+ * files/directories listed for the {@link ignore} option.*
+ */
+ type IgnoreFunction = (path: string) => boolean;
+ /**
+ * A function that is called on the completion of a packaging stage.
+ *
+ * By default, the functions are called in parallel (via
+ * [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)).
+ * If you need the functions called serially, there is a utility function provided. Please note that
+ * **callback-style functions are not supported by `serialHooks`.** For example:
+ *
+ * ```javascript
+ * const packager = require('electron-packager')
+ * const { serialHooks } = require('electron-packager/src/hooks')
+ *
+ * packager({
+ * // ...
+ * afterCopy: [serialHooks([
+ * (buildPath, electronVersion, platform, arch) => {
+ * return new Promise((resolve, reject) => {
+ * setTimeout(() => {
+ * console.log('first function')
+ * resolve()
+ * }, 1000)
+ * })
+ * },
+ * (buildPath, electronVersion, platform, arch) => {
+ * console.log('second function')
+ * }
+ * ])],
+ * // ...
+ * })
+ * ```
+ *
+ * For real-world examples of `HookFunction`s, see the [list of related
+ * plugins](https://github.com/electron/electron-packager#plugins).
+ */
+ type HookFunction =
+ /**
+ * @param buildPath - For {@link afterExtract}, the path to the temporary folder where the prebuilt
+ * Electron binary has been extracted to. For {@link afterCopy} and {@link afterPrune}, the path to the
+ * folder where the Electron app has been copied to. For {@link afterComplete}, the final directory
+ * of the packaged application.
+ * @param electronVersion - the version of Electron that is being bundled with the application.
+ * @param platform - The target platform you are packaging for.
+ * @param arch - The target architecture you are packaging for.
+ * @param callback - Must be called once you have completed your actions.
+ */
+ (
+ buildPath: string,
+ electronVersion: string,
+ platform: TargetArch,
+ arch: TargetArch,
+ callback: (err?: Error | null) => void
+ ) => void;
+
+ type TargetDefinition = {
+ arch: TargetArch;
+ platform: TargetPlatform;
+ }
+ type FinalizePackageTargetsHookFunction = (targets: TargetDefinition[], callback: (err?: Error | null) => void) => void;
+
+ /** See the documentation for [`@electron/osx-sign`](https://npm.im/@electron/osx-sign#opts) for details. */
+ type OsxSignOptions = Omit<SignOptions, 'app' | 'binaries' | 'platform' | 'version'>;
+
+ /**
+ * See the documentation for [`@electron/notarize`](https://npm.im/@electron/notarize#method-notarizeopts-promisevoid)
+ * for details.
+ */
+ type OsxNotarizeOptions =
+ | ({ tool?: 'legacy' } & NotarizeLegacyOptions)
+ | ({ tool: 'notarytool' } & NotaryToolCredentials);
+
+ /**
+ * See the documentation for [`@electron/universal`](https://github.com/electron/universal)
+ * for details.
+ */
+ type OsxUniversalOptions = Omit<MakeUniversalOpts, 'x64AppPath' | 'arm64AppPath' | 'outAppPath' | 'force'>
+
+ /**
+ * Defines URL protocol schemes to be used on macOS.
+ */
+ interface MacOSProtocol {
+ /**
+ * The descriptive name. Maps to the `CFBundleURLName` metadata property.
+ */
+ name: string;
+ /**
+ * One or more protocol schemes associated with the app. For example, specifying `myapp`
+ * would cause URLs such as `myapp://path` to be opened with the app. Maps to the
+ * `CFBundleURLSchemes` metadata property.
+ */
+ schemes: string[];
+ }
+
+ /**
+ * A collection of application metadata to embed into the Windows executable.
+ *
+ * For more information, read the [`rcedit` Node module documentation](https://github.com/electron/node-rcedit#docs).
+ */
+ interface Win32MetadataOptions {
+ /** Defaults to the `author` name from the nearest `package.json`. */
+ CompanyName?: string;
+ /** Defaults to either `productName` or `name` from the nearest `package.json`. */
+ FileDescription?: string;
+ /** Defaults to the renamed Electron `.exe` file. */
+ OriginalFilename?: string;
+ /** Defaults to either `productName` or `name` from the nearest `package.json`. */
+ ProductName?: string;
+ /** Defaults to either `productName` or `name` from the nearest `package.json`. */
+ InternalName?: string;
+ /** See [MSDN](https://msdn.microsoft.com/en-us/library/6ad1fshk.aspx#Anchor_9) for details. */
+ 'requested-execution-level'?: 'asInvoker' | 'highestAvailable' | 'requireAdministrator';
+ /**
+ * Path to a local manifest file.
+ *
+ * See [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374191.aspx) for more details.
+ */
+ 'application-manifest'?: string;
+ }
+
+ /** Options passed to the `packager()` function. */
+ interface Options {
+ /** The source directory. */
+ dir: string;
+ /**
+ * Functions to be called after your app directory has been packaged into an .asar file.
+ *
+ * **Note**: `afterAsar` will only be called if the {@link asar} option is set.
+ */
+ afterAsar?: HookFunction[];
+ /** Functions to be called after the packaged application has been moved to the final directory. */
+ afterComplete?: HookFunction[];
+ /**
+ * Functions to be called after your app directory has been copied to a temporary directory.
+ *
+ * **Note**: `afterCopy` will not be called if the {@link prebuiltAsar} option is set.
+ */
+ afterCopy?: HookFunction[];
+ /**
+ * Functions to be called after the files specified in the {@link extraResource} option have been copied.
+ **/
+ afterCopyExtraResources?: HookFunction[];
+ /** Functions to be called after the prebuilt Electron binary has been extracted to a temporary directory. */
+ afterExtract?: HookFunction[];
+ /**
+ * Functions to be called after the final matrix of platform/arch combination is determined. Use this to
+ * learn what archs/platforms packager is targetting when you pass "all" as a value.
+ */
+ afterFinalizePackageTargets?: FinalizePackageTargetsHookFunction[];
+ /**
+ * Functions to be called after Node module pruning has been applied to the application.
+ *
+ * **Note**: None of these functions will be called if the {@link prune} option is `false` or
+ * the {@link prebuiltAsar} option is set.
+ */
+ afterPrune?: HookFunction[];
+
+ /** When `true`, sets both {@link arch} and {@link platform} to `all`. */
+ all?: boolean;
+ /*
+ * The bundle identifier to use in the application's `Info.plist`.
+ *
+ * @category macOS
+ */
+ appBundleId?: string;
+ /**
+ * The application category type, as shown in the Finder via *View → Arrange by Application
+ * Category* when viewing the Applications directory.
+ *
+ * For example, `app-category-type=public.app-category.developer-tools` will set the
+ * application category to *Developer Tools*.
+ *
+ * Valid values are listed in [Apple's documentation](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/TP40009250-SW8).
+ *
+ * @category macOS
+ */
+ appCategoryType?: string;
+ /**
+ * The human-readable copyright line for the app. Maps to the `LegalCopyright` metadata
+ * property on Windows, and `NSHumanReadableCopyright` on macOS.
+ */
+ appCopyright?: string;
+ /**
+ * The release version of the application.
+ *
+ * By default the `version` property in the `package.json` is used, but it can be overridden
+ * with this argument. If neither are provided, the version of Electron will be used. Maps
+ * to the `ProductVersion` metadata property on Windows, and `CFBundleShortVersionString`
+ * on macOS.
+ */
+ appVersion?: string;
+ /**
+ * The target system architecture(s) to build for.
+ *
+ * Not required if the {@link all} option is set. If `arch` is set to `all`, all supported
+ * architectures for the target platforms specified by {@link platform} will be built.
+ * Arbitrary combinations of individual architectures are also supported via a comma-delimited
+ * string or array of strings. The non-`all` values correspond to the architecture names used
+ * by [Electron releases](https://github.com/electron/electron/releases). This value
+ * is not restricted to the official set if [[download|`download.mirrorOptions`]] is set.
+ *
+ * Defaults to the arch of the host computer running Electron Packager.
+ *
+ * Arch values for the official prebuilt Electron binaries:
+ * - `ia32`
+ * - `x64`
+ * - `armv7l`
+ * - `arm64` _(Linux: Electron 1.8.0 and above; Windows: 6.0.8 and above; macOS: 11.0.0-beta.1 and above)_
+ * - `mips64el` _(Electron 1.8.2-beta.5 to 1.8.8)_
+ */
+ arch?: ArchOption | ArchOption[];
+ /**
+ * Whether to package the application's source code into an archive, using [Electron's
+ * archive format](https://github.com/electron/asar). Reasons why you may want to enable
+ * this feature include mitigating issues around long path names on Windows, slightly speeding
+ * up `require`, and concealing your source code from cursory inspection. When the value
+ * is `true`, it passes the default configuration to the `asar` module. The configuration
+ * values can be customized when the value is an `Object`. Supported sub-options include, but
+ * are not limited to:
+ * - `ordering` (*string*): A path to an ordering file for packing files. An explanation can be
+ * found on the [Atom issue tracker](https://github.com/atom/atom/issues/10163).
+ * - `unpack` (*string*): A [glob expression](https://github.com/isaacs/minimatch#features),
+ * when specified, unpacks the file with matching names to the `app.asar.unpacked` directory.
+ * - `unpackDir` (*string*): Unpacks the dir to the `app.asar.unpacked` directory whose names
+ * exactly or pattern match this string. The `asar.unpackDir` is relative to {@link dir}.
+ *
+ * Defaults to `false`.
+ *
+ * Some examples:
+ *
+ * - `asar.unpackDir = 'sub_dir'` will unpack the directory `/<dir>/sub_dir`
+ * - `asar.unpackDir = path.join('**', '{sub_dir1/sub_sub_dir,sub_dir2}', '*')` will unpack the directories `/<dir>/sub_dir1/sub_sub_dir` and `/<dir>/sub_dir2`, but it will not include their subdirectories.
+ * - `asar.unpackDir = path.join('**', '{sub_dir1/sub_sub_dir,sub_dir2}', '**')` will unpack the subdirectories of the directories `/<dir>/sub_dir1/sub_sub_dir` and `/<dir>/sub_dir2`.
+ * - `asar.unpackDir = path.join('**', '{sub_dir1/sub_sub_dir,sub_dir2}', '**', '*')` will unpack the directories `/<dir>/sub_dir1/sub_sub_dir` and `/<dir>/sub_dir2` and their subdirectories.
+ *
+ * **Note:** `asar` will have no effect if the {@link prebuiltAsar} option is set.
+ */
+ asar?: boolean | AsarOptions;
+ /**
+ * Functions to be called before your app directory is packaged into an .asar file.
+ *
+ * **Note**: `beforeAsar` will only be called if the {@link asar} option is set.
+ */
+ beforeAsar?: HookFunction[];
+ /**
+ * Functions to be called before your app directory is copied to a temporary directory.
+ *
+ * **Note**: `beforeCopy` will not be called if the {@link prebuiltAsar} option is set.
+ */
+ beforeCopy?: HookFunction[];
+ /**
+ * Functions to be called before the files specified in the {@link extraResource} option are copied.
+ **/
+ beforeCopyExtraResources?: HookFunction[];
+ /**
+ * The build version of the application. Defaults to the value of the {@link appVersion} option.
+ * Maps to the `FileVersion` metadata property on Windows, and `CFBundleVersion` on macOS.
+ */
+ buildVersion?: string;
+ /**
+ * Forces support for Mojave (macOS 10.14) dark mode in your packaged app. This sets the
+ * `NSRequiresAquaSystemAppearance` key to `false` in your app's `Info.plist`. For more information,
+ * see the [Electron documentation](https://www.electronjs.org/docs/tutorial/mojave-dark-mode-guide)
+ * and the [Apple developer documentation](https://developer.apple.com/documentation/appkit/nsappearancecustomization/choosing_a_specific_appearance_for_your_app).
+ *
+ * @category macOS
+ */
+ darwinDarkModeSupport?: boolean;
+ /**
+ * Whether symlinks should be dereferenced during the copying of the application source.
+ * Defaults to `true`.
+ *
+ * **Note:** `derefSymlinks` will have no effect if the {@link prebuiltAsar} option is set.
+ */
+ derefSymlinks?: boolean;
+ /**
+ * If present, passes custom options to [`@electron/get`](https://npm.im/@electron/get). See
+ * the module for option descriptions, proxy support, and defaults. Supported parameters
+ * include, but are not limited to:
+ * - `cacheRoot` (*string*): The directory where prebuilt, pre-packaged Electron downloads are cached.
+ * - `mirrorOptions` (*Object*): Options to override the default Electron download location.
+ * - `rejectUnauthorized` (*boolean* - default: `true`): Whether SSL certificates are required to be
+ * valid when downloading Electron.
+ *
+ * **Note:** `download` sub-options will have no effect if the {@link electronZipDir} option is set.
+ */
+ download?: ElectronDownloadOptions;
+ /**
+ * The Electron version with which the app is built (without the leading 'v') - for example,
+ * [`1.4.13`](https://github.com/electron/electron/releases/tag/v1.4.13). See [Electron
+ * releases](https://github.com/electron/electron/releases) for valid versions. If omitted, it
+ * will use the version of the nearest local installation of `electron`,
+ * `electron-prebuilt-compile`, or `electron-prebuilt`, defined in `package.json` in either
+ * `devDependencies` or `dependencies`.
+ */
+ electronVersion?: string;
+ /**
+ * The local path to a directory containing Electron ZIP files for Electron Packager to unzip, instead
+ * of downloading them. The ZIP filenames should be in the same format as the ones downloaded from the
+ * [Electron releases](https://github.com/electron/electron/releases) site.
+ *
+ * **Note:** Setting this option prevents the {@link download} sub-options from being used, as
+ * the functionality gets skipped over.
+ */
+ electronZipDir?: string;
+ /**
+ * The name of the executable file, sans file extension. Defaults to the value for the {@link name}
+ * option. For `darwin` or `mas` target platforms, this does not affect the name of the
+ * `.app` folder - this will use the {@link name} option instead.
+ */
+ executableName?: string;
+ /**
+ * When the value is a string, specifies the filename of a `plist` file. Its contents are merged
+ * into the app's `Info.plist`.
+ * When the value is an `Object`, it specifies an already-parsed `plist` data structure that is
+ * merged into the app's `Info.plist`.
+ *
+ * Entries from `extendInfo` override entries in the base `Info.plist` file supplied by
+ * `electron`, `electron-prebuilt-compile`, or `electron-prebuilt`, but are overridden by other
+ * options such as {@link appVersion} or {@link appBundleId}.
+ *
+ * @category macOS
+ */
+ extendInfo?: string | { [property: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any
+ /**
+ * When the value is a string, specifies the filename of a `plist` file. Its contents are merged
+ * into all the Helper apps' `Info.plist` files.
+ * When the value is an `Object`, it specifies an already-parsed `plist` data structure that is
+ * merged into all the Helper apps' `Info.plist` files.
+ *
+ * Entries from `extendHelperInfo` override entries in the helper apps' `Info.plist` file supplied by
+ * `electron`, `electron-prebuilt-compile`, or `electron-prebuilt`, but are overridden by other
+ * options such as {@link appVersion} or {@link appBundleId}.
+ *
+ * @category macOS
+ */
+ extendHelperInfo?: string | { [property: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any
+ /**
+ * One or more files to be copied directly into the app's `Contents/Resources` directory for
+ * macOS target platforms, and the `resources` directory for other target platforms. The
+ * resources directory can be referenced in the packaged app via the
+ * [`process.resourcesPath`](https://www.electronjs.org/docs/api/process#processresourcespath-readonly) value.
+ */
+ extraResource?: string | string[];
+ /**
+ * The bundle identifier to use in the application helper's `Info.plist`.
+ *
+ * @category macOS
+ */
+ helperBundleId?: string;
+ /**
+ * The local path to the icon file, if the target platform supports setting embedding an icon.
+ *
+ * Currently you must look for conversion tools in order to supply an icon in the format required by the platform:
+ *
+ * - macOS: `.icns`
+ * - Windows: `.ico` ([See the readme](https://github.com/electron/electron-packager#building-windows-apps-from-non-windows-platforms) for details on non-Windows platforms)
+ * - Linux: this option is not supported, as the dock/window list icon is set via
+ * [the `icon` option in the `BrowserWindow` constructor](https://electronjs.org/docs/api/browser-window/#new-browserwindowoptions).
+ * *Please note that you need to use a PNG, and not the macOS or Windows icon formats, in order for it
+ * to show up in the dock/window list.* Setting the icon in the file manager is not currently supported.
+ *
+ * If the file extension is omitted, it is auto-completed to the correct extension based on the
+ * platform, including when [[platform|`platform: 'all'`]] is in effect.
+ */
+ icon?: string;
+ /**
+ * One or more additional [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
+ * patterns which specify which files to ignore when copying files to create the app bundle(s). The
+ * regular expressions are matched against the absolute path of a given file/directory to be copied.
+ *
+ * **Please note that [glob patterns](https://en.wikipedia.org/wiki/Glob_%28programming%29) will not work.**
+ *
+ * The following paths are always ignored (*when you aren't using an {@link IgnoreFunction}*):
+ *
+ * - the directory specified by the {@link out} option
+ * - the temporary directory used to build the Electron app
+ * - `node_modules/.bin`
+ * - `node_modules/electron`
+ * - `node_modules/electron-prebuilt`
+ * - `node_modules/electron-prebuilt-compile`
+ * - `.git`
+ * - files and folders ending in `.o` and `.obj`
+ *
+ * **Note**: Node modules specified in `devDependencies` are ignored by default, via the
+ * {@link prune} option.
+ *
+ * **Note:** `ignore` will have no effect if the {@link prebuiltAsar} option is set.
+ */
+ ignore?: RegExp | RegExp[] | IgnoreFunction;
+ /**
+ * Ignores [system junk files](https://github.com/sindresorhus/junk) when copying the Electron app,
+ * regardless of the {@link ignore} option.
+ *
+ * **Note:** `junk` will have no effect if the {@link prebuiltAsar} option is set.
+ */
+ junk?: boolean;
+ /**
+ * The application name. If omitted, it will use the `productName` or `name` value from the
+ * nearest `package.json`.
+ *
+ * **Regardless of source, characters in the Electron app name which are not allowed in all target
+ * platforms' filenames (e.g., `/`), will be replaced by hyphens (`-`).**
+ */
+ name?: string;
+ /**
+ * If present, notarizes macOS target apps when the host platform is macOS and Xcode is installed.
+ * See [`@electron/notarize`](https://github.com/electron/notarize#method-notarizeopts-promisevoid)
+ * for option descriptions, such as how to use `appleIdPassword` safely or obtain an API key.
+ *
+ * **Requires the {@link osxSign} option to be set.**
+ *
+ * @category macOS
+ */
+ osxNotarize?: OsxNotarizeOptions;
+ /**
+ * If present, signs macOS target apps when the host platform is macOS and Xcode is installed.
+ * When the value is `true`, pass default configuration to the signing module. See
+ * [@electron/osx-sign](https://npm.im/@electron/osx-sign#opts---options) for sub-option descriptions and
+ * their defaults. Options include, but are not limited to:
+ * - `identity` (*string*): The identity used when signing the package via `codesign`.
+ * - `binaries` (*array<string>*): Path to additional binaries that will be signed along with built-ins of Electron/
+ *
+ * @category macOS
+ */
+ osxSign?: true | OsxSignOptions;
+ /**
+ * Used to provide custom options to the internal call to `@electron/universal` when building a macOS
+ * app with the target architecture of "universal". Unused otherwise, providing a value does not imply
+ * a universal app is built.
+ */
+ osxUniversal?: OsxUniversalOptions;
+ /**
+ * The base directory where the finished package(s) are created.
+ *
+ * Defaults to the current working directory.
+ */
+ out?: string;
+ /**
+ * Whether to replace an already existing output directory for a given platform (`true`) or
+ * skip recreating it (`false`). Defaults to `false`.
+ */
+ overwrite?: boolean;
+ /**
+ * The target platform(s) to build for.
+ *
+ * Not required if the {@link all} option is set. If `platform` is set to `all`, all officially
+ * supported target platforms for the target architectures specified by the {@link arch} option
+ * will be built. Arbitrary combinations of individual platforms are also supported via a
+ * comma-delimited string or array of strings.
+ *
+ * The official non-`all` values correspond to the platform names used by [Electron
+ * releases](https://github.com/electron/electron/releases). This value is not restricted to
+ * the official set if [[download|`download.mirrorOptions]] is set.
+ *
+ * Defaults to the platform of the host computer running Electron Packager.
+ *
+ * Platform values for the official prebuilt Electron binaries:
+ * - `darwin` (macOS)
+ * - `linux`
+ * - `mas` (macOS, specifically for submitting to the Mac App Store)
+ * - `win32`
+ */
+ platform?: PlatformOption | PlatformOption[];
+ /**
+ * The path to a prebuilt ASAR file.
+ *
+ * **Note:** Setting this option prevents the following options from being used, as the functionality
+ * gets skipped over:
+ *
+ * - {@link asar}
+ * - {@link afterCopy}
+ * - {@link afterPrune}
+ * - {@link derefSymlinks}
+ * - {@link ignore}
+ * - {@link junk}
+ * - {@link prune}
+ */
+ prebuiltAsar?: string;
+ /**
+ * The URL protocol schemes associated with the Electron app.
+ *
+ * @category macOS
+ */
+ protocols?: MacOSProtocol[];
+ /**
+ * Walks the `node_modules` dependency tree to remove all of the packages specified in the
+ * `devDependencies` section of `package.json` from the outputted Electron app.
+ *
+ * Defaults to `true`.
+ *
+ * **Note:** `prune` will have no effect if the {@link prebuiltAsar} option is set.
+ */
+ prune?: boolean;
+ /**
+ * If `true`, disables printing informational and warning messages to the console when
+ * packaging the application. This does not disable errors.
+ *
+ * Defaults to `false`.
+ */
+ quiet?: boolean;
+ /**
+ * The base directory to use as a temporary directory. Set to `false` to disable use of a
+ * temporary directory. Defaults to the system's temporary directory.
+ */
+ tmpdir?: string | false;
+ /**
+ * Human-readable descriptions of how the Electron app uses certain macOS features. These are displayed
+ * in the App Store. A non-exhaustive list of available properties:
+ *
+ * * `Camera` - required for media access API usage in macOS Catalina
+ * * `Microphone` - required for media access API usage in macOS Catalina
+ *
+ * Valid properties are the [Cocoa keys for MacOS](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html)
+ * of the pattern `NS(.*)UsageDescription`, where the captured group is the key to use.
+ *
+ * Example:
+ *
+ * ```javascript
+ * {
+ * usageDescription: {
+ * Camera: 'Needed for video calls',
+ * Microphone: 'Needed for voice calls'
+ * }
+ * }
+ * ```
+ *
+ * @category macOS
+ */
+ usageDescription?: { [property: string]: string };
+ /**
+ * Application metadata to embed into the Windows executable.
+ * @category Windows
+ */
+ win32metadata?: Win32MetadataOptions;
+ }
+}
+
+export = electronPackager;
diff --git a/desktop/node_modules/electron-packager/src/index.js b/desktop/node_modules/electron-packager/src/index.js
new file mode 100644
index 0000000..d64afd4
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/index.js
@@ -0,0 +1,207 @@
+'use strict'
+
+const common = require('./common')
+const copyFilter = require('./copy-filter')
+const debug = require('debug')('electron-packager')
+const download = require('./download')
+const fs = require('fs-extra')
+const getMetadataFromPackageJSON = require('./infer')
+const hooks = require('./hooks')
+const path = require('path')
+const targets = require('./targets')
+const unzip = require('./unzip')
+const { packageUniversalMac } = require('./universal')
+
+function debugHostInfo () {
+ debug(common.hostInfo())
+}
+
+class Packager {
+ constructor (opts) {
+ this.opts = opts
+ this.tempBase = common.baseTempDir(opts)
+ this.useTempDir = opts.tmpdir !== false
+ this.canCreateSymlinks = undefined
+ }
+
+ async ensureTempDir () {
+ if (this.useTempDir) {
+ await fs.remove(this.tempBase)
+ } else {
+ return Promise.resolve()
+ }
+ }
+
+ async testSymlink (comboOpts, zipPath) {
+ await fs.mkdirp(this.tempBase)
+ const testPath = await fs.mkdtemp(path.join(this.tempBase, `symlink-test-${comboOpts.platform}-${comboOpts.arch}-`))
+ const testFile = path.join(testPath, 'test')
+ const testLink = path.join(testPath, 'testlink')
+
+ try {
+ await fs.outputFile(testFile, '')
+ await fs.symlink(testFile, testLink)
+ this.canCreateSymlinks = true
+ } catch (e) {
+ /* istanbul ignore next */
+ this.canCreateSymlinks = false
+ } finally {
+ await fs.remove(testPath)
+ }
+
+ if (this.canCreateSymlinks) {
+ return this.checkOverwrite(comboOpts, zipPath)
+ }
+
+ /* istanbul ignore next */
+ return this.skipHostPlatformSansSymlinkSupport(comboOpts)
+ }
+
+ /* istanbul ignore next */
+ skipHostPlatformSansSymlinkSupport (comboOpts) {
+ common.info(`Cannot create symlinks (on Windows hosts, it requires admin privileges); skipping ${comboOpts.platform} platform`, this.opts.quiet)
+ return Promise.resolve()
+ }
+
+ async overwriteAndCreateApp (outDir, comboOpts, zipPath) {
+ debug(`Removing ${outDir} due to setting overwrite: true`)
+ await fs.remove(outDir)
+ return this.createApp(comboOpts, zipPath)
+ }
+
+ async extractElectronZip (comboOpts, zipPath, buildDir) {
+ debug(`Extracting ${zipPath} to ${buildDir}`)
+ await unzip(zipPath, buildDir)
+ await hooks.promisifyHooks(this.opts.afterExtract, [buildDir, comboOpts.electronVersion, comboOpts.platform, comboOpts.arch])
+ }
+
+ async buildDir (platform, arch) {
+ let buildParentDir
+ if (this.useTempDir) {
+ buildParentDir = this.tempBase
+ } else {
+ buildParentDir = this.opts.out || process.cwd()
+ }
+ await fs.mkdirp(buildParentDir)
+ return await fs.mkdtemp(path.resolve(buildParentDir, `${platform}-${arch}-template-`))
+ }
+
+ async createApp (comboOpts, zipPath) {
+ const buildDir = await this.buildDir(comboOpts.platform, comboOpts.arch)
+ common.info(`Packaging app for platform ${comboOpts.platform} ${comboOpts.arch} using electron v${comboOpts.electronVersion}`, this.opts.quiet)
+
+ debug(`Creating ${buildDir}`)
+ await fs.ensureDir(buildDir)
+ await this.extractElectronZip(comboOpts, zipPath, buildDir)
+ const os = require(targets.osModules[comboOpts.platform])
+ const app = new os.App(comboOpts, buildDir)
+ return app.create()
+ }
+
+ async checkOverwrite (comboOpts, zipPath) {
+ const finalPath = common.generateFinalPath(comboOpts)
+ if (await fs.pathExists(finalPath)) {
+ if (this.opts.overwrite) {
+ return this.overwriteAndCreateApp(finalPath, comboOpts, zipPath)
+ } else {
+ common.info(`Skipping ${comboOpts.platform} ${comboOpts.arch} (output dir already exists, use --overwrite to force)`, this.opts.quiet)
+ return true
+ }
+ } else {
+ return this.createApp(comboOpts, zipPath)
+ }
+ }
+
+ async getElectronZipPath (downloadOpts) {
+ if (this.opts.electronZipDir) {
+ if (await fs.pathExists(this.opts.electronZipDir)) {
+ const zipPath = path.resolve(
+ this.opts.electronZipDir,
+ `electron-v${downloadOpts.version}-${downloadOpts.platform}-${downloadOpts.arch}.zip`
+ )
+ if (!await fs.pathExists(zipPath)) {
+ throw new Error(`The specified Electron ZIP file does not exist: ${zipPath}`)
+ }
+
+ return zipPath
+ }
+
+ throw new Error(`The specified Electron ZIP directory does not exist: ${this.opts.electronZipDir}`)
+ } else {
+ return download.downloadElectronZip(downloadOpts)
+ }
+ }
+
+ async packageForPlatformAndArchWithOpts (comboOpts, downloadOpts) {
+ const zipPath = await this.getElectronZipPath(downloadOpts)
+
+ if (!this.useTempDir) {
+ return this.createApp(comboOpts, zipPath)
+ }
+
+ if (common.isPlatformMac(comboOpts.platform)) {
+ /* istanbul ignore else */
+ if (this.canCreateSymlinks === undefined) {
+ return this.testSymlink(comboOpts, zipPath)
+ } else if (!this.canCreateSymlinks) {
+ return this.skipHostPlatformSansSymlinkSupport(comboOpts)
+ }
+ }
+
+ return this.checkOverwrite(comboOpts, zipPath)
+ }
+
+ async packageForPlatformAndArch (downloadOpts) {
+ // Create delegated options object with specific platform and arch, for output directory naming
+ const comboOpts = {
+ ...this.opts,
+ arch: downloadOpts.arch,
+ platform: downloadOpts.platform,
+ electronVersion: downloadOpts.version
+ }
+
+ if (common.isPlatformMac(comboOpts.platform) && comboOpts.arch === 'universal') {
+ return packageUniversalMac(this.packageForPlatformAndArchWithOpts.bind(this), await this.buildDir(comboOpts.platform, comboOpts.arch), comboOpts, downloadOpts, this.tempBase)
+ }
+
+ return this.packageForPlatformAndArchWithOpts(comboOpts, downloadOpts)
+ }
+}
+
+async function packageAllSpecifiedCombos (opts, archs, platforms) {
+ const packager = new Packager(opts)
+ await packager.ensureTempDir()
+ return Promise.all(download.createDownloadCombos(opts, platforms, archs).map(
+ downloadOpts => packager.packageForPlatformAndArch(downloadOpts)
+ ))
+}
+
+module.exports = async function packager (opts) {
+ debugHostInfo()
+ if (debug.enabled) debug(`Packager Options: ${JSON.stringify(opts)}`)
+
+ const archs = targets.validateListFromOptions(opts, 'arch')
+ const platforms = targets.validateListFromOptions(opts, 'platform')
+ if (!Array.isArray(archs)) return Promise.reject(archs)
+ if (!Array.isArray(platforms)) return Promise.reject(platforms)
+
+ debug(`Target Platforms: ${platforms.join(', ')}`)
+ debug(`Target Architectures: ${archs.join(', ')}`)
+
+ const packageJSONDir = path.resolve(process.cwd(), opts.dir) || process.cwd()
+
+ await getMetadataFromPackageJSON(platforms, opts, packageJSONDir)
+ if (opts.name.endsWith(' Helper')) {
+ throw new Error('Application names cannot end in " Helper" due to limitations on macOS')
+ }
+
+ debug(`Application name: ${opts.name}`)
+ debug(`Target Electron version: ${opts.electronVersion}`)
+
+ copyFilter.populateIgnoredPaths(opts)
+
+ await hooks.promisifyHooks(opts.afterFinalizePackageTargets, [targets.createPlatformArchPairs(opts, platforms, archs).map(([platform, arch]) => ({ platform, arch }))])
+ const appPaths = await packageAllSpecifiedCombos(opts, archs, platforms)
+ // Remove falsy entries (e.g. skipped platforms)
+ return appPaths.filter(appPath => appPath)
+}
diff --git a/desktop/node_modules/electron-packager/src/infer.js b/desktop/node_modules/electron-packager/src/infer.js
new file mode 100644
index 0000000..9dde6d7
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/infer.js
@@ -0,0 +1,178 @@
+'use strict'
+
+const debug = require('debug')('electron-packager')
+const getPackageInfo = require('get-package-info')
+const parseAuthor = require('parse-author')
+const path = require('path')
+const resolve = require('resolve')
+const semver = require('semver')
+
+function isMissingRequiredProperty (props) {
+ return props.some(prop => prop === 'productName' || prop === 'dependencies.electron')
+}
+
+function errorMessageForProperty (prop) {
+ let hash, propDescription
+ switch (prop) {
+ case 'productName':
+ hash = 'name'
+ propDescription = 'application name'
+ break
+ case 'dependencies.electron':
+ hash = 'electronversion'
+ propDescription = 'Electron version'
+ break
+ case 'version':
+ hash = 'appversion'
+ propDescription = 'application version'
+ break
+ /* istanbul ignore next */
+ default:
+ hash = ''
+ propDescription = `[Unknown Property (${prop})]`
+ }
+
+ return `Unable to determine ${propDescription}. Please specify an ${propDescription}\n\n` +
+ 'For more information, please see\n' +
+ `https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html#${hash}\n`
+}
+
+function resolvePromise (id, options) {
+ // eslint-disable-next-line promise/param-names
+ return new Promise((accept, reject) => {
+ resolve(id, options, (err, mainPath, pkg) => {
+ if (err) {
+ /* istanbul ignore next */
+ reject(err)
+ } else {
+ accept([mainPath, pkg])
+ }
+ })
+ })
+}
+
+function rangeFromElectronVersion (electronVersion) {
+ try {
+ return new semver.Range(electronVersion)
+ } catch (error) {
+ return null
+ }
+}
+
+async function getVersion (opts, electronProp) {
+ const [depType, packageName] = electronProp.prop.split('.')
+ const src = electronProp.src
+ if (packageName === 'electron-prebuilt-compile') {
+ const electronVersion = electronProp.pkg[depType][packageName]
+ const versionRange = rangeFromElectronVersion(electronVersion)
+ if (versionRange !== null && versionRange.intersects(new semver.Range('< 1.6.5'))) {
+ if (!/^\d+\.\d+\.\d+/.test(electronVersion)) {
+ // electron-prebuilt-compile cannot be resolved because `main` does not point
+ // to a valid JS file.
+ throw new Error('Using electron-prebuilt-compile with Electron Packager requires specifying an exact Electron version')
+ }
+
+ opts.electronVersion = electronVersion
+ return Promise.resolve()
+ }
+ }
+
+ const pkg = (await resolvePromise(packageName, { basedir: path.dirname(src) }))[1]
+ debug(`Inferring target Electron version from ${packageName} in ${src}`)
+ opts.electronVersion = pkg.version
+ return null
+}
+
+async function handleMetadata (opts, result) {
+ if (result.values.productName) {
+ debug(`Inferring application name from ${result.source.productName.prop} in ${result.source.productName.src}`)
+ opts.name = result.values.productName
+ }
+
+ if (result.values.version) {
+ debug(`Inferring appVersion from version in ${result.source.version.src}`)
+ opts.appVersion = result.values.version
+ }
+
+ if (result.values.author && !opts.win32metadata) {
+ opts.win32metadata = {}
+ }
+
+ if (result.values.author) {
+ debug(`Inferring win32metadata.CompanyName from author in ${result.source.author.src}`)
+ if (typeof result.values.author === 'string') {
+ opts.win32metadata.CompanyName = parseAuthor(result.values.author).name
+ } else if (result.values.author.name) {
+ opts.win32metadata.CompanyName = result.values.author.name
+ } else {
+ debug('Cannot infer win32metadata.CompanyName from author, no name found')
+ }
+ }
+
+ // eslint-disable-next-line no-prototype-builtins
+ if (result.values.hasOwnProperty('dependencies.electron')) {
+ return getVersion(opts, result.source['dependencies.electron'])
+ } else {
+ return Promise.resolve()
+ }
+}
+
+function handleMissingProperties (opts, err) {
+ const missingProps = err.missingProps.map(prop => {
+ return Array.isArray(prop) ? prop[0] : prop
+ })
+
+ if (isMissingRequiredProperty(missingProps)) {
+ const messages = missingProps.map(errorMessageForProperty)
+
+ debug(err.message)
+ err.message = messages.join('\n') + '\n'
+ throw err
+ } else {
+ // Missing props not required, can continue w/ partial result
+ return handleMetadata(opts, err.result)
+ }
+}
+
+module.exports = async function getMetadataFromPackageJSON (platforms, opts, dir) {
+ const props = []
+ if (!opts.name) props.push(['productName', 'name'])
+ if (!opts.appVersion) props.push('version')
+ if (!opts.electronVersion) {
+ props.push([
+ 'dependencies.electron',
+ 'devDependencies.electron',
+ 'dependencies.electron-nightly',
+ 'devDependencies.electron-nightly',
+ 'dependencies.electron-prebuilt-compile',
+ 'devDependencies.electron-prebuilt-compile',
+ 'dependencies.electron-prebuilt',
+ 'devDependencies.electron-prebuilt'
+ ])
+ }
+
+ if (platforms.includes('win32') && !(opts.win32metadata && opts.win32metadata.CompanyName)) {
+ debug('Requiring author in package.json, as CompanyName was not specified for win32metadata')
+ props.push('author')
+ }
+
+ // Name and version provided, no need to infer
+ if (props.length === 0) return Promise.resolve()
+
+ // Search package.json files to infer name and version from
+ try {
+ const result = await getPackageInfo(props, dir)
+ return handleMetadata(opts, result)
+ } catch (err) {
+ if (err.missingProps) {
+ if (err.missingProps.length === props.length) {
+ debug(err.message)
+ err.message = `Could not locate a package.json file in "${path.resolve(opts.dir)}" or its parent directories for an Electron app with the following fields: ${err.missingProps.join(', ')}`
+ } else {
+ return handleMissingProperties(opts, err)
+ }
+ }
+
+ throw err
+ }
+}
diff --git a/desktop/node_modules/electron-packager/src/linux.js b/desktop/node_modules/electron-packager/src/linux.js
new file mode 100644
index 0000000..1e98414
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/linux.js
@@ -0,0 +1,25 @@
+'use strict'
+
+const App = require('./platform')
+const common = require('./common')
+
+class LinuxApp extends App {
+ get originalElectronName () {
+ return 'electron'
+ }
+
+ get newElectronName () {
+ return common.sanitizeAppName(this.executableName)
+ }
+
+ async create () {
+ await this.initialize()
+ await this.renameElectron()
+ await this.copyExtraResources()
+ return this.move()
+ }
+}
+
+module.exports = {
+ App: LinuxApp
+}
diff --git a/desktop/node_modules/electron-packager/src/mac.js b/desktop/node_modules/electron-packager/src/mac.js
new file mode 100644
index 0000000..6eaf524
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/mac.js
@@ -0,0 +1,440 @@
+'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 { signApp } = 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
+ })
+ } else {
+ delete this.appPlist.ElectronAsarIntegrity
+ }
+ 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.', this.opts.quiet)
+ }
+
+ if (osxSignOpt) {
+ const signOpts = createSignOpts(osxSignOpt, platform, this.renamedAppPath, version, this.opts.quiet)
+ debug(`Running @electron/osx-sign with the options ${JSON.stringify(signOpts)}`)
+ try {
+ await signApp(signOpts)
+ } catch (err) {
+ // Although not signed successfully, the application is packed.
+ common.warning(`Code sign failed; please retry manually. ${err}`, this.opts.quiet)
+ }
+ }
+ }
+
+ 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, 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.', quiet)
+ 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
+ }
+
+ 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
+}
diff --git a/desktop/node_modules/electron-packager/src/platform.js b/desktop/node_modules/electron-packager/src/platform.js
new file mode 100644
index 0000000..18df14f
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/platform.js
@@ -0,0 +1,277 @@
+'use strict'
+
+const asar = require('@electron/asar')
+const crypto = require('crypto')
+const debug = require('debug')('electron-packager')
+const fs = require('fs-extra')
+const path = require('path')
+
+const common = require('./common')
+const copyFilter = require('./copy-filter')
+const hooks = require('./hooks')
+
+class App {
+ constructor (opts, templatePath) {
+ this.opts = opts
+ this.templatePath = templatePath
+ this.asarOptions = common.createAsarOpts(opts)
+
+ if (this.opts.prune === undefined) {
+ this.opts.prune = true
+ }
+ }
+
+ /**
+ * Resource directory path before renaming.
+ */
+ get originalResourcesDir () {
+ return this.resourcesDir
+ }
+
+ /**
+ * Resource directory path after renaming.
+ */
+ get resourcesDir () {
+ return path.join(this.stagingPath, 'resources')
+ }
+
+ get originalResourcesAppDir () {
+ return path.join(this.originalResourcesDir, 'app')
+ }
+
+ get electronBinaryDir () {
+ return this.stagingPath
+ }
+
+ get originalElectronName () {
+ /* istanbul ignore next */
+ throw new Error('Child classes must implement this')
+ }
+
+ get newElectronName () {
+ /* istanbul ignore next */
+ throw new Error('Child classes must implement this')
+ }
+
+ get executableName () {
+ return this.opts.executableName || this.opts.name
+ }
+
+ get stagingPath () {
+ if (this.opts.tmpdir === false) {
+ return common.generateFinalPath(this.opts)
+ } else {
+ if (!this.cachedStagingPath) {
+ const parentDir = path.join(
+ common.baseTempDir(this.opts),
+ `${this.opts.platform}-${this.opts.arch}`
+ )
+ fs.mkdirpSync(parentDir)
+ this.cachedStagingPath = fs.mkdtempSync(path.join(parentDir, `${common.generateFinalBasename(this.opts)}-`))
+ }
+ return this.cachedStagingPath
+ }
+ }
+
+ get appAsarPath () {
+ return path.join(this.originalResourcesDir, 'app.asar')
+ }
+
+ get commonHookArgs () {
+ return [
+ this.opts.electronVersion,
+ this.opts.platform,
+ this.opts.arch
+ ]
+ }
+
+ get hookArgsWithOriginalResourcesAppDir () {
+ return [
+ this.originalResourcesAppDir,
+ ...this.commonHookArgs
+ ]
+ }
+
+ async relativeRename (basePath, oldName, newName) {
+ debug(`Renaming ${oldName} to ${newName} in ${basePath}`)
+ await fs.rename(path.join(basePath, oldName), path.join(basePath, newName))
+ }
+
+ async renameElectron () {
+ return this.relativeRename(this.electronBinaryDir, this.originalElectronName, this.newElectronName)
+ }
+
+ /**
+ * Performs the following initial operations for an app:
+ * * Creates temporary directory
+ * * Remove default_app (which is either a folder or an asar file)
+ * * If a prebuilt asar is specified:
+ * * Copies asar into temporary directory as app.asar
+ * * Otherwise:
+ * * Copies template into temporary directory
+ * * Copies user's app into temporary directory
+ * * Prunes non-production node_modules (if opts.prune is either truthy or undefined)
+ * * Creates an asar (if opts.asar is set)
+ *
+ * Prune and asar are performed before platform-specific logic, primarily so that
+ * this.originalResourcesAppDir is predictable (e.g. before .app is renamed for Mac)
+ */
+ async initialize () {
+ debug(`Initializing app in ${this.stagingPath} from ${this.templatePath} template`)
+
+ await fs.move(this.templatePath, this.stagingPath, { clobber: true })
+ await this.removeDefaultApp()
+ if (this.opts.prebuiltAsar) {
+ await this.copyPrebuiltAsar()
+ } else {
+ await this.buildApp()
+ }
+
+ await hooks.promisifyHooks(this.opts.afterInitialize, this.hookArgsWithOriginalResourcesAppDir)
+ }
+
+ async buildApp () {
+ await this.copyTemplate()
+ await common.validateElectronApp(this.opts.dir, this.originalResourcesAppDir)
+ await this.asarApp()
+ }
+
+ async copyTemplate () {
+ await hooks.promisifyHooks(this.opts.beforeCopy, this.hookArgsWithOriginalResourcesAppDir)
+
+ await fs.copy(this.opts.dir, this.originalResourcesAppDir, {
+ filter: copyFilter.userPathFilter(this.opts),
+ dereference: this.opts.derefSymlinks
+ })
+ await hooks.promisifyHooks(this.opts.afterCopy, this.hookArgsWithOriginalResourcesAppDir)
+ if (this.opts.prune) {
+ await hooks.promisifyHooks(this.opts.afterPrune, this.hookArgsWithOriginalResourcesAppDir)
+ }
+ }
+
+ async removeDefaultApp () {
+ await Promise.all(['default_app', 'default_app.asar'].map(async basename => fs.remove(path.join(this.originalResourcesDir, basename))))
+ }
+
+ /**
+ * Forces an icon filename to a given extension and returns the normalized filename,
+ * if it exists. Otherwise, returns null.
+ *
+ * This error path is used by win32 if no icon is specified.
+ */
+ async normalizeIconExtension (targetExt) {
+ if (!this.opts.icon) throw new Error('No filename specified to normalizeIconExtension')
+
+ let iconFilename = this.opts.icon
+ const ext = path.extname(iconFilename)
+ if (ext !== targetExt) {
+ iconFilename = path.join(path.dirname(iconFilename), path.basename(iconFilename, ext) + targetExt)
+ }
+
+ if (await fs.pathExists(iconFilename)) {
+ return iconFilename
+ } else {
+ /* istanbul ignore next */
+ common.warning(`Could not find icon "${iconFilename}", not updating app icon`, this.opts.quiet)
+ }
+ }
+
+ prebuiltAsarWarning (option, triggerWarning) {
+ if (triggerWarning) {
+ common.warning(`prebuiltAsar and ${option} are incompatible, ignoring the ${option} option`, this.opts.quiet)
+ }
+ }
+
+ async copyPrebuiltAsar () {
+ if (this.asarOptions) {
+ common.warning('prebuiltAsar has been specified, all asar options will be ignored', this.opts.quiet)
+ }
+
+ for (const hookName of ['beforeCopy', 'afterCopy', 'afterPrune']) {
+ if (this.opts[hookName]) {
+ throw new Error(`${hookName} is incompatible with prebuiltAsar`)
+ }
+ }
+
+ this.prebuiltAsarWarning('ignore', this.opts.originalIgnore)
+ this.prebuiltAsarWarning('prune', !this.opts.prune)
+ this.prebuiltAsarWarning('derefSymlinks', this.opts.derefSymlinks !== undefined)
+
+ const src = path.resolve(this.opts.prebuiltAsar)
+
+ const stat = await fs.stat(src)
+ if (!stat.isFile()) {
+ throw new Error(`${src} specified in prebuiltAsar must be an asar file.`)
+ }
+
+ debug(`Copying asar: ${src} to ${this.appAsarPath}`)
+ await fs.copy(src, this.appAsarPath, { overwrite: false, errorOnExist: true })
+ }
+
+ appRelativePath (p) {
+ return path.relative(this.stagingPath, p)
+ }
+
+ async asarApp () {
+ if (!this.asarOptions) {
+ return Promise.resolve()
+ }
+
+ debug(`Running asar with the options ${JSON.stringify(this.asarOptions)}`)
+
+ await hooks.promisifyHooks(this.opts.beforeAsar, this.hookArgsWithOriginalResourcesAppDir)
+
+ await asar.createPackageWithOptions(this.originalResourcesAppDir, this.appAsarPath, this.asarOptions)
+ const { headerString } = asar.getRawHeader(this.appAsarPath)
+ this.asarIntegrity = {
+ [this.appRelativePath(this.appAsarPath)]: {
+ algorithm: 'SHA256',
+ hash: crypto.createHash('SHA256').update(headerString).digest('hex')
+ }
+ }
+ await fs.remove(this.originalResourcesAppDir)
+
+ await hooks.promisifyHooks(this.opts.afterAsar, this.hookArgsWithOriginalResourcesAppDir)
+ }
+
+ async copyExtraResources () {
+ if (!this.opts.extraResource) return Promise.resolve()
+
+ const extraResources = common.ensureArray(this.opts.extraResource)
+
+ const hookArgs = [
+ this.stagingPath,
+ ...this.commonHookArgs
+ ]
+
+ await hooks.promisifyHooks(this.opts.beforeCopyExtraResources, hookArgs)
+
+ await Promise.all(extraResources.map(
+ resource => fs.copy(resource, path.resolve(this.stagingPath, this.resourcesDir, path.basename(resource)))
+ ))
+
+ await hooks.promisifyHooks(this.opts.afterCopyExtraResources, hookArgs)
+ }
+
+ async move () {
+ const finalPath = common.generateFinalPath(this.opts)
+
+ if (this.opts.tmpdir !== false) {
+ debug(`Moving ${this.stagingPath} to ${finalPath}`)
+ await fs.move(this.stagingPath, finalPath)
+ }
+
+ if (this.opts.afterComplete) {
+ const hookArgs = [
+ finalPath,
+ ...this.commonHookArgs
+ ]
+
+ await hooks.promisifyHooks(this.opts.afterComplete, hookArgs)
+ }
+
+ return finalPath
+ }
+}
+
+module.exports = App
diff --git a/desktop/node_modules/electron-packager/src/prune.js b/desktop/node_modules/electron-packager/src/prune.js
new file mode 100644
index 0000000..a94f49a
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/prune.js
@@ -0,0 +1,70 @@
+'use strict'
+
+const common = require('./common')
+const galactus = require('galactus')
+const fs = require('fs-extra')
+const path = require('path')
+
+const ELECTRON_MODULES = [
+ 'electron',
+ 'electron-nightly',
+ 'electron-prebuilt',
+ 'electron-prebuilt-compile'
+]
+
+class Pruner {
+ constructor (dir, quiet) {
+ this.baseDir = common.normalizePath(dir)
+ this.quiet = quiet
+ this.galactus = new galactus.DestroyerOfModules({
+ rootDirectory: dir,
+ shouldKeepModuleTest: (module, isDevDep) => this.shouldKeepModule(module, isDevDep)
+ })
+ this.walkedTree = false
+ }
+
+ setModules (moduleMap) {
+ const modulePaths = Array.from(moduleMap.keys()).map(modulePath => `/${common.normalizePath(modulePath)}`)
+ this.modules = new Set(modulePaths)
+ this.walkedTree = true
+ }
+
+ async pruneModule (name) {
+ if (this.walkedTree) {
+ return this.isProductionModule(name)
+ } else {
+ const moduleMap = await this.galactus.collectKeptModules({ relativePaths: true })
+ this.setModules(moduleMap)
+ return this.isProductionModule(name)
+ }
+ }
+
+ shouldKeepModule (module, isDevDep) {
+ if (isDevDep || module.depType === galactus.DepType.ROOT) {
+ return false
+ }
+
+ if (ELECTRON_MODULES.includes(module.name)) {
+ common.warning(`Found '${module.name}' but not as a devDependency, pruning anyway`, this.quiet)
+ return false
+ }
+
+ return true
+ }
+
+ isProductionModule (name) {
+ return this.modules.has(name)
+ }
+}
+
+function isNodeModuleFolder (pathToCheck) {
+ return path.basename(path.dirname(pathToCheck)) === 'node_modules' ||
+ (path.basename(path.dirname(pathToCheck)).startsWith('@') && path.basename(path.resolve(pathToCheck, `..${path.sep}..`)) === 'node_modules')
+}
+
+module.exports = {
+ isModule: async function isModule (pathToCheck) {
+ return (await fs.pathExists(path.join(pathToCheck, 'package.json'))) && isNodeModuleFolder(pathToCheck)
+ },
+ Pruner: Pruner
+}
diff --git a/desktop/node_modules/electron-packager/src/targets.js b/desktop/node_modules/electron-packager/src/targets.js
new file mode 100644
index 0000000..aba6cc0
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/targets.js
@@ -0,0 +1,149 @@
+'use strict'
+
+const common = require('./common')
+const { getHostArch } = require('@electron/get')
+const semver = require('semver')
+
+const officialArchs = ['ia32', 'x64', 'armv7l', 'arm64', 'mips64el', 'universal']
+const officialPlatforms = ['darwin', 'linux', 'mas', 'win32']
+const officialPlatformArchCombos = {
+ darwin: ['x64', 'arm64', 'universal'],
+ linux: ['ia32', 'x64', 'armv7l', 'arm64', 'mips64el'],
+ mas: ['x64', 'arm64', 'universal'],
+ win32: ['ia32', 'x64', 'arm64']
+}
+
+const buildVersions = {
+ darwin: {
+ arm64: '>= 11.0.0-beta.1',
+ universal: '>= 11.0.0-beta.1'
+ },
+ linux: {
+ arm64: '>= 1.8.0',
+ ia32: '<19.0.0-beta.1',
+ mips64el: '^1.8.2-beta.5'
+ },
+ mas: {
+ arm64: '>= 11.0.0-beta.1',
+ universal: '>= 11.0.0-beta.1'
+ },
+ win32: {
+ arm64: '>= 6.0.8'
+ }
+}
+
+// Maps to module filename for each platform (lazy-required if used)
+const osModules = {
+ darwin: './mac',
+ linux: './linux',
+ mas: './mac', // map to darwin
+ win32: './win32'
+}
+
+const supported = {
+ arch: new Set(officialArchs),
+ platform: new Set(officialPlatforms)
+}
+
+function createPlatformArchPairs (opts, selectedPlatforms, selectedArchs, ignoreFunc) {
+ const combinations = []
+ for (const arch of selectedArchs) {
+ for (const platform of selectedPlatforms) {
+ if (usingOfficialElectronPackages(opts)) {
+ if (!validOfficialPlatformArch(opts, platform, arch)) {
+ warnIfAllNotSpecified(opts, `The platform/arch combination ${platform}/${arch} is not currently supported by Electron Packager`)
+ continue
+ } else if (buildVersions[platform] && buildVersions[platform][arch]) {
+ const buildVersion = buildVersions[platform][arch]
+ if (buildVersion && !officialBuildExists(opts, buildVersion)) {
+ warnIfAllNotSpecified(opts, `Official ${platform}/${arch} support only exists in Electron ${buildVersion}`)
+ continue
+ }
+ }
+ if (typeof ignoreFunc === 'function' && ignoreFunc(platform, arch)) continue
+ }
+ combinations.push([platform, arch])
+ }
+ }
+
+ return combinations
+}
+
+function unsupportedListOption (name, value, supported) {
+ return new Error(`Unsupported ${name}=${value} (${typeof value}); must be a string matching: ${Array.from(supported.values()).join(', ')}`)
+}
+
+function usingOfficialElectronPackages (opts) {
+ return !opts.download || !Object.prototype.hasOwnProperty.call(opts.download, 'mirrorOptions')
+}
+
+function validOfficialPlatformArch (opts, platform, arch) {
+ return officialPlatformArchCombos[platform] && officialPlatformArchCombos[platform].includes(arch)
+}
+
+function officialBuildExists (opts, buildVersion) {
+ return semver.satisfies(opts.electronVersion, buildVersion, { includePrerelease: true })
+}
+
+function allPlatformsOrArchsSpecified (opts) {
+ return opts.all || opts.arch === 'all' || opts.platform === 'all'
+}
+
+function warnIfAllNotSpecified (opts, message) {
+ if (!allPlatformsOrArchsSpecified(opts)) {
+ common.warning(message, opts.quiet)
+ }
+}
+
+module.exports = {
+ allOfficialArchsForPlatformAndVersion: function allOfficialArchsForPlatformAndVersion (platform, electronVersion) {
+ const archs = officialPlatformArchCombos[platform]
+ if (buildVersions[platform]) {
+ const excludedArchs = Object.keys(buildVersions[platform])
+ .filter(arch => !officialBuildExists({ electronVersion: electronVersion }, buildVersions[platform][arch]))
+ return archs.filter(arch => !excludedArchs.includes(arch))
+ }
+
+ return archs
+ },
+ createPlatformArchPairs,
+ officialArchs,
+ officialPlatformArchCombos,
+ officialPlatforms,
+ osModules,
+ supported,
+ // Validates list of architectures or platforms.
+ // Returns a normalized array if successful, or throws an Error.
+ validateListFromOptions: function validateListFromOptions (opts, name) {
+ if (opts.all) return Array.from(supported[name].values())
+
+ let list = opts[name]
+ if (!list) {
+ if (name === 'arch') {
+ list = getHostArch()
+ } else {
+ list = process[name]
+ }
+ } else if (list === 'all') {
+ return Array.from(supported[name].values())
+ }
+
+ if (!Array.isArray(list)) {
+ if (typeof list === 'string') {
+ list = list.split(/,\s*/)
+ } else {
+ return unsupportedListOption(name, list, supported[name])
+ }
+ }
+
+ const officialElectronPackages = usingOfficialElectronPackages(opts)
+
+ for (const value of list) {
+ if (officialElectronPackages && !supported[name].has(value)) {
+ return unsupportedListOption(name, value, supported[name])
+ }
+ }
+
+ return list
+ }
+}
diff --git a/desktop/node_modules/electron-packager/src/universal.js b/desktop/node_modules/electron-packager/src/universal.js
new file mode 100644
index 0000000..8ae7cb1
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/universal.js
@@ -0,0 +1,80 @@
+'use strict'
+
+const universal = require('@electron/universal')
+const common = require('./common')
+const fs = require('fs-extra')
+const path = require('path')
+
+async function packageUniversalMac (packageForPlatformAndArchWithOpts, buildDir, comboOpts, downloadOpts, tempBase) {
+ // In order to generate a universal macOS build we actually need to build the x64 and the arm64 app
+ // and then glue them together
+ common.info(`Packaging app for platform ${comboOpts.platform} universal using electron v${comboOpts.electronVersion} - Building x64 and arm64 slices now`, comboOpts.quiet)
+ await fs.mkdirp(tempBase)
+ const tempDir = await fs.mkdtemp(path.resolve(tempBase, 'electron-packager-universal-'))
+
+ const { App } = require('./mac')
+ const app = new App(comboOpts, buildDir)
+ const universalStagingPath = app.stagingPath
+ const finalUniversalPath = common.generateFinalPath(app.opts)
+
+ if (await fs.pathExists(finalUniversalPath)) {
+ if (comboOpts.overwrite) {
+ await fs.remove(finalUniversalPath)
+ } else {
+ common.info(`Skipping ${comboOpts.platform} ${comboOpts.arch} (output dir already exists, use --overwrite to force)`, comboOpts.quiet)
+ return true
+ }
+ }
+
+ const tempPackages = {}
+
+ for (const tempArch of ['x64', 'arm64']) {
+ const tempOpts = {
+ ...comboOpts,
+ arch: tempArch,
+ out: tempDir
+ }
+ const tempDownloadOpts = {
+ ...downloadOpts,
+ arch: tempArch
+ }
+ // Do not sign or notarize the individual slices, we sign and notarize the merged app later
+ delete tempOpts.osxSign
+ delete tempOpts.osxNotarize
+
+ tempPackages[tempArch] = await packageForPlatformAndArchWithOpts(tempOpts, tempDownloadOpts)
+ }
+
+ const x64AppPath = tempPackages.x64
+ const arm64AppPath = tempPackages.arm64
+
+ common.info(`Stitching universal app for platform ${comboOpts.platform}`, comboOpts.quiet)
+
+ const generatedFiles = await fs.readdir(x64AppPath)
+ const appName = generatedFiles.filter(file => path.extname(file) === '.app')[0]
+
+ await universal.makeUniversalApp({
+ ...comboOpts.osxUniversal,
+ x64AppPath: path.resolve(x64AppPath, appName),
+ arm64AppPath: path.resolve(arm64AppPath, appName),
+ outAppPath: path.resolve(universalStagingPath, appName)
+ })
+
+ await app.signAppIfSpecified()
+ await app.notarizeAppIfSpecified()
+ await app.move()
+
+ for (const generatedFile of generatedFiles) {
+ if (path.extname(generatedFile) === '.app') continue
+
+ await fs.copy(path.resolve(x64AppPath, generatedFile), path.resolve(finalUniversalPath, generatedFile))
+ }
+
+ await fs.remove(tempDir)
+
+ return finalUniversalPath
+}
+
+module.exports = {
+ packageUniversalMac
+}
diff --git a/desktop/node_modules/electron-packager/src/unzip.js b/desktop/node_modules/electron-packager/src/unzip.js
new file mode 100644
index 0000000..705c552
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/unzip.js
@@ -0,0 +1,7 @@
+'use strict'
+
+const extractZip = require('extract-zip')
+
+module.exports = async function extractElectronZip (zipPath, targetDir) {
+ await extractZip(zipPath, { dir: targetDir })
+}
diff --git a/desktop/node_modules/electron-packager/src/win32.js b/desktop/node_modules/electron-packager/src/win32.js
new file mode 100644
index 0000000..9416617
--- /dev/null
+++ b/desktop/node_modules/electron-packager/src/win32.js
@@ -0,0 +1,113 @@
+'use strict'
+
+const debug = require('debug')('electron-packager')
+const path = require('path')
+const { WrapperError } = require('cross-spawn-windows-exe')
+
+const App = require('./platform')
+const common = require('./common')
+
+function updateWineMissingException (err) {
+ if (err instanceof WrapperError) {
+ err.message += '\n\n' +
+ 'Wine is required to use the appCopyright, appVersion, buildVersion, icon, and \n' +
+ 'win32metadata parameters for Windows targets.\n\n' +
+ 'See https://github.com/electron/electron-packager#building-windows-apps-from-non-windows-platforms for details.'
+ }
+
+ return err
+}
+
+class WindowsApp extends App {
+ get originalElectronName () {
+ return 'electron.exe'
+ }
+
+ get newElectronName () {
+ return `${common.sanitizeAppName(this.executableName)}.exe`
+ }
+
+ get electronBinaryPath () {
+ return path.join(this.stagingPath, this.newElectronName)
+ }
+
+ generateRceditOptionsSansIcon () {
+ const win32metadata = {
+ FileDescription: this.opts.name,
+ InternalName: this.opts.name,
+ OriginalFilename: this.newElectronName,
+ ProductName: this.opts.name,
+ ...this.opts.win32metadata
+ }
+
+ const rcOpts = { 'version-string': win32metadata }
+
+ if (this.opts.appVersion) {
+ rcOpts['product-version'] = rcOpts['file-version'] = this.opts.appVersion
+ }
+
+ if (this.opts.buildVersion) {
+ rcOpts['file-version'] = this.opts.buildVersion
+ }
+
+ if (this.opts.appCopyright) {
+ rcOpts['version-string'].LegalCopyright = this.opts.appCopyright
+ }
+
+ const manifestProperties = ['application-manifest', 'requested-execution-level']
+ for (const manifestProperty of manifestProperties) {
+ if (win32metadata[manifestProperty]) {
+ rcOpts[manifestProperty] = win32metadata[manifestProperty]
+ }
+ }
+
+ return rcOpts
+ }
+
+ async getIconPath () {
+ if (!this.opts.icon) {
+ return Promise.resolve()
+ }
+
+ return this.normalizeIconExtension('.ico')
+ }
+
+ needsRcedit () {
+ return this.opts.icon || this.opts.win32metadata || this.opts.appCopyright || this.opts.appVersion || this.opts.buildVersion
+ }
+
+ async runRcedit () {
+ /* istanbul ignore if */
+ if (!this.needsRcedit()) {
+ return Promise.resolve()
+ }
+
+ const rcOpts = this.generateRceditOptionsSansIcon()
+
+ // Icon might be omitted or only exist in one OS's format, so skip it if normalizeExt reports an error
+ const icon = await this.getIconPath()
+ if (icon) {
+ rcOpts.icon = icon
+ }
+
+ debug(`Running rcedit with the options ${JSON.stringify(rcOpts)}`)
+ try {
+ await require('rcedit')(this.electronBinaryPath, rcOpts)
+ } catch (err) {
+ throw updateWineMissingException(err)
+ }
+ }
+
+ async create () {
+ await this.initialize()
+ await this.renameElectron()
+ await this.copyExtraResources()
+ await this.runRcedit()
+ return this.move()
+ }
+}
+
+module.exports = {
+ App: WindowsApp,
+ updateWineMissingException: updateWineMissingException
+}