diff --git a/patches/app-builder-lib+26.15.2.patch b/patches/app-builder-lib+26.15.2.patch index df9f9177e..481bff4ce 100644 --- a/patches/app-builder-lib+26.15.2.patch +++ b/patches/app-builder-lib+26.15.2.patch @@ -18,3 +18,27 @@ index c433dbb..1274151 100644 } return typeof (e === null || e === void 0 ? void 0 : e.code) === "string" && ["ENOTFOUND", "ETIMEDOUT", "ECONNRESET", "EPIPE", "ENOENT"].includes(e.code); }, +diff --git a/node_modules/app-builder-lib/out/codeSign/macCodeSign.js b/node_modules/app-builder-lib/out/codeSign/macCodeSign.js +--- a/node_modules/app-builder-lib/out/codeSign/macCodeSign.js ++++ b/node_modules/app-builder-lib/out/codeSign/macCodeSign.js +@@ -156,16 +156,16 @@ + if (cscIKeyPassword != null) { + cscPasswords.push(cscIKeyPassword); + } +- return await importCerts(keychainFile, certPaths, cscPasswords); +-} +-async function importCerts(keychainFile, paths, keyPasswords) { ++ return await importCerts(keychainFile, certPaths, cscPasswords, keychainPassword); ++} ++async function importCerts(keychainFile, paths, keyPasswords, keychainPassword) { + var _a; + for (let i = 0; i < paths.length; i++) { + const password = (_a = keyPasswords[i]) !== null && _a !== void 0 ? _a : ""; + await (0, builder_util_1.exec)("/usr/bin/security", ["import", paths[i], "-k", keychainFile, "-T", "/usr/bin/codesign", "-T", "/usr/bin/productbuild", "-P", password]); + // https://stackoverflow.com/questions/39868578/security-codesign-in-sierra-keychain-ignores-access-control-settings-and-ui-p + // https://github.com/electron-userland/electron-packager/issues/701#issuecomment-322315996 +- await (0, builder_util_1.exec)("/usr/bin/security", ["set-key-partition-list", "-S", "apple-tool:,apple:", "-s", "-k", password, keychainFile]); ++ await (0, builder_util_1.exec)("/usr/bin/security", ["set-key-partition-list", "-S", "apple-tool:,apple:", "-s", "-k", keychainPassword, keychainFile]); + } + return { + keychainFile, diff --git a/scripts/electron-builder-keychain.test.cjs b/scripts/electron-builder-keychain.test.cjs new file mode 100644 index 000000000..1e8b4f53f --- /dev/null +++ b/scripts/electron-builder-keychain.test.cjs @@ -0,0 +1,38 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const { readFileSync } = require('node:fs'); +const { createRequire } = require('node:module'); +const path = require('node:path'); +const vm = require('node:vm'); + +test('macOS signing separates temporary keychain and certificate passwords', async () => { + const modulePath = require.resolve('app-builder-lib/out/codeSign/macCodeSign.js'); + const localRequire = createRequire(modulePath); + const calls = []; + const sandbox = { + exports: {}, + __dirname: path.dirname(modulePath), + process: { env: { TRAVIS: 'true' } }, + require(id) { + if (id === 'builder-util') return { + exec: async (file, args) => { assert.equal(file, '/usr/bin/security'); calls.push(args); return ''; }, + }; + if (id === './codesign') return { importCertificate: async (file) => file }; + return localRequire(id); + }, + }; + vm.runInNewContext(readFileSync(modulePath, 'utf8'), sandbox, { filename: modulePath }); + await sandbox.exports.createKeychain({ + tmpDir: {}, currentDir: '/signing-test', cscLink: '/app.p12', cscKeyPassword: 'application-password', + cscILink: '/installer.p12', cscIKeyPassword: 'installer-password', + }); + const flag = (args, name) => args[args.indexOf(name) + 1]; + const keychainPassword = flag(calls.find((args) => args[0] === 'create-keychain'), '-p'); + assert.equal(flag(calls.find((args) => args[0] === 'unlock-keychain'), '-p'), keychainPassword); + const partitions = calls.filter((args) => args[0] === 'set-key-partition-list'); + assert.equal(partitions.length, 2); + for (const args of partitions) assert.equal(flag(args, '-k'), keychainPassword); + assert.deepEqual(calls.filter((args) => args[0] === 'import').map((args) => flag(args, '-P')), [ + 'application-password', 'installer-password', + ]); +});