abort on 'continue' - no client support

This commit is contained in:
Daniel Gultsch 2022-08-29 18:53:34 +02:00
parent 6202cbe26b
commit 928a16d31d
4 changed files with 75 additions and 23 deletions

View file

@ -640,6 +640,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
TLS_ERROR, TLS_ERROR,
TLS_ERROR_DOMAIN, TLS_ERROR_DOMAIN,
INCOMPATIBLE_SERVER, INCOMPATIBLE_SERVER,
INCOMPATIBLE_CLIENT,
TOR_NOT_AVAILABLE, TOR_NOT_AVAILABLE,
DOWNGRADE_ATTACK, DOWNGRADE_ATTACK,
SESSION_FAILURE, SESSION_FAILURE,
@ -709,6 +710,8 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
return R.string.account_status_tls_error_domain; return R.string.account_status_tls_error_domain;
case INCOMPATIBLE_SERVER: case INCOMPATIBLE_SERVER:
return R.string.account_status_incompatible_server; return R.string.account_status_incompatible_server;
case INCOMPATIBLE_CLIENT:
return R.string.account_status_incompatible_client;
case TOR_NOT_AVAILABLE: case TOR_NOT_AVAILABLE:
return R.string.account_status_tor_unavailable; return R.string.account_status_tor_unavailable;
case BIND_FAILURE: case BIND_FAILURE:

View file

