diff --git a/.github/workflows/build-mac.yml b/.github/workflows/build-mac.yml index 539aa4c..01b0e3e 100644 --- a/.github/workflows/build-mac.yml +++ b/.github/workflows/build-mac.yml @@ -8,6 +8,10 @@ on: sem-version: description: 'Version' required: false + notarize: + description: 'Notarize app' + required: false + type: boolean permissions: contents: write @@ -28,7 +32,11 @@ jobs: outputs: semVerStr: ${{ steps.determine-version.outputs.version }} semVerNum: ${{steps.determine-number.outputs.number}} + revisionNum: ${{steps.determine-number.outputs.revision}} steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 - id: determine-version shell: pwsh run: | @@ -45,6 +53,8 @@ jobs: run: | SEM_VER_NUM=$(echo "${{ steps.determine-version.outputs.version }}" | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/') echo "number=${SEM_VER_NUM}" >> "$GITHUB_OUTPUT" + REVISION_NUM=`git rev-list --count HEAD` + echo "revision=${REVISION_NUM}" >> "$GITHUB_OUTPUT" build-binary: name: Build java app image @@ -56,9 +66,11 @@ jobs: - os: macos-latest architecture: arm64 artifact-name: cryptomator-cli-${{ needs.prepare.outputs.semVerStr }}-mac-arm64.zip + xcode-path: /Applications/Xcode_16.app - os: macos-13 architecture: x64 artifact-name: cryptomator-cli-${{ needs.prepare.outputs.semVerStr }}-mac-x64.zip + xcode-path: /Applications/Xcode_15.2.app runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -86,15 +98,107 @@ jobs: JP_APP_VERSION: ${{ needs.prepare.outputs.semVerNum }} APP_VERSION: ${{ needs.prepare.outputs.semVerStr }} NATIVE_ACCESS_PACKAGE: org.cryptomator.jfuse.mac - - uses: actions/upload-artifact@v4 - with: - name: cryptomator-cli-mac-${{ matrix.architecture }} - path: ./target/cryptomator-cli.app - if-no-files-found: error - - name: TODO sign binaries - run: echo "TODO sign it and notarize it" - - name: Zip binary for release - run: zip -r ./${{ matrix.artifact-name}} ./target/cryptomator-cli.app + - name: Patch .app dir + run: | + sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" cryptomator-cli.app/Contents/Info.plist + sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" cryptomator-cli.app/Contents/Info.plist + echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode -o "cryptomator-cli.app/Contents/embedded.provisionprofile" + working-directory: target + env: + VERSION_NO: ${{ needs.prepare.outputs.semVerNum }} + REVISION_NO: ${{ needs.prepare.outputs.revisionNum }} + PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }} + - name: Install codesign certificate + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$CODESIGN_P12_BASE64" | base64 --decode -o $CERTIFICATE_PATH + + # create temporary keychain + security create-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH + security set-keychain-settings -lut 900 $KEYCHAIN_PATH + security unlock-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$CODESIGN_P12_PW" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + env: + CODESIGN_P12_BASE64: ${{ secrets.MACOS_CODESIGN_P12_BASE64 }} + CODESIGN_P12_PW: ${{ secrets.MACOS_CODESIGN_P12_PW }} + CODESIGN_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_TMP_KEYCHAIN_PW }} + - name: Codesign + run: | + echo "Codesigning jdk files..." + find cryptomator-cli.app/Contents/runtime/Contents/Home/lib/ -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + find cryptomator-cli.app/Contents/runtime/Contents/Home/lib/ \( -name 'jspawnhelper' -o -name 'pauseengine' -o -name 'simengine' \) -exec codesign --force -o runtime -s ${CODESIGN_IDENTITY} {} \; + echo "Codesigning jar contents..." + find cryptomator-cli.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + for JAR_PATH in `find cryptomator-cli.app -name "*.jar"`; do + if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then + JAR_FILENAME=$(basename ${JAR_PATH}) + OUTPUT_PATH=${JAR_PATH%.*} + echo "Codesigning libs in ${JAR_FILENAME}..." + unzip -q ${JAR_PATH} -d ${OUTPUT_PATH} + find ${OUTPUT_PATH} -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + find ${OUTPUT_PATH} -name '*.jnilib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + rm ${JAR_PATH} + pushd ${OUTPUT_PATH} > /dev/null + zip -qr ../${JAR_FILENAME} * + popd > /dev/null + rm -r ${OUTPUT_PATH} + fi + done + echo "Codesigning Cryptomator-cli.app..." + sed -i '' "s|###APP_IDENTIFIER_PREFIX###|${TEAM_IDENTIFIER}.|g" ../dist/mac/cryptomator-cli.entitlements + sed -i '' "s|###TEAM_IDENTIFIER###|${TEAM_IDENTIFIER}|g" ../dist/mac/cryptomator-cli.entitlements + codesign --force --deep --entitlements ../dist/mac/cryptomator-cli.entitlements -o runtime -s ${CODESIGN_IDENTITY} cryptomator-cli.app + env: + CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }} + TEAM_IDENTIFIER: ${{ secrets.MACOS_TEAM_IDENTIFIER }} + working-directory: target + # ditto must be used, see https://developer.apple.com/documentation/xcode/packaging-mac-software-for-distribution#Build-a-zip-archive + - name: Zip binary for notarization + if: inputs.notarize + run: ditto -c -k --keepParent ./target/cryptomator-cli.app ./${{ matrix.artifact-name}} + - name: Setup Xcode + if: inputs.notarize + run: sudo xcode-select -s ${{ matrix.xcode-path}} + shell: bash + #would like to uses cocoalibs/xcode-notarization-action@v1, but blocked due to https://github.com/cocoalibs/xcode-notarization-action/issues/1 + - name: Prepare Notarization Credentials + if: inputs.notarize + run: | + # create temporary keychain + KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db + KEYCHAIN_PASS=$(uuidgen) + security create-keychain -p "${KEYCHAIN_PASS}" ${KEYCHAIN_PATH} + security set-keychain-settings -lut 900 ${KEYCHAIN_PATH} + security unlock-keychain -p "${KEYCHAIN_PASS}" ${KEYCHAIN_PATH} + # import credentials from secrets + xcrun notarytool store-credentials "notary" --apple-id "${{ secrets.MACOS_NOTARIZATION_APPLE_ID }}" --password "${{ secrets.MACOS_NOTARIZATION_PW }}" --team-id "${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}" --keychain "${KEYCHAIN_PATH}" + shell: bash + - name: Notarize + if: inputs.notarize + run: | + KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db + xcrun notarytool submit ${{ matrix.artifact-name }} --keychain-profile "notary" --keychain "${KEYCHAIN_PATH}" --wait + shell: bash + - name: Staple + if: inputs.notarize + run: xcrun stapler staple ./target/cryptomator-cli.app + shell: bash + - name: Cleanup + if: ${{ always() }} + run: | + rm -f ./${{ matrix.artifact-name}} + security delete-keychain $RUNNER_TEMP/notarization.keychain-db + shell: bash + continue-on-error: true + - name: Zip app for distribution + run: ditto -c -k --keepParent ./target/cryptomator-cli.app ./${{ matrix.artifact-name}} - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import @@ -102,6 +206,13 @@ jobs: env: GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - uses: actions/upload-artifact@v4 + with: + name: cryptomator-cli-mac-${{ matrix.architecture }} + path: | + ${{ matrix.artifact-name}} + *.asc + if-no-files-found: error - name: Publish artefact on GitHub Releases if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' uses: softprops/action-gh-release@v2 @@ -110,5 +221,4 @@ jobs: token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} files: | ${{ matrix.artifact-name }} - cryptomator-cli-*.asc - + cryptomator-cli-*.asc \ No newline at end of file diff --git a/.github/workflows/build-win.yml b/.github/workflows/build-win.yml index 639ba44..febbdfe 100644 --- a/.github/workflows/build-win.yml +++ b/.github/workflows/build-win.yml @@ -78,13 +78,50 @@ jobs: JP_APP_VERSION: ${{ needs.prepare.outputs.semVerNum }} APP_VERSION: ${{ needs.prepare.outputs.semVerStr }} NATIVE_ACCESS_PACKAGE: org.cryptomator.jfuse.win - - uses: actions/upload-artifact@v4 + - name: Fix permissions + run: attrib -r target/cryptomator-cli/cryptomator-cli.exe + shell: pwsh + - name: Extract jars with DLLs for Codesigning + shell: pwsh + run: | + Add-Type -AssemblyName "System.io.compression.filesystem" + $jarFolder = Resolve-Path ".\target\Cryptomator-cli\app\mods" + $jarExtractDir = New-Item -Path ".\target\jar-extract" -ItemType Directory + + #for all jars inspect + Get-ChildItem -Path $jarFolder -Filter "*.jar" | ForEach-Object { + $jar = [Io.compression.zipfile]::OpenRead($_.FullName) + if (@($jar.Entries | Where-Object {$_.Name.ToString().EndsWith(".dll")} | Select-Object -First 1).Count -gt 0) { + #jars containing dlls extract + Set-Location $jarExtractDir + Expand-Archive -Path $_.FullName + } + $jar.Dispose() + } + - name: Codesign + uses: skymatic/code-sign-action@v3 with: - name: cryptomator-cli-win-x64 - path: ./target/cryptomator-cli - if-no-files-found: error - - name: TODO Sign binaries - run: echo TODO + certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} + password: ${{ secrets.WIN_CODESIGN_P12_PW }} + certificatesha1: ${{ vars.WIN_CODESIGN_CERT_SHA1 }} + description: Cryptomator + timestampUrl: 'http://timestamp.digicert.com' + folder: target + recursive: true + - name: Replace DLLs inside jars with signed ones + shell: pwsh + run: | + $jarExtractDir = Resolve-Path ".\target\jar-extract" + $jarFolder = Resolve-Path ".\target\cryptomator-cli\app\mods" + Get-ChildItem -Path $jarExtractDir | ForEach-Object { + $jarName = $_.Name + $jarFile = "${jarFolder}\${jarName}.jar" + Set-Location $_ + Get-ChildItem -Path $_ -Recurse -File "*.dll" | ForEach-Object { + # update jar with signed dll + jar --file="$jarFile" --update $(Resolve-Path -Relative -Path $_) + } + } - name: Zip binary for release shell: pwsh run: Compress-Archive -Path .\target\cryptomator-cli -DestinationPath .\${{ env.artifact-name}} @@ -95,6 +132,13 @@ jobs: env: GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - uses: actions/upload-artifact@v4 + with: + name: cryptomator-cli-win-x64 + path: | + ${{ env.artifact-name}} + *.asc + if-no-files-found: error - name: Publish artefact on GitHub Releases if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' uses: softprops/action-gh-release@v2 diff --git a/dist/mac/cryptomator-cli.entitlements b/dist/mac/cryptomator-cli.entitlements new file mode 100644 index 0000000..b4939b1 --- /dev/null +++ b/dist/mac/cryptomator-cli.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.application-identifier + ###APP_IDENTIFIER_PREFIX###org.cryptomator.cli + com.apple.developer.team-identifier + ###TEAM_IDENTIFIER### + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.disable-library-validation + + +