技術(tech)

Environment-Specific Signing Configuration for Electron Applications

Introduction

  • This article introduces methods to switch code signing requirements based on the environment for Electron application distribution
  • Technical stack: Electron, TypeScript, Node.js

This article is a continuation of the following articles:

https://gonkunblog.com/mac-globalsign-signing/2551/

https://gonkunblog.com/mac-code-signing/2556/

https://gonkunblog.com/electron-windoes-usb-token-build/2577/

Target Audience

  • Developers with experience in Electron application development
  • Those interested in application signing processes
  • Developers looking to set up conditional signing in CI/CD environments

Background

  • Code signing is recommended for Electron applications before distribution
  • However, signing during development is time-consuming
  • We wanted to implement signing only for production builds while skipping it for development builds
  • USB tokens became mandatory, limiting the number of machines capable of both building and signing
  • Particularly in CI/CD environments, signing processes cannot be executed because USB tokens cannot be connected
  • We decided to separate processes for production and other environments since signing is not necessarily required for development and testing environments

Challenges to Solve

  • Create environment-dependent branching for the signing process
  • Ensure signing is always performed in production environments
  • Skip the signing process in development environments to save time
  • Maintain a simple build process while implementing conditional branching
  • Enable signature-free builds in CI/CD environments

Implementation Method

  • Set up environment-specific build commands in package.json
  • Toggle signing settings using electron-builder command-line arguments
  • Prepare a TypeScript file for the signing process

Implementation Details

1. Environment-specific Build Script Configuration in package.json

{
  "scripts": {
    "build:win:prod": "yarn build && electron-builder -w --publish=never --config.win.sign=./sign-with-token.ts",
    "build:win": "yarn build && electron-builder -w --publish=never"
  }
}
  • build:win:prod: Production environment build command. The --config.win.sign option specifies the signing script
  • build:win: Development environment build command. Signing option is omitted

2. Signing Script Implementation

Here’s an example of the sign-with-token.ts file we actually use. This script uses the signtool command to sign Windows applications:

// sign-with-token.ts
exports.default = async function(configuration) {
    const { path } = configuration;
    const { execSync } = require('child_process');

    console.log(`Signing: ${path}`);

    try {
      execSync(`signtool sign /tr http://timestamp.globalsign.com/tsa/r6advanced1 /fd sha256 /td sha256 /n "Example Company" "${path}"`, 
        { stdio: 'inherit' });
      return true;
    } catch (error) {
      console.error('Signing error:', error);
      throw error;
    }
  };

The role and behavior of this script are as follows:

  • Retrieve the path of the file to be signed from the configuration object
  • Execute the signtool command using Node.js’s child_process module
  • Specify a timestamp server to prevent signature expiration
  • Use SHA256 hash algorithm
  • Specify the certificate issuer name (replaced with a generic name above)
  • Return true if signing is successful, or throw an error if it fails

For Windows, signing uses signtool.exe, but this method requires a physical certificate like a USB token on the development machine.

Implementation Results

  • Development builds can be created quickly by skipping the signing process
  • The signing process is automatically executed for production builds
  • Development teams can select the appropriate environment simply by using different commands
  • CI pipelines only need to run build:win:prod as configured
  • Staging environment (stg) builds can now be executed from CI/CD
  • USB token-dependent signing processes are limited to production environments only

Conclusion

  • While code signing for Electron applications is important, consider the balance with development efficiency
  • Flexible environment branching can be achieved by customizing package.json script settings
  • The method introduced here can be applied to other environment-specific settings beyond signing
  • Even with physical constraints like USB tokens, efficient development workflows can be maintained through environment-specific settings

References