diff --git a/app/build.gradle b/app/build.gradle index 0e83e107..363d5a21 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -119,6 +119,7 @@ dependencies { implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" + implementation "eu.szkolny:ssl-provider:1.0.0" implementation "pl.szczodrzynski:navlib:0.7.2" implementation "pl.szczodrzynski:numberslidingpicker:2921225f76" implementation "pl.szczodrzynski:recyclertablayout:700f980584" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 8fac3da3..d8a2ec6a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -26,6 +26,8 @@ import com.google.firebase.messaging.FirebaseMessaging import com.google.gson.Gson import com.hypertrack.hyperlog.HyperLog import com.mikepenz.iconics.Iconics +import eu.szkolny.sslprovider.SSLProvider +import eu.szkolny.sslprovider.enableSupportedTls import im.wangchao.mhttp.MHttp import kotlinx.coroutines.* import me.leolin.shortcutbadger.ShortcutBadger @@ -44,6 +46,7 @@ import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity import pl.szczodrzynski.edziennik.utils.* import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.managers.* +import timber.log.Timber import java.util.concurrent.TimeUnit import kotlin.coroutines.CoroutineContext @@ -94,17 +97,20 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { | __ | | | | | | ___/ | | | | | | | | | | |_| |_| |_| |_| |*/ - val http: OkHttpClient by lazy { + lateinit var http: OkHttpClient + lateinit var httpLazy: OkHttpClient + + private fun buildHttp() { val builder = OkHttpClient.Builder() - .cache(null) - .followRedirects(true) - .followSslRedirects(true) - .retryOnConnectionFailure(true) - .cookieJar(cookieJar) - .connectTimeout(15, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - builder.installHttpsSupport(this) + .cache(null) + .followRedirects(true) + .followSslRedirects(true) + .retryOnConnectionFailure(true) + .cookieJar(cookieJar) + .connectTimeout(15, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .enableSupportedTls(enableCleartext = true) if (devMode) { HyperLog.initialize(this) @@ -115,13 +121,14 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { builder.addInterceptor(chuckerInterceptor) } - builder.build() - } - val httpLazy: OkHttpClient by lazy { - http.newBuilder() - .followRedirects(false) - .followSslRedirects(false) - .build() + http = builder.build() + + httpLazy = http.newBuilder() + .followRedirects(false) + .followSslRedirects(false) + .build() + + MHttp.instance().customOkHttpClient(http) } val cookieJar by lazy { DumbCookieJar(this) } @@ -170,7 +177,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { db.profileDao().firstId?.let { profileLoadById(it) } } - MHttp.instance().customOkHttpClient(http) + buildHttp() Themes.themeInt = config.ui.theme config.ui.language?.let { @@ -183,6 +190,13 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { withContext(Dispatchers.Default) { config.migrate(this@App) + SSLProvider.install(applicationContext, downloadIfNeeded = true, supportTls13 = true, onFinish = { + buildHttp() + }, onError = { + Timber.e("Failed to install SSLProvider: $it") + it.printStackTrace() + }) + if (config.devModePassword != null) checkDevModePassword() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index 71febada..d7855364 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -40,7 +40,6 @@ import androidx.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.viewpager.widget.ViewPager -import com.google.android.gms.security.ProviderInstaller import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.gson.* @@ -50,10 +49,7 @@ import im.wangchao.mhttp.Response import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import okhttp3.ConnectionSpec -import okhttp3.OkHttpClient import okhttp3.RequestBody -import okhttp3.TlsVersion import okio.Buffer import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -63,7 +59,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Notification import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Team -import pl.szczodrzynski.edziennik.network.TLSSocketFactory import pl.szczodrzynski.edziennik.utils.models.Time import java.io.InterruptedIOException import java.io.PrintWriter @@ -73,17 +68,13 @@ import java.net.ConnectException import java.net.SocketTimeoutException import java.net.UnknownHostException import java.nio.charset.Charset -import java.security.KeyStore import java.security.MessageDigest import java.text.SimpleDateFormat import java.util.* import java.util.zip.CRC32 import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec -import javax.net.ssl.SSLContext import javax.net.ssl.SSLException -import javax.net.ssl.TrustManagerFactory -import javax.net.ssl.X509TrustManager import kotlin.Pair @@ -1107,40 +1098,6 @@ fun Cursor?.getString(columnName: String) = this?.getStringOrNull(getColumnIndex fun Cursor?.getInt(columnName: String) = this?.getIntOrNull(getColumnIndex(columnName)) fun Cursor?.getLong(columnName: String) = this?.getLongOrNull(getColumnIndex(columnName)) -fun OkHttpClient.Builder.installHttpsSupport(context: Context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) { - try { - try { - ProviderInstaller.installIfNeeded(context) - } catch (e: Exception) { - Log.e("OkHttpTLSCompat", "Play Services not found or outdated") - - val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) - trustManagerFactory.init(null as KeyStore?) - - val x509TrustManager = trustManagerFactory.trustManagers.singleOrNull { it is X509TrustManager } as X509TrustManager? - ?: return - - val sc = SSLContext.getInstance("TLSv1.2") - sc.init(null, null, null) - sslSocketFactory(TLSSocketFactory(sc.socketFactory), x509TrustManager) - val cs: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .tlsVersions(TlsVersion.TLS_1_0) - .tlsVersions(TlsVersion.TLS_1_1) - .tlsVersions(TlsVersion.TLS_1_2) - .build() - val specs: MutableList = ArrayList() - specs.add(cs) - specs.add(ConnectionSpec.COMPATIBLE_TLS) - specs.add(ConnectionSpec.CLEARTEXT) - connectionSpecs(specs) - } - } catch (exc: Exception) { - Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc) - } - } -} - fun CharSequence.containsAll(list: List, ignoreCase: Boolean = false): Boolean { for (i in list) { if (!contains(i, ignoreCase))