X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/1f0c2d5c782d2d2663dc8b4147b1fbb8df53bc97..62d8873a9288bcfe79d8eb3a2b7b3b467451db72:/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 6d91ba11..05700379 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -40,8 +40,10 @@ import org.asamk.signal.manager.helper.GroupHelper; import org.asamk.signal.manager.helper.GroupV2Helper; import org.asamk.signal.manager.helper.IncomingMessageHandler; import org.asamk.signal.manager.helper.PinHelper; +import org.asamk.signal.manager.helper.PreKeyHelper; 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; @@ -61,14 +63,11 @@ import org.asamk.signal.manager.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.libsignal.IdentityKey; -import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.ecc.ECPublicKey; import org.whispersystems.libsignal.fingerprint.Fingerprint; import org.whispersystems.libsignal.fingerprint.FingerprintParsingException; import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException; -import org.whispersystems.libsignal.state.PreKeyRecord; -import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalSessionLock; @@ -133,14 +132,17 @@ 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; private final GroupHelper groupHelper; private final ContactHelper contactHelper; private final IncomingMessageHandler incomingMessageHandler; + private final PreKeyHelper preKeyHelper; private final Context context; + private boolean hasCaughtUpWithOldMessages = false; Manager( SignalAccount account, @@ -164,8 +166,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(), @@ -186,8 +187,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, @@ -211,6 +210,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, @@ -218,15 +218,17 @@ public class Manager implements Closeable { groupHelper, avatarStore, this::resolveSignalServiceAddress); + preKeyHelper = new PreKeyHelper(account, dependencies); this.context = new Context(account, - dependencies.getAccountManager(), - dependencies.getMessageReceiver(), + dependencies, stickerPackStore, sendHelper, groupHelper, syncHelper, - profileHelper); + profileHelper, + storageHelper, + preKeyHelper); var jobExecutor = new JobExecutor(context); this.incomingMessageHandler = new IncomingMessageHandler(account, @@ -237,6 +239,7 @@ public class Manager implements Closeable { contactHelper, attachmentHelper, syncHelper, + this::getRecipientProfile, jobExecutor); } @@ -248,10 +251,6 @@ public class Manager implements Closeable { return account.getSelfRecipientId(); } - private IdentityKeyPair getIdentityKeyPair() { - return account.getIdentityKeyPair(); - } - public int getDeviceId() { return account.getDeviceId(); } @@ -308,13 +307,11 @@ public class Manager implements Closeable { days); } } - if (dependencies.getAccountManager().getPreKeysCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) { - refreshPreKeys(); - } + preKeyHelper.refreshPreKeysIfNecessary(); if (account.getUuid() == null) { account.setUuid(dependencies.getAccountManager().getOwnUuid()); } - updateAccountAttributes(); + updateAccountAttributes(null); } /** @@ -346,14 +343,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(), @@ -397,6 +401,10 @@ public class Manager implements Closeable { account.setRegistered(false); } + public void submitRateLimitRecaptchaChallenge(String challenge, String captcha) throws IOException { + dependencies.getAccountManager().submitRateLimitRecaptchaChallenge(challenge, captcha); + } + public List getLinkedDevices() throws IOException { var devices = dependencies.getAccountManager().getDevices(); account.setMultiDevice(devices.size() > 1); @@ -427,7 +435,7 @@ public class Manager implements Closeable { } private void addDevice(String deviceIdentifier, ECPublicKey deviceKey) throws IOException, InvalidKeyException { - var identityKeyPair = getIdentityKeyPair(); + var identityKeyPair = account.getIdentityKeyPair(); var verificationCode = dependencies.getAccountManager().getNewDeviceVerificationCode(); dependencies.getAccountManager() @@ -460,29 +468,7 @@ public class Manager implements Closeable { } void refreshPreKeys() throws IOException { - var oneTimePreKeys = generatePreKeys(); - final var identityKeyPair = getIdentityKeyPair(); - var signedPreKeyRecord = generateSignedPreKey(identityKeyPair); - - dependencies.getAccountManager().setPreKeys(identityKeyPair.getPublicKey(), signedPreKeyRecord, oneTimePreKeys); - } - - private List generatePreKeys() { - final var offset = account.getPreKeyIdOffset(); - - var records = KeyUtils.generatePreKeyRecords(offset, ServiceConfig.PREKEY_BATCH_SIZE); - account.addPreKeys(records); - - return records; - } - - private SignedPreKeyRecord generateSignedPreKey(IdentityKeyPair identityKeyPair) { - final var signedPreKeyId = account.getNextSignedPreKeyId(); - - var record = KeyUtils.generateSignedPreKeyRecord(identityKeyPair, signedPreKeyId); - account.addSignedPreKey(record); - - return record; + preKeyHelper.refreshPreKeys(); } public Profile getRecipientProfile(RecipientId recipientId) { @@ -743,6 +729,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() { @@ -869,7 +862,7 @@ public class Manager implements Closeable { final var signalWebSocket = dependencies.getSignalWebSocket(); signalWebSocket.connect(); - var hasCaughtUpWithOldMessages = false; + hasCaughtUpWithOldMessages = false; while (!Thread.interrupted()) { SignalServiceEnvelope envelope; @@ -884,16 +877,19 @@ public class Manager implements Closeable { // store message on disk, before acknowledging receipt to the server cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId); }); - logger.debug("New message received from server"); if (result.isPresent()) { envelope = result.get(); + logger.debug("New message received from server"); } else { - // Received indicator that server queue is empty - hasCaughtUpWithOldMessages = true; - + logger.debug("Received indicator that server queue is empty"); handleQueuedActions(queuedActions); queuedActions.clear(); + hasCaughtUpWithOldMessages = true; + synchronized (this) { + this.notifyAll(); + } + // Continue to wait another timeout for new messages continue; } @@ -940,17 +936,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) { @@ -1143,16 +1149,12 @@ public class Manager implements Closeable { ) { return Utils.computeSafetyNumber(capabilities.isUuid(), account.getSelfAddress(), - getIdentityKeyPair().getPublicKey(), + account.getIdentityKeyPair().getPublicKey(), theirAddress, theirIdentityKey); } public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) { - if (address.matches(account.getSelfAddress())) { - return account.getSelfAddress(); - } - return resolveSignalServiceAddress(resolveRecipient(address)); }