]> nmode's Git Repositories - signal-cli/blobdiff - src/main/java/org/asamk/signal/Manager.java
Cleanup
[signal-cli] / src / main / java / org / asamk / signal / Manager.java
index 6ed8b04517b8f556d8424ae9b575eacd1516535f..42f5ba859a8cebd3ba62367afa2fb5aa2bbe3bc8 100644 (file)
@@ -31,6 +31,8 @@ import org.whispersystems.libsignal.*;
 import org.whispersystems.libsignal.ecc.Curve;
 import org.whispersystems.libsignal.ecc.ECKeyPair;
 import org.whispersystems.libsignal.ecc.ECPublicKey;
+import org.whispersystems.libsignal.fingerprint.Fingerprint;
+import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
 import org.whispersystems.libsignal.state.PreKeyRecord;
 import org.whispersystems.libsignal.state.SignedPreKeyRecord;
 import org.whispersystems.libsignal.util.KeyHelper;
@@ -91,7 +93,7 @@ class Manager implements Signal {
     private FileChannel fileChannel;
     private FileLock lock;
 
-    private final ObjectMapper jsonProcessot = new ObjectMapper();
+    private final ObjectMapper jsonProcessor = new ObjectMapper();
     private String username;
     private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
     private String password;
@@ -113,18 +115,22 @@ class Manager implements Signal {
         this.attachmentsPath = this.settingsPath + "/attachments";
         this.avatarsPath = this.settingsPath + "/avatars";
 
-        jsonProcessot.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect
-        jsonProcessot.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print, you can disable it.
-        jsonProcessot.enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
-        jsonProcessot.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
-        jsonProcessot.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
-        jsonProcessot.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+        jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect
+        jsonProcessor.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print, you can disable it.
+        jsonProcessor.enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
+        jsonProcessor.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+        jsonProcessor.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
+        jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
     }
 
     public String getUsername() {
         return username;
     }
 
+    private IdentityKey getIdentity() {
+        return signalProtocolStore.getIdentityKeyPair().getPublicKey();
+    }
+
     public int getDeviceId() {
         return deviceId;
     }
@@ -205,9 +211,25 @@ class Manager implements Signal {
         }
     }
 
