mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 23:03:00 +00:00 
			
		
		
		
	Enable TLS v1.1/1.2 for KitKat devices
This enables modern TLS versions in the collection browser, the Downloader and the Player. This is neccessary because media.ccc.de rejects all older TLS connection attempts, see issue #2777.
This commit is contained in:
		| @@ -1,20 +1,32 @@ | ||||
| package org.schabi.newpipe; | ||||
|  | ||||
| import android.os.Build; | ||||
| import android.text.TextUtils; | ||||
|  | ||||
| import org.schabi.newpipe.extractor.downloader.Downloader; | ||||
| import org.schabi.newpipe.extractor.downloader.Request; | ||||
| import org.schabi.newpipe.extractor.downloader.Response; | ||||
| import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; | ||||
| import org.schabi.newpipe.util.TLSSocketFactoryCompat; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.security.KeyManagementException; | ||||
| import java.security.KeyStore; | ||||
| import java.security.KeyStoreException; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import javax.net.ssl.SSLContext; | ||||
| import javax.net.ssl.SSLSocketFactory; | ||||
| import javax.net.ssl.TrustManager; | ||||
| import javax.net.ssl.TrustManagerFactory; | ||||
| import javax.net.ssl.X509TrustManager; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
|  | ||||
| import okhttp3.OkHttpClient; | ||||
| @@ -29,6 +41,9 @@ public class DownloaderImpl extends Downloader { | ||||
|     private OkHttpClient client; | ||||
|  | ||||
|     private DownloaderImpl(OkHttpClient.Builder builder) { | ||||
|         if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { | ||||
|             enableModernTLS(builder); | ||||
|         } | ||||
|         this.client = builder | ||||
|                 .readTimeout(30, TimeUnit.SECONDS) | ||||
|                 //.cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024)) | ||||
| @@ -154,4 +169,34 @@ public class DownloaderImpl extends Downloader { | ||||
|  | ||||
|         return new Response(response.code(), response.message(), response.headers().toMultimap(), responseBodyToReturn); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Enable TLS 1.2 and 1.1 on Android Kitkat. This function is mostly taken from the documentation of | ||||
|      * OkHttpClient.Builder.sslSocketFactory(_,_) | ||||
|      * | ||||
|      * If there is an error, It will safely fall back to doing nothing and printing the Error to the console. | ||||
|      * @param builder The HTTPClient Builder on which TLS is enabled on (will be modified in-place) | ||||
|      */ | ||||
|     private static void enableModernTLS(OkHttpClient.Builder builder) { | ||||
|         try { | ||||
|             TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( | ||||
|                     TrustManagerFactory.getDefaultAlgorithm()); | ||||
|             trustManagerFactory.init((KeyStore) null); | ||||
|             TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); | ||||
|             if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { | ||||
|                 throw new IllegalStateException("Unexpected default trust managers:" | ||||
|                         + Arrays.toString(trustManagers)); | ||||
|             } | ||||
|             X509TrustManager trustManager = (X509TrustManager) trustManagers[0]; | ||||
|  | ||||
|             SSLContext sslContext = SSLContext.getInstance("TLS"); | ||||
|             sslContext.init(null, new TrustManager[] { trustManager }, null); | ||||
|             //SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); | ||||
|             SSLSocketFactory sslSocketFactory = TLSSocketFactoryCompat.getInstance(); | ||||
|  | ||||
|             builder.sslSocketFactory(sslSocketFactory, trustManager); | ||||
|         } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -72,6 +72,7 @@ import org.schabi.newpipe.util.PeertubeHelper; | ||||
| import org.schabi.newpipe.util.PermissionHelper; | ||||
| import org.schabi.newpipe.util.ServiceHelper; | ||||
| import org.schabi.newpipe.util.StateSaver; | ||||
| import org.schabi.newpipe.util.TLSSocketFactoryCompat; | ||||
| import org.schabi.newpipe.util.ThemeHelper; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| @@ -108,6 +109,10 @@ public class MainActivity extends AppCompatActivity { | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]"); | ||||
|  | ||||
|         //enable TLS1.1/1.2 for kitkat devices, to fix download and play for mediaCCC sources | ||||
|         if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) | ||||
|             TLSSocketFactoryCompat.setAsDefault(); | ||||
|  | ||||
|         ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this)); | ||||
|  | ||||
|         super.onCreate(savedInstanceState); | ||||
|   | ||||
| @@ -0,0 +1,127 @@ | ||||
| package org.schabi.newpipe.util; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.net.InetAddress; | ||||
| import java.net.Socket; | ||||
| import java.net.UnknownHostException; | ||||
| import java.security.KeyManagementException; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
|  | ||||
| import javax.net.ssl.HttpsURLConnection; | ||||
| import javax.net.ssl.SSLContext; | ||||
| import javax.net.ssl.SSLSocket; | ||||
| import javax.net.ssl.SSLSocketFactory; | ||||
| import javax.net.ssl.TrustManager; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * This is an extension of the SSLSocketFactory which enables TLS 1.2 and 1.1. | ||||
|  * Created for usage on Android 4.1-4.4 devices, which haven't enabled those by default. | ||||
|  */ | ||||
| public class TLSSocketFactoryCompat extends SSLSocketFactory { | ||||
|  | ||||
|  | ||||
|     private static TLSSocketFactoryCompat instance=null; | ||||
|  | ||||
|     private SSLSocketFactory internalSSLSocketFactory; | ||||
|  | ||||
|     public static TLSSocketFactoryCompat getInstance() throws NoSuchAlgorithmException, KeyManagementException { | ||||
|         if(instance!=null) | ||||
|             return instance; | ||||
|         return instance=new TLSSocketFactoryCompat(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public TLSSocketFactoryCompat() throws KeyManagementException, NoSuchAlgorithmException { | ||||
|         SSLContext context = SSLContext.getInstance("TLS"); | ||||
|         context.init(null, null, null); | ||||
|         internalSSLSocketFactory = context.getSocketFactory(); | ||||
|     } | ||||
|  | ||||
|     public TLSSocketFactoryCompat(TrustManager[] tm) throws KeyManagementException, NoSuchAlgorithmException { | ||||
|         SSLContext context = SSLContext.getInstance("TLS"); | ||||
|         context.init(null, tm, new java.security.SecureRandom()); | ||||
|         internalSSLSocketFactory = context.getSocketFactory(); | ||||
|     } | ||||
|  | ||||
|     public static void setAsDefault() { | ||||
|         try { | ||||
|             HttpsURLConnection.setDefaultSSLSocketFactory(getInstance()); | ||||
|         } catch (NoSuchAlgorithmException | KeyManagementException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String[] getDefaultCipherSuites() { | ||||
|         return internalSSLSocketFactory.getDefaultCipherSuites(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String[] getSupportedCipherSuites() { | ||||
|         return internalSSLSocketFactory.getSupportedCipherSuites(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Socket createSocket() throws IOException { | ||||
|         return enableTLSOnSocket(internalSSLSocketFactory.createSocket()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { | ||||
|         return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Socket createSocket(String host, int port) throws IOException, UnknownHostException { | ||||
|         return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { | ||||
|         return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Socket createSocket(InetAddress host, int port) throws IOException { | ||||
|         return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { | ||||
|         return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); | ||||
|     } | ||||
|  | ||||
|     private Socket enableTLSOnSocket(Socket socket) { | ||||
|         if(socket != null && (socket instanceof SSLSocket)) { | ||||
|             /* | ||||
|             //Create list of supported protocols | ||||
|             ArrayList<String> supportedProtocols = new ArrayList<>(); | ||||
|             for (String protocol : ((SSLSocket)socket).getEnabledProtocols()) { | ||||
|  | ||||
|                 //Log.d("TLSSocketFactory", "Supported protocol:" + protocol); | ||||
|                 //Only add TLS protocols (don't want ot support older SSL versions) | ||||
|                 if (protocol.toUpperCase().contains("TLS")) { | ||||
|                     supportedProtocols.add(protocol); | ||||
|                 } | ||||
|             } | ||||
|             //Force add TLSv1.1 and 1.2 if not already added | ||||
|             if (!supportedProtocols.contains("TLSv1.1")) { | ||||
|                 supportedProtocols.add("TLSv1.1"); | ||||
|             } | ||||
|             if (!supportedProtocols.contains("TLSv1.2")) { | ||||
|                 supportedProtocols.add("TLSv1.2"); | ||||
|             } | ||||
|  | ||||
|             String[] protocolArray = supportedProtocols.toArray(new String[supportedProtocols.size()]); | ||||
|  | ||||
|             //enable protocols in our list | ||||
|             //((SSLSocket)socket).setEnabledProtocols(protocolArray); | ||||
|             */ | ||||
|             // OR: only enable TLS 1.1 and 1.2! | ||||
|             ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"}); | ||||
|  | ||||
|         } | ||||
|         return socket; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Markus Richter
					Markus Richter