aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/xmpp
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2018-04-01 14:12:35 +0200
committerChristian Schneppe <christian@pix-art.de>2018-04-01 14:12:35 +0200
commita70f8423f0389916b3c2d7b1b708feebce1aa59b (patch)
treec284fdd22f77dc4d52845b14eb267fdd3655e24a /src/main/java/de/pixart/messenger/xmpp
parent186bf6e9ffbe1ae14cd68a46cdba15f4bb8337d0 (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.java325
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();
- }
}