diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7fa1d2..9519186 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,8 +56,25 @@ jobs: exit 1 fi if [[ "$tidal_src" == *.apkm ]]; then - echo "Extracting base.apk from $tidal_src" - unzip -p "$tidal_src" base.apk > ./dist/tidal-stock.apk + echo "Extracting & merging splits from $tidal_src" + workdir=$(mktemp -d) + unzip -q "$tidal_src" -d "$workdir" + cp "$workdir/base.apk" ./dist/tidal-stock.apk + + # Merge native libs from arm64-v8a split into base.apk + for split in "$workdir"/split_config.arm64_v8a.apk \ + "$workdir"/split_config.xxhdpi.apk \ + "$workdir"/split_config.en.apk; do + [ -f "$split" ] || continue + echo "Merging $(basename "$split")" + libdir=$(mktemp -d) + unzip -q "$split" -d "$libdir" + # Drop META-INF (signatures) and the split's manifest + rm -rf "$libdir/META-INF" "$libdir/AndroidManifest.xml" + (cd "$libdir" && zip -qr "$OLDPWD/dist/tidal-stock.apk" .) + rm -rf "$libdir" + done + rm -rf "$workdir" else cp "$tidal_src" ./dist/tidal-stock.apk fi diff --git a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/patcher/steps/download/DownloadTidalStep.kt b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/patcher/steps/download/DownloadTidalStep.kt index ec73308..e08b754 100644 --- a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/patcher/steps/download/DownloadTidalStep.kt +++ b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/patcher/steps/download/DownloadTidalStep.kt @@ -1,19 +1,13 @@ package com.meowarex.rlmobile.patcher.steps.download -import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.runtime.Stable import com.meowarex.rlmobile.R import com.meowarex.rlmobile.manager.PathManager import com.meowarex.rlmobile.patcher.StepRunner import com.meowarex.rlmobile.patcher.steps.base.DownloadStep import com.meowarex.rlmobile.patcher.steps.prepare.FetchInfoStep -import com.android.apksig.ApkVerifier -import okio.ByteString.Companion.decodeHex -import okio.ByteString.Companion.toByteString import org.koin.core.component.KoinComponent import org.koin.core.component.inject -import java.io.File @Stable class DownloadTidalStep : DownloadStep(), KoinComponent { @@ -29,51 +23,4 @@ class DownloadTidalStep : DownloadStep(), KoinComponent { override fun getStoredFile(container: StepRunner) = paths.cachedTidalApk(getVersion(container)) - - override suspend fun verify(container: StepRunner) { - super.verify(container) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - container.log("Verifying APK signature") - verifySignature(getStoredFile(container)) - } else { - container.log("Skipping APK signature verification, API level too old") - } - } - - @RequiresApi(Build.VERSION_CODES.P) - private fun verifySignature(apk: File) { - val verifier = ApkVerifier.Builder(apk).build() - val result = try { - verifier.verify() - } catch (e: Exception) { - throw IllegalStateException("Failed to verify APK! It may have been corrupted or tampered with.", e) - } - - if (!result.isVerified) - throw SignatureVerificationException(result.allErrors) - - if (TIDAL_CERTIFICATE_SHA256 != null) { - if (result.signerCertificates.singleOrNull() - ?.let { it.encoded.toByteString().sha256() == TIDAL_CERTIFICATE_SHA256.decodeHex() } != true - ) { - throw VerifyError("Failed to verify TIDAL APK signatures! This is an unoriginal APK that has been tampered with.") - } - } - } - - private companion object { - // TODO: populate with actual TIDAL signing certificate SHA-256 - // Run: apksigner verify --print-certs tidal.apk - val TIDAL_CERTIFICATE_SHA256: String? = null - - fun getStoredFilePath(paths: PathManager, version: Int): File = - paths.cachedTidalApk(version) - } - - private class SignatureVerificationException(errors: List) : Exception( - "Failed to verify APK signatures! " + - "This is an unoriginal APK that has been tampered with. " + - "Verification errors: " + errors.joinToString() - ) }