diff --git a/app/src/main/assets/*.wikimedia.beta.wmflabs.org.cer b/app/src/main/assets/*.wikimedia.beta.wmflabs.org.cer new file mode 100644 index 0000000000..ffb4c37c99 Binary files /dev/null and b/app/src/main/assets/*.wikimedia.beta.wmflabs.org.cer differ diff --git a/app/src/main/java/fr/free/nrw/commons/OkHttpConnectionFactory.java b/app/src/main/java/fr/free/nrw/commons/OkHttpConnectionFactory.java index 6fe317c0a4..3e7f973031 100644 --- a/app/src/main/java/fr/free/nrw/commons/OkHttpConnectionFactory.java +++ b/app/src/main/java/fr/free/nrw/commons/OkHttpConnectionFactory.java @@ -8,6 +8,8 @@ import java.io.File; import java.io.IOException; +import fr.free.nrw.commons.di.SslUtils; +import fr.free.nrw.commons.utils.ConfigUtils; import okhttp3.Cache; import okhttp3.Interceptor; import okhttp3.OkHttpClient; @@ -29,13 +31,17 @@ public final class OkHttpConnectionFactory { @NonNull private static OkHttpClient createClient() { - return new OkHttpClient.Builder() + OkHttpClient.Builder builder = new OkHttpClient.Builder() .cookieJar(SharedPreferenceCookieManager.getInstance()) .cache(NET_CACHE) .addInterceptor(getLoggingInterceptor()) .addInterceptor(new UnsuccessfulResponseInterceptor()) - .addInterceptor(new CommonHeaderRequestInterceptor()) - .build(); + .addInterceptor(new CommonHeaderRequestInterceptor()); + + if(ConfigUtils.isBetaFlavour()){ + builder.sslSocketFactory(SslUtils.INSTANCE.getSslContextForCertificateFile(CommonsApplication.getInstance(), "*.wikimedia.beta.wmflabs.org.cer").getSocketFactory()); + } + return builder.build(); } private static HttpLoggingInterceptor getLoggingInterceptor() { diff --git a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java index c6e6033f58..581ff37fd1 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java @@ -18,6 +18,8 @@ import javax.inject.Named; import javax.inject.Singleton; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; import dagger.Module; import dagger.Provides; @@ -31,6 +33,7 @@ import fr.free.nrw.commons.mwapi.UserInterface; import fr.free.nrw.commons.review.ReviewInterface; import fr.free.nrw.commons.upload.UploadInterface; +import fr.free.nrw.commons.utils.ConfigUtils; import fr.free.nrw.commons.wikidata.WikidataInterface; import okhttp3.Cache; import okhttp3.HttpUrl; @@ -58,14 +61,20 @@ public class NetworkingModule { public OkHttpClient provideOkHttpClient(Context context, HttpLoggingInterceptor httpLoggingInterceptor) { File dir = new File(context.getCacheDir(), "okHttpCache"); - return new OkHttpClient.Builder().connectTimeout(60, TimeUnit.SECONDS) - .writeTimeout(60, TimeUnit.SECONDS) + OkHttpClient.Builder builder = new OkHttpClient.Builder().connectTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) .addInterceptor(httpLoggingInterceptor) - .readTimeout(60, TimeUnit.SECONDS) - .cache(new Cache(dir, OK_HTTP_CACHE_SIZE)) - .build(); + .readTimeout(60, TimeUnit.SECONDS) + .cache(new Cache(dir, OK_HTTP_CACHE_SIZE)); + + if(ConfigUtils.isBetaFlavour()){ + builder.sslSocketFactory(SslUtils.INSTANCE.getSslContextForCertificateFile(context, "*.wikimedia.beta.wmflabs.org.cer").getSocketFactory()); + } + return builder.build(); } + + @Provides @Singleton public HttpLoggingInterceptor provideHttpLoggingInterceptor() { diff --git a/app/src/main/java/fr/free/nrw/commons/di/SslUtils.kt b/app/src/main/java/fr/free/nrw/commons/di/SslUtils.kt new file mode 100644 index 0000000000..a24c6ddf91 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/SslUtils.kt @@ -0,0 +1,90 @@ +package fr.free.nrw.commons.di + +import android.content.Context +import android.util.Log +import java.security.KeyManagementException +import java.security.KeyStore +import java.security.NoSuchAlgorithmException +import java.security.SecureRandom +import java.security.cert.Certificate +import java.security.cert.CertificateException +import java.security.cert.CertificateFactory +import java.security.cert.X509Certificate +import javax.net.ssl.* + +object SslUtils { + + fun getSslContextForCertificateFile(context: Context, fileName: String): SSLContext { + try { + val keyStore = SslUtils.getKeyStore(context, fileName) + val sslContext = SSLContext.getInstance("SSL") + val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) + trustManagerFactory.init(keyStore) + sslContext.init(null, trustManagerFactory.trustManagers, SecureRandom()) + return sslContext + } catch (e: Exception) { + val msg = "Error during creating SslContext for certificate from assets" + e.printStackTrace() + throw RuntimeException(msg) + } + } + + private fun getKeyStore(context: Context, fileName: String): KeyStore? { + var keyStore: KeyStore? = null + try { + val assetManager = context.assets + val cf = CertificateFactory.getInstance("X.509") + val caInput = assetManager.open(fileName) + val ca: Certificate + try { + ca = cf.generateCertificate(caInput) + Log.d("SslUtilsAndroid", "ca=" + (ca as X509Certificate).subjectDN) + } finally { + caInput.close() + } + + val keyStoreType = KeyStore.getDefaultType() + keyStore = KeyStore.getInstance(keyStoreType) + keyStore!!.load(null, null) + keyStore.setCertificateEntry("ca", ca) + } catch (e: Exception) { + e.printStackTrace() + } + + return keyStore + } + + fun getTrustAllHostsSSLSocketFactory(): SSLSocketFactory? { + try { + // Create a trust manager that does not validate certificate chains + val trustAllCerts = arrayOf(object : X509TrustManager { + + override fun getAcceptedIssuers(): Array { + return arrayOf() + } + + @Throws(CertificateException::class) + override fun checkClientTrusted(chain: Array, authType: String) { + } + + @Throws(CertificateException::class) + override fun checkServerTrusted(chain: Array, authType: String) { + } + }) + + // Install the all-trusting trust manager + val sslContext = SSLContext.getInstance("SSL") + sslContext.init(null, trustAllCerts, java.security.SecureRandom()) + // Create an ssl socket factory with our all-trusting manager + + return sslContext.socketFactory + } catch (e: KeyManagementException) { + e.printStackTrace() + return null + } catch (e: NoSuchAlgorithmException) { + e.printStackTrace() + return null + } + + } +} \ No newline at end of file