Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
return pattern.replace(/\${([_a-zA-Z./*]+)}/g, (match, p1): string => {
switch (p1) {
case "productName":
return isProductNameSanitized ? appInfo.productFilename : appInfo.productName
case "arch":
if (arch == null) {
// see above, we remove macro if no arch
return ""
}
return arch
case "author":
const companyName = appInfo.companyName
if (companyName == null) {
throw new InvalidConfigurationError(`cannot expand pattern "${pattern}": author is not specified`, "ERR_ELECTRON_BUILDER_AUTHOR_UNSPECIFIED")
}
return companyName
case "platform":
return process.platform
case "channel":
return appInfo.channel || "latest"
default:
if (p1 in appInfo) {
return (appInfo as any)[p1]
}
if (p1.startsWith("env.")) {
const envName = p1.substring("env.".length)
if (identity == null) {
if (!isMas && !isDevelopment && explicitType !== "distribution") {
identity = await findIdentity("Mac Developer", qualifier, keychainFile)
if (identity != null) {
log.warn("Mac Developer is used to sign app — it is only for development and testing, not for production")
}
}
if (identity == null) {
await reportError(isMas, certificateType, qualifier, keychainFile, this.forceCodeSigning)
return
}
}
if (!isMacOsHighSierra()) {
throw new InvalidConfigurationError("macOS High Sierra 10.13.6 is required to sign")
}
const signOptions: any = {
"identity-validation": false,
// https://github.com/electron-userland/electron-builder/issues/1699
// kext are signed by the chipset manufacturers. You need a special certificate (only available on request) from Apple to be able to sign kext.
ignore: (file: string) => {
return file.endsWith(".kext") || file.startsWith("/Contents/PlugIns", appPath.length) ||
// https://github.com/electron-userland/electron-builder/issues/2010
file.includes("/node_modules/puppeteer/.local-chromium")
},
identity: identity!,
type,
platform: isMas ? "mas" : "darwin",
version: this.config.electronVersion,
app: appPath,
export async function validateConfig(config: Configuration, debugLogger: DebugLogger) {
const extraMetadata = config.extraMetadata
if (extraMetadata != null) {
if (extraMetadata.build != null) {
throw new InvalidConfigurationError(`--em.build is deprecated, please specify as -c"`)
}
if (extraMetadata.directories != null) {
throw new InvalidConfigurationError(`--em.directories is deprecated, please specify as -c.directories"`)
}
}
const oldConfig: any = config
if (oldConfig.npmSkipBuildFromSource === false) {
throw new InvalidConfigurationError(`npmSkipBuildFromSource is deprecated, please use buildDependenciesFromSource"`)
}
if (oldConfig.appImage != null && oldConfig.appImage.systemIntegration != null) {
throw new InvalidConfigurationError(`appImage.systemIntegration is deprecated, https://github.com/TheAssassin/AppImageLauncher is used for desktop integration"`)
}
// noinspection JSUnusedGlobalSymbols
validateSchema(await schemeDataPromise.value, config, {
export function getEffectiveOptions(options: CommonWindowsInstallerConfiguration, packager: WinPackager): FinalCommonWindowsInstallerOptions {
const appInfo = packager.appInfo
let menuCategory: string | null = null
if (options.menuCategory != null && options.menuCategory !== false) {
if (options.menuCategory === true) {
const companyName = packager.appInfo.companyName
if (companyName == null) {
throw new InvalidConfigurationError(`Please specify "author" in the application package.json — it is required because "menuCategory" is set to true.`)
}
menuCategory = sanitizeFileName(companyName)
}
else {
menuCategory = (options.menuCategory as string).split(/[\/\\]/).map(it => sanitizeFileName(it)).join("\\")
}
}
return {
isPerMachine: options.perMachine === true,
isAssisted: options.oneClick === false,
shortcutName: isEmptyOrSpaces(options.shortcutName) ? appInfo.productFilename : packager.expandMacro(options.shortcutName!!),
isCreateDesktopShortcut: convertToDesktopShortcutCreationPolicy(options.createDesktopShortcut),
isCreateStartMenuShortcut: options.createStartMenuShortcut !== false,
menuCategory,
log.warn("Electron version is set to \"latest\", but it is recommended to set it to some more restricted version range.")
try {
const releaseInfo = JSON.parse((await httpExecutor.request({
hostname: "github.com",
path: "/electron/electron/releases/latest",
headers: {
accept: "application/json",
},
}))!!)
return (releaseInfo.tag_name.startsWith("v")) ? releaseInfo.tag_name.substring(1) : releaseInfo.tag_name
}
catch (e) {
log.warn(e)
}
throw new InvalidConfigurationError(`Cannot find electron dependency to get electron version in the '${path.join(projectDir, "package.json")}'`)
}
if (electronVersionFromMetadata == null || !/^\d/.test(electronVersionFromMetadata)) {
const versionMessage = electronVersionFromMetadata == null ? "" : ` and version ("${electronVersionFromMetadata}") is not fixed in project`
throw new InvalidConfigurationError(`Cannot compute electron version from installed node modules - none of the possible electron modules are installed${versionMessage}.\nSee https://github.com/electron-userland/electron-builder/issues/3984#issuecomment-504968246`)
}
return semver.coerce(electronVersionFromMetadata)!!.toString()
}
async sign(file: string, logMessagePrefix?: string): Promise {
const signOptions: WindowsSignOptions = {
path: file,
name: this.appInfo.productName,
site: await this.appInfo.computePackageUrl(),
options: this.platformSpecificBuildOptions,
}
const cscInfo = await this.cscInfo.value
if (cscInfo == null) {
if (this.platformSpecificBuildOptions.sign != null) {
await sign(signOptions, this)
}
else if (this.forceCodeSigning) {
throw new InvalidConfigurationError(`App is not signed and "forceCodeSigning" is set to true, please ensure that code signing configuration is correct, please see https://electron.build/code-signing`)
}
return
}
if (logMessagePrefix == null) {
logMessagePrefix = "signing"
}
if ("file" in cscInfo) {
log.info({
file: log.filePath(file),
certificateFile: (cscInfo as FileCodeSigningInfo).file,
}, logMessagePrefix)
}
else {
const info = cscInfo as CertificateFromStoreInfo
async function doBuild(data: BuildTask): Promise {
if (process.env.APP_BUILDER_TMP_DIR == null) {
throw new InvalidConfigurationError("Env APP_BUILDER_TMP_DIR must be set for builder process")
}
const projectDir = process.env.PROJECT_DIR
if (projectDir == null) {
throw new InvalidConfigurationError("Env PROJECT_DIR must be set for builder process")
}
const targets = data.targets
if (data.platform == null) {
throw new InvalidConfigurationError("platform not specified")
}
if (targets == null) {
throw new InvalidConfigurationError("targets path not specified")
}
if (!Array.isArray(targets)) {
throw new InvalidConfigurationError("targets must be array of target name")
}
const infoFile = projectDir + path.sep + "info.json"
const info = await readJson(infoFile)
}
if (nodeVersion == null || nodeVersion === "current") {
nodeVersion = process.versions.node
}
const distMacOsName = `${packager.appInfo.productFilename}.app`
const isUseLaunchUi = configuration.launchUiVersion !== false
if (framework === "proton" || framework === "proton-native") {
return new ProtonFramework(nodeVersion, distMacOsName, isUseLaunchUi)
}
else if (framework === "libui") {
return new LibUiFramework(nodeVersion, distMacOsName, isUseLaunchUi)
}
else {
throw new InvalidConfigurationError(`Unknown framework: ${framework}`)
}
}
if (options.allowElevation !== false) {
defines.MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = null
}
}
if (options.perMachine === true) {
defines.INSTALL_MODE_PER_ALL_USERS = null
}
if (!oneClick || options.perMachine === true) {
defines.INSTALL_MODE_PER_ALL_USERS_REQUIRED = null
}
if (options.allowToChangeInstallationDirectory) {
if (oneClick) {
throw new InvalidConfigurationError("allowToChangeInstallationDirectory makes sense only for assisted installer (please set oneClick to false)")
}
defines.allowToChangeInstallationDirectory = null
}
const commonOptions = getEffectiveOptions(options, packager)
if (commonOptions.menuCategory != null) {
defines.MENU_FILENAME = commonOptions.menuCategory
}
defines.SHORTCUT_NAME = commonOptions.shortcutName
if (options.deleteAppDataOnUninstall) {
defines.DELETE_APP_DATA_ON_UNINSTALL = null
}
constructor(context: PublishContext, info: BintrayOptions, private readonly version: string, private readonly options: PublishOptions = {}) {
super(context)
let token = info.token
if (isEmptyOrSpaces(token)) {
token = process.env.BT_TOKEN
if (isEmptyOrSpaces(token)) {
throw new InvalidConfigurationError(`Bintray token is not set, neither programmatically, nor using env "BT_TOKEN" (see https://www.electron.build/configuration/publish#bintrayoptions)`)
}
token = token.trim()
if (!isTokenCharValid(token)) {
throw new InvalidConfigurationError(`Bintray token (${JSON.stringify(token)}) contains invalid characters, please check env "BT_TOKEN"`)
}
}
this.client = new BintrayClient(info, httpExecutor, this.context.cancellationToken, token)
}