]> nmode's Git Repositories - signal-cli/commitdiff
Implement listIdentities and trust commands
authorAsamK <asamk@gmx.de>
Thu, 14 Jul 2016 13:35:59 +0000 (15:35 +0200)
committerAsamK <asamk@gmx.de>
Thu, 14 Jul 2016 14:21:05 +0000 (16:21 +0200)
Print the fingerprints of all known phone numbers and can set their trust

src/main/java/org/asamk/signal/Hex.java
src/main/java/org/asamk/signal/JsonIdentityKeyStore.java
src/main/java/org/asamk/signal/JsonSignalProtocolStore.java
src/main/java/org/asamk/signal/Main.java
src/main/java/org/asamk/signal/Manager.java

index 43d77cc5b26c3c0ffcaa5c35cb6d692921e09cf9..696ca62b9aa4407d1266399787f81d80cea5e136 100644 (file)
@@ -19,4 +19,13 @@ public class Hex {
         buf.append(HEX_DIGITS[b & 0xf]);
         buf.append(" ");
     }
+
+    public static byte[] toByteArray(String s) {
+        int len = s.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
+        }
+        return data;
+    }
 }
index d4d0ea3e7f0d12319321d94b782024febc1a764b..7cde350c670a16bb8a7ec9a9a722b7f515404f92 100644 (file)
@@ -85,6 +85,16 @@ class JsonIdentityKeyStore implements IdentityKeyStore {
         return false;
     }
 
+    public Map<String, List<Identity>> getIdentities() {
+        // TODO deep copy
+        return trustedKeys;
+    }
+
+    public List<Identity> getIdentities(String name) {
+        // TODO deep copy
+        return trustedKeys.get(name);
+    }
+
     public static class JsonIdentityKeyStoreDeserializer extends JsonDeserializer<JsonIdentityKeyStore> {
 
         @Override
@@ -165,8 +175,8 @@ class JsonIdentityKeyStore implements IdentityKeyStore {
                     trustLevel == TrustLevel.TRUSTED_VERIFIED;
         }
 
-        public String getFingerprint() {
-            return Hex.toStringCondensed(identityKey.getPublicKey().serialize());
+        public byte[] getFingerprint() {
+            return identityKey.getPublicKey().serialize();
         }
     }
 }
index 015707ae5be1c01e6c50e6786b282fadb0b91272..a3159e48d5bec6a99954a2a169049fd2bb92614b 100644 (file)
@@ -13,6 +13,7 @@ import org.whispersystems.libsignal.state.SignalProtocolStore;
 import org.whispersystems.libsignal.state.SignedPreKeyRecord;
 
 import java.util.List;
