aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/parser/IqParser.java
diff options
context:
space:
mode:
authorAndreas Straub <andreas.straub@rwth-aachen.de>2015-06-25 16:58:24 +0200
committerAndreas Straub <andy@strb.org>2015-07-19 21:32:26 +0200
commit77619b55e47aafbe6b5a530b33ce8b6a77a615dd (patch)
treef77394162a87438c223642d0fa7cf6a29f0aafd8 /src/main/java/eu/siacs/conversations/parser/IqParser.java
parentf73aa1a2006beb741bc39026bfd10e6166d7951a (diff)
Added PEP and message protocol layers
Can now fetch/retrieve from PEP, as well as encode/decode messages
Diffstat (limited to 'src/main/java/eu/siacs/conversations/parser/IqParser.java')
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java158
1 files changed, 157 insertions, 1 deletions
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index 6039d395..00f96885 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -1,9 +1,19 @@
package eu.siacs.conversations.parser;
+import android.util.Base64;
import android.util.Log;
+import org.whispersystems.libaxolotl.IdentityKey;
+import org.whispersystems.libaxolotl.InvalidKeyException;
+import org.whispersystems.libaxolotl.ecc.Curve;
+import org.whispersystems.libaxolotl.ecc.ECPublicKey;
+import org.whispersystems.libaxolotl.state.PreKeyBundle;
+
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
@@ -60,7 +70,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
public String avatarData(final IqPacket packet) {
final Element pubsub = packet.findChild("pubsub",
- "http://jabber.org/protocol/pubsub");
+ "http://jabber.org/protocol/pubsub");
if (pubsub == null) {
return null;
}
@@ -71,6 +81,152 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
return super.avatarData(items);
}
+ public Element getItem(final IqPacket packet) {
+ final Element pubsub = packet.findChild("pubsub",
+ "http://jabber.org/protocol/pubsub");
+ if (pubsub == null) {
+ return null;
+ }
+ final Element items = pubsub.findChild("items");
+ if (items == null) {
+ return null;
+ }
+ return items.findChild("item");
+ }
+
+ public List<Integer> deviceIds(final Element item) {
+ List<Integer> deviceIds = new ArrayList<>();
+ if (item == null) {
+ return null;
+ }
+ final Element list = item.findChild("list");
+ if(list == null) {
+ return null;
+ }
+ for(Element device : list.getChildren()) {
+ if(!device.getName().equals("device")) {
+ continue;
+ }
+ try {
+ Integer id = Integer.valueOf(device.getAttribute("id"));
+ deviceIds.add(id);
+ } catch (NumberFormatException e) {
+ Log.e(Config.LOGTAG, "Encountered nvalid <device> node in PEP:" + device.toString()
+ + ", skipping...");
+ continue;
+ }
+ }
+ return deviceIds;
+ }
+
+ public Integer signedPreKeyId(final Element bundle) {
+ final Element signedPreKeyPublic = bundle.findChild("signedPreKeyPublic");
+ if(signedPreKeyPublic == null) {
+ return null;
+ }
+ return Integer.valueOf(signedPreKeyPublic.getAttribute("signedPreKeyId"));
+ }
+
+ public ECPublicKey signedPreKeyPublic(final Element bundle) {
+ ECPublicKey publicKey = null;
+ final Element signedPreKeyPublic = bundle.findChild("signedPreKeyPublic");
+ if(signedPreKeyPublic == null) {
+ return null;
+ }
+ try {
+ publicKey = Curve.decodePoint(Base64.decode(signedPreKeyPublic.getContent(),Base64.DEFAULT), 0);
+ } catch (InvalidKeyException e) {
+ Log.e(Config.LOGTAG, "Invalid signedPreKeyPublic in PEP: " + e.getMessage());
+ }
+ return publicKey;
+ }
+
+ public byte[] signedPreKeySignature(final Element bundle) {
+ final Element signedPreKeySignature = bundle.findChild("signedPreKeySignature");
+ if(signedPreKeySignature == null) {
+ return null;
+ }
+ return Base64.decode(signedPreKeySignature.getContent(),Base64.DEFAULT);
+ }
+
+ public IdentityKey identityKey(final Element bundle) {
+ IdentityKey identityKey = null;
+ final Element identityKeyElement = bundle.findChild("identityKey");
+ if(identityKeyElement == null) {
+ return null;
+ }
+ try {
+ identityKey = new IdentityKey(Base64.decode(identityKeyElement.getContent(), Base64.DEFAULT), 0);
+ } catch (InvalidKeyException e) {
+ Log.e(Config.LOGTAG,"Invalid identityKey in PEP: "+e.getMessage());
+ }
+ return identityKey;
+ }
+
+ public Map<Integer, ECPublicKey> preKeyPublics(final IqPacket packet) {
+ Map<Integer, ECPublicKey> preKeyRecords = new HashMap<>();
+ Element prekeysItem = getItem(packet);
+ if (prekeysItem == null) {
+ Log.d(Config.LOGTAG, "Couldn't find <item> in preKeyPublic IQ packet: " + packet);
+ return null;
+ }
+ final Element prekeysElement = prekeysItem.findChild("prekeys");
+ if(prekeysElement == null) {
+ Log.d(Config.LOGTAG, "Couldn't find <prekeys> in preKeyPublic IQ packet: " + packet);
+ return null;
+ }
+ for(Element preKeyPublicElement : prekeysElement.getChildren()) {
+ if(!preKeyPublicElement.getName().equals("preKeyPublic")){
+ Log.d(Config.LOGTAG, "Encountered unexpected tag in prekeys list: " + preKeyPublicElement);
+ continue;
+ }
+ Integer preKeyId = Integer.valueOf(preKeyPublicElement.getAttribute("preKeyId"));
+ try {
+ ECPublicKey preKeyPublic = Curve.decodePoint(Base64.decode(preKeyPublicElement.getContent(), Base64.DEFAULT), 0);
+ preKeyRecords.put(preKeyId, preKeyPublic);
+ } catch (InvalidKeyException e) {
+ Log.e(Config.LOGTAG, "Invalid preKeyPublic (ID="+preKeyId+") in PEP: "+ e.getMessage()+", skipping...");
+ continue;
+ }
+ }
+ return preKeyRecords;
+ }
+
+ public PreKeyBundle bundle(final IqPacket bundle) {
+ Element bundleItem = getItem(bundle);
+ if(bundleItem == null) {
+ return null;
+ }
+ final Element bundleElement = bundleItem.findChild("bundle");
+ if(bundleElement == null) {
+ return null;
+ }
+ ECPublicKey signedPreKeyPublic = signedPreKeyPublic(bundleElement);
+ Integer signedPreKeyId = signedPreKeyId(bundleElement);
+ byte[] signedPreKeySignature = signedPreKeySignature(bundleElement);
+ IdentityKey identityKey = identityKey(bundleElement);
+ if(signedPreKeyPublic == null || identityKey == null) {
+ return null;
+ }
+
+ return new PreKeyBundle(0, 0, 0, null,
+ signedPreKeyId, signedPreKeyPublic, signedPreKeySignature, identityKey);
+ }
+
+ public List<PreKeyBundle> preKeys(final IqPacket preKeys) {
+ List<PreKeyBundle> bundles = new ArrayList<>();
+ Map<Integer, ECPublicKey> preKeyPublics = preKeyPublics(preKeys);
+ if ( preKeyPublics != null) {
+ for (Integer preKeyId : preKeyPublics.keySet()) {
+ ECPublicKey preKeyPublic = preKeyPublics.get(preKeyId);
+ bundles.add(new PreKeyBundle(0, 0, preKeyId, preKeyPublic,
+ 0, null, null, null));
+ }
+ }
+
+ return bundles;
+ }
+
@Override
public void onIqPacketReceived(final Account account, final IqPacket packet) {
if (packet.hasChild("query", Xmlns.ROSTER) && packet.fromServer(account)) {