respond to software version requests
This commit is contained in:
parent
e073f22ec0
commit
f1e1cf9653
|
@ -1,6 +1,7 @@
|
|||
package im.conversations.android.xmpp.manager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.common.base.Strings;
|
||||
|
@ -25,8 +26,10 @@ 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 im.conversations.android.xmpp.model.version.Version;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -34,10 +37,8 @@ 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 Logger LOGGER = LoggerFactory.getLogger(DiscoManager.class);
|
||||
private static final Collection<String> FEATURES_BASE =
|
||||
Arrays.asList(
|
||||
Namespace.JINGLE,
|
||||
|
@ -55,7 +56,6 @@ public class DiscoManager extends AbstractManager {
|
|||
Namespace.ENTITY_CAPABILITIES_2,
|
||||
Namespace.DISCO_INFO,
|
||||
Namespace.PING,
|
||||
Namespace.VERSION,
|
||||
Namespace.CHAT_STATES,
|
||||
Namespace.LAST_MESSAGE_CORRECTION,
|
||||
Namespace.DELIVERY_RECEIPTS);
|
||||
|
@ -69,6 +69,9 @@ public class DiscoManager extends AbstractManager {
|
|||
Namespace.JINGLE_APPS_DTLS,
|
||||
Namespace.JINGLE_MESSAGE);
|
||||
|
||||
private static final Collection<String> FEATURES_IMPACTING_PRIVACY =
|
||||
Collections.singleton(Namespace.VERSION);
|
||||
|
||||
private static final Collection<String> FEATURES_NOTIFY =
|
||||
Arrays.asList(Namespace.NICK, Namespace.AVATAR_METADATA, Namespace.BOOKMARKS2);
|
||||
|
||||
|
@ -76,6 +79,38 @@ public class DiscoManager extends AbstractManager {
|
|||
super(context, connection);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public ListenableFuture<InfoQuery> info(final Entity entity) {
|
||||
return info(entity, null);
|
||||
}
|
||||
|
@ -210,30 +245,29 @@ public class DiscoManager extends AbstractManager {
|
|||
}
|
||||
|
||||
public ServiceDescription getServiceDescription() {
|
||||
return getServiceDescription(false);
|
||||
return getServiceDescription(isPrivacyModeEnabled());
|
||||
}
|
||||
|
||||
private ServiceDescription getServiceDescription(final boolean privacyMode) {
|
||||
final ImmutableList.Builder<String> stringFeatureBuilder = ImmutableList.builder();
|
||||
stringFeatureBuilder.addAll(FEATURES_BASE);
|
||||
stringFeatureBuilder.addAll(
|
||||
final ImmutableList.Builder<String> builder = ImmutableList.builder();
|
||||
final List<String> features;
|
||||
builder.addAll(FEATURES_BASE);
|
||||
builder.addAll(
|
||||
Collections2.transform(FEATURES_NOTIFY, fn -> String.format("%s+notify", fn)));
|
||||
if (!privacyMode) {
|
||||
stringFeatureBuilder.addAll(FEATURES_AV_CALLS);
|
||||
if (privacyMode) {
|
||||
features = builder.build();
|
||||
} else {
|
||||
features = builder.addAll(FEATURES_AV_CALLS).addAll(FEATURES_IMPACTING_PRIVACY).build();
|
||||
}
|
||||
return new ServiceDescription(
|
||||
stringFeatureBuilder.build(),
|
||||
new ServiceDescription.Identity(getIdentityName(), "client", getIdentityType()));
|
||||
features,
|
||||
new ServiceDescription.Identity(BuildConfig.APP_NAME, "client", getIdentityType()));
|
||||
}
|
||||
|
||||
String getIdentityVersion() {
|
||||
return BuildConfig.VERSION_NAME;
|
||||
}
|
||||
|
||||
String getIdentityName() {
|
||||
return BuildConfig.APP_NAME;
|
||||
}
|
||||
|
||||
String getIdentityType() {
|
||||
if ("chromium".equals(android.os.Build.BRAND)) {
|
||||
return "pc";
|
||||
|
@ -270,35 +304,19 @@ public class DiscoManager extends AbstractManager {
|
|||
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);
|
||||
}
|
||||
public void handleVersion(final Iq request) {
|
||||
if (isPrivacyModeEnabled()) {
|
||||
connection.sendErrorFor(request, new Condition.ServiceUnavailable());
|
||||
} else {
|
||||
final var version = new Version();
|
||||
version.setSoftwareName(BuildConfig.APP_NAME);
|
||||
version.setVersion(BuildConfig.VERSION_NAME);
|
||||
version.setOs(String.format("Android %s", Build.VERSION.RELEASE));
|
||||
connection.sendResultFor(request, version);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isPrivacyModeEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package im.conversations.android.xmpp.model.version;
|
||||
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
import im.conversations.android.annotation.XmlElement;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
|
||||
@XmlElement(name = "query", namespace = Namespace.VERSION)
|
||||
public class Version extends Extension {
|
||||
|
||||
public Version() {
|
||||
super(Version.class);
|
||||
}
|
||||
|
||||
public void setSoftwareName(final String name) {
|
||||
this.addChild("name").setContent(name);
|
||||
}
|
||||
|
||||
public void setVersion(final String version) {
|
||||
this.addChild("version").setContent(version);
|
||||
}
|
||||
|
||||
public void setOs(final String os) {
|
||||
this.addChild("os").setContent(os);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import im.conversations.android.xmpp.model.error.Condition;
|
|||
import im.conversations.android.xmpp.model.ping.Ping;
|
||||
import im.conversations.android.xmpp.model.roster.Query;
|
||||
import im.conversations.android.xmpp.model.stanza.Iq;
|
||||
import im.conversations.android.xmpp.model.version.Version;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -62,6 +63,11 @@ public class IqProcessor extends XmppConnection.Delegate implements Consumer<Iq>
|
|||
return;
|
||||
}
|
||||
|
||||
if (type == Iq.Type.GET && packet.hasExtension(Version.class)) {
|
||||
getManager(DiscoManager.class).handleVersion(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
final var extensionIds = packet.getExtensionIds();
|
||||
LOGGER.info("Could not handle {}. Sending feature-not-implemented", extensionIds);
|
||||
connection.sendErrorFor(packet, new Condition.FeatureNotImplemented());
|
||||
|
|
Loading…
Reference in a new issue