diff options
3 files changed, 467 insertions, 11 deletions
diff --git a/src/main/java/de/pixart/messenger/http/NoSSLv3SocketFactory.java b/src/main/java/de/pixart/messenger/http/NoSSLv3SocketFactory.java new file mode 100644 index 000000000..2a7794c92 --- /dev/null +++ b/src/main/java/de/pixart/messenger/http/NoSSLv3SocketFactory.java @@ -0,0 +1,419 @@ +package de.pixart.messenger.http; + +/*Copyright 2015 Bhavit Singh Sengar +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License.You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + + +public class NoSSLv3SocketFactory extends SSLSocketFactory { + private final SSLSocketFactory delegate; + + public NoSSLv3SocketFactory() { + this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory(); + } + + public NoSSLv3SocketFactory(SSLSocketFactory delegate) { + this.delegate = delegate; + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + private Socket makeSocketSafe(Socket socket) { + if (socket instanceof SSLSocket) { + socket = new NoSSLv3SSLSocket((SSLSocket) socket); + } + return socket; + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + return makeSocketSafe(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return makeSocketSafe(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort)); + } + + private class NoSSLv3SSLSocket extends DelegateSSLSocket { + + private NoSSLv3SSLSocket(SSLSocket delegate) { + super(delegate); + + } + + @Override + public void setEnabledProtocols(String[] protocols) { + if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) { + + List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols())); + if (enabledProtocols.size() > 1) { + enabledProtocols.remove("SSLv3"); + System.out.println("Removed SSLv3 from enabled protocols"); + } else { + System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols)); + } + protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]); + } + + super.setEnabledProtocols(protocols); + } + } + + public class DelegateSSLSocket extends SSLSocket { + + protected final SSLSocket delegate; + + DelegateSSLSocket(SSLSocket delegate) { + this.delegate = delegate; + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public String[] getEnabledCipherSuites() { + return delegate.getEnabledCipherSuites(); + } + + @Override + public void setEnabledCipherSuites(String[] suites) { + delegate.setEnabledCipherSuites(suites); + } + + @Override + public String[] getSupportedProtocols() { + return delegate.getSupportedProtocols(); + } + + @Override + public String[] getEnabledProtocols() { + return delegate.getEnabledProtocols(); + } + + @Override + public void setEnabledProtocols(String[] protocols) { + delegate.setEnabledProtocols(protocols); + } + + @Override + public SSLSession getSession() { + return delegate.getSession(); + } + + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) { + delegate.addHandshakeCompletedListener(listener); + } + + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) { + delegate.removeHandshakeCompletedListener(listener); + } + + @Override + public void startHandshake() throws IOException { + delegate.startHandshake(); + } + + @Override + public void setUseClientMode(boolean mode) { + delegate.setUseClientMode(mode); + } + + @Override + public boolean getUseClientMode() { + return delegate.getUseClientMode(); + } + + @Override + public void setNeedClientAuth(boolean need) { + delegate.setNeedClientAuth(need); + } + + @Override + public void setWantClientAuth(boolean want) { + delegate.setWantClientAuth(want); + } + + @Override + public boolean getNeedClientAuth() { + return delegate.getNeedClientAuth(); + } + + @Override + public boolean getWantClientAuth() { + return delegate.getWantClientAuth(); + } + + @Override + public void setEnableSessionCreation(boolean flag) { + delegate.setEnableSessionCreation(flag); + } + + @Override + public boolean getEnableSessionCreation() { + return delegate.getEnableSessionCreation(); + } + + @Override + public void bind(SocketAddress localAddr) throws IOException { + delegate.bind(localAddr); + } + + @Override + public synchronized void close() throws IOException { + delegate.close(); + } + + @Override + public void connect(SocketAddress remoteAddr) throws IOException { + delegate.connect(remoteAddr); + } + + @Override + public void connect(SocketAddress remoteAddr, int timeout) throws IOException { + delegate.connect(remoteAddr, timeout); + } + + @Override + public SocketChannel getChannel() { + return delegate.getChannel(); + } + + @Override + public InetAddress getInetAddress() { + return delegate.getInetAddress(); + } + + @Override + public InputStream getInputStream() throws IOException { + return delegate.getInputStream(); + } + + @Override + public boolean getKeepAlive() throws SocketException { + return delegate.getKeepAlive(); + } + + @Override + public InetAddress getLocalAddress() { + return delegate.getLocalAddress(); + } + + @Override + public int getLocalPort() { + return delegate.getLocalPort(); + } + + @Override + public SocketAddress getLocalSocketAddress() { + return delegate.getLocalSocketAddress(); + } + + @Override + public boolean getOOBInline() throws SocketException { + return delegate.getOOBInline(); + } + + @Override + public OutputStream getOutputStream() throws IOException { + return delegate.getOutputStream(); + } + + @Override + public int getPort() { + return delegate.getPort(); + } + + @Override + public synchronized int getReceiveBufferSize() throws SocketException { + return delegate.getReceiveBufferSize(); + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return delegate.getRemoteSocketAddress(); + } + + @Override + public boolean getReuseAddress() throws SocketException { + return delegate.getReuseAddress(); + } + + @Override + public synchronized int getSendBufferSize() throws SocketException { + return delegate.getSendBufferSize(); + } + + @Override + public int getSoLinger() throws SocketException { + return delegate.getSoLinger(); + } + + @Override + public synchronized int getSoTimeout() throws SocketException { + return delegate.getSoTimeout(); + } + + @Override + public boolean getTcpNoDelay() throws SocketException { + return delegate.getTcpNoDelay(); + } + + @Override + public int getTrafficClass() throws SocketException { + return delegate.getTrafficClass(); + } + + @Override + public boolean isBound() { + return delegate.isBound(); + } + + @Override + public boolean isClosed() { + return delegate.isClosed(); + } + + @Override + public boolean isConnected() { + return delegate.isConnected(); + } + + @Override + public boolean isInputShutdown() { + return delegate.isInputShutdown(); + } + + @Override + public boolean isOutputShutdown() { + return delegate.isOutputShutdown(); + } + + @Override + public void sendUrgentData(int value) throws IOException { + delegate.sendUrgentData(value); + } + + @Override + public void setKeepAlive(boolean keepAlive) throws SocketException { + delegate.setKeepAlive(keepAlive); + } + + @Override + public void setOOBInline(boolean oobinline) throws SocketException { + delegate.setOOBInline(oobinline); + } + + @Override + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { + delegate.setPerformancePreferences(connectionTime, latency, bandwidth); + } + + @Override + public synchronized void setReceiveBufferSize(int size) throws SocketException { + delegate.setReceiveBufferSize(size); + } + + @Override + public void setReuseAddress(boolean reuse) throws SocketException { + delegate.setReuseAddress(reuse); + } + + @Override + public synchronized void setSendBufferSize(int size) throws SocketException { + delegate.setSendBufferSize(size); + } + + @Override + public void setSoLinger(boolean on, int timeout) throws SocketException { + delegate.setSoLinger(on, timeout); + } + + @Override + public synchronized void setSoTimeout(int timeout) throws SocketException { + delegate.setSoTimeout(timeout); + } + + @Override + public void setTcpNoDelay(boolean on) throws SocketException { + delegate.setTcpNoDelay(on); + } + + @Override + public void setTrafficClass(int value) throws SocketException { + delegate.setTrafficClass(value); + } + + @Override + public void shutdownInput() throws IOException { + delegate.shutdownInput(); + } + + @Override + public void shutdownOutput() throws IOException { + delegate.shutdownOutput(); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public boolean equals(Object o) { + return delegate.equals(o); + } + } +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/services/UpdateService.java b/src/main/java/de/pixart/messenger/services/UpdateService.java index 64347bd5a..27b40e986 100644 --- a/src/main/java/de/pixart/messenger/services/UpdateService.java +++ b/src/main/java/de/pixart/messenger/services/UpdateService.java @@ -15,13 +15,18 @@ import org.json.JSONObject; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; import de.pixart.messenger.BuildConfig; import de.pixart.messenger.Config; import de.pixart.messenger.R; +import de.pixart.messenger.http.NoSSLv3SocketFactory; import de.pixart.messenger.ui.UpdaterActivity; import me.drakeet.support.toast.ToastCompat; @@ -32,6 +37,7 @@ public class UpdateService extends AsyncTask<String, Object, UpdateService.Wrapp private Context context; private String store; private NotificationService getNotificationService; + public UpdateService() { } @@ -52,9 +58,19 @@ public class UpdateService extends AsyncTask<String, Object, UpdateService.Wrapp if (params[0].equals("true")) { showNoUpdateToast = true; } - + SSLContext sslcontext = null; + SSLSocketFactory NoSSLv3Factory = null; + try { + sslcontext = SSLContext.getInstance("TLSv1"); + if (sslcontext != null) { + sslcontext.init(null, null, null); + NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); + } + } catch (NoSuchAlgorithmException | KeyManagementException e) { + e.printStackTrace(); + } + HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory); HttpsURLConnection connection = null; - try { URL url = new URL(Config.UPDATE_URL); if (mUseTor) { @@ -163,7 +179,7 @@ public class UpdateService extends AsyncTask<String, Object, UpdateService.Wrapp String[] remoteV = null; String[] installedV = null; try { - installedV = installedVersion.split(" "); + installedV = installedVersion.split("-"); Log.d(Config.LOGTAG, "AppUpdater: Version installed: " + installedV[0]); installed = installedV[0].split("\\."); } catch (Exception e) { @@ -172,7 +188,7 @@ public class UpdateService extends AsyncTask<String, Object, UpdateService.Wrapp try { remoteV = remoteVersion.split(" "); if (installedV != null && installedV.length > 1) { - if (installedV[1] != null) { + if (installedV[1] != null && installedV[1].toLowerCase().contains("beta")) { remoteV[0] = remoteV[0] + ".1"; } } diff --git a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java index 6cc3571b5..f3b233f20 100644 --- a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java +++ b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java @@ -25,12 +25,18 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.HttpURLConnection; import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.util.List; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; + import de.pixart.messenger.Config; import de.pixart.messenger.R; +import de.pixart.messenger.http.NoSSLv3SocketFactory; import de.pixart.messenger.persistance.FileBackend; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.utils.WakeLockHelper; @@ -284,7 +290,7 @@ public class UpdaterActivity extends XmppActivity { } private class DownloadTask extends AsyncTask<String, Integer, String> { - + XmppActivity activity; File dir = new File(FileBackend.getAppUpdateDirectory()); File file = new File(dir, FileName); XmppConnectionService xmppConnectionService; @@ -325,7 +331,19 @@ public class UpdaterActivity extends XmppActivity { protected String doInBackground(String... sUrl) { InputStream is = null; OutputStream os = null; - HttpURLConnection connection = null; + SSLContext sslcontext = null; + SSLSocketFactory NoSSLv3Factory = null; + try { + sslcontext = SSLContext.getInstance("TLSv1"); + if (sslcontext != null) { + sslcontext.init(null, null, null); + NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); + } + } catch (NoSuchAlgorithmException | KeyManagementException e) { + e.printStackTrace(); + } + HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory); + HttpsURLConnection connection = null; try { Log.d(Config.LOGTAG, "AppUpdater: save file to " + file.toString()); Log.d(Config.LOGTAG, "AppUpdater: download update from url: " + sUrl[0] + " to file name: " + file.toString()); @@ -333,15 +351,18 @@ public class UpdaterActivity extends XmppActivity { URL url = new URL(sUrl[0]); if (mUseTor) { - connection = (HttpURLConnection) url.openConnection(getProxy()); + connection = (HttpsURLConnection) url.openConnection(getProxy()); } else { - connection = (HttpURLConnection) url.openConnection(); + connection = (HttpsURLConnection) url.openConnection(); } + connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000); + connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000); + connection.setRequestProperty("User-Agent", context.getString(R.string.app_name)); connection.connect(); // expect HTTP 200 OK, so we don't mistakenly save error report // instead of the file - if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { + if (connection.getResponseCode() != HttpsURLConnection.HTTP_OK) { ToastCompat.makeText(getApplicationContext(), getText(R.string.failed), Toast.LENGTH_LONG).show(); return connection.getResponseCode() + ": " + connection.getResponseMessage(); } @@ -355,7 +376,7 @@ public class UpdaterActivity extends XmppActivity { if (parentDirectory.mkdirs()) { Log.d(Config.LOGTAG, "created " + parentDirectory.getAbsolutePath()); } - + // download the file is = connection.getInputStream(); os = new FileOutputStream(file); |