diff --git a/.gitea/play-key-export/encryption_public_key.pem b/.gitea/play-key-export/encryption_public_key.pem new file mode 100644 index 0000000..21a951a --- /dev/null +++ b/.gitea/play-key-export/encryption_public_key.pem @@ -0,0 +1,11 @@ +-----BEGIN PUBLIC KEY----- +MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAsovs0QR6VmHX+q1Zv3SQ +WIkcR04Vwv4WLhbOt/OAaW2dBFsmRyskPx5W5RJ9gS12/BU8sUKAUh4aALwQMfLS +u4Tugb6FpI5rBY10ydMx6D1EbU+UMwdIlBnm8EYoI5oUdY9VEjWihUZHSoBnC/LW +/UbJx+HmA7tA7BEIx4KBmOmZUTnDSCRTi48IBjfKslZem6bkcTeIrxzY+faBZYRM +s9Q11kxEsHbpIJ8af1HTO7JtCRxAlGkzFsT7IyVOtVdpLTKlPcuVsocyY0/Wl641 +O9YmEutJnyoQbAekQnkJxyNeq1BuT5syhS6nEDUwqKgiahKHuWr99MqFLDEkuZZ+ +rKXDlb1j3CJ0wTAu68aizCtOFMoOuVJjd/rHmuyRePpvZXsql03tQW5PP3R2yrKe +KFSPVNmhWhWqZiaXoqyyLK7uoxjLgF/K0ekHHcKivTm4WvT52V5TTsN2jleMbkpM +EO2KajkBwWkvVBcTaUmt9yFq4fzifPq2z1sebP3RRycTAgMBAAE= +-----END PUBLIC KEY----- diff --git a/.gitea/workflows/play-key-export.yml b/.gitea/workflows/play-key-export.yml new file mode 100644 index 0000000..8e514df --- /dev/null +++ b/.gitea/workflows/play-key-export.yml @@ -0,0 +1,77 @@ +# ONE-SHOT, never merged: exports the release signing key for Play App Signing +# ("Export and upload a key from Java keystore"). Lives only on the branch +# chore/play-key-export and runs when that branch is pushed; the branch is +# deleted once the zip is uploaded to the Play Console. +# +# What leaves the run: output.zip, which PEPK encrypts with Google's public key +# (.gitea/play-key-export/encryption_public_key.pem), so only Google can open it. +# What the log shows: the certificate's SHA-256 (public; it is in every APK) and +# pepk.jar's checksum. Nothing derived from a secret is ever printed: no set -x, +# no echo of a variable, the keystore is decoded to a private temp dir and removed. + +name: Play key export (one-shot) + +on: + push: + branches: + - chore/play-key-export + +jobs: + export: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Install JDK 17 + run: | + apt-get update + apt-get install -y curl openjdk-17-jdk-headless + + - name: Check out this branch + uses: actions/checkout@v4 + + - name: Export the signing key, encrypted to Google + env: + ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} + ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + # The certificate every Gitea release APK is signed with (v0.6.0). + EXPECTED_SHA256: '59:7B:79:ED:54:2A:91:43:73:59:03:5D:3F:C4:39:B5:DA:8B:D8:E7:26:E7:30:03:B8:B4:1A:F6:0E:14:A4:82' + run: | + set -euo pipefail + umask 077 + WORK="$(mktemp -d)" + trap 'rm -rf "$WORK"' EXIT + printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > "$WORK/release.jks" + + FP="$(keytool -list -v -keystore "$WORK/release.jks" -storepass "$ANDROID_KEYSTORE_PASSWORD" \ + -alias "$ANDROID_KEY_ALIAS" | sed -n 's/^[[:space:]]*SHA256: //p')" + echo "Keystore certificate SHA-256: ${FP}" + if [ "$FP" != "$EXPECTED_SHA256" ]; then + echo "::error::not the key the release APKs are signed with; nothing exported" + exit 1 + fi + + curl -fsSL -o "$WORK/pepk.jar" \ + https://www.gstatic.com/play-apps-publisher-rapid/signing-tool/prod/pepk.jar + echo "pepk.jar SHA-256: $(sha256sum "$WORK/pepk.jar" | cut -d' ' -f1)" + + mkdir -p out + java -jar "$WORK/pepk.jar" \ + --keystore="$WORK/release.jks" \ + --alias="$ANDROID_KEY_ALIAS" \ + --keystore-pass="$ANDROID_KEYSTORE_PASSWORD" \ + --key-pass="$ANDROID_KEY_PASSWORD" \ + --output="$PWD/out/output.zip" \ + --include-cert \ + --rsa-aes-encryption \ + --encryption-key-path=.gitea/play-key-export/encryption_public_key.pem \ + > /dev/null 2>&1 || { echo "::error::pepk failed (its output is suppressed)"; exit 1; } + ls -l out/output.zip + + - name: Upload the encrypted zip + uses: actions/upload-artifact@v3 + with: + name: play-signing-key-export + path: out/output.zip + retention-days: 1