+import java.util.Map;
 
 class JsonSignalProtocolStore implements SignalProtocolStore {
 
@@ -72,6 +73,14 @@ class JsonSignalProtocolStore implements SignalProtocolStore {
         identityKeyStore.saveIdentity(name, identityKey, trustLevel, null);
     }
 
+    public Map<String, List<JsonIdentityKeyStore.Identity>> getIdentities() {
+        return identityKeyStore.getIdentities();
+    }
+
+    public List<JsonIdentityKeyStore.Identity> getIdentities(String name) {
+        return identityKeyStore.getIdentities(name);
+    }
+
     @Override
     public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
         return identityKeyStore.isTrustedIdentity(name, identityKey);
index 3b76a2b842a23a6357030433a8fd55b1b8ae1090..25807a6b5e58840bdc16aed3e7ffd81a720e2aed 100644 (file)
@@ -48,6 +48,8 @@ import java.nio.charset.Charset;
 import java.security.Security;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.TimeoutException;
 
 public class Main {
@@ -436,6 +438,65 @@ public class Main {
                         return 3;
                     }
 
+                    break;
+                case "listIdentities":
+                    if (dBusConn != null) {
+                        System.err.println("listIdentities is not yet implemented via dbus");
+                        return 1;
+                    }
+                    if (!m.isRegistered()) {
+                        System.err.println("User is not registered.");
+                        return 1;
+                    }
+                    if (ns.get("number") == null) {
+                        for (Map.Entry<String, List<JsonIdentityKeyStore.Identity>> keys : m.getIdentities().entrySet()) {
+                            for (JsonIdentityKeyStore.Identity id : keys.getValue()) {
+                                System.out.println(String.format("%s: %s Added: %s Fingerprint: %s", keys.getKey(), id.trustLevel, id.added, Hex.toStringCondensed(id.getFingerprint())));
+                            }
+                        }
+                    } else {
+                        String number = ns.getString("number");
+                        for (JsonIdentityKeyStore.Identity id : m.getIdentities(number)) {
+                            System.out.println(String.format("%s: %s Added: %s Fingerprint: %s", number, id.trustLevel, id.added, Hex.toStringCondensed(id.getFingerprint())));
+                        }
+                    }
+                    break;
+                case "trust":
+                    if (dBusConn != null) {
+                        System.err.println("trust is not yet implemented via dbus");
+                        return 1;
+                    }
+                    if (!m.isRegistered()) {
+                        System.err.println("User is not registered.");
+                        return 1;
+                    }
+                    String number = ns.getString("number");
+                    if (ns.getBoolean("trust_all_known_keys")) {
+                        boolean res = m.trustIdentityAllKeys(number);
+                        if (!res) {
+                            System.err.println("Failed to set the trust for this number, make sure the number is correct.");
+                            return 1;
+                        }
+                    } else {
+                        String fingerprint = ns.getString("verified_fingerprint");
+                        if (fingerprint != null) {
+                            byte[] fingerprintBytes;
+                            try {
+                                fingerprintBytes = Hex.toByteArray(fingerprint.replaceAll(" ", "").toLowerCase(Locale.ROOT));
+                            } catch (Exception e) {
+                                System.err.println("Failed to parse the fingerprint, make sure the fingerprint is a correctly encoded hex string without additional characters.");
+                                return 1;
+                            }
+                            boolean res = m.trustIdentityVerified(number, fingerprintBytes);
+                            if (!res) {
+                                System.err.println("Failed to set the trust for the fingerprint of this number, make sure the number and the fingerprint are correct.");
+                                return 1;
+                            }
+                        } else {
+                            System.err.println("You need to specify the fingerprint you have verified with -v FINGERPRINT");
+                            return 1;
+                        }
+                    }
                     break;
                 case "daemon":
                     if (dBusConn != null) {
@@ -593,6 +654,21 @@ public class Main {
                 .nargs("*")
                 .help("Specify one or more members to add to the group");
 
+        Subparser parserListIdentities = subparsers.addParser("listIdentities");
+        parserListIdentities.addArgument("-n", "--number")
+                .help("Only show identity keys for the given phone number.");
+
+        Subparser parserTrust = subparsers.addParser("trust");
+        parserTrust.addArgument("number")
+                .help("Specify the phone number, for which to set the trust.")
+                .required(true);
+        MutuallyExclusiveGroup mutTrust = parserTrust.addMutuallyExclusiveGroup();
+        mutTrust.addArgument("-a", "--trust-all-known-keys")
+                .help("Trust all known keys of this user, only use this for testing.")
+                .action(Arguments.storeTrue());
+        mutTrust.addArgument("-v", "--verified-fingerprint")
+                .help("Specify the fingerprint of the key, only use this option if you have verified the fingerprint.");
+
         Subparser parserReceive = subparsers.addParser("receive");
         parserReceive.addArgument("-t", "--timeout")
                 .type(int.class)
index 3ce9dfbe144595ad3a76563fcf020717bfabcdd2..3e36e319c35825b93fbdcf2a7d6b5dc7add2a23f 100644 (file)
@@ -1100,4 +1100,54 @@ class Manager implements Signal {
     public GroupInfo getGroup(byte[] groupId) {
         return groupStore.getGroup(groupId);
     }
+
+    public Map<String, List<JsonIdentityKeyStore.Identity>> getIdentities() {
+        return signalProtocolStore.getIdentities();
+    }
+
+    public List<JsonIdentityKeyStore.Identity> getIdentities(String number) {
+        return signalProtocolStore.getIdentities(number);
+    }
+
+    /**
+     * Trust this the identity with this fingerprint
+     *
+     * @param name        username of the identity
+     * @param fingerprint Fingerprint
+     */
+    public boolean trustIdentityVerified(String name, byte[] fingerprint) {
+        List<JsonIdentityKeyStore.Identity> ids = signalProtocolStore.getIdentities(name);
+        if (ids == null) {
+            return false;
+        }
+        for (JsonIdentityKeyStore.Identity id : ids) {
+            if (!Arrays.equals(id.identityKey.serialize(), fingerprint)) {
+                continue;
+            }
+
+            signalProtocolStore.saveIdentity(name, id.identityKey, TrustLevel.TRUSTED_VERIFIED);
+            save();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Trust all keys of this identity without verification
+     *
+     * @param name username of the identity
+     */
+    public boolean trustIdentityAllKeys(String name) {
+        List<JsonIdentityKeyStore.Identity> ids = signalProtocolStore.getIdentities(name);
+        if (ids == null) {
+            return false;
+        }
+        for (JsonIdentityKeyStore.Identity id : ids) {
+            if (id.trustLevel == TrustLevel.UNTRUSTED) {
+                signalProtocolStore.saveIdentity(name, id.identityKey, TrustLevel.TRUSTED_UNVERIFIED);
+            }
+        }
+        save();
+        return true;
+    }
 }