Saltar al contenido principal

Integración con Electron Builder

Este documento describe cómo integrar el servicio de firma de código remota en el flujo de compilación de una aplicación Electron, utilizando electron-builder para firmar automáticamente los paquetes de instalación y archivos ejecutables de la plataforma Windows.

Consejo

Aquí se utiliza un proyecto de código abierto para las pruebas vite-electron-builder.

Requisitos previos

  1. Ya dispone de una cuenta válida del servicio de firma de código remota sslTrus y ha obtenido credenciales de acceso válidas (AK/SK).
  2. Ya dispone de un servicio de firma de código remota para firmar.
  3. El proyecto se compila con electron-builder.

Pasos de integración

Paso 1: Configurar el archivo de Electron Builder

En el directorio raíz de su proyecto Electron, localice y modifique el archivo electron-builder.mjs (o electron-builder.yml/config.js).

A continuación se muestra un ejemplo de configuración completo; es necesario modificar la configuración predeterminada y agregar el método de firma personalizado signtoolOptions.sign.

export default /** @type import('electron-builder').Configuration */
({
win: {
target: [
{
target: 'nsis',
arch: ['x64'],
},
],
signtoolOptions: {
sign: customSign,
signingHashAlgorithms: ['sha256'], // 这里只需要选择一个即可,实际的双签由 customSign 执行
},
},
});

async function customSign(configuration) {
const srcPath = configuration.path;
const cwd = process.cwd();
const relPath = relative(cwd, srcPath);

// 设置环境变量 export SIGNTOOL_ACCESS_KEY='' SIGNTOOL_ACCESS_SECRET='' SIGNTOOL_CERT_CODE=''
const {SIGNTOOL_ACCESS_KEY, SIGNTOOL_ACCESS_SECRET, SIGNTOOL_CERT_CODE} = process.env;
if (!SIGNTOOL_ACCESS_KEY || !SIGNTOOL_ACCESS_SECRET || !SIGNTOOL_CERT_CODE) {
console.error(`[ERROR] Missing environment variables: SIGNTOOL_ACCESS_KEY, SIGNTOOL_ACCESS_SECRET, SIGNTOOL_CERT_CODE`);
return;
}

// 下载对应平台的命令行工具
const signtoolPath = join(cwd, 'signtool', 'signtool');
const dir = dirname(srcPath);
const ext = extname(srcPath);
const name = basename(srcPath, ext);
const randomStr = randomBytes(4).toString('hex');
const tempPath = join(dir, `${name}-${randomStr}${ext}`);

const startTime = Date.now();

try {
console.log(`[SIGNING] ${relPath}`);

const logFilePath = join(cwd, 'signtool', name + '.log');
writeFileSync(logFilePath, `Source: ${srcPath}\nTime: ${new Date().toLocaleString()}\n\n`);
const logFd = openSync(logFilePath, 'a');

// 签名默认不会覆盖源文件,且目标文件不存在,所以先将源文件重命名为临时文件
renameSync(srcPath, tempPath);

// 参数可参考 signtool 命令行解析
const command = [
signtoolPath,
'sign',
`-k "${SIGNTOOL_ACCESS_KEY}"`,
`-s "${SIGNTOOL_ACCESS_SECRET}"`,
`-c "${SIGNTOOL_CERT_CODE}"`,
`-f "${tempPath}"`, // 源文件
`-o "${srcPath}"`, // 目标文件
'--nest=true', // 嵌套签名
'--sha1=false', // sha1 签名,对于 bool 值的参数传递需要使用 arg=value 的方式,不可使用 arg value 的形式
'--timestamp http://timestamp.sectigo.com',
'--sha2=true', // sha2 签名
'--timestamp-rfc3161 http://timestamp.sectigo.com',
].join(' ');

// 将 signtool 的日志输出到文件
execSync(command, {stdio: ['ignore', logFd, logFd]});

// 删除临时文件
rmSync(tempPath, {force: true});

const duration = ((Date.now() - startTime) / 1000).toFixed(2);
console.log(`[SUCCESS] Finished in ${duration}s -> ${relPath}`);
} catch (e) {
console.error(`[FAILURE] Failed to sign: ${relPath}`);
console.error(` Check log: signtool/${name}.log`);
process.exit(1);
}
}

Paso 2: Compilación

Una vez completada la configuración, ejecute su comando de compilación de Electron. Durante el proceso de compilación, se invocará automáticamente la función de firma personalizada mencionada anteriormente.

# 示例:构建 Windows 64位 安装包
npm run compile -- --win --x64
# 或使用 npx
npx electron-builder build --config electron-builder.mjs --win --x64

Proceso de compilación

Servicio de firma de código remota integrado con Electron Builder

Resultado de la compilación

El paquete de instalación y el programa principal están firmados

Servicio de firma de código remota integrado con Electron Builder

Servicio de firma de código remota integrado con Electron Builder