diff --git a/app/build.gradle b/app/build.gradle index e695e1d44..989e687b8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "fr.gouv.etalab.mastodon" minSdkVersion 15 targetSdkVersion 25 - versionCode 6 - versionName "1.0.6" + versionCode 7 + versionName "1.1.0" } buildTypes { release { diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java index bf55f53d0..fee1fc9cc 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java @@ -50,6 +50,7 @@ import java.util.HashMap; import fr.gouv.etalab.mastodon.asynctasks.UpdateAccountInfoByIDAsyncTask; import fr.gouv.etalab.mastodon.client.Entities.Account; +import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; import fr.gouv.etalab.mastodon.fragments.DisplayAccountsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment; import fr.gouv.etalab.mastodon.helper.Helper; @@ -115,12 +116,12 @@ public class MainActivity extends AppCompatActivity navigationView.setNavigationItemSelectedListener(this); - //Image loader configuration imageLoader = ImageLoader.getInstance(); File cacheDir = new File(getCacheDir(), getString(R.string.app_name)); ImageLoaderConfiguration configImg = new ImageLoaderConfiguration.Builder(this) .threadPoolSize(5) + .imageDownloader(new PatchBaseImageDownloader(getApplicationContext())) .threadPriority(Thread.MIN_PRIORITY + 3) .denyCacheImageMultipleSizesInMemory() .diskCache(new UnlimitedDiskCache(cacheDir)) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/PatchBaseImageDownloader.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/PatchBaseImageDownloader.java new file mode 100644 index 000000000..a80527c1d --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/PatchBaseImageDownloader.java @@ -0,0 +1,127 @@ +package fr.gouv.etalab.mastodon.client; + +import android.content.Context; + +import com.nostra13.universalimageloader.core.assist.ContentLengthInputStream; +import com.nostra13.universalimageloader.core.download.BaseImageDownloader; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.Socket; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +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; +import javax.net.ssl.X509TrustManager; + +/** + * Created by Thomas on 21/05/2017. + * Patch for universal image loader to support TLS 1.1+ + */ + +public class PatchBaseImageDownloader extends BaseImageDownloader { + + private SSLSocketFactory sf; + + public PatchBaseImageDownloader(Context context) { + super(context); + + initSSLSocketFactory(); + } + + private void initSSLSocketFactory() { + sf = (SSLSocketFactory) SSLSocketFactory.getDefault(); + try { + sf = new MySSLSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException { + HttpURLConnection conn = createConnection(imageUri, extra); + if (conn instanceof HttpsURLConnection) { + ((HttpsURLConnection) conn).setSSLSocketFactory(sf); + } + return new ContentLengthInputStream(new BufferedInputStream(conn.getInputStream(), BUFFER_SIZE), conn.getContentLength()); + } + + private static class MySSLSocketFactory extends SSLSocketFactory { + SSLContext sslContext = SSLContext.getInstance("TLS"); + + MySSLSocketFactory() throws Exception { + super(); + TrustManager tm = new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + + sslContext.init(null, new TrustManager[]{tm}, null); + } + + @Override + public String[] getDefaultCipherSuites() { + return new String[0]; + } + + @Override + public String[] getSupportedCipherSuites() { + return new String[0]; + } + + + @Override + public Socket createSocket(String host, int port) throws IOException { + return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(address, port, localAddress, localPort)); + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { + return enableTLSOnSocket(sslContext.getSocketFactory().createSocket(socket, host, port, autoClose)); + } + + @Override + public Socket createSocket() throws IOException { + return enableTLSOnSocket(sslContext.getSocketFactory().createSocket()); + } + + private Socket enableTLSOnSocket(Socket socket) { + if(socket != null && (socket instanceof SSLSocket)) { + ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"}); + } + return socket; + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java index 2d187e900..41ed06f85 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java @@ -37,6 +37,7 @@ import java.util.concurrent.TimeUnit; import fr.gouv.etalab.mastodon.asynctasks.RetrieveHomeTimelineServiceAsyncTask; import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Status; +import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveHomeTimelineServiceInterface; import fr.gouv.etalab.mastodon.sqlite.AccountDAO; @@ -132,6 +133,7 @@ public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineSe ImageLoader imageLoaderNoty = ImageLoader.getInstance(); File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name)); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext()) + .imageDownloader(new PatchBaseImageDownloader(getContext())) .threadPoolSize(5) .threadPriority(Thread.MIN_PRIORITY + 3) .denyCacheImageMultipleSizesInMemory() diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java index a116e1b2f..84510a7e1 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java @@ -36,6 +36,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; import fr.gouv.etalab.mastodon.helper.Helper; import mastodon.etalab.gouv.fr.mastodon.R; import fr.gouv.etalab.mastodon.asynctasks.RetrieveNotificationsAsyncTask; @@ -190,6 +191,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications ImageLoader imageLoaderNoty = ImageLoader.getInstance(); File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name)); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext()) + .imageDownloader(new PatchBaseImageDownloader(getContext())) .threadPoolSize(5) .threadPriority(Thread.MIN_PRIORITY + 3) .denyCacheImageMultipleSizesInMemory()