-    public void load() throws IOException, InvalidKeyException {
+    public void init() throws IOException {
+        load();
+
+        migrateLegacyConfigs();
+
+        accountManager = new SignalServiceAccountManager(URL, TRUST_STORE, username, password, deviceId, USER_AGENT);
+        try {
+            if (registered && accountManager.getPreKeysCount() < PREKEY_MINIMUM_COUNT) {
+                refreshPreKeys();
+                save();
+            }
+        } catch (AuthorizationFailedException e) {
+            System.err.println("Authorization failed, was the number registered elsewhere?");
+        }
+    }
+
+    private void load() throws IOException {
         openFileChannel();
-        JsonNode rootNode = jsonProcessot.readTree(Channels.newInputStream(fileChannel));
+        JsonNode rootNode = jsonProcessor.readTree(Channels.newInputStream(fileChannel));
 
         JsonNode node = rootNode.get("deviceId");
         if (node != null) {
@@ -228,19 +250,30 @@ class Manager implements Signal {
         } else {
             nextSignedPreKeyId = 0;
         }
-        signalProtocolStore = jsonProcessot.convertValue(getNotNullNode(rootNode, "axolotlStore"), JsonSignalProtocolStore.class);
+        signalProtocolStore = jsonProcessor.convertValue(getNotNullNode(rootNode, "axolotlStore"), JsonSignalProtocolStore.class);
         registered = getNotNullNode(rootNode, "registered").asBoolean();
         JsonNode groupStoreNode = rootNode.get("groupStore");
         if (groupStoreNode != null) {
-            groupStore = jsonProcessot.convertValue(groupStoreNode, JsonGroupStore.class);
+            groupStore = jsonProcessor.convertValue(groupStoreNode, JsonGroupStore.class);
         }
         if (groupStore == null) {
             groupStore = new JsonGroupStore();
         }
+
+        JsonNode contactStoreNode = rootNode.get("contactStore");
+        if (contactStoreNode != null) {
+            contactStore = jsonProcessor.convertValue(contactStoreNode, JsonContactsStore.class);
+        }
+        if (contactStore == null) {
+            contactStore = new JsonContactsStore();
+        }
+    }
+
+    private void migrateLegacyConfigs() {
         // Copy group avatars that were previously stored in the attachments folder
         // to the new avatar folder
-        if (groupStore.groupsWithLegacyAvatarId.size() > 0) {
-            for (GroupInfo g : groupStore.groupsWithLegacyAvatarId) {
+        if (JsonGroupStore.groupsWithLegacyAvatarId.size() > 0) {
+            for (GroupInfo g : JsonGroupStore.groupsWithLegacyAvatarId) {
                 File avatarFile = getGroupAvatarFile(g.groupId);
                 File attachmentFile = getAttachmentFile(g.getAvatarId());
                 if (!avatarFile.exists() && attachmentFile.exists()) {
@@ -252,34 +285,16 @@ class Manager implements Signal {
                     }
                 }
             }
-            groupStore.groupsWithLegacyAvatarId.clear();
+            JsonGroupStore.groupsWithLegacyAvatarId.clear();
             save();
         }
-
-        JsonNode contactStoreNode = rootNode.get("contactStore");
-        if (contactStoreNode != null) {
-            contactStore = jsonProcessot.convertValue(contactStoreNode, JsonContactsStore.class);
-        }
-        if (contactStore == null) {
-            contactStore = new JsonContactsStore();
-        }
-
-        accountManager = new SignalServiceAccountManager(URL, TRUST_STORE, username, password, deviceId, USER_AGENT);
-        try {
-            if (registered && accountManager.getPreKeysCount() < PREKEY_MINIMUM_COUNT) {
-                refreshPreKeys();
-                save();
-            }
-        } catch (AuthorizationFailedException e) {
-            System.err.println("Authorization failed, was the number registered elsewhere?");
-        }
     }
 
     private void save() {
         if (username == null) {
             return;
         }
-        ObjectNode rootNode = jsonProcessot.createObjectNode();
+        ObjectNode rootNode = jsonProcessor.createObjectNode();
         rootNode.put("username", username)
                 .put("deviceId", deviceId)
                 .put("password", password)
@@ -294,7 +309,7 @@ class Manager implements Signal {
         try {
             openFileChannel();
             fileChannel.position(0);
-            jsonProcessot.writeValue(Channels.newOutputStream(fileChannel), rootNode);
+            jsonProcessor.writeValue(Channels.newOutputStream(fileChannel), rootNode);
             fileChannel.truncate(fileChannel.position());
             fileChannel.force(false);
         } catch (Exception e) {
@@ -1026,8 +1041,11 @@ class Manager implements Signal {
                         DeviceContactsInputStream s = new DeviceContactsInputStream(retrieveAttachmentAsStream(syncMessage.getContacts().get().asPointer()));
                         DeviceContact c;
                         while ((c = s.read()) != null) {
-                            ContactInfo contact = new ContactInfo();
-                            contact.number = c.getNumber();
+                            ContactInfo contact = contactStore.getContact(c.getNumber());
+                            if (contact == null) {
+                                contact = new ContactInfo();
+                                contact.number = c.getNumber();
+                            }
                             if (c.getName().isPresent()) {
                                 contact.name = c.getName().get();
                             }
@@ -1330,6 +1348,29 @@ class Manager implements Signal {
         return false;
     }
 
+    /**
+     * Trust this the identity with this safety number
+     *
+     * @param name         username of the identity
+     * @param safetyNumber Safety number
+     */
+    public boolean trustIdentityVerifiedSafetyNumber(String name, String safetyNumber) {
+        List<JsonIdentityKeyStore.Identity> ids = signalProtocolStore.getIdentities(name);
+        if (ids == null) {
+            return false;
+        }
+        for (JsonIdentityKeyStore.Identity id : ids) {
+            if (!safetyNumber.equals(computeSafetyNumber(name, id.identityKey))) {
+                continue;
+            }
+
+            signalProtocolStore.saveIdentity(name, id.identityKey, TrustLevel.TRUSTED_VERIFIED);
+            save();
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Trust all keys of this identity without verification
      *
@@ -1348,4 +1389,9 @@ class Manager implements Signal {
         save();
         return true;
     }
+
+    public String computeSafetyNumber(String theirUsername, IdentityKey theirIdentityKey) {
+        Fingerprint fingerprint = new NumericFingerprintGenerator(5200).createFor(username, getIdentity(), theirUsername, theirIdentityKey);
+        return fingerprint.getDisplayableFingerprint().getDisplayText();
+    }
 }