mirror of
https://github.com/whyorean/AuroraStore.git
synced 2026-04-25 17:29:44 -04:00
HttpClient: Enable SSL pinning for google domains
.pem file obtained from https://pki.goog/roots.pem Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.aurora.store.data.model
|
||||
|
||||
enum class Algorithm(var value: String) {
|
||||
SHA("SHA"),
|
||||
SHA1("SHA-1"),
|
||||
SHA256("SHA-256")
|
||||
}
|
||||
|
||||
@@ -43,18 +43,17 @@ object HttpClient {
|
||||
val proxyEnabled = Preferences.getBoolean(context, Preferences.PREFERENCE_PROXY_ENABLED)
|
||||
val proxyInfoString = Preferences.getString(context, Preferences.PREFERENCE_PROXY_INFO)
|
||||
|
||||
return if (proxyEnabled && proxyInfoString.isNotBlank() && proxyInfoString != "{}") {
|
||||
val okHttpClient = OkHttpClient.builder(context)
|
||||
if (proxyEnabled && proxyInfoString.isNotBlank() && proxyInfoString != "{}") {
|
||||
val proxyInfo = gson.fromJson(proxyInfoString, ProxyInfo::class.java)
|
||||
|
||||
if (proxyInfo != null) {
|
||||
OkHttpClient.setProxy(proxyInfo)
|
||||
} else {
|
||||
Log.e(TAG, "Proxy info is unavailable, using default client")
|
||||
OkHttpClient
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "Proxy is disabled")
|
||||
OkHttpClient
|
||||
}
|
||||
return okHttpClient.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
|
||||
package com.aurora.store.data.network
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.aurora.gplayapi.data.models.PlayResponse
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.model.ProxyInfo
|
||||
import com.aurora.store.util.CertUtil
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -47,7 +49,7 @@ object OkHttpClient : IProxyHttpClient {
|
||||
override val responseCode: StateFlow<Int>
|
||||
get() = _responseCode.asStateFlow()
|
||||
|
||||
private var okHttpClient = OkHttpClient()
|
||||
private lateinit var okHttpClient: okhttp3.OkHttpClient
|
||||
private val okHttpClientBuilder = OkHttpClient().newBuilder()
|
||||
.connectTimeout(25, TimeUnit.SECONDS)
|
||||
.readTimeout(25, TimeUnit.SECONDS)
|
||||
@@ -56,6 +58,16 @@ object OkHttpClient : IProxyHttpClient {
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
|
||||
fun builder(context: Context): OkHttpClient {
|
||||
setupSSLPinning(context)
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): OkHttpClient {
|
||||
okHttpClient = okHttpClientBuilder.build()
|
||||
return this
|
||||
}
|
||||
|
||||
override fun setProxy(proxyInfo: ProxyInfo): OkHttpClient {
|
||||
val proxy = Proxy(
|
||||
if (proxyInfo.protocol == "SOCKS") Proxy.Type.SOCKS else Proxy.Type.HTTP,
|
||||
@@ -80,10 +92,22 @@ object OkHttpClient : IProxyHttpClient {
|
||||
}
|
||||
|
||||
okHttpClientBuilder.proxy(proxy)
|
||||
okHttpClient = okHttpClientBuilder.build()
|
||||
return this
|
||||
}
|
||||
|
||||
private fun setupSSLPinning(context: Context) {
|
||||
// Google needs special handling, see: https://pki.goog/faq/#faq-27
|
||||
val googleRootCerts = CertUtil.getGoogleRootCertHashes(context).map { "sha256/$it" }
|
||||
.toTypedArray()
|
||||
|
||||
val certificatePinner = CertificatePinner.Builder()
|
||||
.add("*.googleapis.com", *googleRootCerts)
|
||||
.add("*.google.com", *googleRootCerts)
|
||||
.build()
|
||||
|
||||
okHttpClientBuilder.certificatePinner(certificatePinner)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun post(url: String, headers: Map<String, String>, requestBody: RequestBody): PlayResponse {
|
||||
val request = Request.Builder()
|
||||
|
||||
@@ -27,8 +27,13 @@ import android.util.Log
|
||||
import com.aurora.extensions.generateX509Certificate
|
||||
import com.aurora.extensions.getInstallerPackageNameCompat
|
||||
import com.aurora.extensions.isPAndAbove
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.model.Algorithm
|
||||
import com.aurora.store.util.PackageUtil.getPackageInfo
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.security.MessageDigest
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
object CertUtil {
|
||||
@@ -52,7 +57,7 @@ object CertUtil {
|
||||
return try {
|
||||
val certificates = getX509Certificates(context, packageName)
|
||||
certificates.map {
|
||||
val messageDigest = MessageDigest.getInstance("SHA")
|
||||
val messageDigest = MessageDigest.getInstance(Algorithm.SHA.value)
|
||||
messageDigest.update(it.encoded)
|
||||
Base64.encodeToString(
|
||||
messageDigest.digest(),
|
||||
@@ -65,6 +70,20 @@ object CertUtil {
|
||||
}
|
||||
}
|
||||
|
||||
fun getGoogleRootCertHashes(context: Context): List<String> {
|
||||
return try {
|
||||
val certs = getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca))
|
||||
certs.map {
|
||||
val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value)
|
||||
messageDigest.update(it.publicKey.encoded)
|
||||
Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to get SHA256 certificate hash", exception)
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSignedByFDroid(context: Context, packageName: String): Boolean {
|
||||
return try {
|
||||
getX509Certificates(context, packageName).any { cert ->
|
||||
@@ -88,6 +107,24 @@ object CertUtil {
|
||||
)
|
||||
}
|
||||
|
||||
private fun getX509Certificates(inputStream: InputStream): List<X509Certificate> {
|
||||
val certificateFactory = CertificateFactory.getInstance("X509")
|
||||
val rawCerts = inputStream
|
||||
.bufferedReader()
|
||||
.use { it.readText() }
|
||||
.split("-----END CERTIFICATE-----")
|
||||
.map {
|
||||
it.substringAfter("-----BEGIN CERTIFICATE-----")
|
||||
.substringBefore("-----END CERTIFICATE-----")
|
||||
.replace("\n", "")
|
||||
}
|
||||
.filterNot { it.isBlank() }
|
||||
val decodedCerts = rawCerts.map { Base64.decode(it, Base64.DEFAULT) }
|
||||
return decodedCerts.map {
|
||||
certificateFactory.generateCertificate(ByteArrayInputStream(it)) as X509Certificate
|
||||
}
|
||||
}
|
||||
|
||||
private fun getX509Certificates(context: Context, packageName: String): List<X509Certificate> {
|
||||
return try {
|
||||
val packageInfo = getPackageInfoWithSignature(context, packageName)
|
||||
|
||||
1128
app/src/main/res/raw/google_roots_ca.pem
Normal file
1128
app/src/main/res/raw/google_roots_ca.pem
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user