From d38cd2547a251b1cbaa52fe54042744cfd6376cf Mon Sep 17 00:00:00 2001
From: paronos <paronos@users.noreply.github.com>
Date: Sun, 25 Mar 2018 17:08:29 +0200
Subject: [PATCH] Enable TLS 1.1 and TLS 1.2 on Android KitKat (and older)
 (#1316)

* Enable TLS 1.1 and TLS 1.2 on Android KitKat (and older)

* enable SSLv3

* use extension function
---
 .../kanade/tachiyomi/network/NetworkHelper.kt | 85 +++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt
index b8f5d756ab..97d4b4d7da 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt
@@ -1,9 +1,22 @@
 package eu.kanade.tachiyomi.network
 
 import android.content.Context
+import android.os.Build
 import okhttp3.Cache
 import okhttp3.OkHttpClient
 import java.io.File
+import java.io.IOException
+import java.net.InetAddress
+import java.net.Socket
+import java.net.UnknownHostException
+import java.security.KeyManagementException
+import java.security.KeyStore
+import java.security.NoSuchAlgorithmException
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
 
 class NetworkHelper(context: Context) {
 
@@ -16,6 +29,7 @@ class NetworkHelper(context: Context) {
     val client = OkHttpClient.Builder()
             .cookieJar(cookieManager)
             .cache(Cache(cacheDir, cacheSize))
+            .enableTLS12()
             .build()
 
     val cloudflareClient = client.newBuilder()
@@ -25,4 +39,75 @@ class NetworkHelper(context: Context) {
     val cookies: PersistentCookieStore
         get() = cookieManager.store
 
+    private fun OkHttpClient.Builder.enableTLS12(): OkHttpClient.Builder {
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
+            return this
+        }
+
+        val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+        trustManagerFactory.init(null as KeyStore?)
+        val trustManagers = trustManagerFactory.trustManagers
+        if (trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
+            class TLSSocketFactory @Throws(KeyManagementException::class, NoSuchAlgorithmException::class)
+            constructor() : SSLSocketFactory() {
+
+                private val internalSSLSocketFactory: SSLSocketFactory
+
+                init {
+                    val context = SSLContext.getInstance("TLS")
+                    context.init(null, null, null)
+                    internalSSLSocketFactory = context.socketFactory
+                }
+
+                override fun getDefaultCipherSuites(): Array<String> {
+                    return internalSSLSocketFactory.defaultCipherSuites
+                }
+
+                override fun getSupportedCipherSuites(): Array<String> {
+                    return internalSSLSocketFactory.supportedCipherSuites
+                }
+
+                @Throws(IOException::class)
+                override fun createSocket(): Socket? {
+                    return enableTLSOnSocket(internalSSLSocketFactory.createSocket())
+                }
+
+                @Throws(IOException::class)
+                override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket? {
+                    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose))
+                }
+
+                @Throws(IOException::class, UnknownHostException::class)
+                override fun createSocket(host: String, port: Int): Socket? {
+                    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
+                }
+
+                @Throws(IOException::class, UnknownHostException::class)
+                override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket? {
+                    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort))
+                }
+
+                @Throws(IOException::class)
+                override fun createSocket(host: InetAddress, port: Int): Socket? {
+                    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
+                }
+
+                @Throws(IOException::class)
+                override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket? {
+                    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort))
+                }
+
+                private fun enableTLSOnSocket(socket: Socket?): Socket? {
+                    if (socket != null && socket is SSLSocket) {
+                        socket.enabledProtocols = socket.supportedProtocols
+                    }
+                    return socket
+                }
+            }
+
+            sslSocketFactory(TLSSocketFactory(), trustManagers[0] as X509TrustManager)
+        }
+
+        return this
+    }
 }