Skip to content

Commit

Permalink
fix: auto-update powershell script requires reset of PSModulePath (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mmaietta committed Feb 17, 2024
1 parent 0403278 commit 48603ba
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/gorgeous-poems-joke.md
@@ -0,0 +1,5 @@
---
"electron-updater": patch
---

fix: auto-update powershell script requires reset of `PSModulePath`
16 changes: 6 additions & 10 deletions .github/workflows/test.yaml
Expand Up @@ -8,14 +8,9 @@ on:

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
build-docker-locally:
type: boolean
description: Force rebuild docker images for CI tests
required: false

permissions:
contents: read # to fetch code (actions/checkout)
contents: read

jobs:
test-linux:
Expand Down Expand Up @@ -55,7 +50,7 @@ jobs:
env:
TEST_FILES: ${{ matrix.testFiles }}
FORCE_COLOR: 1

test-mac:
runs-on: macos-latest
steps:
Expand All @@ -73,7 +68,7 @@ jobs:
env:
TEST_FILES: masTest,dmgTest,filesTest,macPackagerTest
FORCE_COLOR: 1

# Need to separate from other tests because logic is specific to when TOKEN env vars are set
test-updater:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -101,8 +96,9 @@ jobs:
strategy:
matrix:
testFiles:
- winCodeSignTest
- installerTest,appxTest,msiTest,portableTest,assistedInstallerTest,protonTest
- BuildTest,oneClickInstallerTest,winCodeSignTest,winPackagerTest,webInstallerTest
- BuildTest,oneClickInstallerTest,winPackagerTest,nsisUpdaterTest,webInstallerTest
steps:
- name: Checkout code repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
Expand All @@ -112,7 +108,7 @@ jobs:
with:
cache-key: v-17.0.0-windows-electron
cache-path: ~\AppData\Local\electron\Cache

- name: Test
run: pnpm ci:test
env:
Expand Down
3 changes: 1 addition & 2 deletions package.json
Expand Up @@ -34,8 +34,7 @@
"ci:publish": "pnpm compile && pnpm publish -r && changeset tag",
"jsdoc": "ts2jsdoc packages/builder-util-runtime packages/builder-util packages/app-builder-lib packages/electron-builder packages/electron-publish packages/electron-updater packages/dmg-builder",
"jsdoc2md2html": "node scripts/jsdoc2md2html.js",
"prepare": "husky install",
"update-deps": "pnpm update -i -r --latest"
"prepare": "husky install"
},
"//": "repository must be specified otherwise conventional-changelog will use forked repo (currently cloned)",
"repository": "https://github.com/electron-userland/electron-builder",
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/targets/nsis/NsisTarget.ts
Expand Up @@ -397,7 +397,7 @@ export class NsisTarget extends Target {
} else {
await execWine(installerPath, null, [], { env: { __COMPAT_LAYER: "RunAsInvoker" } })
}
await packager.sign(uninstallerPath, " Signing NSIS uninstaller")
await packager.sign(uninstallerPath, "signing NSIS uninstaller")

