From 7d70931c863e1649551a217ba4f5f308c3cd745e Mon Sep 17 00:00:00 2001 From: Lukas Holzner Date: Fri, 2 Oct 2026 16:57:56 +0200 Subject: [PATCH] Wave 3 (#3): encrypted keystore in repo, passphrase-only secret --- .gitea/workflows/release.yml | 27 +++++++++++---------------- android/release-keystore.enc | Bin 0 -> 2672 bytes 2 files changed, 11 insertions(+), 16 deletions(-) create mode 100644 android/release-keystore.enc diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 9d70c69..01a63cf 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -2,10 +2,10 @@ # Gitea release, so Obtainium can track updates. See issue #3. # # Required repository secrets (Settings → Secrets → Actions): -# RELEASE_KEYSTORE_BASE64 — base64 of android/mindlist-release.keystore -# RELEASE_STORE_PASSWORD — keystore password -# RELEASE_KEY_ALIAS — key alias (mindlist) -# RELEASE_KEY_PASSWORD — key password +# KEYSTORE_PASSPHRASE — decrypts android/release-keystore.enc (committed) +# RELEASE_STORE_PASSWORD — keystore password +# RELEASE_KEY_ALIAS — key alias (mindlist) +# RELEASE_KEY_PASSWORD — key password # # Obtainium: Add App → Gitea → paste the repo URL. If the repo is private, # enter an access token (account → Settings → Applications → token with @@ -73,23 +73,18 @@ jobs: npx cap sync android - name: Restore release keystore + # The keystore lives in git AES-encrypted (android/release-keystore.enc); + # only this short passphrase travels as a secret, so there is no + # multi-KB paste to corrupt. Decryption is verified by hash + keytool. env: - KS1: ${{ secrets.RELEASE_KS_1 }} - KS2: ${{ secrets.RELEASE_KS_2 }} - KS3: ${{ secrets.RELEASE_KS_3 }} - KS4: ${{ secrets.RELEASE_KS_4 }} + ENC_PASS: ${{ secrets.KEYSTORE_PASSPHRASE }} STORE_PASSWORD: ${{ secrets.RELEASE_STORE_PASSWORD }} KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }} KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }} run: | - test -n "$KS1" || { echo "::error::Missing RELEASE_KS_* secrets"; exit 1; } - # Per-chunk integrity first (pinpoints a bad paste), then full hash. - # NB: printf, not echo — reference hashes are over raw chunk bytes. - printf '%s' "$KS1" | sha256sum | grep -q '^52725c9484af20ba' || { echo "::error::keystore chunk 1 mismatch"; exit 1; } - printf '%s' "$KS2" | sha256sum | grep -q '^9babcf38c4486686' || { echo "::error::keystore chunk 2 mismatch"; exit 1; } - printf '%s' "$KS3" | sha256sum | grep -q '^570b472c2ff9f449' || { echo "::error::keystore chunk 3 mismatch"; exit 1; } - printf '%s' "$KS4" | sha256sum | grep -q '^294b486d5531b5ae' || { echo "::error::keystore chunk 4 mismatch"; exit 1; } - printf '%s%s%s%s' "$KS1" "$KS2" "$KS3" "$KS4" | base64 -d > android/mindlist-release.keystore + test -n "$ENC_PASS" || { echo "::error::Missing KEYSTORE_PASSPHRASE secret"; exit 1; } + openssl enc -d -aes-256-cbc -pbkdf2 -in android/release-keystore.enc \ + -out android/mindlist-release.keystore -pass pass:"$ENC_PASS" printf 'storeFile=../mindlist-release.keystore\nstorePassword=%s\nkeyAlias=%s\nkeyPassword=%s\n' \ "$STORE_PASSWORD" "$KEY_ALIAS" "$KEY_PASSWORD" > android/keystore.properties echo "sdk.dir=$ANDROID_HOME" > android/local.properties diff --git a/android/release-keystore.enc b/android/release-keystore.enc new file mode 100644 index 0000000000000000000000000000000000000000..eaa876e4ceb6e38794e49953afaa4437533fc8a6 GIT binary patch literal 2672 zcmV-$3Xk@-wm<~Wr7Eq18*qwG|nXH zhETKp6oGr-)0_jMFNb(6n)mN}&huv%=5T(jq*DJvnj8^M;wQJs7`~D%M~F;-6(u<8@5k|;yEjU&snK`i{f_?r%)kjveVCT1X8_A{y9nBl-a`S_&1OVEbvs?zBulH zoq?#owE5|Bp4OcdNG$d!pAYd3({R+lU%F%JTsb`UoS{h^evPm5-dkz)Nvj<%xkqIes|=S2n} z{E*qtuSMN1E2^Z=jSM5eGdq8urg;Er@egLcljXMM1C`XEv<*25k|g`MbzZ5Oju(Cm z#I+;Hac9#13PDEZ=YQEc%M-#+1tS8N>e!hIO??yXI*PR6&49<$zR1Q*E@5*_CGtcE zrJ^-7ThP^6b-|Yf=R683BQ6MVws{s5=r740kdJBgV8zd1;6e0eCLBfXxzizf1 z+v!uuhR)fMli#|0`7jhuwZ3v^Plf^Cg(mVOr%a#8fZvrA3Q;KV?8y@e$on`L-ZM^L z1+ERPD7$rH7hcVlm4J_}nbb^2Uni(f=5_2NYGb0cC1#bIoNUDKpGsoAm%h==O>Nn#)ludHkQF;b@-!U6QGFCl-2Uy+Axc;q z$`59?KcsGb3|{J(W@8D|C+H;DH;UO&nu7L?v`9sUkZGn{&8F4jnmPyZY(^MQu(fz)@g}$4A5pg*&DP!bMn(3Qb5$OhMPSX-cx?_jq4|s z(J&y`;poSOy~gauDL~Y;rYFsE=N?*_@EO|3_cZE8iDs@A#(thL19~WvSYW%GUISs; zptm?ja5pf@4=u2Y@SMZui*xeZ#FGw#j8!#r&B?#_%4Ny1L3mK|ht!18ao{(;_mHN@DP==w$s=`t{ zQ&ngQAiy-q!rm^IV`m!|^|{EdqOM_P)WD4MOhGAgl0xT*IyS~hhm9uqTKY>gtwmxH zv8O48;^8C#c#yvH^{Dnh9KcxZ!UC{b?3+6J>3Paktns{J*H^N6Dg37|7ncPIk#Z;e zhRt&_Y9t>Hj+0!yB`GH*cTFQHT&JrI|2OHy$}3SwVS1SgT~VfLx5nV89IXJ88_SNo z8eczw@HBvjQy|&Ob0G}DG@1&+5j2Bw6?DlmHV zzoVxDV796xilOJ5?25?olHY12DbZ>oyT`mmZ#D zKL-ZTpVxYgabPv^4V581kN%nuZY@vy(J6y^VW(H@dv;W_Pz!4Ho!~CNP9BQBek854 z{nT0@A#F!5jUTweR+Qb$2(3H_!%xDR=jPVtI|yA6%~wM{1@0zWCr-P0txf5Zmlwl& z^u7G5j)l8iFoXt-;`d8%Lw9n5W(1k61=8Hu5a~?fr7B;bB>-`Y>cEgp3TAE-bGM7uB7)XQ7-Q5B% zZ>$pFjeMU+#W3)kDDTVwc%mQWy&>Q7EuZCaRjvR_l~h=-9)jwYom6H67>S(8FU(68>vV;OrZ1kL-fiQOb3)D+ACZP^lu0^_&O!Fu%nOm$0O(Kskn zwE90Z5-sf*#n%&(9~lsxK2#>n^eDnbeJX$KPT|=Q|3P$#y&lD77DxznkO4_Z9HHnT zUWSUFg$pWt{E4?feK4^lV!>;S0K0<`e0>r^I#c#P=-wsyCpbPj@j0h6`{MF5qVm8d zEwXAWshYsz)SkXcjmjJ(eq7ZkEX`0DBZz~aaC>Pi#rWW<2&B|+J5LJy%o;Y&dFpPY zYD-Dj_{7|smMvir{TTb|MrEx)$Z;Feg{>%vO} zjVLBkzHFcV(>gwKpe8eI0c&fn5O(>;B@D#N1r+}oIR3n@6|{8`pNH|Hk>aQXeD~zG z02^)+Zb*1~xH0`gLnG|!94%V!@aI?Ta32UJu;All^3=T<|cP+G6nz31j zVr(7x7{f*)GpK2VowxIDRy+q!}g}rO>n-o+K;vj zQNT!6C&qz9r4)hq-UFJGo%&~@NEv2j`J*@qaMG6``+Pcp!_YdXT|7?Hp>&Nh0Dy^I%O1W#${EqO?GzzQx8vV46YzM{ eQ(~9KQG=(d7qbN+6OkK^neAA+#n+`>fpz4;MI}N2 literal 0 HcmV?d00001