respond to XEP-0202: Entity Time

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java |  6 
src/main/java/eu/siacs/conversations/generator/IqGenerator.java       | 14 
src/main/java/eu/siacs/conversations/parser/IqParser.java             | 16 
3 files changed, 34 insertions(+), 2 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java 🔗

@@ -42,6 +42,9 @@ public abstract class AbstractGenerator {
 	private final String[] MESSAGE_CORRECTION_FEATURES = {
 			"urn:xmpp:message-correct:0"
 	};
+	private final String[] PRIVACY_SENSITIVE = {
+			"urn:xmpp:time" //XEP-0202: Entity Time leaks time zone
+	};
 	private String mVersion = null;
 	protected final String IDENTITY_NAME = "Conversations";
 	protected final String IDENTITY_TYPE = "phone";
@@ -99,6 +102,9 @@ public abstract class AbstractGenerator {
 		if (Config.supportOmemo()) {
 			features.add(AxolotlService.PEP_DEVICE_LIST_NOTIFY);
 		}
+		if (!mXmppConnectionService.useTorToConnect()) {
+			features.addAll(Arrays.asList(PRIVACY_SENSITIVE));
+		}
 		Collections.sort(features);
 		return features;
 	}

src/main/java/eu/siacs/conversations/generator/IqGenerator.java 🔗

@@ -15,6 +15,7 @@ import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.TimeZone;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -61,6 +62,19 @@ public class IqGenerator extends AbstractGenerator {
 		return packet;
 	}
 
+	public IqPacket entityTimeResponse(IqPacket request) {
+		final IqPacket packet = request.generateResponse(IqPacket.TYPE.RESULT);
+		Element time = packet.addChild("time","urn:xmpp:time");
+		final long now = System.currentTimeMillis();
+		time.addChild("utc").setContent(getTimestamp(now));
+		TimeZone ourTimezone = TimeZone.getDefault();
+		long offsetSeconds = ourTimezone.getOffset(now) / 1000;
+		long offsetMinutes = offsetSeconds % (60 * 60);
+		long offsetHours = offsetSeconds / (60 * 60);
+		time.addChild("tzo").setContent(String.format("%02d",offsetHours)+":"+String.format("%02d",offsetMinutes));
+		return packet;
+	}
+
 	protected IqPacket publish(final String node, final Element item) {
 		final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
 		final Element pubsub = packet.addChild("pubsub",

src/main/java/eu/siacs/conversations/parser/IqParser.java 🔗

@@ -277,6 +277,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
 
 	@Override
 	public void onIqPacketReceived(final Account account, final IqPacket packet) {
+		final boolean isGet = packet.getType() == IqPacket.TYPE.GET;
 		if (packet.getType() == IqPacket.TYPE.ERROR || packet.getType() == IqPacket.TYPE.TIMEOUT) {
 			return;
 		} else if (packet.hasChild("query", Xmlns.ROSTER) && packet.fromServer(account)) {
@@ -348,12 +349,23 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
 		} else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) {
 			final IqPacket response = mXmppConnectionService.getIqGenerator().discoResponse(packet);
 			mXmppConnectionService.sendIqPacket(account, response, null);
-		} else if (packet.hasChild("query","jabber:iq:version")) {
+		} else if (packet.hasChild("query","jabber:iq:version") && isGet) {
 			final IqPacket response = mXmppConnectionService.getIqGenerator().versionResponse(packet);
 			mXmppConnectionService.sendIqPacket(account,response,null);
-		} else if (packet.hasChild("ping", "urn:xmpp:ping")) {
+		} else if (packet.hasChild("ping", "urn:xmpp:ping") && isGet) {
 			final IqPacket response = packet.generateResponse(IqPacket.TYPE.RESULT);
 			mXmppConnectionService.sendIqPacket(account, response, null);
+		} else if (packet.hasChild("time","urn:xmpp:time") && isGet) {
+			final IqPacket response;
+			if (mXmppConnectionService.useTorToConnect()) {
+				response = packet.generateResponse(IqPacket.TYPE.ERROR);
+				final Element error = response.addChild("error");
+				error.setAttribute("type","cancel");
+				error.addChild("not-allowed","urn:ietf:params:xml:ns:xmpp-stanzas");
+			} else {
+				response = mXmppConnectionService.getIqGenerator().entityTimeResponse(packet);
+			}
+			mXmppConnectionService.sendIqPacket(account,response, null);
 		} else {
 			if (packet.getType() == IqPacket.TYPE.GET || packet.getType() == IqPacket.TYPE.SET) {
 				final IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR);