mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Add support for PniSignatureMessages.
This commit is contained in:
@@ -8,6 +8,7 @@ package org.whispersystems.signalservice.api;
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.signal.libsignal.metadata.certificate.SenderCertificate;
|
||||
import org.signal.libsignal.protocol.IdentityKeyPair;
|
||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||
import org.signal.libsignal.protocol.InvalidRegistrationIdException;
|
||||
import org.signal.libsignal.protocol.NoSessionException;
|
||||
@@ -63,6 +64,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMes
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage;
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.DistributionId;
|
||||
import org.whispersystems.signalservice.api.push.PNI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
||||
@@ -81,6 +83,7 @@ import org.whispersystems.signalservice.api.util.CredentialsProvider;
|
||||
import org.whispersystems.signalservice.api.util.Preconditions;
|
||||
import org.whispersystems.signalservice.api.util.Uint64RangeException;
|
||||
import org.whispersystems.signalservice.api.util.Uint64Util;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException;
|
||||
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
|
||||
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream;
|
||||
@@ -96,6 +99,7 @@ import org.whispersystems.signalservice.internal.push.PushAttachmentData;
|
||||
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.signalservice.internal.push.SendGroupMessageResponse;
|
||||
import org.whispersystems.signalservice.internal.push.SendMessageResponse;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.CallMessage;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content;
|
||||
@@ -155,11 +159,13 @@ public class SignalServiceMessageSender {
|
||||
private static final int RETRY_COUNT = 4;
|
||||
|
||||
private final PushServiceSocket socket;
|
||||
private final SignalServiceAccountDataStore store;
|
||||
private final SignalServiceAccountDataStore aciStore;
|
||||
private final SignalSessionLock sessionLock;
|
||||
private final SignalServiceAddress localAddress;
|
||||
private final int localDeviceId;
|
||||
private final PNI localPni;
|
||||
private final Optional<EventListener> eventListener;
|
||||
private final IdentityKeyPair localPniIdentity;
|
||||
|
||||
private final AttachmentService attachmentService;
|
||||
private final MessagingService messagingService;
|
||||
@@ -180,15 +186,17 @@ public class SignalServiceMessageSender {
|
||||
boolean automaticNetworkRetry)
|
||||
{
|
||||
this.socket = new PushServiceSocket(urls, credentialsProvider, signalAgent, clientZkProfileOperations, automaticNetworkRetry);
|
||||
this.store = store.aci();
|
||||
this.aciStore = store.aci();
|
||||
this.sessionLock = sessionLock;
|
||||
this.localAddress = new SignalServiceAddress(credentialsProvider.getAci(), credentialsProvider.getE164());
|
||||
this.localDeviceId = credentialsProvider.getDeviceId();
|
||||
this.localPni = credentialsProvider.getPni();
|
||||
this.attachmentService = new AttachmentService(signalWebSocket);
|
||||
this.messagingService = new MessagingService(signalWebSocket);
|
||||
this.eventListener = eventListener;
|
||||
this.executor = executor != null ? executor : Executors.newSingleThreadExecutor();
|
||||
this.maxEnvelopeSize = maxEnvelopeSize;
|
||||
this.localPniIdentity = store.pni().getIdentityKeyPair();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,10 +207,18 @@ public class SignalServiceMessageSender {
|
||||
*/
|
||||
public SendMessageResult sendReceipt(SignalServiceAddress recipient,
|
||||
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
||||
SignalServiceReceiptMessage message)
|
||||
SignalServiceReceiptMessage message,
|
||||
boolean includePniSignature)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
Content content = createReceiptContent(message);
|
||||
Content content = createReceiptContent(message);
|
||||
|
||||
if (includePniSignature) {
|
||||
content = content.toBuilder()
|
||||
.setPniSignatureMessage(createPniSignatureMessage())
|
||||
.build();
|
||||
}
|
||||
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
return sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getWhen(), envelopeContent, false, null, false);
|
||||
@@ -264,7 +280,7 @@ public class SignalServiceMessageSender {
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
List<SendMessageResult> sendMessageResults = sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null, null, false);
|
||||
|
||||
if (store.isMultiDevice()) {
|
||||
if (aciStore.isMultiDevice()) {
|
||||
SignalServiceSyncMessage syncMessage = createSelfSendSyncMessageForStory(message, timestamp, isRecipientUpdate, manifest);
|
||||
sendSyncMessage(syncMessage, Optional.empty());
|
||||
}
|
||||
@@ -288,7 +304,7 @@ public class SignalServiceMessageSender {
|
||||
Content content = createStoryContent(message);
|
||||
List<SendMessageResult> sendMessageResults = sendGroupMessage(distributionId, recipients, unidentifiedAccess, timestamp, content, ContentHint.IMPLICIT, groupId, false, SenderKeyGroupEvents.EMPTY, false);
|
||||
|
||||
if (store.isMultiDevice()) {
|
||||
if (aciStore.isMultiDevice()) {
|
||||
SignalServiceSyncMessage syncMessage = createSelfSendSyncMessageForStory(message, timestamp, isRecipientUpdate, manifest);
|
||||
sendSyncMessage(syncMessage, Optional.empty());
|
||||
}
|
||||
@@ -363,13 +379,22 @@ public class SignalServiceMessageSender {
|
||||
ContentHint contentHint,
|
||||
SignalServiceDataMessage message,
|
||||
IndividualSendEvents sendEvents,
|
||||
boolean urgent)
|
||||
boolean urgent,
|
||||
boolean includePniSignature)
|
||||
throws UntrustedIdentityException, IOException
|
||||
{
|
||||
Log.d(TAG, "[" + message.getTimestamp() + "] Sending a data message.");
|
||||
|
||||
Content content = createMessageContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, contentHint, message.getGroupId());
|
||||
Content content = createMessageContent(message);
|
||||
|
||||
if (includePniSignature) {
|
||||
Log.d(TAG, "[" + message.getTimestamp() + "] Including PNI signature.");
|
||||
content = content.toBuilder()
|
||||
.setPniSignatureMessage(createPniSignatureMessage())
|
||||
.build();
|
||||
}
|
||||
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, contentHint, message.getGroupId());
|
||||
|
||||
sendEvents.onMessageEncrypted();
|
||||
|
||||
@@ -396,7 +421,7 @@ public class SignalServiceMessageSender {
|
||||
*/
|
||||
public SenderKeyDistributionMessage getOrCreateNewGroupSession(DistributionId distributionId) {
|
||||
SignalProtocolAddress self = new SignalProtocolAddress(localAddress.getIdentifier(), localDeviceId);
|
||||
return new SignalGroupSessionBuilder(sessionLock, new GroupSessionBuilder(store)).create(self, distributionId.asUuid());
|
||||
return new SignalGroupSessionBuilder(sessionLock, new GroupSessionBuilder(aciStore)).create(self, distributionId.asUuid());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -423,7 +448,7 @@ public class SignalServiceMessageSender {
|
||||
* Processes an inbound {@link SenderKeyDistributionMessage}.
|
||||
*/
|
||||
public void processSenderKeyDistributionMessage(SignalProtocolAddress sender, SenderKeyDistributionMessage senderKeyDistributionMessage) {
|
||||
new SignalGroupSessionBuilder(sessionLock, new GroupSessionBuilder(store)).process(sender, senderKeyDistributionMessage);
|
||||
new SignalGroupSessionBuilder(sessionLock, new GroupSessionBuilder(aciStore)).process(sender, senderKeyDistributionMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,7 +490,7 @@ public class SignalServiceMessageSender {
|
||||
|
||||
sendEvents.onMessageSent();
|
||||
|
||||
if (store.isMultiDevice()) {
|
||||
if (aciStore.isMultiDevice()) {
|
||||
Content syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.empty(), message.getTimestamp(), results, isRecipientUpdate, Collections.emptySet());
|
||||
EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
@@ -511,7 +536,7 @@ public class SignalServiceMessageSender {
|
||||
}
|
||||
}
|
||||
|
||||
if (needsSyncInResults || store.isMultiDevice()) {
|
||||
if (needsSyncInResults || aciStore.isMultiDevice()) {
|
||||
Optional<SignalServiceAddress> recipient = Optional.empty();
|
||||
if (!message.getGroupContext().isPresent() && recipients.size() == 1) {
|
||||
recipient = Optional.of(recipients.get(0));
|
||||
@@ -771,6 +796,15 @@ public class SignalServiceMessageSender {
|
||||
return sendMessage(address, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, false);
|
||||
}
|
||||
|
||||
private SignalServiceProtos.PniSignatureMessage createPniSignatureMessage() {
|
||||
byte[] signature = localPniIdentity.signAlternateIdentity(aciStore.getIdentityKeyPair().getPublicKey());
|
||||
|
||||
return SignalServiceProtos.PniSignatureMessage.newBuilder()
|
||||
.setPni(UuidUtil.toByteString(localPni.uuid()))
|
||||
.setSignature(ByteString.copyFrom(signature))
|
||||
.build();
|
||||
}
|
||||
|
||||
private Content createTypingContent(SignalServiceTypingMessage message) {
|
||||
Content.Builder container = Content.newBuilder();
|
||||
TypingMessage.Builder builder = TypingMessage.newBuilder();
|
||||
@@ -1755,7 +1789,7 @@ public class SignalServiceMessageSender {
|
||||
if (!unidentifiedAccess.isPresent()) {
|
||||
try {
|
||||
SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, Optional.empty()).blockingGet()).getResultOrThrow();
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || aciStore.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
} catch (InvalidUnidentifiedAccessHeaderException | UnregisteredUserException | MismatchedDevicesException | StaleDevicesException e) {
|
||||
// Non-technical failures shouldn't be retried with socket
|
||||
throw e;
|
||||
@@ -1768,7 +1802,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(), response.sentUnidentified(), response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || aciStore.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
} catch (InvalidUnidentifiedAccessHeaderException | UnregisteredUserException | MismatchedDevicesException | StaleDevicesException e) {
|
||||
// Non-technical failures shouldn't be retried with socket
|
||||
throw e;
|
||||
@@ -1789,7 +1823,7 @@ public class SignalServiceMessageSender {
|
||||
|
||||
SendMessageResponse response = socket.sendMessage(messages, unidentifiedAccess);
|
||||
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || aciStore.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
|
||||
} catch (InvalidKeyException ike) {
|
||||
Log.w(TAG, ike);
|
||||
@@ -1849,7 +1883,7 @@ public class SignalServiceMessageSender {
|
||||
|
||||
for (int i = 0; i < RETRY_COUNT; i++) {
|
||||
GroupTargetInfo targetInfo = buildGroupTargetInfo(recipients);
|
||||
Set<SignalProtocolAddress> sharedWith = store.getSenderKeySharedWith(distributionId);
|
||||
Set<SignalProtocolAddress> sharedWith = aciStore.getSenderKeySharedWith(distributionId);
|
||||
List<SignalServiceAddress> needsSenderKey = targetInfo.destinations.stream()
|
||||
.filter(a -> !sharedWith.contains(a))
|
||||
.map(a -> ServiceId.parseOrThrow(a.getName()))
|
||||
@@ -1876,7 +1910,7 @@ public class SignalServiceMessageSender {
|
||||
Set<String> successSids = successes.stream().map(a -> a.getServiceId().toString()).collect(Collectors.toSet());
|
||||
Set<SignalProtocolAddress> successAddresses = targetInfo.destinations.stream().filter(a -> successSids.contains(a.getName())).collect(Collectors.toSet());
|
||||
|
||||
store.markSenderKeySharedWith(distributionId, successAddresses);
|
||||
aciStore.markSenderKeySharedWith(distributionId, successAddresses);
|
||||
|
||||
Log.i(TAG, "[sendGroupMessage][" + timestamp + "] Successfully sent sender keys to " + successes.size() + "/" + needsSenderKey.size() + " recipients.");
|
||||
|
||||
@@ -1909,7 +1943,7 @@ public class SignalServiceMessageSender {
|
||||
|
||||
sendEvents.onSenderKeyShared();
|
||||
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, localDeviceId, store, sessionLock, null);
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, localDeviceId, aciStore, sessionLock, null);
|
||||
SenderCertificate senderCertificate = unidentifiedAccess.get(0).getUnidentifiedCertificate();
|
||||
|
||||
byte[] ciphertext;
|
||||
@@ -1963,7 +1997,7 @@ public class SignalServiceMessageSender {
|
||||
|
||||
private GroupTargetInfo buildGroupTargetInfo(List<SignalServiceAddress> recipients) {
|
||||
List<String> addressNames = recipients.stream().map(SignalServiceAddress::getIdentifier).collect(Collectors.toList());
|
||||
Set<SignalProtocolAddress> destinations = store.getAllAddressesWithActiveSessions(addressNames);
|
||||
Set<SignalProtocolAddress> destinations = aciStore.getAllAddressesWithActiveSessions(addressNames);
|
||||
Map<String, List<Integer>> devicesByAddressName = new HashMap<>();
|
||||
|
||||
destinations.addAll(recipients.stream()
|
||||
@@ -2009,7 +2043,7 @@ public class SignalServiceMessageSender {
|
||||
List<SendMessageResult> success = recipients.keySet()
|
||||
.stream()
|
||||
.filter(r -> !unregistered.contains(r.getServiceId()))
|
||||
.map(a -> SendMessageResult.success(a, recipients.get(a), true, store.isMultiDevice(), -1, Optional.of(content)))
|
||||
.map(a -> SendMessageResult.success(a, recipients.get(a), true, aciStore.isMultiDevice(), -1, Optional.of(content)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<SendMessageResult> results = new ArrayList<>(success.size() + failures.size());
|
||||
@@ -2109,7 +2143,7 @@ public class SignalServiceMessageSender {
|
||||
{
|
||||
List<OutgoingPushMessage> messages = new LinkedList<>();
|
||||
|
||||
List<Integer> subDevices = store.getSubDeviceSessions(recipient.getIdentifier());
|
||||
List<Integer> subDevices = aciStore.getSubDeviceSessions(recipient.getIdentifier());
|
||||
|
||||
List<Integer> deviceIds = new ArrayList<>(subDevices.size() + 1);
|
||||
deviceIds.add(SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||
@@ -2120,7 +2154,7 @@ public class SignalServiceMessageSender {
|
||||
}
|
||||
|
||||
for (int deviceId : deviceIds) {
|
||||
if (deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID || store.containsSession(new SignalProtocolAddress(recipient.getIdentifier(), deviceId))) {
|
||||
if (deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID || aciStore.containsSession(new SignalProtocolAddress(recipient.getIdentifier(), deviceId))) {
|
||||
messages.add(getEncryptedMessage(socket, recipient, unidentifiedAccess, deviceId, plaintext));
|
||||
}
|
||||
}
|
||||
@@ -2136,16 +2170,16 @@ public class SignalServiceMessageSender {
|
||||
throws IOException, InvalidKeyException, UntrustedIdentityException
|
||||
{
|
||||
SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(recipient.getIdentifier(), deviceId);
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, localDeviceId, store, sessionLock, null);
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, localDeviceId, aciStore, sessionLock, null);
|
||||
|
||||
if (!store.containsSession(signalProtocolAddress)) {
|
||||
if (!aciStore.containsSession(signalProtocolAddress)) {
|
||||
try {
|
||||
List<PreKeyBundle> preKeys = socket.getPreKeys(recipient, unidentifiedAccess, deviceId);
|
||||
|
||||
for (PreKeyBundle preKey : preKeys) {
|
||||
try {
|
||||
SignalProtocolAddress preKeyAddress = new SignalProtocolAddress(recipient.getIdentifier(), preKey.getDeviceId());
|
||||
SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(store, preKeyAddress));
|
||||
SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(aciStore, preKeyAddress));
|
||||
sessionBuilder.process(preKey);
|
||||
} catch (org.signal.libsignal.protocol.UntrustedIdentityException e) {
|
||||
throw new UntrustedIdentityException("Untrusted identity key!", recipient.getIdentifier(), preKey.getIdentityKey());
|
||||
@@ -2179,7 +2213,7 @@ public class SignalServiceMessageSender {
|
||||
PreKeyBundle preKey = socket.getPreKey(recipient, missingDeviceId);
|
||||
|
||||
try {
|
||||
SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(store, new SignalProtocolAddress(recipient.getIdentifier(), missingDeviceId)));
|
||||
SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(aciStore, new SignalProtocolAddress(recipient.getIdentifier(), missingDeviceId)));
|
||||
sessionBuilder.process(preKey);
|
||||
} catch (org.signal.libsignal.protocol.UntrustedIdentityException e) {
|
||||
throw new UntrustedIdentityException("Untrusted identity key!", recipient.getIdentifier(), preKey.getIdentityKey());
|
||||
@@ -2199,7 +2233,7 @@ public class SignalServiceMessageSender {
|
||||
List<SignalProtocolAddress> addressesToClear = convertToProtocolAddresses(recipient, devices);
|
||||
|
||||
for (SignalProtocolAddress address : addressesToClear) {
|
||||
store.archiveSession(address);
|
||||
aciStore.archiveSession(address);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMes
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage;
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.payments.Money;
|
||||
import org.whispersystems.signalservice.api.push.PNI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.storage.StorageKey;
|
||||
@@ -82,17 +83,19 @@ public final class SignalServiceContent {
|
||||
private final Optional<byte[]> groupId;
|
||||
private final String destinationUuid;
|
||||
|
||||
private final Optional<SignalServiceDataMessage> message;
|
||||
private final Optional<SignalServiceSyncMessage> synchronizeMessage;
|
||||
private final Optional<SignalServiceCallMessage> callMessage;
|
||||
private final Optional<SignalServiceReceiptMessage> readMessage;
|
||||
private final Optional<SignalServiceTypingMessage> typingMessage;
|
||||
private final Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage;
|
||||
private final Optional<DecryptionErrorMessage> decryptionErrorMessage;
|
||||
private final Optional<SignalServiceStoryMessage> storyMessage;
|
||||
private final Optional<SignalServiceDataMessage> message;
|
||||
private final Optional<SignalServiceSyncMessage> synchronizeMessage;
|
||||
private final Optional<SignalServiceCallMessage> callMessage;
|
||||
private final Optional<SignalServiceReceiptMessage> readMessage;
|
||||
private final Optional<SignalServiceTypingMessage> typingMessage;
|
||||
private final Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage;
|
||||
private final Optional<DecryptionErrorMessage> decryptionErrorMessage;
|
||||
private final Optional<SignalServiceStoryMessage> storyMessage;
|
||||
private final Optional<SignalServicePniSignatureMessage> pniSignatureMessage;
|
||||
|
||||
private SignalServiceContent(SignalServiceDataMessage message,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -123,10 +126,12 @@ public final class SignalServiceContent {
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceSyncMessage synchronizeMessage,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -157,10 +162,12 @@ public final class SignalServiceContent {
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceCallMessage callMessage,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -191,10 +198,12 @@ public final class SignalServiceContent {
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceReceiptMessage receiptMessage,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -225,10 +234,12 @@ public final class SignalServiceContent {
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
private SignalServiceContent(DecryptionErrorMessage errorMessage,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -259,10 +270,12 @@ public final class SignalServiceContent {
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.of(errorMessage);
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceTypingMessage typingMessage,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -293,9 +306,11 @@ public final class SignalServiceContent {
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
private SignalServiceContent(SenderKeyDistributionMessage senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -326,9 +341,11 @@ public final class SignalServiceContent {
|
||||
this.senderKeyDistributionMessage = Optional.of(senderKeyDistributionMessage);
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceStoryMessage storyMessage,
|
||||
private SignalServiceContent(SignalServicePniSignatureMessage pniSignatureMessage,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
@@ -356,9 +373,46 @@ public final class SignalServiceContent {
|
||||
this.callMessage = Optional.empty();
|
||||
this.readMessage = Optional.empty();
|
||||
this.typingMessage = Optional.empty();
|
||||
this.senderKeyDistributionMessage = Optional.empty();
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.empty();
|
||||
this.pniSignatureMessage = Optional.of(pniSignatureMessage);
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceStoryMessage storyMessage,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
long serverReceivedTimestamp,
|
||||
long serverDeliveredTimestamp,
|
||||
boolean needsReceipt,
|
||||
String serverUuid,
|
||||
Optional<byte[]> groupId,
|
||||
String destinationUuid,
|
||||
SignalServiceContentProto serializedState)
|
||||
{
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serverUuid = serverUuid;
|
||||
this.groupId = groupId;
|
||||
this.destinationUuid = destinationUuid;
|
||||
this.serializedState = serializedState;
|
||||
|
||||
this.message = Optional.empty();
|
||||
this.synchronizeMessage = Optional.empty();
|
||||
this.callMessage = Optional.empty();
|
||||
this.readMessage = Optional.empty();
|
||||
this.typingMessage = Optional.empty();
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.empty();
|
||||
this.storyMessage = Optional.of(storyMessage);
|
||||
this.pniSignatureMessage = pniSignatureMessage;
|
||||
}
|
||||
|
||||
public Optional<SignalServiceDataMessage> getDataMessage() {
|
||||
@@ -393,6 +447,10 @@ public final class SignalServiceContent {
|
||||
return decryptionErrorMessage;
|
||||
}
|
||||
|
||||
public Optional<SignalServicePniSignatureMessage> getPniSignatureMessage() {
|
||||
return pniSignatureMessage;
|
||||
}
|
||||
|
||||
public SignalServiceAddress getSender() {
|
||||
return sender;
|
||||
}
|
||||
@@ -456,20 +514,7 @@ public final class SignalServiceContent {
|
||||
SignalServiceAddress localAddress = SignalServiceAddressProtobufSerializer.fromProtobuf(serviceContentProto.getLocalAddress());
|
||||
|
||||
if (serviceContentProto.getDataCase() == SignalServiceContentProto.DataCase.LEGACYDATAMESSAGE) {
|
||||
SignalServiceProtos.DataMessage message = serviceContentProto.getLegacyDataMessage();
|
||||
|
||||
return new SignalServiceContent(createSignalServiceMessage(metadata, message),
|
||||
Optional.empty(),
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerReceivedTimestamp(),
|
||||
metadata.getServerDeliveredTimestamp(),
|
||||
metadata.isNeedsReceipt(),
|
||||
metadata.getServerGuid(),
|
||||
metadata.getGroupId(),
|
||||
metadata.getDestinationUuid(),
|
||||
serviceContentProto);
|
||||
throw new InvalidMessageStructureException("Legacy message!");
|
||||
} else if (serviceContentProto.getDataCase() == SignalServiceContentProto.DataCase.CONTENT) {
|
||||
SignalServiceProtos.Content message = serviceContentProto.getContent();
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage = Optional.empty();
|
||||
@@ -482,9 +527,21 @@ public final class SignalServiceContent {
|
||||
}
|
||||
}
|
||||
|
||||
Optional<SignalServicePniSignatureMessage> pniSignatureMessage = Optional.empty();
|
||||
|
||||
if (message.hasPniSignatureMessage()) {
|
||||
PNI pni = PNI.parseOrNull(message.getPniSignatureMessage().getPni().toByteArray());
|
||||
if (pni != null) {
|
||||
pniSignatureMessage = Optional.of(new SignalServicePniSignatureMessage(pni, message.getPniSignatureMessage().getSignature().toByteArray()));
|
||||
} else {
|
||||
Log.w(TAG, "Invalid PNI on PNI signature message! Ignoring.");
|
||||
}
|
||||
}
|
||||
|
||||
if (message.hasDataMessage()) {
|
||||
return new SignalServiceContent(createSignalServiceMessage(metadata, message.getDataMessage()),
|
||||
senderKeyDistributionMessage,
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
@@ -498,6 +555,7 @@ public final class SignalServiceContent {
|
||||
} else if (message.hasSyncMessage() && localAddress.matches(metadata.getSender())) {
|
||||
return new SignalServiceContent(createSynchronizeMessage(metadata, message.getSyncMessage()),
|
||||
senderKeyDistributionMessage,
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
@@ -511,6 +569,7 @@ public final class SignalServiceContent {
|
||||
} else if (message.hasCallMessage()) {
|
||||
return new SignalServiceContent(createCallMessage(message.getCallMessage()),
|
||||
senderKeyDistributionMessage,
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
@@ -524,6 +583,7 @@ public final class SignalServiceContent {
|
||||
} else if (message.hasReceiptMessage()) {
|
||||
return new SignalServiceContent(createReceiptMessage(metadata, message.getReceiptMessage()),
|
||||
senderKeyDistributionMessage,
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
@@ -537,6 +597,7 @@ public final class SignalServiceContent {
|
||||
} else if (message.hasTypingMessage()) {
|
||||
return new SignalServiceContent(createTypingMessage(metadata, message.getTypingMessage()),
|
||||
senderKeyDistributionMessage,
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
@@ -550,6 +611,7 @@ public final class SignalServiceContent {
|
||||
} else if (message.hasDecryptionErrorMessage()) {
|
||||
return new SignalServiceContent(createDecryptionErrorMessage(metadata, message.getDecryptionErrorMessage()),
|
||||
senderKeyDistributionMessage,
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
@@ -562,6 +624,21 @@ public final class SignalServiceContent {
|
||||
serviceContentProto);
|
||||
} else if (message.hasStoryMessage()) {
|
||||
return new SignalServiceContent(createStoryMessage(message.getStoryMessage()),
|
||||
senderKeyDistributionMessage,
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerReceivedTimestamp(),
|
||||
metadata.getServerDeliveredTimestamp(),
|
||||
false,
|
||||
metadata.getServerGuid(),
|
||||
metadata.getGroupId(),
|
||||
metadata.getDestinationUuid(),
|
||||
serviceContentProto);
|
||||
} else if (pniSignatureMessage.isPresent()) {
|
||||
return new SignalServiceContent(pniSignatureMessage.get(),
|
||||
senderKeyDistributionMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
@@ -575,6 +652,7 @@ public final class SignalServiceContent {
|
||||
} else if (senderKeyDistributionMessage.isPresent()) {
|
||||
// IMPORTANT: This block should always be last, since you can pair SKDM's with other content
|
||||
return new SignalServiceContent(senderKeyDistributionMessage.get(),
|
||||
pniSignatureMessage,
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
|
||||
@@ -9,10 +9,8 @@ package org.whispersystems.signalservice.api.messages;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
||||
import org.whispersystems.signalservice.api.util.Preconditions;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope;
|
||||
@@ -21,7 +19,6 @@ import org.whispersystems.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class represents an encrypted Signal Service envelope.
|
||||
@@ -162,7 +159,7 @@ public class SignalServiceEnvelope {
|
||||
* @return The envelope's sender as a SignalServiceAddress.
|
||||
*/
|
||||
public SignalServiceAddress getSourceAddress() {
|
||||
return new SignalServiceAddress(ACI.parseOrNull(envelope.getSourceUuid()));
|
||||
return new SignalServiceAddress(ServiceId.parseOrNull(envelope.getSourceUuid()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.whispersystems.signalservice.api.messages;
|
||||
|
||||
|
||||
import org.whispersystems.signalservice.api.push.PNI;
|
||||
|
||||
/**
|
||||
* When someone sends a message to your PNI, you need to attach one of these PNI signature messages,
|
||||
* proving that you own the PNI identity.
|
||||
*
|
||||
* The signature is generated by signing your ACI public key with your PNI identity.
|
||||
*/
|
||||
public class SignalServicePniSignatureMessage {
|
||||
|
||||
private final PNI pni;
|
||||
private final byte[] signature;
|
||||
|
||||
public SignalServicePniSignatureMessage(PNI pni, byte[] signature) {
|
||||
this.pni = pni;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public PNI getPni() {
|
||||
return pni;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return signature;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,11 @@ public final class PNI extends ServiceId {
|
||||
return from(UUID.fromString(raw));
|
||||
}
|
||||
|
||||
public static PNI parseOrNull(byte[] raw) {
|
||||
UUID uuid = UuidUtil.parseOrNull(raw);
|
||||
return uuid != null ? from(uuid) : null;
|
||||
}
|
||||
|
||||
private PNI(UUID uuid) {
|
||||
super(uuid);
|
||||
}
|
||||
|
||||
@@ -39,15 +39,16 @@ message Envelope {
|
||||
}
|
||||
|
||||
message Content {
|
||||
optional DataMessage dataMessage = 1;
|
||||
optional SyncMessage syncMessage = 2;
|
||||
optional CallMessage callMessage = 3;
|
||||
optional NullMessage nullMessage = 4;
|
||||
optional ReceiptMessage receiptMessage = 5;
|
||||
optional TypingMessage typingMessage = 6;
|
||||
optional bytes senderKeyDistributionMessage = 7;
|
||||
optional bytes decryptionErrorMessage = 8;
|
||||
optional StoryMessage storyMessage = 9;
|
||||
optional DataMessage dataMessage = 1;
|
||||
optional SyncMessage syncMessage = 2;
|
||||
optional CallMessage callMessage = 3;
|
||||
optional NullMessage nullMessage = 4;
|
||||
optional ReceiptMessage receiptMessage = 5;
|
||||
optional TypingMessage typingMessage = 6;
|
||||
optional bytes senderKeyDistributionMessage = 7;
|
||||
optional bytes decryptionErrorMessage = 8;
|
||||
optional StoryMessage storyMessage = 9;
|
||||
optional PniSignatureMessage pniSignatureMessage = 10;
|
||||
}
|
||||
|
||||
message CallMessage {
|
||||
@@ -711,3 +712,8 @@ message DecryptionErrorMessage {
|
||||
optional uint64 timestamp = 2;
|
||||
optional uint32 deviceId = 3;
|
||||
}
|
||||
|
||||
message PniSignatureMessage {
|
||||
optional bytes pni = 1;
|
||||
optional bytes signature = 2;
|
||||
}
|
||||
Reference in New Issue
Block a user