package com.xabber.android.data.connection; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Patterns; import com.xabber.android.data.SettingsManager; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.log.LogManager; import org.apache.http.conn.ssl.AllowAllHostnameVerifier; import org.jivesoftware.smack.SASLAuthentication; import org.jivesoftware.smack.proxy.ProxyInfo; import org.jivesoftware.smack.sasl.provided.SASLDigestMD5Mechanism; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; import org.jivesoftware.smack.util.TLSUtils; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import de.duenndns.ssl.MemorizingTrustManager; class ConnectionBuilder { private static final String LOG_TAG = ConnectionBuilder.class.getSimpleName(); public static @NonNull XMPPTCPConnection build(AccountJid account, @NonNull final ConnectionSettings connectionSettings) { XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder(); builder.setXmppDomain(connectionSettings.getServerName()); if (connectionSettings.isCustomHostAndPort()) { setCustomHost(connectionSettings, builder); builder.setPort(connectionSettings.getPort()); } builder.setDebuggerEnabled(true); builder.setSecurityMode(connectionSettings.getTlsMode().getSecurityMode()); builder.setCompressionEnabled(connectionSettings.useCompression()); builder.setSendPresence(false); builder.setUsernameAndPassword(connectionSettings.getUserName(), connectionSettings.getPassword()); builder.setResource(connectionSettings.getResource()); builder.setProxyInfo(getProxyInfo(connectionSettings)); try { LogManager.i(LOG_TAG, "SettingsManager.securityCheckCertificate: " + SettingsManager.securityCheckCertificate()); if (SettingsManager.securityCheckCertificate()) { SSLContext sslContext = SSLContext.getInstance("TLS"); MemorizingTrustManager mtm = CertificateManager.getInstance().getNewMemorizingTrustManager(account); sslContext.init(null, new X509TrustManager[]{mtm}, new java.security.SecureRandom()); builder.setCustomSSLContext(sslContext); builder.setHostnameVerifier( mtm.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier())); } else { TLSUtils.acceptAllCertificates(builder); builder.setHostnameVerifier(new AllowAllHostnameVerifier()); } } catch (NoSuchAlgorithmException | KeyManagementException e) { LogManager.exception(LOG_TAG, e); } setUpSasl(); LogManager.i(LOG_TAG, "new XMPPTCPConnection " + connectionSettings.getServerName()); return new XMPPTCPConnection(builder.build()); } private static void setCustomHost(@NonNull ConnectionSettings connectionSettings, XMPPTCPConnectionConfiguration.Builder builder) { String host = connectionSettings.getHost(); InetAddress ipAddressOrNull = getIpAddressOrNull(host); LogManager.i(LOG_TAG, "setCustomHost. host: " + host + " ip address: " + ipAddressOrNull); if (ipAddressOrNull != null) { LogManager.i(LOG_TAG, "Using custom IP address " + ipAddressOrNull); builder.setHostAddress(ipAddressOrNull); } else { LogManager.i(LOG_TAG, "Using custom host " + host); builder.setHost(host); } } @Nullable private static InetAddress getIpAddressOrNull(String host) { InetAddress ipAddress = null; if (Patterns.IP_ADDRESS.matcher(host).matches()) { try { ipAddress = InetAddress.getByName(host); } catch (UnknownHostException e) { LogManager.exception(LOG_TAG, e); } } return ipAddress; } private static ProxyInfo getProxyInfo(ConnectionSettings connectionSettings) { ProxyInfo proxyInfo = null; ProxyType proxyType = connectionSettings.getProxyType(); String proxyHost = connectionSettings.getProxyHost(); int proxyPort = connectionSettings.getProxyPort(); String proxyPassword = connectionSettings.getProxyPassword(); String proxyUser = connectionSettings.getProxyUser(); if (proxyType != null) { switch (proxyType) { case http: proxyInfo = ProxyInfo.forHttpProxy(proxyHost, proxyPort, proxyUser, proxyPassword); break; case socks4: proxyInfo = ProxyInfo.forSocks4Proxy(proxyHost, proxyPort, proxyUser, proxyPassword); break; case socks5: proxyInfo = ProxyInfo.forSocks5Proxy(proxyHost, proxyPort, proxyUser, proxyPassword); break; case orbot: proxyHost = "localhost"; proxyPort = 9050; proxyPassword = ""; proxyUser = ""; proxyInfo = ProxyInfo.forSocks5Proxy(proxyHost, proxyPort, proxyUser, proxyPassword); break; case none: default: proxyInfo = null; } } return proxyInfo; } private synchronized static void setUpSasl() { // TODO: DIGEST-MD5 mechanism disabled due to implementation problems // should be enabled back when fixed in Smack SASLAuthentication.blacklistSASLMechanism(SASLDigestMD5Mechanism.NAME); } }