diff --git a/src/main/kotlin/me/proxer/app/MainApplication.kt b/src/main/kotlin/me/proxer/app/MainApplication.kt index 93895c53..011f9b65 100755 --- a/src/main/kotlin/me/proxer/app/MainApplication.kt +++ b/src/main/kotlin/me/proxer/app/MainApplication.kt @@ -152,7 +152,16 @@ class MainApplication : Application() { .build() val vmPolicy = StrictModeCompat.VmPolicy.Builder() - .detectAll() + .detectActivityLeaks() + .detectCleartextNetwork() + .detectFileUriExposure() + .detectLeakedClosableObjects() + .detectLeakedRegistrationObjects() + .detectLeakedSqlLiteObjects() + .detectContentUriWithoutPermission() + .detectNonSdkApiUsage() + .detectImplicitDirectBoot() + .detectCredentialProtectedWhileLocked() .penaltyLog() .build() diff --git a/src/main/kotlin/me/proxer/app/MainModules.kt b/src/main/kotlin/me/proxer/app/MainModules.kt index 6dfd07ec..263032d8 100644 --- a/src/main/kotlin/me/proxer/app/MainModules.kt +++ b/src/main/kotlin/me/proxer/app/MainModules.kt @@ -1,7 +1,6 @@ package me.proxer.app import android.content.res.Resources -import android.os.Build import androidx.preference.PreferenceManager import androidx.room.Room import androidx.security.crypto.EncryptedSharedPreferences @@ -55,6 +54,7 @@ import me.proxer.app.profile.settings.ProfileSettingsViewModel import me.proxer.app.profile.topten.TopTenViewModel import me.proxer.app.settings.status.ServerStatusViewModel import me.proxer.app.ui.LinkCheckViewModel +import me.proxer.app.util.Mp4UploadTrustManagerWorkaround import me.proxer.app.util.Validators import me.proxer.app.util.data.HawkMoshiParser import me.proxer.app.util.data.InstantJsonAdapter @@ -87,7 +87,6 @@ import org.koin.dsl.module import org.threeten.bp.Instant import java.io.File import java.security.KeyStore -import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager @@ -162,38 +161,10 @@ private val applicationModules = module { else -> null } - val trustManager = object : X509TrustManager { - private val platformTrustManager = Platform.get().platformTrustManager() - - override fun getAcceptedIssuers(): Array = platformTrustManager.acceptedIssuers - - override fun checkClientTrusted(certs: Array, authType: String) { - platformTrustManager.checkClientTrusted(certs, authType) - } - - override fun checkServerTrusted(certs: Array, authType: String) { - val mp4UploadCert = certs.find { it.subjectDN.name == "CN=*.mp4upload.com" } - - if (mp4UploadCert != null) { - // The certificate chain of MP4Upload contains an expired cross-signed certificate which incorrectly - // leads to an error on older Android Versions. - // Avoid checking the entire chain here to workaround that. - // - // THIS IS A SECURITY ISSUE AND NEEDS TO BE REMOVED AS SOON AS POSSIBLE. - mp4UploadCert.checkValidity() - } else { - platformTrustManager.checkServerTrusted(certs, authType) - } - } - } + val trustManager = Mp4UploadTrustManagerWorkaround.create() OkHttpClient.Builder() - .apply { - // Tested: Only necessary on Lollipop. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - sslSocketFactory(Platform.get().newSslSocketFactory(trustManager), trustManager) - } - } + .sslSocketFactory(Platform.get().newSslSocketFactory(trustManager), trustManager) .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)) .socketFactory(TaggedSocketFactory()) .connectTimeout(5, TimeUnit.SECONDS) diff --git a/src/main/kotlin/me/proxer/app/util/Mp4UploadTrustManagerWorkaround.kt b/src/main/kotlin/me/proxer/app/util/Mp4UploadTrustManagerWorkaround.kt new file mode 100644 index 00000000..97e71439 --- /dev/null +++ b/src/main/kotlin/me/proxer/app/util/Mp4UploadTrustManagerWorkaround.kt @@ -0,0 +1,93 @@ +package me.proxer.app.util + +import android.os.Build +import androidx.annotation.RequiresApi +import okhttp3.internal.platform.Platform +import java.net.Socket +import java.security.cert.X509Certificate +import javax.net.ssl.SSLEngine +import javax.net.ssl.X509ExtendedTrustManager +import javax.net.ssl.X509TrustManager + +object Mp4UploadTrustManagerWorkaround { + + fun create(): X509TrustManager { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + createSdk24() + } else { + createSdk21() + } + } + + private fun createSdk21(): X509TrustManager { + return object : X509TrustManager { + private val platformTrustManager = Platform.get().platformTrustManager() + + override fun getAcceptedIssuers(): Array = platformTrustManager.acceptedIssuers + + override fun checkClientTrusted(chain: Array, authType: String) { + platformTrustManager.checkClientTrusted(chain, authType) + } + + override fun checkServerTrusted(chain: Array, authType: String) { + checkServerTrustedWithMp4Upload(chain) { + platformTrustManager.checkServerTrusted(chain, authType) + } + } + } + } + + @RequiresApi(Build.VERSION_CODES.N) + private fun createSdk24(): X509ExtendedTrustManager { + return object : X509ExtendedTrustManager() { + private val platformTrustManager = Platform.get().platformTrustManager() as X509ExtendedTrustManager + + override fun getAcceptedIssuers(): Array = platformTrustManager.acceptedIssuers + + override fun checkClientTrusted(chain: Array, authType: String, socket: Socket) { + platformTrustManager.checkClientTrusted(chain, authType, socket) + } + + override fun checkClientTrusted(chain: Array, authType: String, engine: SSLEngine) { + platformTrustManager.checkClientTrusted(chain, authType, engine) + } + + override fun checkClientTrusted(chain: Array, authType: String) { + platformTrustManager.checkClientTrusted(chain, authType) + } + + override fun checkServerTrusted(chain: Array, authType: String, socket: Socket) { + checkServerTrustedWithMp4Upload(chain) { + platformTrustManager.checkServerTrusted(chain, authType, socket) + } + } + + override fun checkServerTrusted(chain: Array, authType: String, engine: SSLEngine) { + checkServerTrustedWithMp4Upload(chain) { + platformTrustManager.checkServerTrusted(chain, authType, engine) + } + } + + override fun checkServerTrusted(chain: Array, authType: String) { + checkServerTrustedWithMp4Upload(chain) { + platformTrustManager.checkServerTrusted(chain, authType) + } + } + } + } + + private fun checkServerTrustedWithMp4Upload(chain: Array, delegate: () -> Unit) { + val mp4UploadCert = chain.find { it.subjectDN.name == "CN=*.mp4upload.com" } + + if (mp4UploadCert != null) { + // The certificate chain of MP4Upload contains an expired cross-signed certificate which incorrectly + // leads to an error on various Android Versions. + // Avoid checking the entire chain here to workaround that. + // + // THIS IS A SECURITY ISSUE AND NEEDS TO BE REMOVED AS SOON AS POSSIBLE. + mp4UploadCert.checkValidity() + } else { + delegate() + } + } +}