diff --git a/.vscode/launch.json b/.vscode/launch.json index 9cb3e1c..cdad78d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "configurations": [ { "name": "Debug Release", - "program": "${workspaceFolder}/scripts/release.js", + "program": "${workspaceFolder}/scripts/release.mjs", "request": "launch", "skipFiles": [ "/**" diff --git a/package-lock.json b/package-lock.json index 64e40a7..68949ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "electron-qa", - "version": "0.1.23", + "version": "0.1.25", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "electron-qa", - "version": "0.1.23", + "version": "0.1.25", "license": "MIT", "dependencies": { "electron-is-dev": "2.0.0", @@ -17,7 +17,9 @@ "devDependencies": { "electron": "37.2.3", "electron-builder": "26.0.12", - "fs-extra": "11.1.1" + "fs-extra": "11.1.1", + "p-retry": "7.1.0", + "p-throttle": "8.1.0" } }, "node_modules/@develar/schema-utils": { @@ -1796,6 +1798,35 @@ "node": "*" } }, + "node_modules/dir-compare/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dir-compare/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dmg-builder": { "version": "26.0.12", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.0.12.tgz", @@ -2920,6 +2951,19 @@ "dev": true, "license": "MIT" }, + "node_modules/is-network-error": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz", + "integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3585,14 +3629,14 @@ "node": ">=8" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "aggregate-error": "^3.0.0" }, "engines": { "node": ">=10" @@ -3601,17 +3645,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/p-retry": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-7.1.0.tgz", + "integrity": "sha512-xL4PiFRQa/f9L9ZvR4/gUCRNus4N8YX80ku8kv9Jqz+ZokkiZLM0bcvX0gm1F3PDi9SPRsww1BDsTWgE6Y1GLQ==", "dev": true, "license": "MIT", "dependencies": { - "aggregate-error": "^3.0.0" + "is-network-error": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-throttle": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/p-throttle/-/p-throttle-8.1.0.tgz", + "integrity": "sha512-c1wmXavsHZIC4g1OLhOsafK6jZSAeMo0Ap3yivj59PUcCkpacy5YgWdgIp/dB4vp1JZrfBSsPCR0YuADB+ENLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4691,19 +4748,6 @@ "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/package.json b/package.json index 117d155..be50d7f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Electron updater E2E test", "scripts": { "start": "electron ./src/main.js", - "release": "node ./scripts/release.js" + "release": "node ./scripts/release.mjs" }, "keywords": [ "electron", @@ -28,6 +28,8 @@ "devDependencies": { "electron": "37.2.3", "electron-builder": "26.0.12", - "fs-extra": "11.1.1" + "fs-extra": "11.1.1", + "p-retry": "7.1.0", + "p-throttle": "8.1.0" } } diff --git a/scripts/AzureSignTool-x64-6-0-1.exe b/scripts/AzureSignTool-x64-6-0-1.exe new file mode 100644 index 0000000..edc43ed Binary files /dev/null and b/scripts/AzureSignTool-x64-6-0-1.exe differ diff --git a/scripts/certs/windows-cert.p12.enc b/scripts/certs/windows-cert.p12.enc deleted file mode 100644 index a968d74..0000000 Binary files a/scripts/certs/windows-cert.p12.enc and /dev/null differ diff --git a/scripts/release.js b/scripts/release.mjs similarity index 59% rename from scripts/release.js rename to scripts/release.mjs index c5a4d9f..ae002e2 100644 --- a/scripts/release.js +++ b/scripts/release.mjs @@ -1,6 +1,7 @@ 'use strict' -const exec = require('child_process').execSync +import { exec, execSync } from 'node:child_process' +const __dirname = import.meta.dirname const TEST_BUILD = process.env.TEST_BUILD // set true if you would like to test on your local machine // electron-builder security override. @@ -26,9 +27,12 @@ if (!isReleaseCommit) { process.exit(0) } -const path = require('path') -const builder = require('electron-builder') -const fs = require('fs-extra') +import path from 'node:path' +import {setTimeout} from 'node:timers/promises' +import builder from 'electron-builder' +import fs from 'fs-extra' +import pThrottle from 'p-throttle' +import pRetry from 'p-retry' const Platform = builder.Platform const ELECTRON_BUILD_FOLDER = path.join(__dirname, '../tmp-build') @@ -53,10 +57,7 @@ if (process.platform === 'darwin') { if (process.platform === 'darwin') { const encryptedFile = path.join(__dirname, './certs/mac-cert.p12.enc') const decryptedFile = path.join(__dirname, './certs/mac-cert.p12') - exec(`openssl aes-256-cbc -K $CERT_KEY -iv $CERT_IV -in ${encryptedFile} -out ${decryptedFile} -d`) -} else if (process.platform === 'win32') { - // decrypt windows certificate - exec('openssl aes-256-cbc -K %CERT_KEY% -iv %CERT_IV% -in scripts/certs/windows-cert.p12.enc -out scripts/certs/windows-cert.p12 -d') + execSync(`openssl aes-256-cbc -K $CERT_KEY -iv $CERT_IV -in ${encryptedFile} -out ${decryptedFile} -d`) } const APPLE_TEAM_ID = 'CMXCBCFHDG' @@ -85,8 +86,8 @@ if (TEST_BUILD || gitTag) { win: { signtoolOptions: { publisherName: 'Ultimate Gadget Laboratories Kft.', - certificateFile: path.join(__dirname, 'certs/windows-cert.p12') - } + sign: configuration => azureKeyvaultSign(configuration.path), + }, }, linux: {}, publish: 'github', @@ -125,3 +126,60 @@ function prepareDistDir() { electronJson.dependencies = rootJson.dependencies fs.writeJsonSync(path.join(ELECTRON_BUILD_FOLDER, 'package.json'), electronJson, { spaces: 2 }) } + +// sign only 1 file in every 2 sec +// otherwise we got random singing error +// maybe related issue https://github.com/vcsjones/AzureSignTool/issues/330 +const throttleAzureCodeSign = pThrottle({ + limit: 1, + interval: 2000 +}); + +const azureKeyvaultSign = throttleAzureCodeSign(async (filePath) => { + const { + AZURE_KEY_VAULT_TENANT_ID, + AZURE_KEY_VAULT_CLIENT_ID, + AZURE_KEY_VAULT_SECRET, + AZURE_KEY_VAULT_URL, + AZURE_KEY_VAULT_CERTIFICATE, + } = process.env; + + if (!AZURE_KEY_VAULT_URL) { + console.log('Skipping code signing, no environment variables set for that.') + return + } + + return pRetry(() => new Promise((resolve, reject) => { + console.log('Signing file', filePath); + const signToolPath = path.join(__dirname, 'AzureSignTool-x64-6-0-1.exe') + const command = `${signToolPath} sign -kvu ${AZURE_KEY_VAULT_URL} -kvi ${AZURE_KEY_VAULT_CLIENT_ID} -kvt ${AZURE_KEY_VAULT_TENANT_ID} -kvs ${AZURE_KEY_VAULT_SECRET} -kvc ${AZURE_KEY_VAULT_CERTIFICATE} -tr http://timestamp.identrust.com -v '${filePath}'`; + exec(command, { shell: 'powershell.exe' }, (e, stdout, stderr) => { + if (e instanceof Error) { + console.error(e) + return reject(e) + } + + if (stderr) { + console.error(stderr) + return reject(new Error(stderr)) + } + + if (stdout.indexOf('Signing completed successfully') > -1) { + console.log(stdout) + return resolve() + } + + return reject(new Error(stdout)) + }) + }), { + retries: 5, + onFailedAttempt: async ({error, attemptNumber, retriesLeft, retriesConsumed}) => { + console.log('Signing file failed', filePath); + console.log(`Attempt ${attemptNumber} failed. ${retriesLeft} retries left. ${retriesConsumed} retries consumed.`); + console.error(error) + + console.log('wait 5 sec before retry') + await setTimeout(5000) + }, + }) +})