upgrade OkHttp, add Conscrypt (#1083)
* upgrade OkHttp, add Conscrypt * fix tests
This commit is contained in:
parent
479d210e64
commit
d43b4fef4b
4 changed files with 21 additions and 87 deletions
|
@ -94,8 +94,9 @@ dependencies {
|
||||||
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
||||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
|
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
|
||||||
implementation 'com.squareup.picasso:picasso:2.5.2'
|
implementation 'com.squareup.picasso:picasso:2.5.2'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
|
implementation 'com.squareup.okhttp3:okhttp:3.13.1'
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
|
implementation 'com.squareup.okhttp3:logging-interceptor:3.13.1'
|
||||||
|
implementation "org.conscrypt:conscrypt-android:2.0.0"
|
||||||
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
|
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
|
||||||
implementation 'com.github.connyduck:sparkbutton:2.0.0'
|
implementation 'com.github.connyduck:sparkbutton:2.0.0'
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
|
|
|
@ -32,6 +32,10 @@ import com.keylesspalace.tusky.util.EmojiCompatFont;
|
||||||
import com.keylesspalace.tusky.util.NotificationPullJobCreator;
|
import com.keylesspalace.tusky.util.NotificationPullJobCreator;
|
||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
import org.conscrypt.Conscrypt;
|
||||||
|
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import dagger.android.AndroidInjector;
|
import dagger.android.AndroidInjector;
|
||||||
|
@ -62,6 +66,8 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
|
initSecurityProvider();
|
||||||
|
|
||||||
appDatabase = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tuskyDB")
|
appDatabase = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tuskyDB")
|
||||||
.allowMainThreadQueries()
|
.allowMainThreadQueries()
|
||||||
.addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5,
|
.addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5,
|
||||||
|
@ -93,6 +99,10 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void initSecurityProvider() {
|
||||||
|
Security.insertProviderAt(Conscrypt.newProvider(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method will load the EmojiCompat font which has been selected.
|
* This method will load the EmojiCompat font which has been selected.
|
||||||
* If this font does not work or if the user hasn't selected one (yet), it will use a
|
* If this font does not work or if the user hasn't selected one (yet), it will use a
|
||||||
|
|
|
@ -19,49 +19,21 @@ import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.keylesspalace.tusky.BuildConfig;
|
import com.keylesspalace.tusky.BuildConfig;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.security.KeyManagementException;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import androidx.annotation.NonNull;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
|
|
||||||
import okhttp3.Cache;
|
import okhttp3.Cache;
|
||||||
import okhttp3.ConnectionSpec;
|
|
||||||
import okhttp3.Interceptor;
|
import okhttp3.Interceptor;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
|
|
||||||
public class OkHttpUtils {
|
public class OkHttpUtils {
|
||||||
private static final String TAG = "OkHttpUtils"; // logging tag
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes a Builder with the maximum range of TLS versions and cipher suites enabled.
|
|
||||||
* <p>
|
|
||||||
* It first tries the "approved" list of cipher suites given in OkHttp (the default in
|
|
||||||
* ConnectionSpec.MODERN_TLS) and if that doesn't work falls back to the set of ALL enabled,
|
|
||||||
* then falls back to plain http.
|
|
||||||
* <p>
|
|
||||||
* API level 24 has a regression in elliptic curves where it only supports secp256r1, so this
|
|
||||||
* first tries a fallback without elliptic curves at all, and then tries them after.
|
|
||||||
* <p>
|
|
||||||
* TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20.
|
|
||||||
*/
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static OkHttpClient.Builder getCompatibleClientBuilder(@NonNull Context context) {
|
public static OkHttpClient.Builder getCompatibleClientBuilder(@NonNull Context context) {
|
||||||
|
|
||||||
|
@ -77,25 +49,13 @@ public class OkHttpUtils {
|
||||||
httpPort = -1;
|
httpPort = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionSpec fallback = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
||||||
.allEnabledCipherSuites()
|
|
||||||
.supportsTlsExtensions(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<ConnectionSpec> specList = new ArrayList<>();
|
|
||||||
specList.add(ConnectionSpec.MODERN_TLS);
|
|
||||||
addNougatFixConnectionSpec(specList);
|
|
||||||
specList.add(fallback);
|
|
||||||
specList.add(ConnectionSpec.CLEARTEXT);
|
|
||||||
|
|
||||||
int cacheSize = 25*1024*1024; // 25 MiB
|
int cacheSize = 25*1024*1024; // 25 MiB
|
||||||
|
|
||||||
OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
||||||
.addInterceptor(getUserAgentInterceptor())
|
.addInterceptor(getUserAgentInterceptor())
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
.writeTimeout(30, TimeUnit.SECONDS)
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
.cache(new Cache(context.getCacheDir(), cacheSize))
|
.cache(new Cache(context.getCacheDir(), cacheSize));
|
||||||
.connectionSpecs(specList);
|
|
||||||
|
|
||||||
if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) {
|
if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) {
|
||||||
InetSocketAddress address = InetSocketAddress.createUnresolved(httpServer, httpPort);
|
InetSocketAddress address = InetSocketAddress.createUnresolved(httpServer, httpPort);
|
||||||
|
@ -121,47 +81,6 @@ public class OkHttpUtils {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Android version Nougat has a regression where elliptic curve cipher suites are supported, but
|
|
||||||
* only the curve secp256r1 is allowed. So, first it's best to just disable all elliptic
|
|
||||||
* ciphers, try the connection, and fall back to the all cipher suites enabled list after.
|
|
||||||
*/
|
|
||||||
private static void addNougatFixConnectionSpec(List<ConnectionSpec> specList) {
|
|
||||||
if (Build.VERSION.SDK_INT != Build.VERSION_CODES.N) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SSLSocketFactory socketFactory;
|
|
||||||
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);
|
|
||||||
socketFactory = sslContext.getSocketFactory();
|
|
||||||
} catch (NoSuchAlgorithmException|KeyStoreException|KeyManagementException e) {
|
|
||||||
Log.e(TAG, "Failed obtaining the SSL socket factory.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String[] cipherSuites = socketFactory.getDefaultCipherSuites();
|
|
||||||
ArrayList<String> allowedList = new ArrayList<>();
|
|
||||||
for (String suite : cipherSuites) {
|
|
||||||
if (!suite.contains("ECDH")) {
|
|
||||||
allowedList.add(suite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
||||||
.cipherSuites(allowedList.toArray(new String[0]))
|
|
||||||
.supportsTlsExtensions(true)
|
|
||||||
.build();
|
|
||||||
specList.add(spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,10 @@ class FakeTuskyApplication : TuskyApplication() {
|
||||||
|
|
||||||
lateinit var locator: ServiceLocator
|
lateinit var locator: ServiceLocator
|
||||||
|
|
||||||
|
override fun initSecurityProvider() {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
override fun initAppInjector() {
|
override fun initAppInjector() {
|
||||||
// No-op
|
// No-op
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue