Skip to content

Commit

Permalink
Give the service direct knowledge of linked device status.
Browse files Browse the repository at this point in the history
  • Loading branch information
greyson-signal authored and cody-signal committed Jul 30, 2021
1 parent 75421b1 commit c1c9ca7
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 25 deletions.
Expand Up @@ -2,6 +2,7 @@

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;
Expand All @@ -14,7 +15,7 @@
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;

Expand All @@ -23,15 +24,17 @@
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;
private final SignalServiceSessionStore sessionStore;
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);
Expand Down Expand Up @@ -173,4 +176,9 @@ public void markSenderKeySharedWith(DistributionId distributionId, Collection<Si
public void clearSenderKeySharedWith(Collection<SignalProtocolAddress> addresses) {
senderKeyStore.clearSenderKeySharedWith(addresses);
}

@Override
public boolean isMultiDevice() {
return TextSecurePreferences.isMultiDevice(context);
}
}
Expand Up @@ -181,8 +181,6 @@ public static void init(@NonNull Application application, @NonNull Provider prov
synchronized (LOCK) {
if (messageSender == null) {
messageSender = provider.provideSignalServiceMessageSender(getSignalWebSocket());
} else {
messageSender.update(TextSecurePreferences.isMultiDevice(application));
}
return messageSender;
}
Expand Down
Expand Up @@ -105,7 +105,6 @@ public ApplicationDependencyProvider(@NonNull Application context) {
new SignalProtocolStoreImpl(context),
ReentrantSessionLock.INSTANCE,
BuildConfig.SIGNAL_AGENT,
TextSecurePreferences.isMultiDevice(context),
signalWebSocket,
Optional.of(new SecurityEventListener(context)),
provideClientZkOperations().getProfileOperations(),
Expand Down
Expand Up @@ -6,5 +6,9 @@
* 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();
}
Expand Up @@ -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> eventListener;
private final PushServiceSocket socket;
private final SignalServiceDataStore store;
private final SignalSessionLock sessionLock;
private final SignalServiceAddress localAddress;
private final Optional<EventListener> 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> eventListener,
ClientZkProfileOperations clientZkProfileOperations,
Expand All @@ -177,7 +175,6 @@ public SignalServiceMessageSender(SignalServiceConfiguration urls,
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;
Expand Down Expand Up @@ -403,7 +400,7 @@ public List<SendMessageResult> sendGroupDataMessage(DistributionId d
Optional<byte[]> groupId = message.getGroupId();
List<SendMessageResult> 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());

Expand Down Expand Up @@ -443,7 +440,7 @@ public List<SendMessageResult> sendDataMessage(List<SignalServiceAddress>
}
}

if (needsSyncInResults || isMultiDevice.get()) {
if (needsSyncInResults || store.isMultiDevice()) {
Optional<SignalServiceAddress> recipient = Optional.absent();
if (!message.getGroupContext().isPresent() && recipients.size() == 1) {
recipient = Optional.of(recipients.get(0));
Expand Down Expand Up @@ -512,10 +509,6 @@ public void cancelInFlightRequests() {
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));
Expand Down Expand Up @@ -1608,7 +1601,7 @@ private SendMessageResult sendMessage(SignalServiceAddress recipient,
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) {
Expand All @@ -1618,7 +1611,7 @@ private SendMessageResult sendMessage(SignalServiceAddress recipient,
} 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) {
Expand All @@ -1633,7 +1626,7 @@ private SendMessageResult sendMessage(SignalServiceAddress recipient,

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);
Expand Down Expand Up @@ -1843,7 +1836,7 @@ private List<SendMessageResult> transformGroupResponseToMessageResults(Map<Signa
List<SendMessageResult> 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<SendMessageResult> results = new ArrayList<>(success.size() + failures.size());
Expand Down

0 comments on commit c1c9ca7

Please sign in to comment.