@ -56,11 +56,17 @@ public class Tag {
this.attributes = attributes; this.attributes = attributes;
} }
public boolean isStart(String needle) { public boolean isStart(final String needle) {
if (needle == null) return false; if (needle == null) {
return false;
}
return (this.type == START) && (needle.equals(this.name)); 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) { public boolean isEnd(String needle) {
if (needle == null) return false; if (needle == null) return false;
return (this.type == END) && (needle.equals(this.name)); return (this.type == END) && (needle.equals(this.name));

View file

@ -466,7 +466,7 @@ public class XmppConnection implements Runnable {
processStreamError(nextTag); processStreamError(nextTag);
} else if (nextTag.isStart("features")) { } else if (nextTag.isStart("features")) {
processStreamFeatures(nextTag); processStreamFeatures(nextTag);
} else if (nextTag.isStart("proceed")) { } else if (nextTag.isStart("proceed", Namespace.TLS)) {
switchOverToTls(); switchOverToTls();
} else if (nextTag.isStart("success")) { } else if (nextTag.isStart("success")) {
final Element success = tagReader.readElement(nextTag); final Element success = tagReader.readElement(nextTag);
@ -499,8 +499,13 @@ public class XmppConnection implements Runnable {
account.setKey( account.setKey(
Account.PINNED_MECHANISM_KEY, String.valueOf(saslMechanism.getPriority())); Account.PINNED_MECHANISM_KEY, String.valueOf(saslMechanism.getPriority()));
if (version == SaslMechanism.Version.SASL_2) { if (version == SaslMechanism.Version.SASL_2) {
final String authorizationIdentifier = success.findChildContent("authorization-identifier"); final String authorizationIdentifier =
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": SASL 2.0 authorization identifier was "+authorizationIdentifier); success.findChildContent("authorization-identifier");
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
+ ": SASL 2.0 authorization identifier was "
+ authorizationIdentifier);
} }
if (version == SaslMechanism.Version.SASL) { if (version == SaslMechanism.Version.SASL) {
tagReader.reset(); tagReader.reset();
@ -513,11 +518,10 @@ public class XmppConnection implements Runnable {
} }
break; break;
} }
} else if (nextTag.isStart("failure", Namespace.TLS)) {
throw new StateChangingException(Account.State.TLS_ERROR);
} else if (nextTag.isStart("failure")) { } else if (nextTag.isStart("failure")) {
final Element failure = tagReader.readElement(nextTag); final Element failure = tagReader.readElement(nextTag);
if (Namespace.TLS.equals(failure.getNamespace())) {
throw new StateChangingException(Account.State.TLS_ERROR);
}
final SaslMechanism.Version version; final SaslMechanism.Version version;
try { try {
version = SaslMechanism.Version.of(failure); version = SaslMechanism.Version.of(failure);
@ -547,6 +551,8 @@ public class XmppConnection implements Runnable {
} }
} }
throw new StateChangingException(Account.State.UNAUTHORIZED); 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")) { } else if (nextTag.isStart("challenge")) {
final Element challenge = tagReader.readElement(nextTag); final Element challenge = tagReader.readElement(nextTag);
final SaslMechanism.Version version; final SaslMechanism.Version version;
@ -575,12 +581,19 @@ public class XmppConnection implements Runnable {
final Element enabled = tagReader.readElement(nextTag); final Element enabled = tagReader.readElement(nextTag);
if ("true".equals(enabled.getAttribute("resume"))) { if ("true".equals(enabled.getAttribute("resume"))) {
this.streamId = enabled.getAttribute("id"); this.streamId = enabled.getAttribute("id");
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() Log.d(
+ ": stream management(" + smVersion Config.LOGTAG,
+ ") enabled (resumable)"); account.getJid().asBareJid().toString()
+ ": stream management("
+ smVersion
+ ") enabled (resumable)");
} else { } else {
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() Log.d(
+ ": stream management(" + smVersion + ") enabled"); Config.LOGTAG,
account.getJid().asBareJid().toString()
+ ": stream management("
+ smVersion
+ ") enabled");
} }
this.stanzasReceived = 0; this.stanzasReceived = 0;
this.inSmacksSession = true; this.inSmacksSession = true;
@ -599,11 +612,15 @@ public class XmppConnection implements Runnable {
synchronized (this.mStanzaQueue) { synchronized (this.mStanzaQueue) {
final int serverCount = Integer.parseInt(h); final int serverCount = Integer.parseInt(h);
if (serverCount < stanzasSent) { if (serverCount < stanzasSent) {
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() Log.d(
+ ": session resumed with lost packages"); Config.LOGTAG,
account.getJid().asBareJid().toString()
+ ": session resumed with lost packages");
stanzasSent = serverCount; stanzasSent = serverCount;
} else { } else {
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() + ": session resumed"); Log.d(
Config.LOGTAG,
account.getJid().asBareJid().toString() + ": session resumed");
} }
acknowledgedMessages = acknowledgeStanzaUpTo(serverCount); acknowledgedMessages = acknowledgeStanzaUpTo(serverCount);
for (int i = 0; i < this.mStanzaQueue.size(); ++i) { for (int i = 0; i < this.mStanzaQueue.size(); ++i) {
@ -618,7 +635,8 @@ public class XmppConnection implements Runnable {
for (AbstractAcknowledgeableStanza packet : failedStanzas) { for (AbstractAcknowledgeableStanza packet : failedStanzas) {
if (packet instanceof MessagePacket) { if (packet instanceof MessagePacket) {
MessagePacket message = (MessagePacket) packet; MessagePacket message = (MessagePacket) packet;
mXmppConnectionService.markMessage(account, mXmppConnectionService.markMessage(
account,
message.getTo().asBareJid(), message.getTo().asBareJid(),
message.getId(), message.getId(),
Message.STATUS_UNSEND); Message.STATUS_UNSEND);
@ -627,12 +645,20 @@ public class XmppConnection implements Runnable {
} }
} catch (final NumberFormatException ignored) { } 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); changeStatus(Account.State.ONLINE);
} else if (nextTag.isStart("r")) { } else if (nextTag.isStart("r")) {
tagReader.readElement(nextTag); tagReader.readElement(nextTag);
if (Config.EXTENDED_SM_LOGGING) { 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); final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion);
tagWriter.writeStanzaAsync(ack); tagWriter.writeStanzaAsync(ack);
@ -642,10 +668,19 @@ public class XmppConnection implements Runnable {
if (mWaitingForSmCatchup.compareAndSet(true, false)) { if (mWaitingForSmCatchup.compareAndSet(true, false)) {
final int messageCount = mSmCatchupMessageCounter.get(); final int messageCount = mSmCatchupMessageCounter.get();
final int pendingIQs = packetCallbacks.size(); 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; accountUiNeedsRefresh = true;
if (messageCount > 0) { if (messageCount > 0) {
mXmppConnectionService.getNotificationService().finishBacklog(true, account); mXmppConnectionService
.getNotificationService()
.finishBacklog(true, account);
} }
} }
} }
@ -664,13 +699,20 @@ public class XmppConnection implements Runnable {
mXmppConnectionService.updateConversationUi(); mXmppConnectionService.updateConversationUi();
} }
} catch (NumberFormatException | NullPointerException e) { } 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")) { } else if (nextTag.isStart("failed")) {
Element failed = tagReader.readElement(nextTag); Element failed = tagReader.readElement(nextTag);
try { try {
final int serverCount = Integer.parseInt(failed.getAttribute("h")); 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; final boolean acknowledgedMessages;
synchronized (this.mStanzaQueue) { synchronized (this.mStanzaQueue) {
acknowledgedMessages = acknowledgeStanzaUpTo(serverCount); acknowledgedMessages = acknowledgeStanzaUpTo(serverCount);

View file

@ -168,6 +168,7 @@
<string name="account_status_tls_error_domain">Domain not verifiable</string> <string name="account_status_tls_error_domain">Domain not verifiable</string>
<string name="account_status_policy_violation">Policy violation</string> <string name="account_status_policy_violation">Policy violation</string>
<string name="account_status_incompatible_server">Incompatible server</string> <string name="account_status_incompatible_server">Incompatible server</string>
<string name="account_status_incompatible_client">Incompatible client</string>
<string name="account_status_stream_error">Stream error</string> <string name="account_status_stream_error">Stream error</string>
<string name="account_status_stream_opening_error">Stream opening error</string> <string name="account_status_stream_opening_error">Stream opening error</string>
<string name="encryption_choice_unencrypted">Unencrypted</string> <string name="encryption_choice_unencrypted">Unencrypted</string>