]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/Manager.java
Allow relinking an account if it's no longer authorized
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / Manager.java
index 05aec952aa02bfe33544883d376dc78eb93bf8a0..8632129c44d2d1216656330003000817da739c94 100644 (file)
@@ -16,6 +16,7 @@
  */
 package org.asamk.signal.manager;
 
+import org.asamk.signal.manager.api.Device;
 import org.asamk.signal.manager.config.ServiceConfig;
 import org.asamk.signal.manager.config.ServiceEnvironment;
 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
@@ -108,7 +109,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsO
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
-import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
 import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
 import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
 import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
@@ -119,6 +119,7 @@ import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
 import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
+import org.whispersystems.signalservice.api.util.DeviceNameUtil;
 import org.whispersystems.signalservice.api.util.InvalidNumberException;
 import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
 import org.whispersystems.signalservice.api.util.SleepTimer;
@@ -287,7 +288,7 @@ public class Manager implements Closeable {
             throw new NotRegisteredException();
         }
 
-        var account = SignalAccount.load(pathConfig.getDataPath(), username);
+        var account = SignalAccount.load(pathConfig.getDataPath(), username, true);
 
         if (!account.isRegistered()) {
             throw new NotRegisteredException();
@@ -341,7 +342,8 @@ public class Manager implements Closeable {
     }
 
     public void updateAccountAttributes() throws IOException {
-        accountManager.setAccountAttributes(null,
+        accountManager.setAccountAttributes(account.getEncryptedDeviceName(),
+                null,
                 account.getLocalRegistrationId(),
                 true,
                 // set legacy pin only if no KBS master key is set
@@ -421,10 +423,21 @@ public class Manager implements Closeable {
         account.setRegistered(false);
     }
 
-    public List<DeviceInfo> getLinkedDevices() throws IOException {
+    public List<Device> getLinkedDevices() throws IOException {
         var devices = accountManager.getDevices();
         account.setMultiDevice(devices.size() > 1);
-        return devices;
+        var identityKey = account.getIdentityKeyPair().getPrivateKey();
+        return devices.stream().map(d -> {
+            String deviceName = d.getName();
+            if (deviceName != null) {
+                try {
+                    deviceName = DeviceNameUtil.decryptDeviceName(deviceName, identityKey);
+                } catch (IOException e) {
+                    logger.debug("Failed to decrypt device name, maybe plain text?", e);
+                }
+            }
+            return new Device(d.getId(), deviceName, d.getCreated(), d.getLastSeen());
+        }).collect(Collectors.toList());
     }
 
     public void removeLinkedDevices(int deviceId) throws IOException {
@@ -1088,6 +1101,11 @@ public class Manager implements Closeable {
         }
     }
 
+    SendMessageResult renewSession(RecipientId recipientId) throws IOException {
+        account.getSessionStore().archiveSessions(recipientId);
+        return sendNullMessage(recipientId);
+    }
+
     public String getContactName(String number) throws InvalidNumberException {
         var contact = account.getContactStore().getContact(canonicalizeAndResolveRecipient(number));
         return contact == null || contact.getName() == null ? "" : contact.getName();
@@ -1468,6 +1486,23 @@ public class Manager implements Closeable {
         }
     }
 
+    private SendMessageResult sendNullMessage(RecipientId recipientId) throws IOException {
+        var messageSender = createMessageSender();
+
+        final var address = resolveSignalServiceAddress(recipientId);
+        try {
+            try {
+                return messageSender.sendNullMessage(address, unidentifiedAccessHelper.getAccessFor(recipientId));
+            } catch (UnregisteredUserException e) {
+                final var newRecipientId = refreshRegisteredUser(recipientId);
+                final var newAddress = resolveSignalServiceAddress(newRecipientId);
+                return messageSender.sendNullMessage(newAddress, unidentifiedAccessHelper.getAccessFor(newRecipientId));
+            }
+        } catch (UntrustedIdentityException e) {
+            return SendMessageResult.identityFailure(address, e.getIdentityKey());
+        }
+    }
+
     private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, SelfSendException, UnsupportedDataMessageException, org.whispersystems.libsignal.UntrustedIdentityException {
         var cipher = new SignalServiceCipher(account.getSelfAddress(),
                 account.getSignalProtocolStore(),
@@ -1812,6 +1847,11 @@ public class Manager implements Closeable {
                     exception = e;
                 }
                 var actions = handleMessage(envelope, content, ignoreAttachments);
+                if (exception instanceof ProtocolInvalidMessageException) {
+                    final var sender = resolveRecipient(((ProtocolInvalidMessageException) exception).getSender());
+                    logger.debug("Received invalid message, queuing renew session action.");
+                    actions.add(new RenewSessionAction(sender));
+                }
                 if (hasCaughtUpWithOldMessages) {
                     for (var action : actions) {
                         try {