diff options
author | Christian Schneppe <christian@pix-art.de> | 2018-04-01 14:12:35 +0200 |
---|---|---|
committer | Christian Schneppe <christian@pix-art.de> | 2018-04-01 14:12:35 +0200 |
commit | a70f8423f0389916b3c2d7b1b708feebce1aa59b (patch) | |
tree | c284fdd22f77dc4d52845b14eb267fdd3655e24a /src/main/java/de/pixart/messenger/xmpp | |
parent | 186bf6e9ffbe1ae14cd68a46cdba15f4bb8337d0 (diff) |
get rid of customizable resources
Diffstat (limited to 'src/main/java/de/pixart/messenger/xmpp')
-rw-r--r-- | src/main/java/de/pixart/messenger/xmpp/XmppConnection.java | 325 |
1 files changed, 161 insertions, 164 deletions
diff --git a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java index 1025c5f1d..154627afe 100644 --- a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java +++ b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java @@ -50,9 +50,9 @@ import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509KeyManager; import javax.net.ssl.X509TrustManager; -import de.pixart.messenger.crypto.DomainHostnameVerifier; -import de.pixart.messenger.services.MemorizingTrustManager; import de.pixart.messenger.Config; +import de.pixart.messenger.R; +import de.pixart.messenger.crypto.DomainHostnameVerifier; import de.pixart.messenger.crypto.XmppDomainVerifier; import de.pixart.messenger.crypto.axolotl.AxolotlService; import de.pixart.messenger.crypto.sasl.Anonymous; @@ -67,6 +67,7 @@ import de.pixart.messenger.entities.Message; import de.pixart.messenger.entities.ServiceDiscoveryResult; import de.pixart.messenger.generator.IqGenerator; import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.services.MemorizingTrustManager; import de.pixart.messenger.services.NotificationService; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.ui.EditAccountActivity; @@ -104,21 +105,55 @@ public class XmppConnection implements Runnable { private static final int PACKET_IQ = 0; private static final int PACKET_MESSAGE = 1; private static final int PACKET_PRESENCE = 2; + public final OnIqPacketReceived registrationResponseListener = new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + if (packet.getType() == IqPacket.TYPE.RESULT) { + account.setOption(Account.OPTION_REGISTER, false); + throw new StateChangingError(Account.State.REGISTRATION_SUCCESSFUL); + } else { + final List<String> PASSWORD_TOO_WEAK_MSGS = Arrays.asList( + "The password is too weak", + "Please use a longer password."); + final Element error = packet.findChild("error"); + Account.State state = Account.State.REGISTRATION_FAILED; + mXmppConnectionService.deleteAccount(account); + if (error != null) { + if (error.hasChild("text")) { + errorMessage = error.findChildContent("text"); + Log.d(Config.LOGTAG, "Error creating account : " + error.findChildContent("text")); + } + if (error.hasChild("conflict")) { + state = Account.State.REGISTRATION_CONFLICT; + } else if (error.hasChild("resource-constraint") + && "wait".equals(error.getAttribute("type"))) { + state = Account.State.REGISTRATION_PLEASE_WAIT; + } else if (error.hasChild("not-acceptable") + && PASSWORD_TOO_WEAK_MSGS.contains(error.findChildContent("text"))) { + state = Account.State.REGISTRATION_PASSWORD_TOO_WEAK; + } + } + Log.d(Config.LOGTAG, "Delete account because of error " + error); + throw new StateChangingError(state); + } + } + }; protected final Account account; + private final Features features = new Features(this); + private final HashMap<Jid, ServiceDiscoveryResult> disco = new HashMap<>(); + private final SparseArray<AbstractAcknowledgeableStanza> mStanzaQueue = new SparseArray<>(); + private final Hashtable<String, Pair<IqPacket, OnIqPacketReceived>> packetCallbacks = new Hashtable<>(); + private final ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>(); + private final XmppConnectionService mXmppConnectionService; private Socket socket; private XmlReader tagReader; private TagWriter tagWriter = new TagWriter(); - private final Features features = new Features(this); private boolean isBound = false; private boolean shouldAuthenticate = true; private boolean inSmacksSession = false; private Element streamFeatures; - private final HashMap<Jid, ServiceDiscoveryResult> disco = new HashMap<>(); - private String streamId = null; private int smVersion = 3; - private final SparseArray<AbstractAcknowledgeableStanza> mStanzaQueue = new SparseArray<>(); - private int stanzasReceived = 0; private int stanzasSent = 0; private long lastPacketReceived = 0; @@ -133,101 +168,20 @@ public class XmppConnection implements Runnable { private boolean mInteractive = false; private int attempt = 0; public static String errorMessage = null; - private final Hashtable<String, Pair<IqPacket, OnIqPacketReceived>> packetCallbacks = new Hashtable<>(); private OnPresencePacketReceived presenceListener = null; private OnJinglePacketReceived jingleListener = null; private OnIqPacketReceived unregisteredIqListener = null; private OnMessagePacketReceived messageListener = null; private OnStatusChanged statusListener = null; private OnBindListener bindListener = null; - private final ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>(); private OnMessageAcknowledged acknowledgedListener = null; - private final XmppConnectionService mXmppConnectionService; private EditAccountActivity mEditAccountActivity = null; - private SaslMechanism saslMechanism; private URL redirectionUrl = null; private String verifiedHostname = null; private Thread mThread; private CountDownLatch mStreamCountDownLatch; - private class MyKeyManager implements X509KeyManager { - @Override - public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { - return account.getPrivateKeyAlias(); - } - - @Override - public String chooseServerAlias(String s, Principal[] principals, Socket socket) { - return null; - } - - @Override - public X509Certificate[] getCertificateChain(String alias) { - Log.d(Config.LOGTAG, "getting certificate chain"); - try { - return KeyChain.getCertificateChain(mXmppConnectionService, alias); - } catch (Exception e) { - Log.d(Config.LOGTAG, e.getMessage()); - return new X509Certificate[0]; - } - } - - @Override - public String[] getClientAliases(String s, Principal[] principals) { - final String alias = account.getPrivateKeyAlias(); - return alias != null ? new String[]{alias} : new String[0]; - } - - @Override - public String[] getServerAliases(String s, Principal[] principals) { - return new String[0]; - } - - @Override - public PrivateKey getPrivateKey(String alias) { - try { - return KeyChain.getPrivateKey(mXmppConnectionService, alias); - } catch (Exception e) { - return null; - } - } - } - - public final OnIqPacketReceived registrationResponseListener = new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE.RESULT) { - account.setOption(Account.OPTION_REGISTER, false); - throw new StateChangingError(Account.State.REGISTRATION_SUCCESSFUL); - } else { - final List<String> PASSWORD_TOO_WEAK_MSGS = Arrays.asList( - "The password is too weak", - "Please use a longer password."); - final Element error = packet.findChild("error"); - Account.State state = Account.State.REGISTRATION_FAILED; - mXmppConnectionService.deleteAccount(account); - if (error != null) { - if (error.hasChild("text")) { - errorMessage = error.findChildContent("text"); - Log.d(Config.LOGTAG, "Error creating account : " + error.findChildContent("text")); - } - if (error.hasChild("conflict")) { - state = Account.State.REGISTRATION_CONFLICT; - } else if (error.hasChild("resource-constraint") - && "wait".equals(error.getAttribute("type"))) { - state = Account.State.REGISTRATION_PLEASE_WAIT; - } else if (error.hasChild("not-acceptable") - && PASSWORD_TOO_WEAK_MSGS.contains(error.findChildContent("text"))) { - state = Account.State.REGISTRATION_PASSWORD_TOO_WEAK; - } - } - Log.d(Config.LOGTAG, "Delete account because of error " + error); - throw new StateChangingError(state); - } - } - }; - public XmppConnection(final Account account, final XmppConnectionService service) { this.account = account; final String tag = account.getJid().toBareJid().toPreppedString(); @@ -509,19 +463,6 @@ public class XmppConnection implements Runnable { return tag != null && tag.isStart("stream"); } - private static class TlsFactoryVerifier { - private final SSLSocketFactory factory; - private final DomainHostnameVerifier verifier; - - public TlsFactoryVerifier(final SSLSocketFactory factory, final DomainHostnameVerifier verifier) throws IOException { - this.factory = factory; - this.verifier = verifier; - if (factory == null || verifier == null) { - throw new IOException("could not setup ssl"); - } - } - } - private TlsFactoryVerifier getTlsFactoryVerifier() throws NoSuchAlgorithmException, KeyManagementException, IOException { final SSLContext sc = SSLSocketHelper.getSSLContext(); MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager(); @@ -865,7 +806,6 @@ public class XmppConnection implements Runnable { tagWriter.writeTag(startTLS); } - private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException { tagReader.readTag(); try { @@ -1099,55 +1039,52 @@ public class XmppConnection implements Runnable { return; } clearIqCallbacks(); + if (account.getJid().isBareJid()) { + account.setResource(this.createNewResource()); + } final IqPacket iq = new IqPacket(IqPacket.TYPE.SET); final String resource = Config.USE_RANDOM_RESOURCE_ON_EVERY_BIND ? nextRandomId() : account.getResource(); iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource); - this.sendUnmodifiedIqPacket(iq, new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(final Account account, final IqPacket packet) { - if (packet.getType() == IqPacket.TYPE.TIMEOUT) { - return; - } - final Element bind = packet.findChild("bind"); - if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) { - isBound = true; - final Element jid = bind.findChild("jid"); - if (jid != null && jid.getContent() != null) { - try { - Jid assignedJid = Jid.fromString(jid.getContent()); - if (!account.getJid().getDomainpart().equals(assignedJid.getDomainpart())) { - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server tried to re-assign domain to " + assignedJid.getDomainpart()); - throw new StateChangingError(Account.State.BIND_FAILURE); - } - if (account.setJid(assignedJid)) { - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": bare jid changed during bind. updating database"); - mXmppConnectionService.databaseBackend.updateAccount(account); - } - if (streamFeatures.hasChild("session") - && !streamFeatures.findChild("session").hasChild("optional")) { - sendStartSession(); - } else { - sendPostBindInitialization(); - } - return; - } catch (final InvalidJidException e) { - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server reported invalid jid (" + jid.getContent() + ") on bind"); + this.sendUnmodifiedIqPacket(iq, (account, packet) -> { + if (packet.getType() == IqPacket.TYPE.TIMEOUT) { + return; + } + final Element bind = packet.findChild("bind"); + if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) { + isBound = true; + final Element jid = bind.findChild("jid"); + if (jid != null && jid.getContent() != null) { + try { + Jid assignedJid = Jid.fromString(jid.getContent()); + if (!account.getJid().getDomainpart().equals(assignedJid.getDomainpart())) { + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server tried to re-assign domain to " + assignedJid.getDomainpart()); + throw new StateChangingError(Account.State.BIND_FAILURE); } - } else { - Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure. (no jid)"); + if (account.setJid(assignedJid)) { + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": jid changed during bind. updating database"); + mXmppConnectionService.databaseBackend.updateAccount(account); + } + if (streamFeatures.hasChild("session") + && !streamFeatures.findChild("session").hasChild("optional")) { + sendStartSession(); + } else { + sendPostBindInitialization(); + } + return; + } catch (final InvalidJidException e) { + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server reported invalid jid (" + jid.getContent() + ") on bind"); } } else { - Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure (" + packet.toString()); + Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure. (no jid)"); } - final Element error = packet.findChild("error"); - final String resource = account.getResource().split("\\.")[0]; - if (packet.getType() == IqPacket.TYPE.ERROR && error != null && error.hasChild("conflict")) { - account.setResource(resource + "." + nextRandomId()); - } else { - account.setResource(resource); - } - throw new StateChangingError(Account.State.BIND_FAILURE); + } else { + Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure (" + packet.toString()); } + final Element error = packet.findChild("error"); + if (packet.getType() == IqPacket.TYPE.ERROR && error != null && error.hasChild("conflict")) { + account.setResource(createNewResource()); + } + throw new StateChangingError(Account.State.BIND_FAILURE); }, true); } @@ -1367,18 +1304,14 @@ public class XmppConnection implements Runnable { }); } - private void processStreamError(final Tag currentTag) - throws XmlPullParserException, IOException { + private void processStreamError(final Tag currentTag) throws XmlPullParserException, IOException { final Element streamError = tagReader.readElement(currentTag); if (streamError == null) { return; } if (streamError.hasChild("conflict")) { - final String resource = account.getResource().split("\\.")[0]; - account.setResource(resource + "." + nextRandomId()); - Log.d(Config.LOGTAG, - account.getJid().toBareJid() + ": switching resource due to conflict (" - + account.getResource() + ")"); + account.setResource(createNewResource()); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": switching resource due to conflict (" + account.getResource() + ")"); throw new IOException(); } else if (streamError.hasChild("host-unknown")) { throw new StateChangingException(Account.State.HOST_UNKNOWN); @@ -1400,8 +1333,16 @@ public class XmppConnection implements Runnable { tagWriter.writeTag(stream); } + private String createNewResource() { + return mXmppConnectionService.getString(R.string.app_name) + '.' + nextRandomId(true); + } + private String nextRandomId() { - return CryptoHelper.random(10, mXmppConnectionService.getRNG()); + return nextRandomId(false); + } + + private String nextRandomId(boolean s) { + return CryptoHelper.random(s ? 3 : 9, mXmppConnectionService.getRNG()); } public String sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) { @@ -1690,6 +1631,75 @@ public class XmppConnection implements Runnable { return Identity.UNKNOWN; } + private IqGenerator getIqGenerator() { + return mXmppConnectionService.getIqGenerator(); + } + + public enum Identity { + FACEBOOK, + SLACK, + EJABBERD, + PROSODY, + NIMBUZZ, + UNKNOWN + } + + private static class TlsFactoryVerifier { + private final SSLSocketFactory factory; + private final DomainHostnameVerifier verifier; + + public TlsFactoryVerifier(final SSLSocketFactory factory, final DomainHostnameVerifier verifier) throws IOException { + this.factory = factory; + this.verifier = verifier; + if (factory == null || verifier == null) { + throw new IOException("could not setup ssl"); + } + } + } + + private class MyKeyManager implements X509KeyManager { + @Override + public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { + return account.getPrivateKeyAlias(); + } + + @Override + public String chooseServerAlias(String s, Principal[] principals, Socket socket) { + return null; + } + + @Override + public X509Certificate[] getCertificateChain(String alias) { + Log.d(Config.LOGTAG, "getting certificate chain"); + try { + return KeyChain.getCertificateChain(mXmppConnectionService, alias); + } catch (Exception e) { + Log.d(Config.LOGTAG, e.getMessage()); + return new X509Certificate[0]; + } + } + + @Override + public String[] getClientAliases(String s, Principal[] principals) { + final String alias = account.getPrivateKeyAlias(); + return alias != null ? new String[]{alias} : new String[0]; + } + + @Override + public String[] getServerAliases(String s, Principal[] principals) { + return new String[0]; + } + + @Override + public PrivateKey getPrivateKey(String alias) { + try { + return KeyChain.getPrivateKey(mXmppConnectionService, alias); + } catch (Exception e) { + return null; + } + } + } + private class StateChangingError extends Error { private final Account.State state; @@ -1706,15 +1716,6 @@ public class XmppConnection implements Runnable { } } - public enum Identity { - FACEBOOK, - SLACK, - EJABBERD, - PROSODY, - NIMBUZZ, - UNKNOWN - } - public class Features { XmppConnection connection; private boolean carbonsEnabled = false; @@ -1846,8 +1847,4 @@ public class XmppConnection implements Runnable { return hasDiscoFeature(account.getJid().toBareJid(), Namespace.STANZA_IDS); } } - - private IqGenerator getIqGenerator() { - return mXmppConnectionService.getIqGenerator(); - } } |