Electron Builder CICD 集成 VSign
介绍 Gitlab-CI 中,打包框架 electron_builder 如何配置 vsign 签名
简介
一般桌面程序发布,除了要对安装包签名,还需要对安装包里面的文件起签名。

准备条件
- 注册 VSign 账号
- 购买 EV 证书 或 (使用 Agent 映射本地证书到云端)
- 安装操作员,下载命令行签名工具
编写签名脚本
-
配置 package.json
"win": { "target": [ { "target": "nsis", "arch": [ "ia32" ] } ], "sign": "./sign.js", "certificateSha1": "(指定签名证书的指纹,配置双签名时,以逗号分隔)", "operatorSha1": "(指定操作员证书 'VSign.com Operator: xxx' 的指纹", "rfc3161TimeStampServer": "http://timestamp.trustasia.com/rfc3161", "timeStampServer": "http://timestamp.trustasia.com/timstamp.dll", "icon": "./resources/icon.ico" },
-
编写 sign.js
exports.default = async function (configuration) { const signServer = "api.vsign.com:9010" const signTimestampSrv = "TrustAsia" signedPath = `${configuration.path}.signed` let sParams = `-s ${signServer} -i "${configuration.path}" -o "${signedPath}" --cert_hash ${configuration.options.certificateSha1} --ts ${signTimestampSrv} --operator ${configuration.options.operatorSha1}` let isDualSign = configuration.options.signingHashAlgorithms == null hashes = configuration.options.signingHashAlgorithms || [] if (hashes.length > 1) { // 应用配置了多重签名 sParams += ` --attach --hash ${configuration.hash}` } // [双签优化]忽略第二次签名 if (isDualSign && configuration.isNest) { return } if (isDualSign) { sParams += " --dual" } console.log("sign params: " + sParams) require("child_process").execSync( `ssigncode sign ` + sParams, { stdio: "inherit" } ); await require("fs-extra-p").rename(signedPath, configuration.path) };
签名配置
其他说明
1、为了支持 Windows7,electron-builder 会对每个文件分别执行 sha1 和 sha256 签名,而 vsign 内置双签名加速机制,一次签名请求即可实现。 electron 说明链接
export async function sign(options: WindowsSignOptions, packager: WinPackager) {
let hashes = options.options.signingHashAlgorithms
// msi does not support dual-signing
if (options.path.endsWith(".msi")) {
hashes = [hashes != null && !hashes.includes("sha1") ? "sha256" : "sha1"]
}
else if (options.path.endsWith(".appx")) {
hashes = ["sha256"]
}
else if (hashes == null) {
hashes = ["sha1", "sha256"] // 注意这里!!!
}
else {
hashes = Array.isArray(hashes) ? hashes : [hashes]
}
function defaultExecutor(configuration: CustomWindowsSignTaskConfiguration) {
return doSign(configuration, packager)
}
const executor = resolveFunction(options.options.sign, "sign") || defaultExecutor
let isNest = false
for (const hash of hashes) { // 注意这里!!!
const taskConfiguration: WindowsSignTaskConfiguration = {...options, hash, isNest}
await executor({
...taskConfiguration,
computeSignToolArgs: isWin => computeSignToolArgs(taskConfiguration, isWin)
})
isNest = true
if (taskConfiguration.resultOutputPath != null) {
await rename(taskConfiguration.resultOutputPath, options.path)
}
}
}