Improve app signature check

This commit is contained in:
Isira Seneviratne 2023-11-27 09:08:53 +05:30 committed by Tobi
parent 7edd471ec5
commit bec18e13d3
1 changed files with 15 additions and 73 deletions

View File

@ -1,97 +1,39 @@
package org.schabi.newpipe.util package org.schabi.newpipe.util
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.Signature
import androidx.core.content.pm.PackageInfoCompat import androidx.core.content.pm.PackageInfoCompat
import org.schabi.newpipe.App import org.schabi.newpipe.App
import org.schabi.newpipe.error.ErrorInfo import org.schabi.newpipe.error.ErrorInfo
import org.schabi.newpipe.error.ErrorUtil.Companion.createNotification import org.schabi.newpipe.error.ErrorUtil.Companion.createNotification
import org.schabi.newpipe.error.UserAction import org.schabi.newpipe.error.UserAction
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateEncodingException
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.time.Instant import java.time.Instant
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
object ReleaseVersionUtil { object ReleaseVersionUtil {
// Public key of the certificate that is used in NewPipe release versions // Public key of the certificate that is used in NewPipe release versions
private const val RELEASE_CERT_PUBLIC_KEY_SHA1 = private const val RELEASE_CERT_PUBLIC_KEY_SHA256 =
"B0:2E:90:7C:1C:D6:FC:57:C3:35:F0:88:D0:8F:50:5F:94:E4:D2:15" "cb84069bd68116bafae5ee4ee5b08a567aa6d898404e7cb12f9e756df5cf5cab"
@JvmStatic @JvmStatic
fun isReleaseApk(): Boolean { fun isReleaseApk(): Boolean {
return certificateSHA1Fingerprint == RELEASE_CERT_PUBLIC_KEY_SHA1 @Suppress("NewApi")
} val certificates = mapOf(
RELEASE_CERT_PUBLIC_KEY_SHA256.toByteArray() to PackageManager.CERT_INPUT_SHA256
/**
* Method to get the APK's SHA1 key. See https://stackoverflow.com/questions/9293019/#22506133.
*
* @return String with the APK's SHA1 fingerprint in hexadecimal
*/
private val certificateSHA1Fingerprint: String
get() {
val app = App.getApp()
val signatures: List<Signature> = try {
PackageInfoCompat.getSignatures(app.packageManager, app.packageName)
} catch (e: PackageManager.NameNotFoundException) {
showRequestError(app, e, "Could not find package info")
return ""
}
if (signatures.isEmpty()) {
return ""
}
val x509cert = try {
val cf = CertificateFactory.getInstance("X509")
cf.generateCertificate(signatures[0].toByteArray().inputStream()) as X509Certificate
} catch (e: CertificateException) {
showRequestError(app, e, "Certificate error")
return ""
}
return try {
val md = MessageDigest.getInstance("SHA1")
val publicKey = md.digest(x509cert.encoded)
byte2HexFormatted(publicKey)
} catch (e: NoSuchAlgorithmException) {
showRequestError(app, e, "Could not retrieve SHA1 key")
""
} catch (e: CertificateEncodingException) {
showRequestError(app, e, "Could not retrieve SHA1 key")
""
}
}
private fun byte2HexFormatted(arr: ByteArray): String {
val str = StringBuilder(arr.size * 2)
for (i in arr.indices) {
var h = Integer.toHexString(arr[i].toInt())
val l = h.length
if (l == 1) {
h = "0$h"
}
if (l > 2) {
h = h.substring(l - 2, l)
}
str.append(h.uppercase())
if (i < arr.size - 1) {
str.append(':')
}
}
return str.toString()
}
private fun showRequestError(app: App, e: Exception, request: String) {
createNotification(
app, ErrorInfo(e, UserAction.CHECK_FOR_NEW_APP_VERSION, request)
) )
val app = App.getApp()
return try {
PackageInfoCompat.hasSignatures(app.packageManager, app.packageName, certificates, false)
} catch (e: PackageManager.NameNotFoundException) {
createNotification(
app, ErrorInfo(e, UserAction.CHECK_FOR_NEW_APP_VERSION, "Could not find package info")
)
false
}
} }
fun isLastUpdateCheckExpired(expiry: Long): Boolean { fun isLastUpdateCheckExpired(expiry: Long): Boolean {
return Instant.ofEpochSecond(expiry).isBefore(Instant.now()) return Instant.ofEpochSecond(expiry) < Instant.now()
} }
/** /**