From fe26c92ef0c6b0f2df6919a5b8c5ddcd6b2f1015 Mon Sep 17 00:00:00 2001 From: ali asaria <aliasaria@users.noreply.github.com> Date: Tue, 4 Feb 2025 16:54:56 -0500 Subject: [PATCH] first attempt at signing windows app --- .github/workflows/publish.yml | 20 +++++- release/sign.js | 111 ++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 release/sign.js diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4654a486..ab53ba45 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - os: [macos-latest] + os: [macos-latest, windows-latest] steps: - name: Checkout git repo @@ -30,7 +30,12 @@ jobs: npm run postinstall npm run build + - name: Sign Windows app + if: matrix.os == 'windows-latest' + run: node sign.js "release/build/win-unpacked/" + - name: copy p8 key to file + if: matrix.os == 'macos-latest' run: | echo "${{ secrets.APPLE_API_KEY_P8_FILE }}" > api_key.p8 @@ -46,4 +51,15 @@ jobs: # This is used for uploading release assets to github GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - npm exec electron-builder -- --publish always --win --mac --linux + npm exec electron-builder -- --publish always --mac --linux + + - name: Publish Windows releases + if: matrix.os == 'windows-latest' + env: + # These values are used for auto updates signing + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + # This is used for uploading release assets to github + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm exec electron-builder -- --publish always --win diff --git a/release/sign.js b/release/sign.js new file mode 100644 index 00000000..ca7563ab --- /dev/null +++ b/release/sign.js @@ -0,0 +1,111 @@ +const { execSync } = require('child_process'); +const path = require('path'); +const fs = require('fs'); + +// Azure signing configuration +const config = { + certProfileName: process.env.AZURE_CERT_PROFILE_NAME, + clientId: process.env.AZURE_CLIENT_ID, + clientSecret: process.env.AZURE_CLIENT_SECRET, + codeSigningName: process.env.AZURE_CODE_SIGNING_NAME, + endpoint: process.env.AZURE_ENDPOINT, + tenantId: process.env.AZURE_TENANT_ID, +}; + +// Get signtool path from Windows SDK +const getSignToolPath = () => { + // Default Windows SDK paths in GitHub Actions runners + const windowsSdkPaths = [ + 'C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.17763.0\\x64\\signtool.exe', + 'C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.19041.0\\x64\\signtool.exe', + 'C:\\Program Files (x86)\\Windows Kits\\10\\bin\\x64\\signtool.exe', + ]; + + for (const sdkPath of windowsSdkPaths) { + if (fs.existsSync(sdkPath)) { + return sdkPath; + } + } + + throw new Error('Could not find signtool.exe in Windows SDK paths'); +}; + +// Validate environment variables +const validateConfig = () => { + const requiredVars = [ + 'certProfileName', + 'clientId', + 'clientSecret', + 'codeSigningName', + 'endpoint', + 'tenantId', + ]; + + const missingVars = requiredVars.filter((varName) => !config[varName]); + + if (missingVars.length > 0) { + throw new Error( + `Missing required environment variables: ${missingVars.join(', ')}` + ); + } +}; + +// Sign the application using Azure Trusted Signing +const signApplication = (filePath) => { + if (!fs.existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + console.log(`Signing file: ${filePath}`); + + try { + const signToolPath = getSignToolPath(); + console.log(`Using signtool from: ${signToolPath}`); + + // Construct the signtool command + const signToolCommand = [ + `"${signToolPath}"`, + 'sign', + '/fd SHA256', + '/tr http://timestamp.digicert.com', + '/td SHA256', + `/as "${filePath}"`, + `/dlib "${config.endpoint}"`, + `/dmdf "${config.codeSigningName}"`, + `/dcid "${config.clientId}"`, + `/dcs "${config.clientSecret}"`, + `/dtid "${config.tenantId}"`, + `/dcpn "${config.certProfileName}"`, + ].join(' '); + + // Execute the signing command + execSync(signToolCommand, { stdio: 'inherit' }); + + console.log('Signing completed successfully'); + return true; + } catch (error) { + console.error('Signing failed:', error.message); + throw error; + } +}; + +// Main execution +try { + // Get the file path from command line arguments + const filePath = process.argv[2]; + + if (!filePath) { + throw new Error( + 'Please provide the path to the file to sign as a command line argument' + ); + } + + // Validate environment variables + validateConfig(); + + // Sign the application + signApplication(filePath); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} -- GitLab