Loading app/build.gradle +3 −0 Original line number Original line Diff line number Diff line Loading @@ -150,6 +150,9 @@ dependencies { //logger //logger implementation 'com.jakewharton.timber:timber:5.0.1' implementation 'com.jakewharton.timber:timber:5.0.1' // Bouncy Castle implementation 'org.bouncycastle:bcpg-jdk15on:1.60' // Retrofit // Retrofit def retrofit_version = "2.9.0" def retrofit_version = "2.9.0" implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:retrofit:$retrofit_version" Loading app/src/main/assets/f-droid.org-signing-key.gpg 0 → 100644 +7.83 KiB File added.No diff preview for this file type. View file app/src/main/java/foundation/e/apps/api/cleanapk/ApkSignatureManager.kt 0 → 100644 +100 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 ECORP * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ package foundation.e.apps.api.cleanapk import android.content.Context import org.bouncycastle.jce.provider.BouncyCastleProvider import org.bouncycastle.openpgp.PGPCompressedData import org.bouncycastle.openpgp.PGPPublicKeyRingCollection import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignatureList import org.bouncycastle.openpgp.PGPUtil import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator import java.io.BufferedInputStream import java.io.FileInputStream import java.io.InputStream import java.security.Security object ApkSignatureManager { fun verifyFdroidSignature(context: Context, apkFilePath: String, signature: String): Boolean { Security.addProvider(BouncyCastleProvider()) return verifyAPKSignature( BufferedInputStream(FileInputStream(apkFilePath)), signature.byteInputStream(Charsets.UTF_8), context.assets.open("f-droid.org-signing-key.gpg") ) } private fun verifyAPKSignature( apkInputStream: BufferedInputStream, apkSignatureInputStream: InputStream, publicKeyInputStream: InputStream ): Boolean { try { val signature = extractSignature(apkSignatureInputStream) val pgpPublicKeyRingCollection = PGPPublicKeyRingCollection( PGPUtil.getDecoderStream(publicKeyInputStream), JcaKeyFingerprintCalculator() ) val key = pgpPublicKeyRingCollection.getPublicKey(signature.keyID) signature.init(BcPGPContentVerifierBuilderProvider(), key) updateSignature(apkInputStream, signature) return signature.verify() } catch (e: Exception) { e.printStackTrace() } finally { apkInputStream.close() apkSignatureInputStream.close() publicKeyInputStream.close() } return false } private fun extractSignature(apkSignatureInputStream: InputStream): PGPSignature { var jcaPGPObjectFactory = JcaPGPObjectFactory(PGPUtil.getDecoderStream(apkSignatureInputStream)) val pgpSignatureList: PGPSignatureList val pgpObject = jcaPGPObjectFactory.nextObject() if (pgpObject is PGPCompressedData) { jcaPGPObjectFactory = JcaPGPObjectFactory(pgpObject.dataStream) pgpSignatureList = jcaPGPObjectFactory.nextObject() as PGPSignatureList } else { pgpSignatureList = pgpObject as PGPSignatureList } val signature = pgpSignatureList.get(0) return signature } private fun updateSignature( apkInputStream: BufferedInputStream, signature: PGPSignature ) { val buff = ByteArray(1024) var read = apkInputStream.read(buff) while (read != -1) { signature.update(buff, 0, read) read = apkInputStream.read(buff) } } } app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt +5 −1 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package foundation.e.apps.api.cleanapk package foundation.e.apps.api.cleanapk import android.os.Build import android.util.Log import android.util.Log import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.fasterxml.jackson.dataformat.yaml.YAMLFactory Loading Loading @@ -161,7 +162,10 @@ object RetrofitModule { fun provideInterceptor(): Interceptor { fun provideInterceptor(): Interceptor { return Interceptor { chain -> return Interceptor { chain -> val builder = chain.request().newBuilder() val builder = chain.request().newBuilder() builder.header("Accept-Language", Locale.getDefault().language) builder.header( "User-Agent", "Dalvik/2.1.0 (Linux; U; Android ${Build.VERSION.RELEASE};)" ).header("Accept-Language", Locale.getDefault().language) try { try { return@Interceptor chain.proceed(builder.build()) return@Interceptor chain.proceed(builder.build()) } catch (e: ConnectException) { } catch (e: ConnectException) { Loading app/src/main/java/foundation/e/apps/api/fdroid/FdroidApiInterface.kt +2 −1 Original line number Original line Diff line number Diff line package foundation.e.apps.api.fdroid package foundation.e.apps.api.fdroid import foundation.e.apps.api.fdroid.models.FdroidApiModel import foundation.e.apps.api.fdroid.models.FdroidApiModel import retrofit2.Response import retrofit2.http.GET import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Path Loading @@ -15,5 +16,5 @@ interface FdroidApiInterface { } } @GET("{packageName}.yml") @GET("{packageName}.yml") suspend fun getFdroidInfoForPackage(@Path("packageName") packageName: String): FdroidApiModel? suspend fun getFdroidInfoForPackage(@Path("packageName") packageName: String): Response<FdroidApiModel?> } } Loading
app/build.gradle +3 −0 Original line number Original line Diff line number Diff line Loading @@ -150,6 +150,9 @@ dependencies { //logger //logger implementation 'com.jakewharton.timber:timber:5.0.1' implementation 'com.jakewharton.timber:timber:5.0.1' // Bouncy Castle implementation 'org.bouncycastle:bcpg-jdk15on:1.60' // Retrofit // Retrofit def retrofit_version = "2.9.0" def retrofit_version = "2.9.0" implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:retrofit:$retrofit_version" Loading
app/src/main/assets/f-droid.org-signing-key.gpg 0 → 100644 +7.83 KiB File added.No diff preview for this file type. View file
app/src/main/java/foundation/e/apps/api/cleanapk/ApkSignatureManager.kt 0 → 100644 +100 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 ECORP * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ package foundation.e.apps.api.cleanapk import android.content.Context import org.bouncycastle.jce.provider.BouncyCastleProvider import org.bouncycastle.openpgp.PGPCompressedData import org.bouncycastle.openpgp.PGPPublicKeyRingCollection import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignatureList import org.bouncycastle.openpgp.PGPUtil import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator import java.io.BufferedInputStream import java.io.FileInputStream import java.io.InputStream import java.security.Security object ApkSignatureManager { fun verifyFdroidSignature(context: Context, apkFilePath: String, signature: String): Boolean { Security.addProvider(BouncyCastleProvider()) return verifyAPKSignature( BufferedInputStream(FileInputStream(apkFilePath)), signature.byteInputStream(Charsets.UTF_8), context.assets.open("f-droid.org-signing-key.gpg") ) } private fun verifyAPKSignature( apkInputStream: BufferedInputStream, apkSignatureInputStream: InputStream, publicKeyInputStream: InputStream ): Boolean { try { val signature = extractSignature(apkSignatureInputStream) val pgpPublicKeyRingCollection = PGPPublicKeyRingCollection( PGPUtil.getDecoderStream(publicKeyInputStream), JcaKeyFingerprintCalculator() ) val key = pgpPublicKeyRingCollection.getPublicKey(signature.keyID) signature.init(BcPGPContentVerifierBuilderProvider(), key) updateSignature(apkInputStream, signature) return signature.verify() } catch (e: Exception) { e.printStackTrace() } finally { apkInputStream.close() apkSignatureInputStream.close() publicKeyInputStream.close() } return false } private fun extractSignature(apkSignatureInputStream: InputStream): PGPSignature { var jcaPGPObjectFactory = JcaPGPObjectFactory(PGPUtil.getDecoderStream(apkSignatureInputStream)) val pgpSignatureList: PGPSignatureList val pgpObject = jcaPGPObjectFactory.nextObject() if (pgpObject is PGPCompressedData) { jcaPGPObjectFactory = JcaPGPObjectFactory(pgpObject.dataStream) pgpSignatureList = jcaPGPObjectFactory.nextObject() as PGPSignatureList } else { pgpSignatureList = pgpObject as PGPSignatureList } val signature = pgpSignatureList.get(0) return signature } private fun updateSignature( apkInputStream: BufferedInputStream, signature: PGPSignature ) { val buff = ByteArray(1024) var read = apkInputStream.read(buff) while (read != -1) { signature.update(buff, 0, read) read = apkInputStream.read(buff) } } }
app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt +5 −1 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package foundation.e.apps.api.cleanapk package foundation.e.apps.api.cleanapk import android.os.Build import android.util.Log import android.util.Log import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.fasterxml.jackson.dataformat.yaml.YAMLFactory Loading Loading @@ -161,7 +162,10 @@ object RetrofitModule { fun provideInterceptor(): Interceptor { fun provideInterceptor(): Interceptor { return Interceptor { chain -> return Interceptor { chain -> val builder = chain.request().newBuilder() val builder = chain.request().newBuilder() builder.header("Accept-Language", Locale.getDefault().language) builder.header( "User-Agent", "Dalvik/2.1.0 (Linux; U; Android ${Build.VERSION.RELEASE};)" ).header("Accept-Language", Locale.getDefault().language) try { try { return@Interceptor chain.proceed(builder.build()) return@Interceptor chain.proceed(builder.build()) } catch (e: ConnectException) { } catch (e: ConnectException) { Loading
app/src/main/java/foundation/e/apps/api/fdroid/FdroidApiInterface.kt +2 −1 Original line number Original line Diff line number Diff line package foundation.e.apps.api.fdroid package foundation.e.apps.api.fdroid import foundation.e.apps.api.fdroid.models.FdroidApiModel import foundation.e.apps.api.fdroid.models.FdroidApiModel import retrofit2.Response import retrofit2.http.GET import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Path Loading @@ -15,5 +16,5 @@ interface FdroidApiInterface { } } @GET("{packageName}.yml") @GET("{packageName}.yml") suspend fun getFdroidInfoForPackage(@Path("packageName") packageName: String): FdroidApiModel? suspend fun getFdroidInfoForPackage(@Path("packageName") packageName: String): Response<FdroidApiModel?> } }