diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/Anonymous.java b/src/main/java/eu/siacs/conversations/crypto/sasl/Anonymous.java index 4672bc1ff..a9abb2bf8 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/Anonymous.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/Anonymous.java @@ -7,22 +7,24 @@ import eu.siacs.conversations.xml.TagWriter; public class Anonymous extends SaslMechanism { - public Anonymous(TagWriter tagWriter, Account account, SecureRandom rng) { - super(tagWriter, account, rng); - } + public static final String MECHANISM = "ANONYMOUS"; - @Override - public int getPriority() { - return 0; - } + public Anonymous(TagWriter tagWriter, Account account, SecureRandom rng) { + super(tagWriter, account, rng); + } - @Override - public String getMechanism() { - return "ANONYMOUS"; - } + @Override + public int getPriority() { + return 0; + } - @Override - public String getClientFirstMessage() { - return ""; - } + @Override + public String getMechanism() { + return MECHANISM; + } + + @Override + public String getClientFirstMessage() { + return ""; + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java index 3bf5fe342..74d4463d5 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java @@ -12,79 +12,82 @@ import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.TagWriter; public class DigestMd5 extends SaslMechanism { - public DigestMd5(final TagWriter tagWriter, final Account account, final SecureRandom rng) { - super(tagWriter, account, rng); - } - @Override - public int getPriority() { - return 10; - } + public static final String MECHANISM = "DIGEST-MD5"; - @Override - public String getMechanism() { - return "DIGEST-MD5"; - } + public DigestMd5(final TagWriter tagWriter, final Account account, final SecureRandom rng) { + super(tagWriter, account, rng); + } - private State state = State.INITIAL; + @Override + public int getPriority() { + return 10; + } - @Override - public String getResponse(final String challenge) throws AuthenticationException { - switch (state) { - case INITIAL: - state = State.RESPONSE_SENT; - final String encodedResponse; - try { - final Tokenizer tokenizer = new Tokenizer(Base64.decode(challenge, Base64.DEFAULT)); - String nonce = ""; - for (final String token : tokenizer) { - final String[] parts = token.split("=", 2); - if (parts[0].equals("nonce")) { - nonce = parts[1].replace("\"", ""); - } else if (parts[0].equals("rspauth")) { - return ""; - } - } - final String digestUri = "xmpp/" + account.getServer(); - final String nonceCount = "00000001"; - final String x = account.getUsername() + ":" + account.getServer() + ":" - + account.getPassword(); - final MessageDigest md = MessageDigest.getInstance("MD5"); - final byte[] y = md.digest(x.getBytes(Charset.defaultCharset())); - final String cNonce = CryptoHelper.random(100,rng); - final byte[] a1 = CryptoHelper.concatenateByteArrays(y, - (":" + nonce + ":" + cNonce).getBytes(Charset.defaultCharset())); - final String a2 = "AUTHENTICATE:" + digestUri; - final String ha1 = CryptoHelper.bytesToHex(md.digest(a1)); - final String ha2 = CryptoHelper.bytesToHex(md.digest(a2.getBytes(Charset - .defaultCharset()))); - final String kd = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce - + ":auth:" + ha2; - final String response = CryptoHelper.bytesToHex(md.digest(kd.getBytes(Charset - .defaultCharset()))); - final String saslString = "username=\"" + account.getUsername() - + "\",realm=\"" + account.getServer() + "\",nonce=\"" - + nonce + "\",cnonce=\"" + cNonce + "\",nc=" + nonceCount - + ",qop=auth,digest-uri=\"" + digestUri + "\",response=" - + response + ",charset=utf-8"; - encodedResponse = Base64.encodeToString( - saslString.getBytes(Charset.defaultCharset()), - Base64.NO_WRAP); - } catch (final NoSuchAlgorithmException e) { - throw new AuthenticationException(e); - } + @Override + public String getMechanism() { + return MECHANISM; + } - return encodedResponse; - case RESPONSE_SENT: - state = State.VALID_SERVER_RESPONSE; - break; - case VALID_SERVER_RESPONSE: - if (challenge==null) { - return null; //everything is fine - } - default: - throw new InvalidStateException(state); - } - return null; - } + private State state = State.INITIAL; + + @Override + public String getResponse(final String challenge) throws AuthenticationException { + switch (state) { + case INITIAL: + state = State.RESPONSE_SENT; + final String encodedResponse; + try { + final Tokenizer tokenizer = new Tokenizer(Base64.decode(challenge, Base64.DEFAULT)); + String nonce = ""; + for (final String token : tokenizer) { + final String[] parts = token.split("=", 2); + if (parts[0].equals("nonce")) { + nonce = parts[1].replace("\"", ""); + } else if (parts[0].equals("rspauth")) { + return ""; + } + } + final String digestUri = "xmpp/" + account.getServer(); + final String nonceCount = "00000001"; + final String x = account.getUsername() + ":" + account.getServer() + ":" + + account.getPassword(); + final MessageDigest md = MessageDigest.getInstance("MD5"); + final byte[] y = md.digest(x.getBytes(Charset.defaultCharset())); + final String cNonce = CryptoHelper.random(100, rng); + final byte[] a1 = CryptoHelper.concatenateByteArrays(y, + (":" + nonce + ":" + cNonce).getBytes(Charset.defaultCharset())); + final String a2 = "AUTHENTICATE:" + digestUri; + final String ha1 = CryptoHelper.bytesToHex(md.digest(a1)); + final String ha2 = CryptoHelper.bytesToHex(md.digest(a2.getBytes(Charset + .defaultCharset()))); + final String kd = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce + + ":auth:" + ha2; + final String response = CryptoHelper.bytesToHex(md.digest(kd.getBytes(Charset + .defaultCharset()))); + final String saslString = "username=\"" + account.getUsername() + + "\",realm=\"" + account.getServer() + "\",nonce=\"" + + nonce + "\",cnonce=\"" + cNonce + "\",nc=" + nonceCount + + ",qop=auth,digest-uri=\"" + digestUri + "\",response=" + + response + ",charset=utf-8"; + encodedResponse = Base64.encodeToString( + saslString.getBytes(Charset.defaultCharset()), + Base64.NO_WRAP); + } catch (final NoSuchAlgorithmException e) { + throw new AuthenticationException(e); + } + + return encodedResponse; + case RESPONSE_SENT: + state = State.VALID_SERVER_RESPONSE; + break; + case VALID_SERVER_RESPONSE: + if (challenge == null) { + return null; //everything is fine + } + default: + throw new InvalidStateException(state); + } + return null; + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/External.java b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java index 294f382d7..6e0ed4390 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/External.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.crypto.sasl; import android.util.Base64; + import java.security.SecureRandom; import eu.siacs.conversations.entities.Account; @@ -8,22 +9,24 @@ import eu.siacs.conversations.xml.TagWriter; public class External extends SaslMechanism { - public External(TagWriter tagWriter, Account account, SecureRandom rng) { - super(tagWriter, account, rng); - } + public static final String MECHANISM = "EXTERNAL"; - @Override - public int getPriority() { - return 25; - } + public External(TagWriter tagWriter, Account account, SecureRandom rng) { + super(tagWriter, account, rng); + } - @Override - public String getMechanism() { - return "EXTERNAL"; - } + @Override + public int getPriority() { + return 25; + } - @Override - public String getClientFirstMessage() { - return Base64.encodeToString(account.getJid().asBareJid().toEscapedString().getBytes(),Base64.NO_WRAP); - } + @Override + public String getMechanism() { + return MECHANISM; + } + + @Override + public String getClientFirstMessage() { + return Base64.encodeToString(account.getJid().asBareJid().toEscapedString().getBytes(), Base64.NO_WRAP); + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java b/src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java index 7b774b681..d5cc037e1 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java @@ -8,27 +8,30 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.xml.TagWriter; public class Plain extends SaslMechanism { - public Plain(final TagWriter tagWriter, final Account account) { - super(tagWriter, account, null); - } - @Override - public int getPriority() { - return 10; - } + public static final String MECHANISM = "PLAIN"; - @Override - public String getMechanism() { - return "PLAIN"; - } + public Plain(final TagWriter tagWriter, final Account account) { + super(tagWriter, account, null); + } - @Override - public String getClientFirstMessage() { - return getMessage(account.getUsername(), account.getPassword()); - } + @Override + public int getPriority() { + return 10; + } - public static String getMessage(String username, String password) { - final String message = '\u0000' + username + '\u0000' + password; - return Base64.encodeToString(message.getBytes(Charset.defaultCharset()), Base64.NO_WRAP); - } + @Override + public String getMechanism() { + return MECHANISM; + } + + @Override + public String getClientFirstMessage() { + return getMessage(account.getUsername(), account.getPassword()); + } + + public static String getMessage(String username, String password) { + final String message = '\u0000' + username + '\u0000' + password; + return Base64.encodeToString(message.getBytes(Charset.defaultCharset()), Base64.NO_WRAP); + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java b/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java index 5833309ce..86fd6524e 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java @@ -7,60 +7,63 @@ import eu.siacs.conversations.xml.TagWriter; public abstract class SaslMechanism { - final protected TagWriter tagWriter; - final protected Account account; - final protected SecureRandom rng; + final protected TagWriter tagWriter; + final protected Account account; + final protected SecureRandom rng; - protected enum State { - INITIAL, - AUTH_TEXT_SENT, - RESPONSE_SENT, - VALID_SERVER_RESPONSE, - } + protected enum State { + INITIAL, + AUTH_TEXT_SENT, + RESPONSE_SENT, + VALID_SERVER_RESPONSE, + } - public static class AuthenticationException extends Exception { - public AuthenticationException(final String message) { - super(message); - } + public static class AuthenticationException extends Exception { + public AuthenticationException(final String message) { + super(message); + } - public AuthenticationException(final Exception inner) { - super(inner); - } + public AuthenticationException(final Exception inner) { + super(inner); + } - public AuthenticationException(final String message, final Exception exception) { - super(message,exception); - } - } + public AuthenticationException(final String message, final Exception exception) { + super(message, exception); + } + } - public static class InvalidStateException extends AuthenticationException { - public InvalidStateException(final String message) { - super(message); - } + public static class InvalidStateException extends AuthenticationException { + public InvalidStateException(final String message) { + super(message); + } - public InvalidStateException(final State state) { - this("Invalid state: " + state.toString()); - } - } + public InvalidStateException(final State state) { + this("Invalid state: " + state.toString()); + } + } - public SaslMechanism(final TagWriter tagWriter, final Account account, final SecureRandom rng) { - this.tagWriter = tagWriter; - this.account = account; - this.rng = rng; - } + public SaslMechanism(final TagWriter tagWriter, final Account account, final SecureRandom rng) { + this.tagWriter = tagWriter; + this.account = account; + this.rng = rng; + } - /** - * The priority is used to pin the authentication mechanism. If authentication fails, it MAY be retried with another - * mechanism of the same priority, but MUST NOT be tried with a mechanism of lower priority (to prevent downgrade - * attacks). - * @return An arbitrary int representing the priority - */ - public abstract int getPriority(); + /** + * The priority is used to pin the authentication mechanism. If authentication fails, it MAY be retried with another + * mechanism of the same priority, but MUST NOT be tried with a mechanism of lower priority (to prevent downgrade + * attacks). + * + * @return An arbitrary int representing the priority + */ + public abstract int getPriority(); - public abstract String getMechanism(); - public String getClientFirstMessage() { - return ""; - } - public String getResponse(final String challenge) throws AuthenticationException { - return ""; - } + public abstract String getMechanism(); + + public String getClientFirstMessage() { + return ""; + } + + public String getResponse(final String challenge) throws AuthenticationException { + return ""; + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java index 5af911cc7..807056bf8 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramMechanism.java @@ -1,7 +1,5 @@ package eu.siacs.conversations.crypto.sasl; -import android.annotation.TargetApi; -import android.os.Build; import android.util.Base64; import com.google.common.base.Objects; @@ -21,7 +19,6 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.TagWriter; -@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) abstract class ScramMechanism extends SaslMechanism { // TODO: When channel binding (SCRAM-SHA1-PLUS) is supported in future, generalize this to indicate support and/or usage. private final static String GS2_HEADER = "n,,"; diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha1.java b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha1.java index 5558d6a43..c58dd147c 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha1.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha1.java @@ -11,27 +11,29 @@ import eu.siacs.conversations.xml.TagWriter; public class ScramSha1 extends ScramMechanism { - @Override - protected HMac getHMAC() { - return new HMac(new SHA1Digest()); - } + public static final String MECHANISM = "SCRAM-SHA-1"; - @Override - protected Digest getDigest() { - return new SHA1Digest(); - } + @Override + protected HMac getHMAC() { + return new HMac(new SHA1Digest()); + } - public ScramSha1(final TagWriter tagWriter, final Account account, final SecureRandom rng) { - super(tagWriter, account, rng); - } + @Override + protected Digest getDigest() { + return new SHA1Digest(); + } - @Override - public int getPriority() { - return 20; - } + public ScramSha1(final TagWriter tagWriter, final Account account, final SecureRandom rng) { + super(tagWriter, account, rng); + } - @Override - public String getMechanism() { - return "SCRAM-SHA-1"; - } + @Override + public int getPriority() { + return 20; + } + + @Override + public String getMechanism() { + return MECHANISM; + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha256.java b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha256.java index 866c1ea79..d5dc42b07 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha256.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha256.java @@ -11,27 +11,29 @@ import eu.siacs.conversations.xml.TagWriter; public class ScramSha256 extends ScramMechanism { - @Override - protected HMac getHMAC() { - return new HMac(new SHA256Digest()); - } + public static final String MECHANISM = "SCRAM-SHA-256"; - @Override - protected Digest getDigest() { - return new SHA256Digest(); - } + @Override + protected HMac getHMAC() { + return new HMac(new SHA256Digest()); + } - public ScramSha256(final TagWriter tagWriter, final Account account, final SecureRandom rng) { - super(tagWriter, account, rng); - } + @Override + protected Digest getDigest() { + return new SHA256Digest(); + } - @Override - public int getPriority() { - return 25; - } + public ScramSha256(final TagWriter tagWriter, final Account account, final SecureRandom rng) { + super(tagWriter, account, rng); + } - @Override - public String getMechanism() { - return "SCRAM-SHA-256"; - } + @Override + public int getPriority() { + return 25; + } + + @Override + public String getMechanism() { + return MECHANISM; + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha512.java b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha512.java new file mode 100644 index 000000000..dbd30945c --- /dev/null +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/ScramSha512.java @@ -0,0 +1,39 @@ +package eu.siacs.conversations.crypto.sasl; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.macs.HMac; + +import java.security.SecureRandom; + +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.xml.TagWriter; + +public class ScramSha512 extends ScramMechanism { + + public static final String MECHANISM = "SCRAM-SHA-512"; + + @Override + protected HMac getHMAC() { + return new HMac(new SHA512Digest()); + } + + @Override + protected Digest getDigest() { + return new SHA512Digest(); + } + + public ScramSha512(final TagWriter tagWriter, final Account account, final SecureRandom rng) { + super(tagWriter, account, rng); + } + + @Override + public int getPriority() { + return 30; + } + + @Override + public String getMechanism() { + return MECHANISM; + } +} diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java b/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java index e37e0fa71..f9ba24f09 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/Tokenizer.java @@ -10,69 +10,69 @@ import java.util.NoSuchElementException; * A tokenizer for GS2 header strings */ public final class Tokenizer implements Iterator, Iterable { - private final List parts; - private int index; + private final List parts; + private int index; - public Tokenizer(final byte[] challenge) { - final String challengeString = new String(challenge); - parts = new ArrayList<>(Arrays.asList(challengeString.split(","))); - // Trim parts. - for (int i = 0; i < parts.size(); i++) { - parts.set(i, parts.get(i).trim()); - } - index = 0; - } + public Tokenizer(final byte[] challenge) { + final String challengeString = new String(challenge); + parts = new ArrayList<>(Arrays.asList(challengeString.split(","))); + // Trim parts. + for (int i = 0; i < parts.size(); i++) { + parts.set(i, parts.get(i).trim()); + } + index = 0; + } - /** - * Returns true if there is at least one more element, false otherwise. - * - * @see #next - */ - @Override - public boolean hasNext() { - return parts.size() != index + 1; - } + /** + * Returns true if there is at least one more element, false otherwise. + * + * @see #next + */ + @Override + public boolean hasNext() { + return parts.size() != index + 1; + } - /** - * Returns the next object and advances the iterator. - * - * @return the next object. - * @throws java.util.NoSuchElementException if there are no more elements. - * @see #hasNext - */ - @Override - public String next() { - if (hasNext()) { - return parts.get(index++); - } else { - throw new NoSuchElementException("No such element. Size is: " + parts.size()); - } - } + /** + * Returns the next object and advances the iterator. + * + * @return the next object. + * @throws java.util.NoSuchElementException if there are no more elements. + * @see #hasNext + */ + @Override + public String next() { + if (hasNext()) { + return parts.get(index++); + } else { + throw new NoSuchElementException("No such element. Size is: " + parts.size()); + } + } - /** - * Removes the last object returned by {@code next} from the collection. - * This method can only be called once between each call to {@code next}. - * - * @throws UnsupportedOperationException if removing is not supported by the collection being - * iterated. - * @throws IllegalStateException if {@code next} has not been called, or {@code remove} has - * already been called after the last call to {@code next}. - */ - @Override - public void remove() { - if(index <= 0) { - throw new IllegalStateException("You can't delete an element before first next() method call"); - } - parts.remove(--index); - } + /** + * Removes the last object returned by {@code next} from the collection. + * This method can only be called once between each call to {@code next}. + * + * @throws UnsupportedOperationException if removing is not supported by the collection being + * iterated. + * @throws IllegalStateException if {@code next} has not been called, or {@code remove} has + * already been called after the last call to {@code next}. + */ + @Override + public void remove() { + if (index <= 0) { + throw new IllegalStateException("You can't delete an element before first next() method call"); + } + parts.remove(--index); + } - /** - * Returns an {@link java.util.Iterator} for the elements in this object. - * - * @return An {@code Iterator} instance. - */ - @Override - public Iterator iterator() { - return parts.iterator(); - } + /** + * Returns an {@link java.util.Iterator} for the elements in this object. + * + * @return An {@code Iterator} instance. + */ + @Override + public Iterator iterator() { + return parts.iterator(); + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 3f699e64e..64db553fe 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -64,6 +64,7 @@ import eu.siacs.conversations.crypto.sasl.Plain; import eu.siacs.conversations.crypto.sasl.SaslMechanism; import eu.siacs.conversations.crypto.sasl.ScramSha1; import eu.siacs.conversations.crypto.sasl.ScramSha256; +import eu.siacs.conversations.crypto.sasl.ScramSha512; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.ServiceDiscoveryResult; @@ -870,20 +871,21 @@ public class XmppConnection implements Runnable { } private void authenticate() throws IOException { - final List mechanisms = extractMechanisms(streamFeatures - .findChild("mechanisms")); + final List mechanisms = extractMechanisms(streamFeatures.findChild("mechanisms")); final Element auth = new Element("auth", Namespace.SASL); - if (mechanisms.contains("EXTERNAL") && account.getPrivateKeyAlias() != null) { + if (mechanisms.contains(External.MECHANISM) && account.getPrivateKeyAlias() != null) { saslMechanism = new External(tagWriter, account, mXmppConnectionService.getRNG()); - } else if (mechanisms.contains("SCRAM-SHA-256")) { + } else if (mechanisms.contains(ScramSha512.MECHANISM)) { + saslMechanism = new ScramSha512(tagWriter, account, mXmppConnectionService.getRNG()); + } else if (mechanisms.contains(ScramSha256.MECHANISM)) { saslMechanism = new ScramSha256(tagWriter, account, mXmppConnectionService.getRNG()); - } else if (mechanisms.contains("SCRAM-SHA-1")) { + } else if (mechanisms.contains(ScramSha1.MECHANISM)) { saslMechanism = new ScramSha1(tagWriter, account, mXmppConnectionService.getRNG()); - } else if (mechanisms.contains("PLAIN") && !account.getJid().getDomain().toEscapedString().equals("nimbuzz.com")) { + } else if (mechanisms.contains(Plain.MECHANISM) && !account.getJid().getDomain().toEscapedString().equals("nimbuzz.com")) { saslMechanism = new Plain(tagWriter, account); - } else if (mechanisms.contains("DIGEST-MD5")) { + } else if (mechanisms.contains(DigestMd5.MECHANISM)) { saslMechanism = new DigestMd5(tagWriter, account, mXmppConnectionService.getRNG()); - } else if (mechanisms.contains("ANONYMOUS")) { + } else if (mechanisms.contains(Anonymous.MECHANISM)) { saslMechanism = new Anonymous(tagWriter, account, mXmppConnectionService.getRNG()); } if (saslMechanism != null) { @@ -1265,27 +1267,27 @@ public class XmppConnection implements Runnable { request.setTo(account.getDomain()); request.addChild("query", Namespace.DISCO_ITEMS).setAttribute("node", Namespace.COMMANDS); sendIqPacket(request, (account, response) -> { - if (response.getType() == IqPacket.TYPE.RESULT) { - final Element query = response.findChild("query",Namespace.DISCO_ITEMS); - if (query == null) { - return; - } - final HashMap commands = new HashMap<>(); - for(final Element child : query.getChildren()) { - if ("item".equals(child.getName())) { - final String node = child.getAttribute("node"); - final Jid jid = child.getAttributeAsJid("jid"); - if (node != null && jid != null) { - commands.put(node, jid); - } - } - } - Log.d(Config.LOGTAG,commands.toString()); - synchronized (this.commands) { - this.commands.clear(); - this.commands.putAll(commands); - } - } + if (response.getType() == IqPacket.TYPE.RESULT) { + final Element query = response.findChild("query", Namespace.DISCO_ITEMS); + if (query == null) { + return; + } + final HashMap commands = new HashMap<>(); + for (final Element child : query.getChildren()) { + if ("item".equals(child.getName())) { + final String node = child.getAttribute("node"); + final Jid jid = child.getAttributeAsJid("jid"); + if (node != null && jid != null) { + commands.put(node, jid); + } + } + } + Log.d(Config.LOGTAG, commands.toString()); + synchronized (this.commands) { + this.commands.clear(); + this.commands.putAll(commands); + } + } }); }