Electron Builder 集成 VSign

介绍 Gitlab-CI 中,打包框架 electron_builder 如何配置 vsign 签名

简介

官方 electron 的签名介绍

一般桌面程序发布,除了要对安装包签名,还需要对安装包里面的文件起签名。

electron 签名打包
electron 签名打包

准备条件

编写签名脚本

  1. 配置 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"
        },
    
  2. 编写 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)
    }
  }
}