delete defines.BUILD_UNINSTALLER
// platform-specific path, not wine
Expand Down
Expand Up @@ -25,7 +25,7 @@ export function computeOperations(oldBlockMap: BlockMap, newBlockMap: BlockMap,
let lastOperation: Operation | null = null

// for now only one file is supported in block map
const blockMapFile = newBlockMap.files[0]
const blockMapFile: { name: string; offset: number } = newBlockMap.files[0]
const operations: Array<Operation> = []
const name = blockMapFile.name
const oldEntry = nameToOldBlocks.get(name)
Expand All @@ -41,7 +41,7 @@ export function computeOperations(oldBlockMap: BlockMap, newBlockMap: BlockMap,

let newOffset = blockMapFile.offset
for (let i = 0; i < newFile.checksums.length; newOffset += newFile.sizes[i], i++) {
const blockSize = newFile.sizes[i]
const blockSize: number = newFile.sizes[i]
const checksum = newFile.checksums[i]
let oldOffset = checksumToOldOffset.get(checksum)
if (oldOffset != null && checksumToOldSize.get(checksum) !== blockSize) {
Expand Down
Expand Up @@ -27,11 +27,13 @@ export function verifySignature(publisherNames: Array<string>, unescapedTempUpda
// guaranteed that the path will not contain any illegal characters like <>:"/\|?*
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
const tempUpdateFile = unescapedTempUpdateFile.replace(/'/g, "''")
logger.info(`Verifying signature ${tempUpdateFile}`)

// https://github.com/electron-userland/electron-builder/issues/2421
// https://github.com/electron-userland/electron-builder/issues/2535
// Resetting PSModulePath is necessary https://github.com/electron-userland/electron-builder/issues/7127
execFile(
"chcp 65001 >NUL & powershell.exe",
`set "PSModulePath="; chcp 65001 >NUL & powershell.exe`,
["-NoProfile", "-NonInteractive", "-InputFormat", "None", "-Command", `"Get-AuthenticodeSignature -LiteralPath '${tempUpdateFile}' | ConvertTo-Json -Compress"`],
{
shell: true,
Expand All @@ -44,7 +46,6 @@ export function verifySignature(publisherNames: Array<string>, unescapedTempUpda
resolve(null)
return
}

const data = parseOut(stdout)
if (data.Status === 0) {
const subject = parseDn(data.SignerCertificate.Subject)
Expand Down
33 changes: 33 additions & 0 deletions test/snapshots/updater/nsisUpdaterTest.js.snap
Expand Up @@ -471,6 +471,39 @@ Array [
]
`;

exports[`test custom signature verifier - signing error message 1`] = `"ERR_UPDATER_INVALID_SIGNATURE"`;

exports[`test custom signature verifier - signing error message 2`] = `
Array [
"checking-for-update",
"update-available",
"error",
]
`;

exports[`test custom signature verifier 1`] = `
Object {
"files": Array [
Object {
"sha512": "xrTrW8dzWYlPnu71Y4lpLIAuIurBZJvZmqEZyz1rzM3CbbE1Z+T+P5qYYZgwmhmXdYPOpvnmYKa0HGdgXggwtQ==",
"url": "TestApp-Setup-1.1.0.exe",
},
],
"releaseName": "1.1.0",
"releaseNotes": "",
"tag": "v1.1.0",
"version": "1.1.0",
}
`;

exports[`test custom signature verifier 2`] = `
Array [
"checking-for-update",
"update-available",
"update-downloaded",
]
`;

exports[`test download and install 1`] = `
Object {
"files": Array [
Expand Down
57 changes: 44 additions & 13 deletions test/src/updater/nsisUpdaterTest.ts
Expand Up @@ -186,6 +186,7 @@ test("file url github", async () => {
updater.updateConfigPath = await writeUpdateConfig(options)
updater.signals.updateDownloaded(info => {
expect(info.downloadedFile).not.toBeNull()
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
delete (info as any).downloadedFile
expect(info).toMatchSnapshot()
})
Expand All @@ -203,6 +204,7 @@ test("file url github pre-release and fullChangelog", async () => {
updater.updateConfigPath = await writeUpdateConfig(options)
updater.signals.updateDownloaded(info => {
expect(info.downloadedFile).not.toBeNull()
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
delete (info as any).downloadedFile
expect(info).toMatchSnapshot()
})
Expand Down Expand Up @@ -284,10 +286,11 @@ test.ifAll("valid signature using DN", async () => {
repo: "__test_nsis_release",
publisherName: ["CN=Vladimir Krivosheev, O=Vladimir Krivosheev, L=Grunwald, S=Bayern, C=DE"],
})

await validateDownload(updater)
})

test.skip.ifAll("invalid signature", async () => {
test.ifWindows("invalid signature", async () => {
const updater = await createNsisUpdater("0.0.1")
updater.updateConfigPath = await writeUpdateConfig({
provider: "github",
Expand All @@ -300,6 +303,36 @@ test.skip.ifAll("invalid signature", async () => {
expect(actualEvents).toMatchSnapshot()
})

test.ifWindows("test custom signature verifier", async () => {
const updater = await createNsisUpdater("1.0.2")
updater.updateConfigPath = await writeUpdateConfig<GithubOptions>({
provider: "github",
owner: "develar",
repo: "__test_nsis_release",
publisherName: ["CN=Vladimir Krivosheev, O=Vladimir Krivosheev, L=Grunwald, S=Bayern, C=DE"],
})
updater.verifyUpdateCodeSignature = (publisherName: string[], path: string) => {
return Promise.resolve(null)
}
await validateDownload(updater)
})

test.ifWindows("test custom signature verifier - signing error message", async () => {
const updater = await createNsisUpdater("1.0.2")
updater.updateConfigPath = await writeUpdateConfig<GithubOptions>({
provider: "github",
owner: "develar",
repo: "__test_nsis_release",
publisherName: ["CN=Vladimir Krivosheev, O=Vladimir Krivosheev, L=Grunwald, S=Bayern, C=DE"],
})
updater.verifyUpdateCodeSignature = (publisherName: string[], path: string) => {
return Promise.resolve("signature verification failed")
}
const actualEvents = trackEvents(updater)
await assertThat(updater.checkForUpdates().then((it): any => it?.downloadPromise)).throws()
expect(actualEvents).toMatchSnapshot()
})

// disable for now
test("90 staging percentage", async () => {
const userIdFile = path.join(tmpdir(), "electron-updater-test", "userData", ".updaterId")
Expand Down Expand Up @@ -365,21 +398,19 @@ test.ifAll("test download and install", async () => {
})

await validateDownload(updater)

const actualEvents = trackEvents(updater)
expect(actualEvents).toMatchObject([])
// await updater.quitAndInstall(true, false)
})

test.ifAll("test downloaded installer", async () => {
const updater = await createNsisUpdater()
updater.updateConfigPath = await writeUpdateConfig<GenericServerOptions>({
provider: "generic",
url: "https://develar.s3.amazonaws.com/test",
test.skip.ifWindows("test downloaded installer", async () => {
const updater = await createNsisUpdater("1.0.1")
updater.updateConfigPath = await writeUpdateConfig<GithubOptions>({
provider: "github",
owner: "mmaietta",
repo: "electron-builder-test",
})

const actualEvents = trackEvents(updater)

expect(actualEvents).toMatchObject([])
// await updater.quitAndInstall(true, false)
await validateDownload(updater)
// expect(actualEvents).toMatchObject(["checking-for-update", "update-available", "update-downloaded"])
updater.quitAndInstall(true, false)
expect(actualEvents).toMatchObject(["checking-for-update", "update-available", "update-downloaded", "before-quit-for-update"])
})

0 comments on commit 48603ba

Please sign in to comment.