X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/8bcd8d87d219ae0496986cba4bd6b89f3b2ad6f6..2e01a05e7110b4f94abb10489a28b73d9f4be9c0:/lib/src/main/java/org/asamk/signal/manager/Manager.java diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 9e38853b..a7a691cc 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -42,6 +42,7 @@ import org.asamk.signal.manager.helper.IncomingMessageHandler; import org.asamk.signal.manager.helper.PinHelper; import org.asamk.signal.manager.helper.ProfileHelper; import org.asamk.signal.manager.helper.SendHelper; +import org.asamk.signal.manager.helper.StorageHelper; import org.asamk.signal.manager.helper.SyncHelper; import org.asamk.signal.manager.helper.UnidentifiedAccessHelper; import org.asamk.signal.manager.jobs.Context; @@ -58,7 +59,6 @@ import org.asamk.signal.manager.storage.stickers.StickerPackId; import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.StickerUtils; import org.asamk.signal.manager.util.Utils; -import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.libsignal.IdentityKey; @@ -134,6 +134,7 @@ public class Manager implements Closeable { private final ProfileHelper profileHelper; private final PinHelper pinHelper; + private final StorageHelper storageHelper; private final SendHelper sendHelper; private final SyncHelper syncHelper; private final AttachmentHelper attachmentHelper; @@ -142,6 +143,7 @@ public class Manager implements Closeable { private final IncomingMessageHandler incomingMessageHandler; private final Context context; + private boolean hasCaughtUpWithOldMessages = false; Manager( SignalAccount account, @@ -165,8 +167,7 @@ public class Manager implements Closeable { return LEGACY_LOCK::unlock; } }; - this.dependencies = new SignalDependencies(account.getSelfAddress(), - serviceEnvironmentConfig, + this.dependencies = new SignalDependencies(serviceEnvironmentConfig, userAgent, credentialsProvider, account.getSignalProtocolStore(), @@ -187,8 +188,6 @@ public class Manager implements Closeable { avatarStore, account.getProfileStore()::getProfileKey, unidentifiedAccessHelper::getAccessFor, - dependencies::getProfileService, - dependencies::getMessageReceiver, this::resolveSignalServiceAddress); final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper::getRecipientProfileKeyCredential, this::getRecipientProfile, @@ -212,6 +211,7 @@ public class Manager implements Closeable { avatarStore, this::resolveSignalServiceAddress, account.getRecipientStore()); + this.storageHelper = new StorageHelper(account, dependencies, groupHelper); this.contactHelper = new ContactHelper(account); this.syncHelper = new SyncHelper(account, attachmentHelper, @@ -221,13 +221,13 @@ public class Manager implements Closeable { this::resolveSignalServiceAddress); this.context = new Context(account, - dependencies.getAccountManager(), - dependencies.getMessageReceiver(), + dependencies, stickerPackStore, sendHelper, groupHelper, syncHelper, - profileHelper); + profileHelper, + storageHelper); var jobExecutor = new JobExecutor(context); this.incomingMessageHandler = new IncomingMessageHandler(account, @@ -315,7 +315,7 @@ public class Manager implements Closeable { if (account.getUuid() == null) { account.setUuid(dependencies.getAccountManager().getOwnUuid()); } - updateAccountAttributes(); + updateAccountAttributes(null); } /** @@ -347,14 +347,21 @@ public class Manager implements Closeable { })); } - public void updateAccountAttributes() throws IOException { + public void updateAccountAttributes(String deviceName) throws IOException { + final String encryptedDeviceName; + if (deviceName == null) { + encryptedDeviceName = account.getEncryptedDeviceName(); + } else { + final var privateKey = account.getIdentityKeyPair().getPrivateKey(); + encryptedDeviceName = DeviceNameUtil.encryptDeviceName(deviceName, privateKey); + account.setEncryptedDeviceName(encryptedDeviceName); + } dependencies.getAccountManager() - .setAccountAttributes(account.getEncryptedDeviceName(), + .setAccountAttributes(encryptedDeviceName, null, account.getLocalRegistrationId(), true, - // set legacy pin only if no KBS master key is set - account.getPinMasterKey() == null ? account.getRegistrationLockPin() : null, + null, account.getPinMasterKey() == null ? null : account.getPinMasterKey().deriveRegistrationLock(), account.getSelfUnidentifiedAccessKey(), account.isUnrestrictedUnidentifiedAccess(), @@ -386,6 +393,13 @@ public class Manager implements Closeable { } public void deleteAccount() throws IOException { + try { + pinHelper.removeRegistrationLockPin(); + } catch (UnauthenticatedResponseException e) { + logger.warn("Failed to remove registration lock pin"); + } + account.setRegistrationLockPin(null, null); + dependencies.getAccountManager().deleteAccount(); account.setRegistered(false); @@ -737,6 +751,13 @@ public class Manager implements Closeable { public void requestAllSyncData() throws IOException { syncHelper.requestAllSyncData(); + retrieveRemoteStorage(); + } + + void retrieveRemoteStorage() throws IOException { + if (account.getStorageKey() != null) { + storageHelper.readDataFromStorage(); + } } private byte[] getSenderCertificate() { @@ -818,37 +839,33 @@ public class Manager implements Closeable { ) { var envelope = cachedMessage.loadEnvelope(); if (envelope == null) { + cachedMessage.delete(); return null; } - SignalServiceContent content = null; - List actions = null; - if (!envelope.isReceipt()) { - try { - content = dependencies.getCipher().decrypt(envelope); - } catch (ProtocolUntrustedIdentityException e) { - if (System.currentTimeMillis() - envelope.getServerDeliveredTimestamp() > 1000L * 60 * 60 * 24 * 30) { - // Envelope is more than a month old, cleaning up. - cachedMessage.delete(); - return null; - } - if (!envelope.hasSourceUuid()) { - final var identifier = e.getSender(); - final var recipientId = account.getRecipientStore().resolveRecipient(identifier); - try { - account.getMessageCache().replaceSender(cachedMessage, recipientId); - } catch (IOException ioException) { - logger.warn("Failed to move cached message to recipient folder: {}", ioException.getMessage()); - } - } - return null; - } catch (Exception er) { - // All other errors are not recoverable, so delete the cached message + + final var result = incomingMessageHandler.handleRetryEnvelope(envelope, ignoreAttachments, handler); + final var actions = result.first(); + final var exception = result.second(); + + if (exception instanceof UntrustedIdentityException) { + if (System.currentTimeMillis() - envelope.getServerDeliveredTimestamp() > 1000L * 60 * 60 * 24 * 30) { + // Envelope is more than a month old, cleaning up. cachedMessage.delete(); return null; } - actions = incomingMessageHandler.handleMessage(envelope, content, ignoreAttachments); + if (!envelope.hasSourceUuid()) { + final var identifier = ((UntrustedIdentityException) exception).getSender(); + final var recipientId = account.getRecipientStore().resolveRecipient(identifier); + try { + account.getMessageCache().replaceSender(cachedMessage, recipientId); + } catch (IOException ioException) { + logger.warn("Failed to move cached message to recipient folder: {}", ioException.getMessage()); + } + } + return null; } - handler.handleMessage(envelope, content, null); + + // If successful and for all other errors that are not recoverable, delete the cached message cachedMessage.delete(); return actions; } @@ -867,7 +884,7 @@ public class Manager implements Closeable { final var signalWebSocket = dependencies.getSignalWebSocket(); signalWebSocket.connect(); - var hasCaughtUpWithOldMessages = false; + hasCaughtUpWithOldMessages = false; while (!Thread.interrupted()) { SignalServiceEnvelope envelope; @@ -887,11 +904,14 @@ public class Manager implements Closeable { envelope = result.get(); } else { // Received indicator that server queue is empty - hasCaughtUpWithOldMessages = true; - handleQueuedActions(queuedActions); queuedActions.clear(); + hasCaughtUpWithOldMessages = true; + synchronized (this) { + this.notifyAll(); + } + // Continue to wait another timeout for new messages continue; } @@ -938,17 +958,27 @@ public class Manager implements Closeable { handleQueuedActions(queuedActions); } + public boolean hasCaughtUpWithOldMessages() { + return hasCaughtUpWithOldMessages; + } + private void handleQueuedActions(final Collection queuedActions) { + var interrupted = false; for (var action : queuedActions) { try { action.execute(context); } catch (Throwable e) { - if (e instanceof AssertionError && e.getCause() instanceof InterruptedException) { - Thread.currentThread().interrupt(); + if ((e instanceof AssertionError || e instanceof RuntimeException) + && e.getCause() instanceof InterruptedException) { + interrupted = true; + continue; } logger.warn("Message action failed.", e); } } + if (interrupted) { + Thread.currentThread().interrupt(); + } } public boolean isContactBlocked(final RecipientIdentifier.Single recipient) { @@ -1147,10 +1177,6 @@ public class Manager implements Closeable { } public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) { - if (address.matches(account.getSelfAddress())) { - return account.getSelfAddress(); - } - return resolveSignalServiceAddress(resolveRecipient(address)); }