Bläddra i källkod

Feature: Switch to different windows signer (#3943)

Replace usage of signtool with Actalis code signer.
Armin Schrenk 3 veckor sedan
förälder
incheckning
8b1d2101db
2 ändrade filer med 180 tillägg och 32 borttagningar
  1. 145 0
      .github/actions/win-sign-action/action.yml
  2. 35 32
      .github/workflows/win-exe.yml

+ 145 - 0
.github/actions/win-sign-action/action.yml

@@ -0,0 +1,145 @@
+name: 'Windows Signing'
+description: 'Sign files on Windows'
+inputs:
+  base-dir:
+    description: 'The base directory to search for files'
+    required: true
+  file-extensions:
+    description: 'List of file extensions to sign, separated by comma'
+    required: true
+  username:
+    description: 'Username for signing'
+    required: true
+  password:
+    description: 'Password for signing'
+    required: true
+  recursive:
+    description: 'Whether to search recursively in subdirectories'
+    required: false
+    default: 'false'
+  sign-description:
+    description: 'Signature description'
+    required: false
+    default: 'Cryptomator'
+  sign-url:
+    description: 'Signature URL'
+    required: false
+    default: 'https://cryptomator.org'
+
+runs:
+  using: "composite"
+  steps:
+    - name: Download Actalis CodeSigner if not present
+      id: download-signer
+      run: |
+        if (! (Test-Path -Path '${{ env.SIGNER_PATH }}')) {
+          echo "Downloading Actalis CodeSigner..."
+          curl --output "${{ env.SIGNER_NAME }}.zip" -L "${{ env.SIGNER_URL }}"
+          if (!(Get-FileHash -Path "${{ env.SIGNER_NAME }}.zip" -Algorithm SHA256).Hash.ToLower().equals("${{ env.SIGNER_HASH }}")) {
+            echo "Signer hash mismatch, exiting."
+            exit 1
+          }
+          Expand-Archive -Path "${{ env.SIGNER_NAME }}.zip" -DestinationPath "${{ env.SIGNER_NAME }}" -Force
+        }
+      env:
+        SIGNER_PATH: ${{ github.workspace }}/actalis-signer/ActalisCodeSigner.exe
+        SIGNER_NAME: actalis-signer
+        SIGNER_URL: 'https://static.cryptomator.org/other/CodeSigner-win-x64-latest.zip'
+        SIGNER_HASH: '44a1e09ab72707d049d3e59656e3e35de92e8cda357eec1cfc367016e45835ab'
+      shell: pwsh
+    - name: Generate, mask, and output the input secrets
+      id: set-secrets
+      run: |
+        echo "::add-mask::${{ inputs.username }}"
+        echo "::add-mask::${{ inputs.password }}"
+        echo "username=${{ inputs.username }}" >> "$GITHUB_OUTPUT"
+        echo "password=${{ inputs.password }}" >> "$GITHUB_OUTPUT"
+      shell: bash
+    - name: Sign DLLs with Actalis CodeSigner
+      run: |
+        $signerPath = '${{ env.SIGNER_PATH }}'
+        $username = '${{ steps.set-secrets.outputs.username }}'
+        $password = '${{ steps.set-secrets.outputs.password }}'
+        $signDescription = '${{ inputs.sign-description }}'
+        $signUrl = '${{ inputs.sign-url }}'
+        $extensions = '${{ inputs.file-extensions }}'.split(",") | ForEach-Object { "*.$($_.Trim())" }
+        $recursive = '${{ inputs.recursive }}' -eq 'true'
+        $files = Get-ChildItem -Path '${{ inputs.base-dir }}\*' -Include $extensions -Recurse:$recursive
+
+        if($files.Count -eq 0) {
+            Write-Host "`n❌ No files found to sign."
+            exit 1
+        }
+        Write-Host "`n📝 Found $($files.Count) files to sign:"
+        $files | ForEach-Object { Write-Host "  - $($_.FullName)" }
+
+        # Create log directory
+        $logDir = "~/.Acsi/log"
+        if (!(Test-Path $logDir)) {
+            New-Item -Path $logDir -ItemType Directory -Force | Out-Null
+        }
+
+        $jobs = @()
+        foreach ($file in $files) {
+            # Run signing in a job
+            $job = Start-Job -ScriptBlock {
+                    param($signerPath, $username, $password, $signDescription, $signUrl, $filePath)
+
+                    Write-Host "`n🔐 Signing: $($filePath)"
+                    $logFile = "~/.Acsi/log/$(Split-Path -Leaf $filePath).log"
+                    $arguments = @(
+                        '-ts',
+                        'http://timestamp.digicert.com',
+                        '-fu', $username,
+                        '-fp', $password,
+                        '-pm', "`"$signDescription`"",
+                        '--program-url', $signUrl,
+                        '-in', "`"$filePath`""
+                    )
+                    $process = Start-Process -FilePath "$signerPath" -ArgumentList $arguments -Wait -PassThru -RedirectStandardOutput "$logFile" -NoNewWindow
+
+                    return @{
+                        FilePath = $filePath
+                        ExitCode = $process.ExitCode
+                        LogFile = $logFile
+                    }
+            } -ArgumentList $signerPath, $username, $password, $signDescription, $signUrl, $file.FullName
+            $jobs += $job
+
+            # Throttle to max 5 concurrent jobs
+            if ($jobs.Count -ge 5) {
+                $completed = $jobs | Wait-Job -Any
+                $result = $completed | Receive-Job
+
+                # Check result and exit on failure
+                if ($result.ExitCode -ne 0) {
+                    $jobs | Stop-Job | Remove-Job
+                    Write-Host "❌ Signing failed for $($result.FilePath) with exit code: $($result.ExitCode)"
+                    exit 1
+                }
+                Write-Host "  ✅ Successfully signed $($result.FilePath)"
+
+                $jobs = $jobs | Where-Object { $_.Id -ne $completed.Id }
+                $completed | Remove-Job
+
+            }
+        }
+        # Wait for remaining jobs
+        $jobs | Wait-Job | Receive-Job | ForEach-Object {
+            if ($_.ExitCode -ne 0) {
+                Write-Host "❌ Signing failed for $($_.FilePath) with exit code: $($_.ExitCode)"
+                exit 1
+            }
+            Write-Host "  ✅ Successfully signed $($_.FilePath)"
+        }
+        Write-Host "`n✅ Successfully signed $($files.Count) files."
+      env:
+        SIGNER_PATH: ${{ github.workspace }}/actalis-signer/ActalisCodeSigner.exe
+      shell: pwsh
+    - name: Upload log on failure
+      if: failure()
+      uses: actions/upload-artifact@v4
+      with:
+        name: signing-log-${{ runner.arch }}
+        path: |
+          ~/.Acsi/log/*.log

+ 35 - 32
.github/workflows/win-exe.yml

@@ -12,6 +12,11 @@ on:
         description: 'Build debug version with console output'
         type: boolean
         default: false
+      sign:
+        description: 'Sign binaries'
+        required: false
+        type: boolean
+        default: false
   push:
     branches-ignore:
       - 'dependabot/**'
@@ -205,16 +210,15 @@ jobs:
           New-Item -Path appdir/jpackage-jmod -ItemType Directory
           & $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod"
           Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir"
-      - name: Codesign
-        uses: skymatic/code-sign-action@v3
+      - name: Sign DLLs with Actalis CodeSigner
+        if: inputs.sign || github.event_name == 'release'
+        uses: ./.github/actions/win-sign-action
         with:
-          certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
-          password: ${{ secrets.WIN_CODESIGN_P12_PW }}
-          certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
-          description: Cryptomator
-          timestampUrl: 'http://timestamp.digicert.com'
-          folder: appdir
+          base-dir: 'appdir'
+          file-extensions: 'dll,exe,ps1'
           recursive: true
+          username: ${{ secrets.WIN_CODESIGN_USERNAME }}
+          password: ${{ secrets.WIN_CODESIGN_PW }}
       - name: Replace DLLs inside jars with signed ones
         shell: pwsh
         run: |
@@ -263,15 +267,15 @@ jobs:
         env:
           JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
           JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir
-      - name: Codesign MSI
-        uses: skymatic/code-sign-action@v3
+      - name: Sign msi with Actalis CodeSigner
+        if: inputs.sign || github.event_name == 'release'
+        uses: ./.github/actions/win-sign-action
         with:
-          certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
-          password: ${{ secrets.WIN_CODESIGN_P12_PW }}
-          certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
-          description: Cryptomator Installer
-          timestampUrl: 'http://timestamp.digicert.com'
-          folder: installer
+          base-dir: 'installer'
+          file-extensions: 'msi'
+          sign-description: 'Cryptomator Installer'
+          username: ${{ secrets.WIN_CODESIGN_USERNAME }}
+          password: ${{ secrets.WIN_CODESIGN_PW }}
       - name: Add possible alpha/beta tags and architecture to installer name
         run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.arch }}.msi
       - name: Create detached GPG signature with key 615D449FE6E6A235
@@ -374,27 +378,26 @@ jobs:
       - name: Detach burn engine in preparation to sign
         run: >
           wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe
-      - name: Codesign burn engine
-        uses: skymatic/code-sign-action@v3
+      - name: Sign burn engine with Actalis CodeSigner
+        if: inputs.sign || github.event_name == 'release'
+        uses: ./.github/actions/win-sign-action
         with:
-          certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
-          password: ${{ secrets.WIN_CODESIGN_P12_PW }}
-          certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
-          description: Cryptomator Installer
-          timestampUrl: 'http://timestamp.digicert.com'
-          folder: tmp
+          base-dir: 'tmp'
+          file-extensions: 'exe'
+          username: ${{ secrets.WIN_CODESIGN_USERNAME }}
+          password: ${{ secrets.WIN_CODESIGN_PW }}
       - name: Reattach signed burn engine to installer
         run: >
           wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe
-      - name: Codesign EXE
-        uses: skymatic/code-sign-action@v3
+      - name: Sign installer with Actalis CodeSigner
+        if: inputs.sign || github.event_name == 'release'
+        uses: ./.github/actions/win-sign-action
         with:
-          certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
-          password: ${{ secrets.WIN_CODESIGN_P12_PW }}
-          certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
-          description: Cryptomator Installer
-          timestampUrl: 'http://timestamp.digicert.com'
-          folder: installer
+          base-dir: 'installer'
+          file-extensions: 'exe'
+          sign-description: 'Cryptomator Bundle Installer'
+          username: ${{ secrets.WIN_CODESIGN_USERNAME }}
+          password: ${{ secrets.WIN_CODESIGN_PW }}
       - name: Add possible alpha/beta tags to installer name
         run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.executable-suffix }}.exe
       - name: Create detached GPG signature with key 615D449FE6E6A235