win-exe.yml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. name: Build Windows Installer
  2. on:
  3. release:
  4. types: [published]
  5. workflow_dispatch:
  6. inputs:
  7. version:
  8. description: 'Version'
  9. required: false
  10. isDebug:
  11. description: 'Build debug version with console output'
  12. type: boolean
  13. env:
  14. JAVA_VERSION: 20
  15. JAVA_DIST: 'temurin'
  16. JAVA_CACHE: 'maven'
  17. JFX_JMODS_URL: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_windows-x64_bin-jmods.zip'
  18. JFX_JMODS_HASH: '18625bbc13c57dbf802486564247a8d8cab72ec558c240a401bf6440384ebd77'
  19. defaults:
  20. run:
  21. shell: bash
  22. jobs:
  23. get-version:
  24. uses: ./.github/workflows/get-version.yml
  25. with:
  26. version: ${{ inputs.version }}
  27. build-msi:
  28. name: Build .msi Installer
  29. runs-on: windows-latest
  30. needs: [get-version]
  31. env:
  32. LOOPBACK_ALIAS: 'cryptomator-vault'
  33. WIN_CONSOLE_FLAG: ''
  34. steps:
  35. - uses: actions/checkout@v3
  36. - name: Setup Java
  37. uses: actions/setup-java@v3
  38. with:
  39. distribution: ${{ env.JAVA_DIST }}
  40. java-version: ${{ env.JAVA_VERSION }}
  41. java-package: 'jdk'
  42. check-latest: true
  43. cache: ${{ env.JAVA_CACHE }}
  44. - name: Download and extract JavaFX jmods from Gluon
  45. #In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
  46. run: |
  47. curl --output jfxjmods.zip -L "${{ env.JFX_JMODS_URL }}"
  48. if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.ToLower().equals("${{ env.JFX_JMODS_HASH }}")) {
  49. throw "Wrong checksum of JMOD archive downloaded from ${{ env.JFX_JMODS_URL }}.";
  50. }
  51. Expand-Archive -Path jfxjmods.zip -DestinationPath jfxjmods
  52. Get-ChildItem -Path jfxjmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
  53. shell: pwsh
  54. - name: Ensure major jfx version in pom and in jmods is the same
  55. run: |
  56. JMOD_VERSION_AMD64=$(jmod describe jfxjmods/javafx.base.jmod | head -1)
  57. JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
  58. JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
  59. POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
  60. POM_JFX_VERSION=${POM_JFX_VERSION#*@}
  61. POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
  62. if [ $POM_JFX_VERSION -ne $JMOD_VERSION_AMD64 ]; then
  63. >&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION_AMD64})"
  64. exit 1
  65. fi
  66. - name: Set version
  67. run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
  68. - name: Run maven
  69. run: mvn -B clean package -Pdependency-check,win -DskipTests
  70. - name: Patch target dir
  71. run: |
  72. cp LICENSE.txt target
  73. cp target/cryptomator-*.jar target/mods
  74. - name: Run jlink
  75. run: >
  76. ${JAVA_HOME}/bin/jlink
  77. --verbose
  78. --output runtime
  79. --module-path "jfxjmods;${JAVA_HOME}/jmods"
  80. --add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
  81. --strip-native-commands
  82. --no-header-files
  83. --no-man-pages
  84. --strip-debug
  85. --compress=1
  86. - name: Change win-console flag if debug is active
  87. if: ${{ inputs.isDebug }}
  88. run: echo "WIN_CONSOLE_FLAG=--win-console" >> $GITHUB_ENV
  89. - name: Run jpackage
  90. run: >
  91. ${JAVA_HOME}/bin/jpackage
  92. --verbose
  93. --type app-image
  94. --runtime-image runtime
  95. --input target/libs
  96. --module-path target/mods
  97. --module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
  98. --dest appdir
  99. --name Cryptomator
  100. --vendor "Skymatic GmbH"
  101. --copyright "(C) 2016 - 2023 Skymatic GmbH"
  102. --app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
  103. --java-options "--enable-preview"
  104. --java-options "--enable-native-access=org.cryptomator.jfuse.win"
  105. --java-options "-Xss5m"
  106. --java-options "-Xmx256m"
  107. --java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
  108. --java-options "-Dfile.encoding=\"utf-8\""
  109. --java-options "-Djava.net.useSystemProxies=true"
  110. --java-options "-Dcryptomator.logDir=\"@{localappdata}/Cryptomator\""
  111. --java-options "-Dcryptomator.pluginDir=\"@{appdata}/Cryptomator/Plugins\""
  112. --java-options "-Dcryptomator.settingsPath=\"@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json\""
  113. --java-options "-Dcryptomator.p12Path=\"@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12\""
  114. --java-options "-Dcryptomator.ipcSocketPath=\"@{localappdata}/Cryptomator/ipc.socket\""
  115. --java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Cryptomator\""
  116. --java-options "-Dcryptomator.loopbackAlias=\"${{ env.LOOPBACK_ALIAS }}\""
  117. --java-options "-Dcryptomator.showTrayIcon=true"
  118. --java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
  119. --java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
  120. --java-options "-Dcryptomator.integrationsWin.keychainPaths=\"@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json\""
  121. --java-options "-Djavafx.verbose=${{ inputs.isDebug }}"
  122. --resource-dir dist/win/resources
  123. --icon dist/win/resources/Cryptomator.ico
  124. ${WIN_CONSOLE_FLAG}
  125. - name: Patch Application Directory
  126. run: |
  127. cp dist/win/contrib/* appdir/Cryptomator
  128. - name: Set LOOPBACK_ALIAS in patchWebDAV.bat
  129. shell: pwsh
  130. run: |
  131. $patchScript = "appdir\Cryptomator\patchWebDAV.bat"
  132. try {
  133. (Get-Content $patchScript ) -replace '::REPLACE ME', "SET LOOPBACK_ALIAS=`"${{ env.LOOPBACK_ALIAS}}`"" | Set-Content $patchScript
  134. } catch {
  135. Write-Host "Failed to set LOOPBACK_ALIAS for patchWebDAV.bat"
  136. exit 1
  137. }
  138. - name: Fix permissions
  139. run: attrib -r appdir/Cryptomator/Cryptomator.exe
  140. shell: pwsh
  141. - name: Extract integrations DLL for code signing
  142. shell: pwsh
  143. run: gci ./appdir/Cryptomator/app/mods/ -File integrations-win-*.jar | ForEach-Object {Set-Location -Path $_.Directory; jar --file=$($_.FullName) --extract integrations.dll }
  144. - name: Codesign
  145. uses: skymatic/code-sign-action@v2
  146. with:
  147. certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
  148. password: ${{ secrets.WIN_CODESIGN_P12_PW }}
  149. certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
  150. description: Cryptomator
  151. timestampUrl: 'http://timestamp.digicert.com'
  152. folder: appdir/Cryptomator
  153. recursive: true
  154. - name: Repack signed DLL into jar
  155. shell: pwsh
  156. run: |
  157. gci ./appdir/Cryptomator/app/mods/ -File integrations-win-*.jar | ForEach-Object {Set-Location -Path $_.Directory; jar --file=$($_.FullName) --update integrations.dll; Remove-Item integrations.dll}
  158. - name: Generate license for MSI
  159. run: >
  160. mvn -B license:add-third-party
  161. "-Dlicense.thirdPartyFilename=license.rtf"
  162. "-Dlicense.outputDirectory=dist/win/resources"
  163. "-Dlicense.fileTemplate=dist/win/resources/licenseTemplate.ftl"
  164. "-Dlicense.includedScopes=compile"
  165. "-Dlicense.excludedGroups=^org\.cryptomator"
  166. "-Dlicense.failOnMissing=true"
  167. "-Dlicense.licenseMergesUrl=file:///${{ github.workspace }}/license/merges"
  168. shell: pwsh
  169. - name: Create MSI
  170. run: >
  171. ${JAVA_HOME}/bin/jpackage
  172. --verbose
  173. --type msi
  174. --win-upgrade-uuid bda45523-42b1-4cae-9354-a45475ed4775
  175. --app-image appdir/Cryptomator
  176. --dest installer
  177. --name Cryptomator
  178. --vendor "Skymatic GmbH"
  179. --copyright "(C) 2016 - 2023 Skymatic GmbH"
  180. --app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
  181. --win-menu
  182. --win-dir-chooser
  183. --win-shortcut-prompt
  184. --win-update-url "https:\\cryptomator.org"
  185. --win-menu-group Cryptomator
  186. --resource-dir dist/win/resources
  187. --license-file dist/win/resources/license.rtf
  188. --file-associations dist/win/resources/FAvaultFile.properties
  189. env:
  190. JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
  191. - name: Codesign MSI
  192. uses: skymatic/code-sign-action@v2
  193. with:
  194. certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
  195. password: ${{ secrets.WIN_CODESIGN_P12_PW }}
  196. certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
  197. description: Cryptomator Installer
  198. timestampUrl: 'http://timestamp.digicert.com'
  199. folder: installer
  200. - name: Add possible alpha/beta tags to installer name
  201. run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.msi
  202. - name: Create detached GPG signature with key 615D449FE6E6A235
  203. run: |
  204. echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
  205. echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a Cryptomator-*.msi
  206. env:
  207. GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
  208. GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
  209. - name: Upload artifacts
  210. uses: actions/upload-artifact@v3
  211. with:
  212. name: msi
  213. path: |
  214. Cryptomator-*.msi
  215. Cryptomator-*.asc
  216. if-no-files-found: error
  217. - name: Publish .msi on GitHub Releases
  218. if: startsWith(github.ref, 'refs/tags/')
  219. uses: softprops/action-gh-release@v1
  220. with:
  221. fail_on_unmatched_files: true
  222. token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
  223. files: |
  224. *.msi
  225. *.asc
  226. build-exe:
  227. name: Build .exe installer
  228. runs-on: windows-latest
  229. needs: [get-version, build-msi]
  230. steps:
  231. - uses: actions/checkout@v3
  232. - name: Download .msi
  233. uses: actions/download-artifact@v3
  234. with:
  235. name: msi
  236. path: dist/win/bundle/resources
  237. - name: Strip version info from msi file name
  238. run: mv dist/win/bundle/resources/Cryptomator*.msi dist/win/bundle/resources/Cryptomator.msi
  239. - uses: actions/setup-java@v3
  240. with:
  241. distribution: ${{ env.JAVA_DIST }}
  242. java-version: ${{ env.JAVA_VERSION }}
  243. check-latest: true
  244. cache: ${{ env.JAVA_CACHE }}
  245. - name: Generate license for exe
  246. run: >
  247. mvn -B license:add-third-party
  248. "-Dlicense.thirdPartyFilename=license.rtf"
  249. "-Dlicense.fileTemplate=dist/win/bundle/resources/licenseTemplate.ftl"
  250. "-Dlicense.outputDirectory=dist/win/bundle/resources"
  251. "-Dlicense.includedScopes=compile"
  252. "-Dlicense.excludedGroups=^org\.cryptomator"
  253. "-Dlicense.failOnMissing=true"
  254. "-Dlicense.licenseMergesUrl=file:///${{ github.workspace }}/license/merges"
  255. shell: pwsh
  256. - name: Download WinFsp
  257. run: |
  258. $winfspUrl = (Select-String -Path ".\dist\win\bundle\resources\winFspMetaData.wxi" -Pattern '<\?define BundledWinFspDownloadLink="(.+)".*?>').Matches.Groups[1].Value
  259. curl --output dist/win/bundle/resources/winfsp.msi -L $winfspUrl
  260. shell: pwsh
  261. - name: Compile to wixObj file
  262. run: >
  263. "${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs
  264. -ext WixBalExtension
  265. -ext WixUtilExtension
  266. -out dist/win/bundle/
  267. -dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
  268. -dBundleVendor="Skymatic GmbH"
  269. -dBundleCopyright="(C) 2016 - 2023 Skymatic GmbH"
  270. -dAboutUrl="https://cryptomator.org"
  271. -dHelpUrl="https://cryptomator.org/contact"
  272. -dUpdateUrl="https://cryptomator.org/downloads/"
  273. - name: Create executable with linker
  274. run: >
  275. "${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj
  276. -ext WixBalExtension
  277. -ext WixUtilExtension
  278. -out installer/unsigned/Cryptomator-Installer.exe
  279. - name: Detach burn engine in preparation to sign
  280. run: >
  281. "${WIX}/bin/insignia.exe"
  282. -ib installer/unsigned/Cryptomator-Installer.exe
  283. -o tmp/engine.exe
  284. - name: Codesign burn engine
  285. uses: skymatic/code-sign-action@v2
  286. with:
  287. certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
  288. password: ${{ secrets.WIN_CODESIGN_P12_PW }}
  289. certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
  290. description: Cryptomator Installer
  291. timestampUrl: 'http://timestamp.digicert.com'
  292. folder: tmp
  293. - name: Reattach signed burn engine to installer
  294. run : >
  295. "${WIX}/bin/insignia.exe"
  296. -ab tmp/engine.exe installer/unsigned/Cryptomator-Installer.exe
  297. -o installer/Cryptomator-Installer.exe
  298. - name: Codesign EXE
  299. uses: skymatic/code-sign-action@v2
  300. with:
  301. certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
  302. password: ${{ secrets.WIN_CODESIGN_P12_PW }}
  303. certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
  304. description: Cryptomator Installer
  305. timestampUrl: 'http://timestamp.digicert.com'
  306. folder: installer
  307. - name: Add possible alpha/beta tags to installer name
  308. run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.exe
  309. - name: Create detached GPG signature with key 615D449FE6E6A235
  310. run: |
  311. echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
  312. echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a Cryptomator-*.exe
  313. env:
  314. GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
  315. GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
  316. - name: Upload artifacts
  317. uses: actions/upload-artifact@v3
  318. with:
  319. name: exe
  320. path: |
  321. Cryptomator-*.exe
  322. Cryptomator-*.asc
  323. if-no-files-found: error
  324. - name: Publish .msi on GitHub Releases
  325. if: startsWith(github.ref, 'refs/tags/')
  326. uses: softprops/action-gh-release@v1
  327. with:
  328. fail_on_unmatched_files: true
  329. token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
  330. files: |
  331. Cryptomator-*.exe
  332. Cryptomator-*.asc
  333. allowlist:
  334. name: Anti Virus Allowlisting
  335. if: startsWith(github.ref, 'refs/tags/')
  336. runs-on: ubuntu-latest
  337. needs: [build-msi, build-exe]
  338. steps:
  339. - name: Download .msi
  340. uses: actions/download-artifact@v3
  341. with:
  342. name: msi
  343. path: msi
  344. - name: Download .exe
  345. uses: actions/download-artifact@v3
  346. with:
  347. name: exe
  348. path: exe
  349. - name: Collect files
  350. run: |
  351. mkdir files
  352. cp msi/*.msi files
  353. cp exe/*.exe files
  354. - name: Upload to Kaspersky
  355. uses: SamKirkland/FTP-Deploy-Action@v4.3.4
  356. with:
  357. protocol: ftps
  358. server: allowlist.kaspersky-labs.com
  359. port: 990
  360. username: ${{ secrets.ALLOWLIST_KASPERSKY_USERNAME }}
  361. password: ${{ secrets.ALLOWLIST_KASPERSKY_PASSWORD }}
  362. local-dir: files/
  363. - name: Upload to Avast
  364. uses: SamKirkland/FTP-Deploy-Action@v4.3.4
  365. with:
  366. protocol: ftp
  367. server: whitelisting.avast.com
  368. port: 21
  369. username: ${{ secrets.ALLOWLIST_AVAST_USERNAME }}
  370. password: ${{ secrets.ALLOWLIST_AVAST_PASSWORD }}
  371. local-dir: files/