respond to disco#info queries
This commit is contained in:
parent
57d264d72e
commit
e073f22ec0
|
@ -44,7 +44,7 @@ public class Element {
|
|||
}
|
||||
|
||||
public void addExtensions(final Collection<? extends Extension> extensions) {
|
||||
for(final Extension extension : extensions) {
|
||||
for (final Extension extension : extensions) {
|
||||
addExtension(extension);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
package eu.siacs.conversations.xmpp.jingle.stanzas;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
|
||||
import eu.siacs.conversations.entities.DownloadableFile;
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FileTransferDescription extends GenericDescription {
|
||||
|
||||
public static List<String> NAMESPACES = Arrays.asList(
|
||||
Version.FT_3.namespace,
|
||||
Version.FT_4.namespace,
|
||||
Version.FT_5.namespace
|
||||
);
|
||||
|
||||
public static List<String> NAMESPACES =
|
||||
Arrays.asList(Version.FT_3.namespace, Version.FT_4.namespace, Version.FT_5.namespace);
|
||||
|
||||
private FileTransferDescription(String name, String namespace) {
|
||||
super(name, namespace);
|
||||
|
@ -46,8 +40,10 @@ public class FileTransferDescription extends GenericDescription {
|
|||
}
|
||||
}
|
||||
|
||||
public static FileTransferDescription of(DownloadableFile file, Version version, XmppAxolotlMessage axolotlMessage) {
|
||||
final FileTransferDescription description = new FileTransferDescription("description", version.getNamespace());
|
||||
public static FileTransferDescription of(
|
||||
DownloadableFile file, Version version, XmppAxolotlMessage axolotlMessage) {
|
||||
final FileTransferDescription description =
|
||||
new FileTransferDescription("description", version.getNamespace());
|
||||
final Element fileElement;
|
||||
if (version == Version.FT_3) {
|
||||
Element offer = description.addChild("offer");
|
||||
|
@ -64,9 +60,14 @@ public class FileTransferDescription extends GenericDescription {
|
|||
}
|
||||
|
||||
public static FileTransferDescription upgrade(final Element element) {
|
||||
Preconditions.checkArgument("description".equals(element.getName()), "Name of provided element is not description");
|
||||
Preconditions.checkArgument(NAMESPACES.contains(element.getNamespace()), "Element does not match a file transfer namespace");
|
||||
final FileTransferDescription description = new FileTransferDescription("description", element.getNamespace());
|
||||
Preconditions.checkArgument(
|
||||
"description".equals(element.getName()),
|
||||
"Name of provided element is not description");
|
||||
Preconditions.checkArgument(
|
||||
NAMESPACES.contains(element.getNamespace()),
|
||||
"Element does not match a file transfer namespace");
|
||||
final FileTransferDescription description =
|
||||
new FileTransferDescription("description", element.getNamespace());
|
||||
description.setAttributes(element.getAttributes());
|
||||
description.setChildren(element.getChildren());
|
||||
return description;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package im.conversations.android.xmpp;
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
import im.conversations.android.xmpp.model.disco.info.Feature;
|
||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ServiceDescription {
|
||||
public final List<String> features;
|
||||
public final Identity identity;
|
||||
|
||||
public ServiceDescription(List<String> features, Identity identity) {
|
||||
this.features = features;
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
public InfoQuery asInfoQuery() {
|
||||
final var infoQuery = new InfoQuery();
|
||||
final Collection<Feature> features =
|
||||
Collections2.transform(
|
||||
this.features,
|
||||
sf -> {
|
||||
final var feature = new Feature();
|
||||
feature.setVar(sf);
|
||||
return feature;
|
||||
});
|
||||
infoQuery.addExtensions(features);
|
||||
final var identity =
|
||||
infoQuery.addExtension(
|
||||
new im.conversations.android.xmpp.model.disco.info.Identity());
|
||||
identity.setIdentityName(this.identity.name);
|
||||
identity.setCategory(this.identity.category);
|
||||
identity.setType(this.identity.type);
|
||||
return infoQuery;
|
||||
}
|
||||
|
||||
public static class Identity {
|
||||
public final String name;
|
||||
public final String category;
|
||||
public final String type;
|
||||
|
||||
public Identity(String name, String category, String type) {
|
||||
this.name = name;
|
||||
this.category = category;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,9 +57,12 @@ import im.conversations.android.xml.TagWriter;
|
|||
import im.conversations.android.xmpp.manager.AbstractManager;
|
||||
import im.conversations.android.xmpp.manager.CarbonsManager;
|
||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
import im.conversations.android.xmpp.model.StreamElement;
|
||||
import im.conversations.android.xmpp.model.csi.Active;
|
||||
import im.conversations.android.xmpp.model.csi.Inactive;
|
||||
import im.conversations.android.xmpp.model.error.Condition;
|
||||
import im.conversations.android.xmpp.model.error.Error;
|
||||
import im.conversations.android.xmpp.model.ping.Ping;
|
||||
import im.conversations.android.xmpp.model.register.Register;
|
||||
import im.conversations.android.xmpp.model.sm.Ack;
|
||||
|
@ -2042,6 +2045,29 @@ public class XmppConnection implements Runnable {
|
|||
return packet.getId();
|
||||
}
|
||||
|
||||
public void sendResultFor(final Iq request, final Extension... extensions) {
|
||||
final var from = request.getFrom();
|
||||
final var id = request.getId();
|
||||
final var response = new Iq(Iq.Type.RESULT);
|
||||
response.setTo(from);
|
||||
response.setId(id);
|
||||
for (final Extension extension : extensions) {
|
||||
response.addExtension(extension);
|
||||
}
|
||||
this.sendPacket(response);
|
||||
}
|
||||
|
||||
public void sendErrorFor(final Iq request, final Condition condition) {
|
||||
final var from = request.getFrom();
|
||||
final var id = request.getId();
|
||||
final var response = new Iq(Iq.Type.ERROR);
|
||||
response.setTo(from);
|
||||
response.setId(id);
|
||||
final Error error = response.addExtension(new Error());
|
||||
error.setCondition(condition);
|
||||
this.sendPacket(response);
|
||||
}
|
||||
|
||||
public void sendMessagePacket(final Message packet) {
|
||||
this.sendPacket(packet);
|
||||
}
|
||||
|
@ -2325,7 +2351,7 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
private static class StateChangingError extends Error {
|
||||
private static class StateChangingError extends java.lang.Error {
|
||||
private final ConnectionState state;
|
||||
|
||||
public StateChangingError(ConnectionState state) {
|
||||
|
|
|
@ -10,7 +10,6 @@ import com.google.common.io.BaseEncoding;
|
|||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import eu.siacs.conversations.BuildConfig;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
|
@ -18,20 +17,25 @@ import eu.siacs.conversations.xmpp.Jid;
|
|||
import im.conversations.android.xmpp.Entity;
|
||||
import im.conversations.android.xmpp.EntityCapabilities;
|
||||
import im.conversations.android.xmpp.EntityCapabilities2;
|
||||
import im.conversations.android.xmpp.ServiceDescription;
|
||||
import im.conversations.android.xmpp.XmppConnection;
|
||||
import im.conversations.android.xmpp.model.disco.info.Feature;
|
||||
import im.conversations.android.xmpp.model.disco.info.Identity;
|
||||
import im.conversations.android.xmpp.model.Hash;
|
||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||
import im.conversations.android.xmpp.model.disco.items.Item;
|
||||
import im.conversations.android.xmpp.model.disco.items.ItemsQuery;
|
||||
import im.conversations.android.xmpp.model.error.Condition;
|
||||
import im.conversations.android.xmpp.model.stanza.Iq;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class DiscoManager extends AbstractManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DiscoManager.class);
|
||||
|
||||
public static final String CAPABILITY_NODE = "http://conversations.im";
|
||||
|
||||
private static final Collection<String> FEATURES_BASE =
|
||||
|
@ -205,12 +209,11 @@ public class DiscoManager extends AbstractManager {
|
|||
return hasFeature(getAccount().address.getDomain(), feature);
|
||||
}
|
||||
|
||||
public InfoQuery getInfo() {
|
||||
return getInfo(false);
|
||||
public ServiceDescription getServiceDescription() {
|
||||
return getServiceDescription(false);
|
||||
}
|
||||
|
||||
private InfoQuery getInfo(final boolean privacyMode) {
|
||||
final var infoQuery = new InfoQuery();
|
||||
private ServiceDescription getServiceDescription(final boolean privacyMode) {
|
||||
final ImmutableList.Builder<String> stringFeatureBuilder = ImmutableList.builder();
|
||||
stringFeatureBuilder.addAll(FEATURES_BASE);
|
||||
stringFeatureBuilder.addAll(
|
||||
|
@ -218,21 +221,9 @@ public class DiscoManager extends AbstractManager {
|
|||
if (!privacyMode) {
|
||||
stringFeatureBuilder.addAll(FEATURES_AV_CALLS);
|
||||
}
|
||||
final var stringFeatures = stringFeatureBuilder.build();
|
||||
final Collection<Feature> features =
|
||||
Collections2.transform(
|
||||
stringFeatures,
|
||||
sf -> {
|
||||
final var feature = new Feature();
|
||||
feature.setVar(sf);
|
||||
return feature;
|
||||
});
|
||||
infoQuery.addExtensions(features);
|
||||
final var identity = infoQuery.addExtension(new Identity());
|
||||
identity.setIdentityName(getIdentityName());
|
||||
identity.setCategory("client");
|
||||
identity.setType(getIdentityType());
|
||||
return infoQuery;
|
||||
return new ServiceDescription(
|
||||
stringFeatureBuilder.build(),
|
||||
new ServiceDescription.Identity(getIdentityName(), "client", getIdentityType()));
|
||||
}
|
||||
|
||||
String getIdentityVersion() {
|
||||
|
@ -252,4 +243,62 @@ public class DiscoManager extends AbstractManager {
|
|||
return "phone";
|
||||
}
|
||||
}
|
||||
|
||||
public void handleInfoQuery(final Iq request) {
|
||||
final var infoQueryRequest = request.getExtension(InfoQuery.class);
|
||||
final var nodeRequest = infoQueryRequest.getNode();
|
||||
LOGGER.warn("{} requested disco info for node {}", request.getFrom(), nodeRequest);
|
||||
final ServiceDescription serviceDescription;
|
||||
if (Strings.isNullOrEmpty(nodeRequest)) {
|
||||
serviceDescription = getServiceDescription();
|
||||
} else {
|
||||
final var hash = buildHashFromNode(nodeRequest);
|
||||
final var cachedServiceDescription =
|
||||
hash != null
|
||||
? getManager(PresenceManager.class).getCachedServiceDescription(hash)
|
||||
: null;
|
||||
if (cachedServiceDescription != null) {
|
||||
serviceDescription = cachedServiceDescription;
|
||||
} else {
|
||||
LOGGER.warn("No disco info was cached for node {}", nodeRequest);
|
||||
connection.sendErrorFor(request, new Condition.ItemNotFound());
|
||||
return;
|
||||
}
|
||||
}
|
||||
final var infoQuery = serviceDescription.asInfoQuery();
|
||||
infoQuery.setNode(nodeRequest);
|
||||
connection.sendResultFor(request, infoQuery);
|
||||
}
|
||||
|
||||
public static EntityCapabilities.Hash buildHashFromNode(final String node) {
|
||||
final var capsPrefix = CAPABILITY_NODE + "#";
|
||||
final var caps2Prefix = Namespace.ENTITY_CAPABILITIES_2 + "#";
|
||||
if (node.startsWith(capsPrefix)) {
|
||||
final String hash = node.substring(capsPrefix.length());
|
||||
if (Strings.isNullOrEmpty(hash)) {
|
||||
return null;
|
||||
}
|
||||
if (BaseEncoding.base64().canDecode(hash)) {
|
||||
return EntityCapabilities.EntityCapsHash.of(hash);
|
||||
}
|
||||
} else if (node.startsWith(caps2Prefix)) {
|
||||
final String caps = node.substring(caps2Prefix.length());
|
||||
if (Strings.isNullOrEmpty(caps)) {
|
||||
return null;
|
||||
}
|
||||
final int separator = caps.lastIndexOf('.');
|
||||
if (separator < 0) {
|
||||
return null;
|
||||
}
|
||||
final Hash.Algorithm algorithm = Hash.Algorithm.tryParse(caps.substring(0, separator));
|
||||
final String hash = caps.substring(separator + 1);
|
||||
if (algorithm == null || Strings.isNullOrEmpty(hash)) {
|
||||
return null;
|
||||
}
|
||||
if (BaseEncoding.base64().canDecode(hash)) {
|
||||
return EntityCapabilities2.EntityCaps2Hash.of(algorithm, hash);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
package im.conversations.android.xmpp.manager;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import im.conversations.android.xmpp.EntityCapabilities;
|
||||
import im.conversations.android.xmpp.EntityCapabilities2;
|
||||
import im.conversations.android.xmpp.ServiceDescription;
|
||||
import im.conversations.android.xmpp.XmppConnection;
|
||||
import im.conversations.android.xmpp.model.capabilties.Capabilities;
|
||||
import im.conversations.android.xmpp.model.capabilties.LegacyCapabilities;
|
||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||
import im.conversations.android.xmpp.model.stanza.Presence;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PresenceManager extends AbstractManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PresenceManager.class);
|
||||
|
||||
private final Map<EntityCapabilities.Hash, InfoQuery> outgoingCapsHash = new HashMap<>();
|
||||
private final Map<EntityCapabilities.Hash, ServiceDescription> serviceDescriptions =
|
||||
new HashMap<>();
|
||||
|
||||
public PresenceManager(Context context, XmppConnection connection) {
|
||||
super(context, connection);
|
||||
}
|
||||
|
||||
public void sendPresence() {
|
||||
final var infoQuery = getManager(DiscoManager.class).getInfo();
|
||||
final var serviceDiscoveryFeatures = getManager(DiscoManager.class).getServiceDescription();
|
||||
final var infoQuery = serviceDiscoveryFeatures.asInfoQuery();
|
||||
final var capsHash = EntityCapabilities.hash(infoQuery);
|
||||
final var caps2Hash = EntityCapabilities2.hash(infoQuery);
|
||||
outgoingCapsHash.put(capsHash, infoQuery);
|
||||
outgoingCapsHash.put(caps2Hash, infoQuery);
|
||||
serviceDescriptions.put(capsHash, serviceDiscoveryFeatures);
|
||||
serviceDescriptions.put(caps2Hash, serviceDiscoveryFeatures);
|
||||
final var capabilities = new Capabilities();
|
||||
capabilities.setHash(caps2Hash);
|
||||
final var legacyCapabilities = new LegacyCapabilities();
|
||||
|
@ -45,4 +44,8 @@ public class PresenceManager extends AbstractManager {
|
|||
|
||||
connection.sendPresencePacket(presence);
|
||||
}
|
||||
|
||||
public ServiceDescription getCachedServiceDescription(final EntityCapabilities.Hash hash) {
|
||||
return this.serviceDescriptions.get(hash);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ import android.content.Context;
|
|||
import com.google.common.base.Preconditions;
|
||||
import im.conversations.android.xmpp.XmppConnection;
|
||||
import im.conversations.android.xmpp.manager.BlockingManager;
|
||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||
import im.conversations.android.xmpp.manager.RosterManager;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
import im.conversations.android.xmpp.model.blocking.Block;
|
||||
import im.conversations.android.xmpp.model.blocking.Unblock;
|
||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||
import im.conversations.android.xmpp.model.error.Condition;
|
||||
import im.conversations.android.xmpp.model.error.Error;
|
||||
import im.conversations.android.xmpp.model.ping.Ping;
|
||||
import im.conversations.android.xmpp.model.roster.Query;
|
||||
import im.conversations.android.xmpp.model.stanza.Iq;
|
||||
|
@ -34,54 +34,36 @@ public class IqProcessor extends XmppConnection.Delegate implements Consumer<Iq>
|
|||
&& connection.fromAccount(packet)
|
||||
&& packet.hasExtension(Query.class)) {
|
||||
getManager(RosterManager.class).handlePush(packet.getExtension(Query.class));
|
||||
sendResultFor(packet);
|
||||
connection.sendResultFor(packet);
|
||||
return;
|
||||
}
|
||||
if (type == Iq.Type.SET
|
||||
&& connection.fromAccount(packet)
|
||||
&& packet.hasExtension(Block.class)) {
|
||||
getManager(BlockingManager.class).handlePush(packet.getExtension(Block.class));
|
||||
sendResultFor(packet);
|
||||
connection.sendResultFor(packet);
|
||||
return;
|
||||
}
|
||||
if (type == Iq.Type.SET
|
||||
&& connection.fromAccount(packet)
|
||||
&& packet.hasExtension(Unblock.class)) {
|
||||
getManager(BlockingManager.class).handlePush(packet.getExtension(Unblock.class));
|
||||
sendResultFor(packet);
|
||||
connection.sendResultFor(packet);
|
||||
return;
|
||||
}
|
||||
if (type == Iq.Type.GET && packet.hasExtension(Ping.class)) {
|
||||
LOGGER.debug("Responding to ping from {}", packet.getFrom());
|
||||
sendResultFor(packet);
|
||||
connection.sendResultFor(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Iq.Type.GET && packet.hasExtension(InfoQuery.class)) {
|
||||
getManager(DiscoManager.class).handleInfoQuery(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
final var extensionIds = packet.getExtensionIds();
|
||||
LOGGER.info("Could not handle {}. Sending feature-not-implemented", extensionIds);
|
||||
sendErrorFor(packet, new Condition.FeatureNotImplemented());
|
||||
}
|
||||
|
||||
public void sendResultFor(final Iq request, final Extension... extensions) {
|
||||
final var from = request.getFrom();
|
||||
final var id = request.getId();
|
||||
final var response = new Iq(Iq.Type.RESULT);
|
||||
response.setTo(from);
|
||||
response.setId(id);
|
||||
for (final Extension extension : extensions) {
|
||||
response.addExtension(extension);
|
||||
}
|
||||
connection.sendIqPacket(response, null);
|
||||
}
|
||||
|
||||
public void sendErrorFor(final Iq request, final Condition condition) {
|
||||
final var from = request.getFrom();
|
||||
final var id = request.getId();
|
||||
final var response = new Iq(Iq.Type.ERROR);
|
||||
response.setTo(from);
|
||||
response.setId(id);
|
||||
final Error error = response.addExtension(new Error());
|
||||
error.setCondition(condition);
|
||||
connection.sendIqPacket(response, null);
|
||||
connection.sendErrorFor(packet, new Condition.FeatureNotImplemented());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ public class MessageProcessor extends XmppConnection.Delegate implements Consume
|
|||
LOGGER.info("'{}' from {}", body, message.getFrom());
|
||||
}
|
||||
|
||||
LOGGER.info("Message received {}", message.getExtensionIds());
|
||||
|
||||
// TODO process receipt requests (184 + 333)
|
||||
|
||||
// TODO collect Extensions that require transformation (everything that will end up in the
|
||||
|
|
|
@ -2,9 +2,11 @@ package im.conversations.android.xmpp;
|
|||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xml.XmlElementReader;
|
||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -26,8 +28,8 @@ public class EntityCapabilitiesTest {
|
|||
+ " node='http://code.google.com/p/exodus#QgayPKawpkPSDYmwT/WM94uAlu0='>\n"
|
||||
+ " <identity category='client' name='Exodus 0.9.1' type='pc'/>\n"
|
||||
+ " <feature var='http://jabber.org/protocol/caps'/>\n"
|
||||
+ " <feature var='http://jabber.org/protocol/disco#info'/>\n"
|
||||
+ " <feature var='http://jabber.org/protocol/disco#items'/>\n"
|
||||
+ " <feature var='http://jabber.org/protocol/disco#info'/>\n"
|
||||
+ " <feature var='http://jabber.org/protocol/muc'/>\n"
|
||||
+ " </query>";
|
||||
final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
|
||||
|
@ -182,4 +184,30 @@ public class EntityCapabilitiesTest {
|
|||
final String var = EntityCapabilities2.hash(info).encoded();
|
||||
Assert.assertEquals("u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=", var);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseCaps2Node() {
|
||||
final var caps =
|
||||
DiscoManager.buildHashFromNode(
|
||||
"urn:xmpp:caps#sha-256.u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=");
|
||||
assertThat(caps, instanceOf(EntityCapabilities2.EntityCaps2Hash.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseCaps2NodeMissingHash() {
|
||||
final var caps = DiscoManager.buildHashFromNode("urn:xmpp:caps#sha-256.");
|
||||
assertNull(caps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseCaps2NodeInvalid() {
|
||||
final var caps = DiscoManager.buildHashFromNode("urn:xmpp:caps#-");
|
||||
assertNull(caps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseCaps2NodeUnknownAlgo() {
|
||||
final var caps = DiscoManager.buildHashFromNode("urn:xmpp:caps#test.test");
|
||||
assertNull(caps);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue