Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/serious-forks-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": major
---

fix(nsis): Change the ProgID to a more correct, more unique format
21 changes: 13 additions & 8 deletions packages/app-builder-lib/src/targets/nsis/NsisTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { addCustomMessageFileInclude, createAddLangsMacro, LangConfigurator } fr
import { computeLicensePage } from "./nsisLicense"
import { NsisOptions, PortableOptions } from "./nsisOptions"
import { NsisScriptGenerator } from "./nsisScriptGenerator"
import { AppPackageHelper, NSIS_PATH, NSIS_RESOURCES_PATH, NsisTargetOptions, nsisTemplatesDir, UninstallerReader } from "./nsisUtil"
import { AppPackageHelper, NSIS_PATH, NSIS_RESOURCES_PATH, NsisTargetOptions, nsisTemplatesDir, ProgIdMaker, UninstallerReader } from "./nsisUtil"

const debug = _debug("electron-builder:nsis")

Expand Down Expand Up @@ -167,6 +167,10 @@ export class NsisTarget extends Target {
}
}

get appGuid(): string {
return this.options.guid || UUID.v5(this.packager.appInfo.id, ELECTRON_BUILDER_NS_UUID)
}

private async buildInstaller(archs: Map<Arch, string>): Promise<any> {
const primaryArch: Arch | null = archs.size === 1 ? (archs.keys().next().value ?? null) : null
const packager = this.packager
Expand Down Expand Up @@ -200,11 +204,10 @@ export class NsisTarget extends Target {
logFields
)

const guid = options.guid || UUID.v5(appInfo.id, ELECTRON_BUILDER_NS_UUID)
const uninstallAppKey = guid.replace(/\\/g, " - ")
const uninstallAppKey = this.appGuid.replace(/\\/g, " - ")
const defines: Defines = {
APP_ID: appInfo.id,
APP_GUID: guid,
APP_GUID: this.appGuid,
// Windows bug - entry in Software\Microsoft\Windows\CurrentVersion\Uninstall cannot have \ symbols (dir)
UNINSTALL_APP_KEY: uninstallAppKey,
PRODUCT_NAME: appInfo.productName,
Expand All @@ -221,8 +224,8 @@ export class NsisTarget extends Target {
if (options.customNsisBinary?.debugLogging) {
defines.ENABLE_LOGGING_ELECTRON_BUILDER = null
}
if (uninstallAppKey !== guid) {
defines.UNINSTALL_REGISTRY_KEY_2 = `Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${guid}`
if (uninstallAppKey !== this.appGuid) {
defines.UNINSTALL_REGISTRY_KEY_2 = `Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${this.appGuid}`
}

const { homepage } = this.packager.info.metadata
Expand Down Expand Up @@ -728,6 +731,7 @@ export class NsisTarget extends Target {
const fileAssociations = packager.fileAssociations
if (fileAssociations.length !== 0) {
scriptGenerator.include(path.join(path.join(nsisTemplatesDir, "include"), "FileAssociation.nsh"))
const progIdMaker = new ProgIdMaker(this.appGuid, packager.appInfo.productFilename)
if (isInstaller) {
const registerFileAssociationsScript = new NsisScriptGenerator()
for (const item of fileAssociations) {
Expand All @@ -740,18 +744,19 @@ export class NsisTarget extends Target {
registerFileAssociationsScript.file(installedIconPath, customIcon)
}

const progID = progIdMaker.progId(item.name || ext)
const icon = `"${installedIconPath}"`
const commandText = `"Open with ${packager.appInfo.productName}"`
const command = '"$appExe $\\"%1$\\""'
registerFileAssociationsScript.insertMacro("APP_ASSOCIATE", `"${ext}" "${item.name || ext}" "${item.description || ""}" ${icon} ${commandText} ${command}`)
registerFileAssociationsScript.insertMacro("APP_ASSOCIATE", `"${ext}" "${progID}" "${item.description || ""}" ${icon} ${commandText} ${command}`)
}
}
scriptGenerator.macro("registerFileAssociations", registerFileAssociationsScript)
} else {
const unregisterFileAssociationsScript = new NsisScriptGenerator()
for (const item of fileAssociations) {
for (const ext of asArray(item.ext)) {
unregisterFileAssociationsScript.insertMacro("APP_UNASSOCIATE", `"${normalizeExt(ext)}" "${item.name || ext}"`)
unregisterFileAssociationsScript.insertMacro("APP_UNASSOCIATE", `"${normalizeExt(ext)}" "${progIdMaker.progId(item.name || ext)}"`)
}
}
scriptGenerator.macro("unregisterFileAssociations", unregisterFileAssociationsScript)
Expand Down
27 changes: 27 additions & 0 deletions packages/app-builder-lib/src/targets/nsis/nsisUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getBinFromCustomLoc, getBinFromUrl } from "../../binDownload"
import { getTemplatePath } from "../../util/pathManager"
import { NsisOptions } from "./nsisOptions"
import { NsisTarget } from "./NsisTarget"
import { UUID } from "builder-util-runtime"

export const nsisTemplatesDir = getTemplatePath("nsis")

Expand Down Expand Up @@ -283,3 +284,29 @@ export class UninstallerReader {
await fs.appendFile(uninstallerPath, innerBuffer)
}
}

export class ProgIdMaker {
private readonly program: string
private readonly guid: Buffer

constructor(guid: string, productFilename: string) {
this.guid = UUID.parse(guid)
let program = this.sanitize(productFilename)
if (program === "") {
program = this.sanitize(`App${guid}`)
} else if (program.match(/^\d/)) {
program = `App${program}`
}
this.program = program.slice(0, 19)
}

progId(nameOrExt: string): string {
const componentPrefix = this.sanitize(nameOrExt).slice(0, 31 - this.program.length)
const componentUuid = this.sanitize(UUID.v5(nameOrExt, this.guid))
return `${this.program}.${componentPrefix}${componentUuid}`.slice(0, 39)
}

private sanitize(value: string) {
return value.replace(/[^A-Za-z0-9]/g, "")
}
}