From 928a16d31d215a4eda2ba4e03d84e8651301a2e3 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 29 Aug 2022 18:53:34 +0200 Subject: [PATCH] abort on 'continue' - no client support --- .../siacs/conversations/entities/Account.java | 3 + .../java/eu/siacs/conversations/xml/Tag.java | 10 ++- .../conversations/xmpp/XmppConnection.java | 84 ++++++++++++++----- src/main/res/values/strings.xml | 1 + 4 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index dc354adc4..9220cc192 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -640,6 +640,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable TLS_ERROR, TLS_ERROR_DOMAIN, INCOMPATIBLE_SERVER, + INCOMPATIBLE_CLIENT, TOR_NOT_AVAILABLE, DOWNGRADE_ATTACK, SESSION_FAILURE, @@ -709,6 +710,8 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable return R.string.account_status_tls_error_domain; case INCOMPATIBLE_SERVER: return R.string.account_status_incompatible_server; + case INCOMPATIBLE_CLIENT: + return R.string.account_status_incompatible_client; case TOR_NOT_AVAILABLE: return R.string.account_status_tor_unavailable; case BIND_FAILURE: diff --git a/src/main/java/eu/siacs/conversations/xml/Tag.java b/src/main/java/eu/siacs/conversations/xml/Tag.java index 2e6098522..db2b11172 100644 --- a/src/main/java/eu/siacs/conversations/xml/Tag.java +++ b/src/main/java/eu/siacs/conversations/xml/Tag.java @@ -56,11 +56,17 @@ public class Tag { this.attributes = attributes; } - public boolean isStart(String needle) { - if (needle == null) return false; + public boolean isStart(final String needle) { + if (needle == null) { + return false; + } return (this.type == START) && (needle.equals(this.name)); } + public boolean isStart(final String name, final String namespace) { + return isStart(name) && namespace != null && namespace.equals(this.getAttribute("xmlns")); + } + public boolean isEnd(String needle) { if (needle == null) return false; return (this.type == END) && (needle.equals(this.name)); diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index bd11fcbe2..0fbb85768 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -466,7 +466,7 @@ public class XmppConnection implements Runnable { processStreamError(nextTag); } else if (nextTag.isStart("features")) { processStreamFeatures(nextTag); - } else if (nextTag.isStart("proceed")) { + } else if (nextTag.isStart("proceed", Namespace.TLS)) { switchOverToTls(); } else if (nextTag.isStart("success")) { final Element success = tagReader.readElement(nextTag); @@ -499,8 +499,13 @@ public class XmppConnection implements Runnable { account.setKey( Account.PINNED_MECHANISM_KEY, String.valueOf(saslMechanism.getPriority())); if (version == SaslMechanism.Version.SASL_2) { - final String authorizationIdentifier = success.findChildContent("authorization-identifier"); - Log.d(Config.LOGTAG,account.getJid().asBareJid()+": SASL 2.0 authorization identifier was "+authorizationIdentifier); + final String authorizationIdentifier = + success.findChildContent("authorization-identifier"); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": SASL 2.0 authorization identifier was " + + authorizationIdentifier); } if (version == SaslMechanism.Version.SASL) { tagReader.reset(); @@ -513,11 +518,10 @@ public class XmppConnection implements Runnable { } break; } + } else if (nextTag.isStart("failure", Namespace.TLS)) { + throw new StateChangingException(Account.State.TLS_ERROR); } else if (nextTag.isStart("failure")) { final Element failure = tagReader.readElement(nextTag); - if (Namespace.TLS.equals(failure.getNamespace())) { - throw new StateChangingException(Account.State.TLS_ERROR); - } final SaslMechanism.Version version; try { version = SaslMechanism.Version.of(failure); @@ -547,6 +551,8 @@ public class XmppConnection implements Runnable { } } throw new StateChangingException(Account.State.UNAUTHORIZED); + } else if (nextTag.isStart("continue", Namespace.SASL_2)) { + throw new StateChangingException(Account.State.INCOMPATIBLE_CLIENT); } else if (nextTag.isStart("challenge")) { final Element challenge = tagReader.readElement(nextTag); final SaslMechanism.Version version; @@ -575,12 +581,19 @@ public class XmppConnection implements Runnable { final Element enabled = tagReader.readElement(nextTag); if ("true".equals(enabled.getAttribute("resume"))) { this.streamId = enabled.getAttribute("id"); - Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() - + ": stream management(" + smVersion - + ") enabled (resumable)"); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid().toString() + + ": stream management(" + + smVersion + + ") enabled (resumable)"); } else { - Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() - + ": stream management(" + smVersion + ") enabled"); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid().toString() + + ": stream management(" + + smVersion + + ") enabled"); } this.stanzasReceived = 0; this.inSmacksSession = true; @@ -599,11 +612,15 @@ public class XmppConnection implements Runnable { synchronized (this.mStanzaQueue) { final int serverCount = Integer.parseInt(h); if (serverCount < stanzasSent) { - Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() - + ": session resumed with lost packages"); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid().toString() + + ": session resumed with lost packages"); stanzasSent = serverCount; } else { - Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() + ": session resumed"); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid().toString() + ": session resumed"); } acknowledgedMessages = acknowledgeStanzaUpTo(serverCount); for (int i = 0; i < this.mStanzaQueue.size(); ++i) { @@ -618,7 +635,8 @@ public class XmppConnection implements Runnable { for (AbstractAcknowledgeableStanza packet : failedStanzas) { if (packet instanceof MessagePacket) { MessagePacket message = (MessagePacket) packet; - mXmppConnectionService.markMessage(account, + mXmppConnectionService.markMessage( + account, message.getTo().asBareJid(), message.getId(), Message.STATUS_UNSEND); @@ -627,12 +645,20 @@ public class XmppConnection implements Runnable { } } catch (final NumberFormatException ignored) { } - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": online with resource " + account.getResource()); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": online with resource " + + account.getResource()); changeStatus(Account.State.ONLINE); } else if (nextTag.isStart("r")) { tagReader.readElement(nextTag); if (Config.EXTENDED_SM_LOGGING) { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": acknowledging stanza #" + this.stanzasReceived); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": acknowledging stanza #" + + this.stanzasReceived); } final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion); tagWriter.writeStanzaAsync(ack); @@ -642,10 +668,19 @@ public class XmppConnection implements Runnable { if (mWaitingForSmCatchup.compareAndSet(true, false)) { final int messageCount = mSmCatchupMessageCounter.get(); final int pendingIQs = packetCallbacks.size(); - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": SM catchup complete (messages=" + messageCount + ", pending IQs=" + pendingIQs + ")"); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": SM catchup complete (messages=" + + messageCount + + ", pending IQs=" + + pendingIQs + + ")"); accountUiNeedsRefresh = true; if (messageCount > 0) { - mXmppConnectionService.getNotificationService().finishBacklog(true, account); + mXmppConnectionService + .getNotificationService() + .finishBacklog(true, account); } } } @@ -664,13 +699,20 @@ public class XmppConnection implements Runnable { mXmppConnectionService.updateConversationUi(); } } catch (NumberFormatException | NullPointerException e) { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": server send ack without sequence number"); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": server send ack without sequence number"); } } else if (nextTag.isStart("failed")) { Element failed = tagReader.readElement(nextTag); try { final int serverCount = Integer.parseInt(failed.getAttribute("h")); - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": resumption failed but server acknowledged stanza #" + serverCount); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": resumption failed but server acknowledged stanza #" + + serverCount); final boolean acknowledgedMessages; synchronized (this.mStanzaQueue) { acknowledgedMessages = acknowledgeStanzaUpTo(serverCount); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index c51be907e..cd4412588 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -168,6 +168,7 @@ Domain not verifiable Policy violation Incompatible server + Incompatible client Stream error Stream opening error Unencrypted