Aller au contenu principal

Intégration avec Electron Builder

Ce document décrit comment intégrer le service de signature de code à distance dans le flux de construction d’une application Electron, en utilisant electron-builder pour signer automatiquement les paquets d’installation et les fichiers exécutables de la plateforme Windows.

Astuce

Un projet open source est utilisé ici pour les tests vite-electron-builder.

Prérequis

  1. Vous disposez déjà d’un compte de service de signature de code à distance sslTrus valide et avez obtenu des informations d’identification d’accès valides (AK/SK).
  2. Un service de signature de code à distance est déjà disponible pour la signature.
  3. Le projet est construit sur la base de electron-builder.

Étapes d’intégration

Étape 1 : Configurer le fichier Electron Builder

Dans le répertoire racine de votre projet Electron, recherchez et modifiez le fichier electron-builder.mjs (ou electron-builder.yml/config.js).

Voici un exemple de configuration complet : vous devez modifier la configuration par défaut et ajouter la méthode de signature personnalisée 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);
}
}

Étape 2 : Compilation

Une fois la configuration terminée, exécutez votre commande de build Electron. Pendant le processus de build, la fonction de signature personnalisée décrite ci-dessus sera automatiquement appelée.

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

Processus de compilation

Service de signature de code à distance intégré à Electron Builder

Résultat de la compilation

Le paquet d’installation et le programme principal sont tous deux signés

Service de signature de code à distance intégré à Electron Builder

Service de signature de code à distance intégré à Electron Builder