diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java index bd8302363a..1d4bc58249 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.crypto.storage; import android.content.Context; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.InvalidKeyIdException; @@ -14,7 +15,7 @@ import org.whispersystems.libsignal.state.PreKeyStore; import org.whispersystems.libsignal.state.SessionRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyStore; -import org.whispersystems.signalservice.api.SignalServiceProtocolStore; +import org.whispersystems.signalservice.api.SignalServiceDataStore; import org.whispersystems.signalservice.api.SignalServiceSessionStore; import org.whispersystems.signalservice.api.push.DistributionId; @@ -23,8 +24,9 @@ import java.util.List; import java.util.Set; import java.util.UUID; -public class SignalProtocolStoreImpl implements SignalServiceProtocolStore { +public class SignalProtocolStoreImpl implements SignalServiceDataStore { + private final Context context; private final PreKeyStore preKeyStore; private final SignedPreKeyStore signedPreKeyStore; private final IdentityKeyStore identityKeyStore; @@ -32,6 +34,7 @@ public class SignalProtocolStoreImpl implements SignalServiceProtocolStore { private final SignalSenderKeyStore senderKeyStore; public SignalProtocolStoreImpl(Context context) { + this.context = context; this.preKeyStore = new TextSecurePreKeyStore(context); this.signedPreKeyStore = new TextSecurePreKeyStore(context); this.identityKeyStore = new TextSecureIdentityKeyStore(context); @@ -173,4 +176,9 @@ public class SignalProtocolStoreImpl implements SignalServiceProtocolStore { public void clearSenderKeySharedWith(Collection addresses) { senderKeyStore.clearSenderKeySharedWith(addresses); } + + @Override + public boolean isMultiDevice() { + return TextSecurePreferences.isMultiDevice(context); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java index 865961e39b..766bc02dc8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencies.java @@ -181,8 +181,6 @@ public class ApplicationDependencies { synchronized (LOCK) { if (messageSender == null) { messageSender = provider.provideSignalServiceMessageSender(getSignalWebSocket()); - } else { - messageSender.update(TextSecurePreferences.isMultiDevice(application)); } return messageSender; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index e98c02131b..e0103f4e36 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -105,7 +105,6 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr new SignalProtocolStoreImpl(context), ReentrantSessionLock.INSTANCE, BuildConfig.SIGNAL_AGENT, - TextSecurePreferences.isMultiDevice(context), signalWebSocket, Optional.of(new SecurityEventListener(context)), provideClientZkOperations().getProfileOperations(), diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceProtocolStore.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceDataStore.java similarity index 53% rename from libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceProtocolStore.java rename to libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceDataStore.java index 7f0a4c6484..0f50416ed0 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceProtocolStore.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceDataStore.java @@ -6,5 +6,9 @@ import org.whispersystems.libsignal.state.SignalProtocolStore; * And extension of the normal protocol store interface that has additional methods that are needed * in the service layer, but not the protocol layer. */ -public interface SignalServiceProtocolStore extends SignalProtocolStore, SignalServiceSessionStore, SignalServiceSenderKeyStore { +public interface SignalServiceDataStore extends SignalProtocolStore, SignalServiceSessionStore, SignalServiceSenderKeyStore { + /** + * @return True if the active account has linked devices, otherwise false. + */ + boolean isMultiDevice(); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index 4cdf1920e3..4856964936 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -145,25 +145,23 @@ public class SignalServiceMessageSender { private static final int RETRY_COUNT = 4; - private final PushServiceSocket socket; - private final SignalServiceProtocolStore store; - private final SignalSessionLock sessionLock; - private final SignalServiceAddress localAddress; - private final Optional eventListener; + private final PushServiceSocket socket; + private final SignalServiceDataStore store; + private final SignalSessionLock sessionLock; + private final SignalServiceAddress localAddress; + private final Optional eventListener; private final AttachmentService attachmentService; private final MessagingService messagingService; - private final AtomicBoolean isMultiDevice; private final ExecutorService executor; private final long maxEnvelopeSize; public SignalServiceMessageSender(SignalServiceConfiguration urls, CredentialsProvider credentialsProvider, - SignalServiceProtocolStore store, + SignalServiceDataStore store, SignalSessionLock sessionLock, String signalAgent, - boolean isMultiDevice, SignalWebSocket signalWebSocket, Optional eventListener, ClientZkProfileOperations clientZkProfileOperations, @@ -177,7 +175,6 @@ public class SignalServiceMessageSender { this.localAddress = new SignalServiceAddress(credentialsProvider.getUuid(), credentialsProvider.getE164()); this.attachmentService = new AttachmentService(signalWebSocket); this.messagingService = new MessagingService(signalWebSocket); - this.isMultiDevice = new AtomicBoolean(isMultiDevice); this.eventListener = eventListener; this.executor = executor != null ? executor : Executors.newSingleThreadExecutor(); this.maxEnvelopeSize = maxEnvelopeSize; @@ -403,7 +400,7 @@ public class SignalServiceMessageSender { Optional groupId = message.getGroupId(); List results = sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, contentHint, groupId.orNull(), false); - if (isMultiDevice.get()) { + if (store.isMultiDevice()) { Content syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.absent(), message.getTimestamp(), results, isRecipientUpdate); EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.absent()); @@ -443,7 +440,7 @@ public class SignalServiceMessageSender { } } - if (needsSyncInResults || isMultiDevice.get()) { + if (needsSyncInResults || store.isMultiDevice()) { Optional recipient = Optional.absent(); if (!message.getGroupContext().isPresent() && recipients.size() == 1) { recipient = Optional.of(recipients.get(0)); @@ -512,10 +509,6 @@ public class SignalServiceMessageSender { socket.cancelInFlightRequests(); } - public void update(boolean isMultiDevice) { - this.isMultiDevice.set(isMultiDevice); - } - public SignalServiceAttachmentPointer uploadAttachment(SignalServiceAttachmentStream attachment) throws IOException { byte[] attachmentKey = attachment.getResumableUploadSpec().transform(ResumableUploadSpec::getSecretKey).or(() -> Util.getSecretBytes(64)); byte[] attachmentIV = attachment.getResumableUploadSpec().transform(ResumableUploadSpec::getIV).or(() -> Util.getSecretBytes(16)); @@ -1608,7 +1601,7 @@ public class SignalServiceMessageSender { if (!unidentifiedAccess.isPresent()) { try { SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, Optional.absent()).blockingGet()).getResultOrThrow(); - return SendMessageResult.success(recipient, messages.getDevices(), false, response.getNeedsSync() || isMultiDevice.get(), System.currentTimeMillis() - startTime, content.getContent()); + return SendMessageResult.success(recipient, messages.getDevices(), false, response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent()); } catch (WebSocketUnavailableException e) { Log.i(TAG, "[sendMessage] Pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); } catch (IOException e) { @@ -1618,7 +1611,7 @@ public class SignalServiceMessageSender { } else if (unidentifiedAccess.isPresent()) { try { SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, unidentifiedAccess).blockingGet()).getResultOrThrow(); - return SendMessageResult.success(recipient, messages.getDevices(), true, response.getNeedsSync() || isMultiDevice.get(), System.currentTimeMillis() - startTime, content.getContent()); + return SendMessageResult.success(recipient, messages.getDevices(), true, response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent()); } catch (WebSocketUnavailableException e) { Log.i(TAG, "[sendMessage] Unidentified pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); } catch (IOException e) { @@ -1633,7 +1626,7 @@ public class SignalServiceMessageSender { SendMessageResponse response = socket.sendMessage(messages, unidentifiedAccess); - return SendMessageResult.success(recipient, messages.getDevices(), unidentifiedAccess.isPresent(), response.getNeedsSync() || isMultiDevice.get(), System.currentTimeMillis() - startTime, content.getContent()); + return SendMessageResult.success(recipient, messages.getDevices(), unidentifiedAccess.isPresent(), response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent()); } catch (InvalidKeyException ike) { Log.w(TAG, ike); @@ -1843,7 +1836,7 @@ public class SignalServiceMessageSender { List success = recipients.keySet() .stream() .filter(r -> !unregistered.contains(r.getUuid().get())) - .map(a -> SendMessageResult.success(a, recipients.get(a), true, isMultiDevice.get(), -1, Optional.of(content))) + .map(a -> SendMessageResult.success(a, recipients.get(a), true, store.isMultiDevice(), -1, Optional.of(content))) .collect(Collectors.toList()); List results = new ArrayList<>(success.size() + failures.size());