mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-24 07:38:49 +00:00
Support for sealed sender - Part 1
This commit is contained in:
committed by
Greyson Parrelli
parent
b7b9554364
commit
5f31762220
@@ -193,7 +193,7 @@ public class AttachmentDownloadJob extends MasterSecretJob implements Injectable
|
||||
Log.i(TAG, "Downloading attachment with no digest...");
|
||||
}
|
||||
|
||||
return new SignalServiceAttachmentPointer(id, null, key, relay,
|
||||
return new SignalServiceAttachmentPointer(id, null, key,
|
||||
Optional.of(Util.toIntExact(attachment.getSize())),
|
||||
Optional.absent(),
|
||||
0, 0,
|
||||
|
||||
@@ -98,7 +98,7 @@ public class AvatarDownloadJob extends MasterSecretJob implements InjectableType
|
||||
attachment = File.createTempFile("avatar", "tmp", context.getCacheDir());
|
||||
attachment.deleteOnExit();
|
||||
|
||||
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, relay, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false);
|
||||
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false);
|
||||
InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE);
|
||||
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ public class MmsDownloadJob extends MasterSecretJob {
|
||||
group = Optional.of(Address.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), true)));
|
||||
}
|
||||
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false, false);
|
||||
Optional<InsertResult> insertResult = database.insertMessageInbox(message, contentLocation, threadId);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientReader;
|
||||
@@ -30,6 +31,7 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = MultiDeviceBlockedUpdateJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
@@ -75,7 +77,8 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
||||
}
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blockedIndividuals, blockedGroups)));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blockedIndividuals, blockedGroups)),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
@@ -238,7 +239,8 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
||||
.build();
|
||||
|
||||
try {
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, complete)));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, complete)),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
} catch (IOException ioe) {
|
||||
throw new NetworkException(ioe);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
@@ -131,7 +132,8 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject
|
||||
.withLength(contactsFile.length())
|
||||
.build();
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forGroups(attachmentStream));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forGroups(attachmentStream),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
@@ -86,7 +87,7 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I
|
||||
|
||||
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
|
||||
|
||||
messageSender.sendMessage(syncMessage);
|
||||
messageSender.sendMessage(syncMessage, UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
@@ -58,7 +59,8 @@ public class MultiDeviceReadReceiptUpdateJob extends ContextJob implements Injec
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled))));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled))),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
@@ -100,7 +101,8 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
||||
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,11 +7,14 @@ import android.support.annotation.NonNull;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
@@ -101,7 +104,8 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
||||
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
||||
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage),
|
||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(destination), false)));
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -7,11 +8,18 @@ import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.signal.libsignal.metadata.InvalidMetadataMessageException;
|
||||
import org.signal.libsignal.metadata.InvalidMetadataVersionException;
|
||||
import org.signal.libsignal.metadata.ProtocolDuplicateMessageException;
|
||||
import org.signal.libsignal.metadata.ProtocolInvalidKeyException;
|
||||
import org.signal.libsignal.metadata.ProtocolInvalidKeyIdException;
|
||||
import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
|
||||
import org.signal.libsignal.metadata.ProtocolInvalidVersionException;
|
||||
import org.signal.libsignal.metadata.ProtocolLegacyMessageException;
|
||||
import org.signal.libsignal.metadata.ProtocolNoSessionException;
|
||||
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -22,6 +30,7 @@ import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.contactshare.ContactModelMapper;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
@@ -40,6 +49,8 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
||||
@@ -53,25 +64,13 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
||||
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.DuplicateMessageException;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.InvalidKeyIdException;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
import org.whispersystems.libsignal.InvalidVersionException;
|
||||
import org.whispersystems.libsignal.LegacyMessageException;
|
||||
import org.whispersystems.libsignal.NoSessionException;
|
||||
import org.whispersystems.libsignal.UntrustedIdentityException;
|
||||
import org.whispersystems.libsignal.protocol.PreKeySignalMessage;
|
||||
import org.whispersystems.libsignal.state.SessionStore;
|
||||
import org.whispersystems.libsignal.state.SignalProtocolStore;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
@@ -212,11 +211,11 @@ public class PushDecryptJob extends ContextJob {
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
|
||||
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore);
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore, UnidentifiedAccessUtil.getCertificateValidator());
|
||||
|
||||
SignalServiceContent content = cipher.decrypt(envelope);
|
||||
|
||||
if (shouldIgnore(envelope, content)) {
|
||||
if (shouldIgnore(content)) {
|
||||
Log.i(TAG, "Ignoring message.");
|
||||
return;
|
||||
}
|
||||
@@ -225,41 +224,45 @@ public class PushDecryptJob extends ContextJob {
|
||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent();
|
||||
|
||||
if (message.isEndSession()) handleEndSessionMessage(envelope, message, smsMessageId);
|
||||
else if (message.isGroupUpdate()) handleGroupMessage(envelope, message, smsMessageId);
|
||||
else if (message.isExpirationUpdate()) handleExpirationUpdate(envelope, message, smsMessageId);
|
||||
else if (isMediaMessage) handleMediaMessage(envelope, message, smsMessageId);
|
||||
else if (message.getBody().isPresent()) handleTextMessage(envelope, message, smsMessageId);
|
||||
if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId);
|
||||
else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId);
|
||||
else if (message.isExpirationUpdate()) handleExpirationUpdate(content, message, smsMessageId);
|
||||
else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId);
|
||||
else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId);
|
||||
|
||||
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) {
|
||||
handleUnknownGroupMessage(envelope, message.getGroupInfo().get());
|
||||
handleUnknownGroupMessage(content, message.getGroupInfo().get());
|
||||
}
|
||||
|
||||
if (message.getProfileKey().isPresent() && message.getProfileKey().get().length == 32) {
|
||||
handleProfileKey(envelope, message);
|
||||
handleProfileKey(content, message);
|
||||
}
|
||||
|
||||
if (content.isNeedsReceipt()) {
|
||||
handleNeedsDeliveryReceipt(content, message);
|
||||
}
|
||||
} else if (content.getSyncMessage().isPresent()) {
|
||||
SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
|
||||
|
||||
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(envelope, syncMessage.getSent().get());
|
||||
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get());
|
||||
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(syncMessage.getRequest().get());
|
||||
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), envelope.getTimestamp());
|
||||
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp());
|
||||
else if (syncMessage.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get());
|
||||
else Log.w(TAG, "Contains no known sync types...");
|
||||
} else if (content.getCallMessage().isPresent()) {
|
||||
Log.i(TAG, "Got call message...");
|
||||
SignalServiceCallMessage message = content.getCallMessage().get();
|
||||
|
||||
if (message.getOfferMessage().isPresent()) handleCallOfferMessage(envelope, message.getOfferMessage().get(), smsMessageId);
|
||||
else if (message.getAnswerMessage().isPresent()) handleCallAnswerMessage(envelope, message.getAnswerMessage().get());
|
||||
else if (message.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(envelope, message.getIceUpdateMessages().get());
|
||||
else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(envelope, message.getHangupMessage().get(), smsMessageId);
|
||||
else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(envelope, message.getBusyMessage().get());
|
||||
if (message.getOfferMessage().isPresent()) handleCallOfferMessage(content, message.getOfferMessage().get(), smsMessageId);
|
||||
else if (message.getAnswerMessage().isPresent()) handleCallAnswerMessage(content, message.getAnswerMessage().get());
|
||||
else if (message.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(content, message.getIceUpdateMessages().get());
|
||||
else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(content, message.getHangupMessage().get(), smsMessageId);
|
||||
else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(content, message.getBusyMessage().get());
|
||||
} else if (content.getReceiptMessage().isPresent()) {
|
||||
SignalServiceReceiptMessage message = content.getReceiptMessage().get();
|
||||
|
||||
if (message.isReadReceipt()) handleReadReceipt(envelope, message);
|
||||
else if (message.isDeliveryReceipt()) handleDeliveryReceipt(envelope, message);
|
||||
if (message.isReadReceipt()) handleReadReceipt(content, message);
|
||||
else if (message.isDeliveryReceipt()) handleDeliveryReceipt(content, message);
|
||||
} else {
|
||||
Log.w(TAG, "Got unrecognized message...");
|
||||
}
|
||||
@@ -267,28 +270,30 @@ public class PushDecryptJob extends ContextJob {
|
||||
if (envelope.isPreKeySignalMessage()) {
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob(context));
|
||||
}
|
||||
} catch (InvalidVersionException e) {
|
||||
} catch (ProtocolInvalidVersionException e) {
|
||||
Log.w(TAG, e);
|
||||
handleInvalidVersionMessage(envelope, smsMessageId);
|
||||
} catch (InvalidMessageException | InvalidKeyIdException | InvalidKeyException | MmsException e) {
|
||||
handleInvalidVersionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolInvalidMessageException | ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
|
||||
Log.w(TAG, e);
|
||||
handleCorruptMessage(envelope, smsMessageId);
|
||||
} catch (NoSessionException e) {
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (StorageFailedException e) {
|
||||
Log.w(TAG, e);
|
||||
handleNoSessionMessage(envelope, smsMessageId);
|
||||
} catch (LegacyMessageException e) {
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolNoSessionException e) {
|
||||
Log.w(TAG, e);
|
||||
handleLegacyMessage(envelope, smsMessageId);
|
||||
} catch (DuplicateMessageException e) {
|
||||
handleNoSessionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolLegacyMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleDuplicateMessage(envelope, smsMessageId);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
handleLegacyMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolDuplicateMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleDuplicateMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (InvalidMetadataVersionException | InvalidMetadataMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleUntrustedIdentityMessage(envelope, smsMessageId);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCallOfferMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleCallOfferMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull OfferMessage message,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
@@ -301,29 +306,29 @@ public class PushDecryptJob extends ContextJob {
|
||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_INCOMING_CALL);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_TIMESTAMP, envelope.getTimestamp());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_TIMESTAMP, content.getTimestamp());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent);
|
||||
else context.startService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCallAnswerMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleCallAnswerMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull AnswerMessage message)
|
||||
{
|
||||
Log.i(TAG, "handleCallAnswerMessage...");
|
||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_RESPONSE_MESSAGE);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
private void handleCallIceUpdateMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleCallIceUpdateMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull List<IceUpdateMessage> messages)
|
||||
{
|
||||
Log.w(TAG, "handleCallIceUpdateMessage... " + messages.size());
|
||||
@@ -331,7 +336,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_ICE_MESSAGE);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP, message.getSdp());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_MID, message.getSdpMid());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_LINE_INDEX, message.getSdpMLineIndex());
|
||||
@@ -340,7 +345,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCallHangupMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleCallHangupMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull HangupMessage message,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
@@ -351,32 +356,32 @@ public class PushDecryptJob extends ContextJob {
|
||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_REMOTE_HANGUP);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCallBusyMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleCallBusyMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull BusyMessage message)
|
||||
{
|
||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_REMOTE_BUSY);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
private void handleEndSessionMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
@NonNull SignalServiceDataMessage message,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
private void handleEndSessionMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||
envelope.getSourceDevice(),
|
||||
message.getTimestamp(),
|
||||
"", Optional.absent(), 0);
|
||||
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Address.fromExternal(context, content.getSender()),
|
||||
content.getSenderDevice(),
|
||||
content.getTimestamp(),
|
||||
"", Optional.absent(), 0,
|
||||
content.isNeedsReceipt());
|
||||
|
||||
Long threadId;
|
||||
|
||||
@@ -393,7 +398,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
|
||||
if (threadId != null) {
|
||||
SessionStore sessionStore = new TextSecureSessionStore(context);
|
||||
sessionStore.deleteAllSessions(envelope.getSource());
|
||||
sessionStore.deleteAllSessions(content.getSender());
|
||||
|
||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||
MessageNotifier.updateNotification(context, threadId);
|
||||
@@ -424,15 +429,15 @@ public class PushDecryptJob extends ContextJob {
|
||||
return threadId;
|
||||
}
|
||||
|
||||
private void handleGroupMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleGroupMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
throws MmsException
|
||||
throws StorageFailedException
|
||||
{
|
||||
GroupMessageProcessor.process(context, envelope, message, false);
|
||||
GroupMessageProcessor.process(context, content, message, false);
|
||||
|
||||
if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getMessageDestination(envelope, message).getExpireMessages()) {
|
||||
handleExpirationUpdate(envelope, message, Optional.absent());
|
||||
if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getMessageDestination(content, message).getExpireMessages()) {
|
||||
handleExpirationUpdate(content, message, Optional.absent());
|
||||
}
|
||||
|
||||
if (smsMessageId.isPresent()) {
|
||||
@@ -440,36 +445,41 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnknownGroupMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleUnknownGroupMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceGroup group)
|
||||
{
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RequestGroupInfoJob(context, envelope.getSource(), group.getGroupId()));
|
||||
.add(new RequestGroupInfoJob(context, content.getSender(), group.getGroupId()));
|
||||
}
|
||||
|
||||
private void handleExpirationUpdate(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleExpirationUpdate(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
throws MmsException
|
||||
throws StorageFailedException
|
||||
{
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getMessageDestination(envelope, message);
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, envelope.getSource()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, true,
|
||||
Optional.fromNullable(envelope.getRelay()),
|
||||
Optional.absent(), message.getGroupInfo(),
|
||||
Optional.absent(), Optional.absent(), Optional.absent());
|
||||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getMessageDestination(content, message);
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, true,
|
||||
content.isNeedsReceipt(),
|
||||
Optional.absent(),
|
||||
message.getGroupInfo(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
|
||||
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, message.getExpiresInSeconds());
|
||||
|
||||
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, message.getExpiresInSeconds());
|
||||
|
||||
if (smsMessageId.isPresent()) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||
if (smsMessageId.isPresent()) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||
}
|
||||
} catch (MmsException e) {
|
||||
throw new StorageFailedException(e, content.getSender(), content.getSenderDevice());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,48 +487,53 @@ public class PushDecryptJob extends ContextJob {
|
||||
IdentityUtil.processVerifiedMessage(context, verifiedMessage);
|
||||
}
|
||||
|
||||
private void handleSynchronizeSentMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull SentTranscriptMessage message)
|
||||
throws MmsException
|
||||
throws StorageFailedException
|
||||
|
||||
{
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
try {
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
|
||||
Long threadId;
|
||||
Long threadId;
|
||||
|
||||
if (message.getMessage().isEndSession()) {
|
||||
threadId = handleSynchronizeSentEndSessionMessage(message);
|
||||
} else if (message.getMessage().isGroupUpdate()) {
|
||||
threadId = GroupMessageProcessor.process(context, envelope, message.getMessage(), true);
|
||||
} else if (message.getMessage().isExpirationUpdate()) {
|
||||
threadId = handleSynchronizeSentExpirationUpdate(message);
|
||||
} else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent()) {
|
||||
threadId = handleSynchronizeSentMediaMessage(message);
|
||||
} else {
|
||||
threadId = handleSynchronizeSentTextMessage(message);
|
||||
}
|
||||
|
||||
if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false))) {
|
||||
handleUnknownGroupMessage(envelope, message.getMessage().getGroupInfo().get());
|
||||
}
|
||||
|
||||
if (message.getMessage().getProfileKey().isPresent()) {
|
||||
Recipient recipient = null;
|
||||
|
||||
if (message.getDestination().isPresent()) recipient = Recipient.from(context, Address.fromExternal(context, message.getDestination().get()), false);
|
||||
else if (message.getMessage().getGroupInfo().isPresent()) recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false)), false);
|
||||
|
||||
|
||||
if (recipient != null && !recipient.isSystemContact() && !recipient.isProfileSharing()) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
|
||||
if (message.getMessage().isEndSession()) {
|
||||
threadId = handleSynchronizeSentEndSessionMessage(message);
|
||||
} else if (message.getMessage().isGroupUpdate()) {
|
||||
threadId = GroupMessageProcessor.process(context, content, message.getMessage(), true);
|
||||
} else if (message.getMessage().isExpirationUpdate()) {
|
||||
threadId = handleSynchronizeSentExpirationUpdate(message);
|
||||
} else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent()) {
|
||||
threadId = handleSynchronizeSentMediaMessage(message);
|
||||
} else {
|
||||
threadId = handleSynchronizeSentTextMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
if (threadId != null) {
|
||||
DatabaseFactory.getThreadDatabase(getContext()).setRead(threadId, true);
|
||||
MessageNotifier.updateNotification(getContext());
|
||||
}
|
||||
if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false))) {
|
||||
handleUnknownGroupMessage(content, message.getMessage().getGroupInfo().get());
|
||||
}
|
||||
|
||||
MessageNotifier.setLastDesktopActivityTimestamp(message.getTimestamp());
|
||||
if (message.getMessage().getProfileKey().isPresent()) {
|
||||
Recipient recipient = null;
|
||||
|
||||
if (message.getDestination().isPresent()) recipient = Recipient.from(context, Address.fromExternal(context, message.getDestination().get()), false);
|
||||
else if (message.getMessage().getGroupInfo().isPresent()) recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false)), false);
|
||||
|
||||
|
||||
if (recipient != null && !recipient.isSystemContact() && !recipient.isProfileSharing()) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (threadId != null) {
|
||||
DatabaseFactory.getThreadDatabase(getContext()).setRead(threadId, true);
|
||||
MessageNotifier.updateNotification(getContext());
|
||||
}
|
||||
|
||||
MessageNotifier.setLastDesktopActivityTimestamp(message.getTimestamp());
|
||||
} catch (MmsException e) {
|
||||
throw new StorageFailedException(e, content.getSender(), content.getSenderDevice());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSynchronizeRequestMessage(@NonNull RequestMessage message)
|
||||
@@ -572,51 +587,48 @@ public class PushDecryptJob extends ContextJob {
|
||||
MessageNotifier.updateNotification(context);
|
||||
}
|
||||
|
||||
private void handleMediaMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleMediaMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
throws MmsException
|
||||
throws StorageFailedException
|
||||
{
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getMessageDestination(envelope, message);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getQuote());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getSharedContacts());
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, envelope.getSource()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, false,
|
||||
Optional.fromNullable(envelope.getRelay()),
|
||||
message.getBody(),
|
||||
message.getGroupInfo(),
|
||||
message.getAttachments(),
|
||||
quote,
|
||||
sharedContacts);
|
||||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getQuote());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getSharedContacts());
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, false,
|
||||
content.isNeedsReceipt(),
|
||||
message.getBody(),
|
||||
message.getGroupInfo(),
|
||||
message.getAttachments(),
|
||||
quote,
|
||||
sharedContacts);
|
||||
|
||||
if (message.getExpiresInSeconds() != recipient.getExpireMessages()) {
|
||||
handleExpirationUpdate(envelope, message, Optional.absent());
|
||||
}
|
||||
Optional<InsertResult> insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
|
||||
Optional<InsertResult> insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
if (insertResult.isPresent()) {
|
||||
List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(insertResult.get().getMessageId());
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(insertResult.get().getMessageId());
|
||||
for (DatabaseAttachment attachment : attachments) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, insertResult.get().getMessageId(), attachment.getAttachmentId(), false));
|
||||
}
|
||||
|
||||
for (DatabaseAttachment attachment : attachments) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, insertResult.get().getMessageId(), attachment.getAttachmentId(), false));
|
||||
if (smsMessageId.isPresent()) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||
}
|
||||
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
|
||||
if (smsMessageId.isPresent()) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||
}
|
||||
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
} catch (MmsException e) {
|
||||
throw new StorageFailedException(e, content.getSender(), content.getSenderDevice());
|
||||
}
|
||||
}
|
||||
|
||||
private long handleSynchronizeSentExpirationUpdate(@NonNull SentTranscriptMessage message)
|
||||
throws MmsException
|
||||
{
|
||||
private long handleSynchronizeSentExpirationUpdate(@NonNull SentTranscriptMessage message) throws MmsException {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getSyncMessageDestination(message);
|
||||
|
||||
@@ -646,7 +658,8 @@ public class PushDecryptJob extends ContextJob {
|
||||
message.getTimestamp(), -1,
|
||||
message.getMessage().getExpiresInSeconds() * 1000,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
|
||||
sharedContacts.or(Collections.emptyList()));
|
||||
sharedContacts.or(Collections.emptyList()),
|
||||
Collections.emptyList(), Collections.emptyList());
|
||||
|
||||
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
|
||||
|
||||
@@ -677,17 +690,17 @@ public class PushDecryptJob extends ContextJob {
|
||||
return threadId;
|
||||
}
|
||||
|
||||
private void handleTextMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleTextMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
throws MmsException
|
||||
throws StorageFailedException
|
||||
{
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
String body = message.getBody().isPresent() ? message.getBody().get() : "";
|
||||
Recipient recipient = getMessageDestination(envelope, message);
|
||||
Recipient recipient = getMessageDestination(content, message);
|
||||
|
||||
if (message.getExpiresInSeconds() != recipient.getExpireMessages()) {
|
||||
handleExpirationUpdate(envelope, message, Optional.absent());
|
||||
handleExpirationUpdate(content, message, Optional.absent());
|
||||
}
|
||||
|
||||
Long threadId;
|
||||
@@ -695,11 +708,12 @@ public class PushDecryptJob extends ContextJob {
|
||||
if (smsMessageId.isPresent() && !message.getGroupInfo().isPresent()) {
|
||||
threadId = database.updateBundleMessageBody(smsMessageId.get(), body).second;
|
||||
} else {
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||
envelope.getSourceDevice(),
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, content.getSender()),
|
||||
content.getSenderDevice(),
|
||||
message.getTimestamp(), body,
|
||||
message.getGroupInfo(),
|
||||
message.getExpiresInSeconds() * 1000L);
|
||||
message.getExpiresInSeconds() * 1000L,
|
||||
content.isNeedsReceipt());
|
||||
|
||||
textMessage = new IncomingEncryptedMessage(textMessage, body);
|
||||
Optional<InsertResult> insertResult = database.insertMessageInbox(textMessage);
|
||||
@@ -758,13 +772,13 @@ public class PushDecryptJob extends ContextJob {
|
||||
return threadId;
|
||||
}
|
||||
|
||||
private void handleInvalidVersionMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleInvalidVersionMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
|
||||
if (!smsMessageId.isPresent()) {
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(envelope);
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsInvalidVersionKeyExchange(insertResult.get().getMessageId());
|
||||
@@ -775,13 +789,13 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCorruptMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleCorruptMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
|
||||
if (!smsMessageId.isPresent()) {
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(envelope);
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsDecryptFailed(insertResult.get().getMessageId());
|
||||
@@ -792,13 +806,13 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNoSessionMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleNoSessionMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
|
||||
if (!smsMessageId.isPresent()) {
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(envelope);
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsNoSession(insertResult.get().getMessageId());
|
||||
@@ -809,13 +823,13 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLegacyMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleLegacyMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
|
||||
if (!smsMessageId.isPresent()) {
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(envelope);
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsLegacyVersion(insertResult.get().getMessageId());
|
||||
@@ -827,7 +841,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void handleDuplicateMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleDuplicateMessage(@NonNull String sender, int senderDeviceId, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
// Let's start ignoring these now
|
||||
@@ -842,45 +856,11 @@ public class PushDecryptJob extends ContextJob {
|
||||
// }
|
||||
}
|
||||
|
||||
private void handleUntrustedIdentityMessage(@NonNull SignalServiceEnvelope envelope,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
try {
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
Address sourceAddress = Address.fromExternal(context, envelope.getSource());
|
||||
byte[] serialized = envelope.hasLegacyMessage() ? envelope.getLegacyMessage() : envelope.getContent();
|
||||
PreKeySignalMessage whisperMessage = new PreKeySignalMessage(serialized);
|
||||
IdentityKey identityKey = whisperMessage.getIdentityKey();
|
||||
String encoded = Base64.encodeBytes(serialized);
|
||||
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(sourceAddress,
|
||||
envelope.getSourceDevice(),
|
||||
envelope.getTimestamp(), encoded,
|
||||
Optional.absent(), 0);
|
||||
|
||||
if (!smsMessageId.isPresent()) {
|
||||
IncomingPreKeyBundleMessage bundleMessage = new IncomingPreKeyBundleMessage(textMessage, encoded, envelope.hasLegacyMessage());
|
||||
Optional<InsertResult> insertResult = database.insertMessageInbox(bundleMessage);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
database.setMismatchedIdentity(insertResult.get().getMessageId(), sourceAddress, identityKey);
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
} else {
|
||||
database.updateMessageBody(smsMessageId.get(), encoded);
|
||||
database.markAsPreKeyBundle(smsMessageId.get());
|
||||
database.setMismatchedIdentity(smsMessageId.get(), sourceAddress, identityKey);
|
||||
}
|
||||
} catch (InvalidMessageException | InvalidVersionException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleProfileKey(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleProfileKey(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message)
|
||||
{
|
||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||
Address sourceAddress = Address.fromExternal(context, envelope.getSource());
|
||||
Address sourceAddress = Address.fromExternal(context, content.getSender());
|
||||
Recipient recipient = Recipient.from(context, sourceAddress, false);
|
||||
|
||||
if (recipient.getProfileKey() == null || !MessageDigest.isEqual(recipient.getProfileKey(), message.getProfileKey().get())) {
|
||||
@@ -889,17 +869,27 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDeliveryReceipt(@NonNull SignalServiceEnvelope envelope,
|
||||
private void handleNeedsDeliveryReceipt(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message)
|
||||
{
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new SendDeliveryReceiptJob(context, Address.fromExternal(context, content.getSender()), message.getTimestamp()));
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void handleDeliveryReceipt(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceReceiptMessage message)
|
||||
{
|
||||
for (long timestamp : message.getTimestamps()) {
|
||||
Log.i(TAG, String.format("Received encrypted delivery receipt: (XXXXX, %d)", timestamp));
|
||||
DatabaseFactory.getMmsSmsDatabase(context)
|
||||
.incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()), timestamp), System.currentTimeMillis());
|
||||
.incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, content.getSender()), timestamp), System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReadReceipt(@NonNull SignalServiceEnvelope envelope,
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void handleReadReceipt(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceReceiptMessage message)
|
||||
{
|
||||
if (TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
@@ -907,7 +897,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
Log.i(TAG, String.format("Received encrypted read receipt: (XXXXX, %d)", timestamp));
|
||||
|
||||
DatabaseFactory.getMmsSmsDatabase(context)
|
||||
.incrementReadReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()), timestamp), envelope.getTimestamp());
|
||||
.incrementReadReceiptCount(new SyncMessageId(Address.fromExternal(context, content.getSender()), timestamp), content.getTimestamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -960,12 +950,11 @@ public class PushDecryptJob extends ContextJob {
|
||||
return Optional.of(contacts);
|
||||
}
|
||||
|
||||
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {
|
||||
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp) {
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||
envelope.getSourceDevice(),
|
||||
envelope.getTimestamp(), "",
|
||||
Optional.absent(), 0);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, sender),
|
||||
senderDevice, timestamp, "",
|
||||
Optional.absent(), 0, false);
|
||||
|
||||
textMessage = new IncomingEncryptedMessage(textMessage, "");
|
||||
return database.insertMessageInbox(textMessage);
|
||||
@@ -979,21 +968,20 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Recipient getMessageDestination(SignalServiceEnvelope envelope, SignalServiceDataMessage message) {
|
||||
private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
if (message.getGroupInfo().isPresent()) {
|
||||
return Recipient.from(context, Address.fromExternal(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false)), false);
|
||||
} else {
|
||||
return Recipient.from(context, Address.fromExternal(context, envelope.getSource()), false);
|
||||
return Recipient.from(context, Address.fromExternal(context, content.getSender()), false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldIgnore(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content) {
|
||||
Recipient sender = Recipient.from(context, Address.fromExternal(context, envelope.getSource()), false);
|
||||
private boolean shouldIgnore(@NonNull SignalServiceContent content) {
|
||||
Recipient sender = Recipient.from(context, Address.fromExternal(context, content.getSender()), false);
|
||||
|
||||
if (content.getDataMessage().isPresent()) {
|
||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||
Recipient conversation = getMessageDestination(envelope, message);
|
||||
Recipient conversation = getMessageDestination(content, message);
|
||||
|
||||
if (conversation.isGroupRecipient() && conversation.isBlocked()) {
|
||||
return true;
|
||||
@@ -1023,4 +1011,25 @@ public class PushDecryptJob extends ContextJob {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
private static class StorageFailedException extends Exception {
|
||||
private final String sender;
|
||||
private final int senderDevice;
|
||||
|
||||
private StorageFailedException(Exception e, String sender, int senderDevice) {
|
||||
super(e);
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
}
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public int getSenderDevice() {
|
||||
return senderDevice;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,15 +4,18 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
@@ -24,25 +27,27 @@ import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Quote;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.EncapsulatedExceptions;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NetworkFailureException;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -96,47 +101,56 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
|
||||
@Override
|
||||
public void onPushSend()
|
||||
throws MmsException, IOException, NoSuchMessageException
|
||||
throws IOException, MmsException, NoSuchMessageException, RetryLaterException
|
||||
{
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
|
||||
List<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
|
||||
List<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Sending message: " + messageId);
|
||||
List<Address> target;
|
||||
|
||||
deliver(message, filterAddress == null ? null : Address.fromSerialized(filterAddress));
|
||||
if (filterAddress != null) target = Collections.singletonList(Address.fromSerialized(filterAddress));
|
||||
else if (!existingNetworkFailures.isEmpty()) target = Stream.of(existingNetworkFailures).map(NetworkFailure::getAddress).toList();
|
||||
else target = getGroupMessageRecipients(message.getRecipient().getAddress().toGroupString(), messageId);
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
markAttachmentsUploaded(messageId, message.getAttachments());
|
||||
List<SendMessageResult> results = deliver(message, target);
|
||||
List<NetworkFailure> networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(Address.fromSerialized(result.getAddress().getNumber()))).toList();
|
||||
List<IdentityKeyMismatch> identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null).map(result -> new IdentityKeyMismatch(Address.fromSerialized(result.getAddress().getNumber()), result.getIdentityFailure().getIdentityKey())).toList();
|
||||
Set<Address> successAddresses = Stream.of(results).filter(result -> result.getSuccess() != null).map(result -> Address.fromSerialized(result.getAddress().getNumber())).collect(Collectors.toSet());
|
||||
List<NetworkFailure> resolvedNetworkFailures = Stream.of(existingNetworkFailures).filter(failure -> successAddresses.contains(failure.getAddress())).toList();
|
||||
List<IdentityKeyMismatch> resolvedIdentityFailures = Stream.of(existingIdentityMismatches).filter(failure -> successAddresses.contains(failure.getAddress())).toList();
|
||||
List<SendMessageResult> successes = Stream.of(results).filter(result -> result.getSuccess() != null).toList();
|
||||
|
||||
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
|
||||
database.markExpireStarted(messageId);
|
||||
ApplicationContext.getInstance(context)
|
||||
.getExpiringMessageManager()
|
||||
.scheduleDeletion(messageId, true, message.getExpiresIn());
|
||||
for (NetworkFailure resolvedFailure : resolvedNetworkFailures) {
|
||||
database.removeFailure(messageId, resolvedFailure);
|
||||
existingNetworkFailures.remove(resolvedFailure);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Sent message: " + messageId);
|
||||
} catch (InvalidNumberException | RecipientFormattingException | UndeliverableMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
database.markAsSentFailed(messageId);
|
||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||
} catch (EncapsulatedExceptions e) {
|
||||
Log.w(TAG, e);
|
||||
List<NetworkFailure> failures = new LinkedList<>();
|
||||
|
||||
for (NetworkFailureException nfe : e.getNetworkExceptions()) {
|
||||
failures.add(new NetworkFailure(Address.fromSerialized(nfe.getE164number())));
|
||||
for (IdentityKeyMismatch resolvedIdentity : resolvedIdentityFailures) {
|
||||
database.removeMismatchedIdentity(messageId, resolvedIdentity.getAddress(), resolvedIdentity.getIdentityKey());
|
||||
existingIdentityMismatches.remove(resolvedIdentity);
|
||||
}
|
||||
|
||||
for (UntrustedIdentityException uie : e.getUntrustedIdentityExceptions()) {
|
||||
database.addMismatchedIdentity(messageId, Address.fromSerialized(uie.getE164Number()), uie.getIdentityKey());
|
||||
if (!networkFailures.isEmpty()) {
|
||||
database.addFailures(messageId, networkFailures);
|
||||
}
|
||||
|
||||
database.addFailures(messageId, failures);
|
||||
for (IdentityKeyMismatch mismatch : identityMismatches) {
|
||||
database.addMismatchedIdentity(messageId, mismatch.getAddress(), mismatch.getIdentityKey());
|
||||
}
|
||||
|
||||
if (e.getNetworkExceptions().isEmpty() && e.getUntrustedIdentityExceptions().isEmpty()) {
|
||||
for (SendMessageResult success : successes) {
|
||||
DatabaseFactory.getGroupReceiptDatabase(context).setUnidentified(Address.fromSerialized(success.getAddress().getNumber()),
|
||||
messageId,
|
||||
success.getSuccess().isUnidentified());
|
||||
}
|
||||
|
||||
if (existingNetworkFailures.isEmpty() && networkFailures.isEmpty() && identityMismatches.isEmpty() && existingIdentityMismatches.isEmpty()) {
|
||||
database.markAsSent(messageId, true);
|
||||
|
||||
markAttachmentsUploaded(messageId, message.getAttachments());
|
||||
|
||||
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
|
||||
@@ -145,16 +159,28 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
.getExpiringMessageManager()
|
||||
.scheduleDeletion(messageId, true, message.getExpiresIn());
|
||||
}
|
||||
} else {
|
||||
} else if (!networkFailures.isEmpty()) {
|
||||
throw new RetryLaterException();
|
||||
} else if (!identityMismatches.isEmpty()) {
|
||||
database.markAsSentFailed(messageId);
|
||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||
}
|
||||
|
||||
} catch (InvalidNumberException | RecipientFormattingException | UndeliverableMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
database.markAsSentFailed(messageId);
|
||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
Log.w(TAG, e);
|
||||
database.markAsSentFailed(messageId);
|
||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetryThrowable(Exception exception) {
|
||||
if (exception instanceof IOException) return true;
|
||||
if (exception instanceof IOException) return true;
|
||||
if (exception instanceof RetryLaterException) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -163,23 +189,24 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSentFailed(messageId);
|
||||
}
|
||||
|
||||
private void deliver(OutgoingMediaMessage message, @Nullable Address filterAddress)
|
||||
private List<SendMessageResult> deliver(OutgoingMediaMessage message, @NonNull List<Address> destinations)
|
||||
throws IOException, RecipientFormattingException, InvalidNumberException,
|
||||
EncapsulatedExceptions, UndeliverableMessageException
|
||||
UndeliverableMessageException, UntrustedIdentityException
|
||||
{
|
||||
String groupId = message.getRecipient().getAddress().toGroupString();
|
||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||
List<Address> recipients = getGroupMessageRecipients(groupId, messageId);
|
||||
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
||||
List<Attachment> scaledAttachments = scaleAndStripExifFromAttachments(mediaConstraints, message.getAttachments());
|
||||
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(scaledAttachments);
|
||||
Optional<Quote> quote = getQuoteFor(message);
|
||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||
List<SignalServiceAddress> addresses = Stream.of(destinations).map(this::getPushAddress).toList();
|
||||
|
||||
List<SignalServiceAddress> addresses;
|
||||
|
||||
if (filterAddress != null) addresses = getPushAddresses(filterAddress);
|
||||
else addresses = getPushAddresses(recipients);
|
||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(addresses)
|
||||
.map(address -> Address.fromSerialized(address.getNumber()))
|
||||
.map(address -> Recipient.from(context, address, false))
|
||||
.map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient))
|
||||
.toList();
|
||||
|
||||
if (message.isGroup()) {
|
||||
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
||||
@@ -193,7 +220,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
.asGroupMessage(group)
|
||||
.build();
|
||||
|
||||
messageSender.sendMessage(addresses, groupDataMessage);
|
||||
return messageSender.sendMessage(addresses, unidentifiedAccess, groupDataMessage);
|
||||
} else {
|
||||
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedId(groupId));
|
||||
SignalServiceDataMessage groupMessage = SignalServiceDataMessage.newBuilder()
|
||||
@@ -208,20 +235,10 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
.withSharedContacts(sharedContacts)
|
||||
.build();
|
||||
|
||||
messageSender.sendMessage(addresses, groupMessage);
|
||||
return messageSender.sendMessage(addresses, unidentifiedAccess, groupMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private List<SignalServiceAddress> getPushAddresses(Address address) {
|
||||
List<SignalServiceAddress> addresses = new LinkedList<>();
|
||||
addresses.add(getPushAddress(address));
|
||||
return addresses;
|
||||
}
|
||||
|
||||
private List<SignalServiceAddress> getPushAddresses(List<Address> addresses) {
|
||||
return Stream.of(addresses).map(this::getPushAddress).toList();
|
||||
}
|
||||
|
||||
private @NonNull List<Address> getGroupMessageRecipients(String groupId, long messageId) {
|
||||
List<GroupReceiptInfo> destinations = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageId);
|
||||
if (!destinations.isEmpty()) return Stream.of(destinations).map(GroupReceiptInfo::getAddress).toList();
|
||||
|
||||
@@ -4,15 +4,15 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
@@ -122,7 +122,9 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType {
|
||||
.withExpiration(groupRecipient.getExpireMessages())
|
||||
.build();
|
||||
|
||||
messageSender.sendMessage(new SignalServiceAddress(source), message);
|
||||
messageSender.sendMessage(new SignalServiceAddress(source),
|
||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(source), false)),
|
||||
message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,16 +3,16 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
@@ -80,9 +80,10 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
try {
|
||||
Log.i(TAG, "Sending message: " + messageId);
|
||||
|
||||
deliver(message);
|
||||
boolean unidentified = deliver(message);
|
||||
database.markAsSent(messageId, true);
|
||||
markAttachmentsUploaded(messageId, message.getAttachments());
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
|
||||
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
|
||||
database.markExpireStarted(messageId);
|
||||
@@ -117,7 +118,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||
}
|
||||
|
||||
private void deliver(OutgoingMediaMessage message)
|
||||
private boolean deliver(OutgoingMediaMessage message)
|
||||
throws RetryLaterException, InsecureFallbackApprovalException, UntrustedIdentityException,
|
||||
UndeliverableMessageException
|
||||
{
|
||||
@@ -144,7 +145,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
.asExpirationUpdate(message.isExpirationUpdate())
|
||||
.build();
|
||||
|
||||
messageSender.sendMessage(address, mediaMessage);
|
||||
return messageSender.sendMessage(address, UnidentifiedAccessUtil.getAccessFor(context, message.getRecipient()), mediaMessage).getSuccess().isUnidentified();
|
||||
} catch (UnregisteredUserException e) {
|
||||
Log.w(TAG, e);
|
||||
throw new InsecureFallbackApprovalException(e);
|
||||
|
||||
@@ -4,15 +4,12 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
@@ -25,17 +26,19 @@ public abstract class PushReceivedJob extends ContextJob {
|
||||
|
||||
public void processEnvelope(@NonNull SignalServiceEnvelope envelope) {
|
||||
synchronized (RECEIVE_LOCK) {
|
||||
Address source = Address.fromExternal(context, envelope.getSource());
|
||||
Recipient recipient = Recipient.from(context, source, false);
|
||||
if (envelope.hasSource()) {
|
||||
Address source = Address.fromExternal(context, envelope.getSource());
|
||||
Recipient recipient = Recipient.from(context, source, false);
|
||||
|
||||
if (!isActiveNumber(recipient)) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setRegistered(recipient, RecipientDatabase.RegisteredState.REGISTERED);
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, recipient, false));
|
||||
if (!isActiveNumber(recipient)) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setRegistered(recipient, RecipientDatabase.RegisteredState.REGISTERED);
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, recipient, false));
|
||||
}
|
||||
}
|
||||
|
||||
if (envelope.isReceipt()) {
|
||||
handleReceipt(envelope);
|
||||
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()) {
|
||||
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage() || envelope.isUnidentifiedSender()) {
|
||||
handleMessage(envelope);
|
||||
} else {
|
||||
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
|
||||
@@ -47,6 +50,7 @@ public abstract class PushReceivedJob extends ContextJob {
|
||||
new PushDecryptJob(context).processMessage(envelope);
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void handleReceipt(SignalServiceEnvelope envelope) {
|
||||
Log.i(TAG, String.format("Received receipt: (XXXXX, %d)", envelope.getTimestamp()));
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()),
|
||||
|
||||
@@ -92,7 +92,6 @@ public abstract class PushSendJob extends SendJob {
|
||||
}
|
||||
|
||||
protected SignalServiceAddress getPushAddress(Address address) {
|
||||
// String relay = TextSecureDirectory.getInstance(context).getRelay(address.toPhoneString());
|
||||
String relay = null;
|
||||
return new SignalServiceAddress(address.toPhoneString(), Optional.fromNullable(relay));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
@@ -20,7 +21,9 @@ import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
@@ -76,8 +79,9 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
try {
|
||||
Log.i(TAG, "Sending message: " + messageId);
|
||||
|
||||
deliver(record);
|
||||
boolean unidentified = deliver(record);
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
|
||||
if (record.getExpiresIn() > 0) {
|
||||
database.markExpireStarted(messageId);
|
||||
@@ -118,22 +122,25 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private void deliver(SmsMessageRecord message)
|
||||
private boolean deliver(SmsMessageRecord message)
|
||||
throws UntrustedIdentityException, InsecureFallbackApprovalException, RetryLaterException
|
||||
{
|
||||
try {
|
||||
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getAddress());
|
||||
Optional<byte[]> profileKey = getProfileKey(message.getIndividualRecipient());
|
||||
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
||||
.withTimestamp(message.getDateSent())
|
||||
.withBody(message.getBody())
|
||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||
.withProfileKey(profileKey.orNull())
|
||||
.asEndSessionMessage(message.isEndSession())
|
||||
.build();
|
||||
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getAddress());
|
||||
Optional<byte[]> profileKey = getProfileKey(message.getIndividualRecipient());
|
||||
Optional<UnidentifiedAccessPair> unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, message.getIndividualRecipient());
|
||||
|
||||
Log.w(TAG, "Have access key to use: " + unidentifiedAccess.isPresent());
|
||||
|
||||
messageSender.sendMessage(address, textSecureMessage);
|
||||
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
||||
.withTimestamp(message.getDateSent())
|
||||
.withBody(message.getBody())
|
||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||
.withProfileKey(profileKey.orNull())
|
||||
.asEndSessionMessage(message.isEndSession())
|
||||
.build();
|
||||
|
||||
return messageSender.sendMessage(address, unidentifiedAccess, textSecureMessage).getSuccess().isUnidentified();
|
||||
} catch (UnregisteredUserException e) {
|
||||
Log.w(TAG, e);
|
||||
throw new InsecureFallbackApprovalException(e);
|
||||
|
||||
@@ -8,6 +8,12 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NetworkFailureException;
|
||||
@@ -48,12 +54,15 @@ public class RefreshAttributesJob extends ContextJob implements InjectableType {
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException {
|
||||
String signalingKey = TextSecurePreferences.getSignalingKey(context);
|
||||
int registrationId = TextSecurePreferences.getLocalRegistrationId(context);
|
||||
boolean fetchesMessages = TextSecurePreferences.isGcmDisabled(context);
|
||||
String pin = TextSecurePreferences.getRegistrationLockPin(context);
|
||||
String signalingKey = TextSecurePreferences.getSignalingKey(context);
|
||||
int registrationId = TextSecurePreferences.getLocalRegistrationId(context);
|
||||
boolean fetchesMessages = TextSecurePreferences.isGcmDisabled(context);
|
||||
String pin = TextSecurePreferences.getRegistrationLockPin(context);
|
||||
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(context);
|
||||
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
|
||||
|
||||
signalAccountManager.setAccountAttributes(signalingKey, registrationId, fetchesMessages, pin);
|
||||
signalAccountManager.setAccountAttributes(signalingKey, registrationId, fetchesMessages, pin,
|
||||
unidentifiedAccessKey, universalUnidentifiedAccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,10 +3,14 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
@@ -23,6 +27,7 @@ import androidx.work.Data;
|
||||
|
||||
public class RequestGroupInfoJob extends ContextJob implements InjectableType {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = RequestGroupInfoJob.class.getSimpleName();
|
||||
|
||||
private static final long serialVersionUID = 0L;
|
||||
@@ -77,7 +82,9 @@ public class RequestGroupInfoJob extends ContextJob implements InjectableType {
|
||||
.withTimestamp(System.currentTimeMillis())
|
||||
.build();
|
||||
|
||||
messageSender.sendMessage(new SignalServiceAddress(source), message);
|
||||
messageSender.sendMessage(new SignalServiceAddress(source),
|
||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromExternal(context, source), false)),
|
||||
message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,14 +5,16 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
@@ -20,11 +22,15 @@ import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessagePipe;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -88,12 +94,26 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
private void handleIndividualRecipient(Recipient recipient)
|
||||
throws IOException, InvalidKeyException, InvalidNumberException
|
||||
{
|
||||
String number = recipient.getAddress().toPhoneString();
|
||||
SignalServiceProfile profile = retrieveProfile(number);
|
||||
String number = recipient.getAddress().toPhoneString();
|
||||
Optional<UnidentifiedAccess> unidentifiedAccess = getUnidentifiedAccess(recipient);
|
||||
|
||||
SignalServiceProfile profile;
|
||||
|
||||
try {
|
||||
profile = retrieveProfile(number, unidentifiedAccess);
|
||||
} catch (AuthorizationFailedException e) {
|
||||
if (unidentifiedAccess.isPresent()) {
|
||||
// XXX Update UI
|
||||
profile = retrieveProfile(number, Optional.absent());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
setIdentityKey(recipient, profile.getIdentityKey());
|
||||
setProfileName(recipient, profile.getName());
|
||||
setProfileAvatar(recipient, profile.getAvatar());
|
||||
setUnidentifiedAccessMode(recipient, profile.getUnidentifiedAccess(), profile.isUnrestrictedUnidentifiedAccess());
|
||||
}
|
||||
|
||||
private void handleGroupRecipient(Recipient group)
|
||||
@@ -106,18 +126,20 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private SignalServiceProfile retrieveProfile(@NonNull String number) throws IOException {
|
||||
private SignalServiceProfile retrieveProfile(@NonNull String number, Optional<UnidentifiedAccess> unidentifiedAccess)
|
||||
throws IOException
|
||||
{
|
||||
SignalServiceMessagePipe pipe = IncomingMessageObserver.getPipe();
|
||||
|
||||
if (pipe != null) {
|
||||
try {
|
||||
return pipe.getProfile(new SignalServiceAddress(number));
|
||||
return pipe.getProfile(new SignalServiceAddress(number), unidentifiedAccess);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
return receiver.retrieveProfile(new SignalServiceAddress(number));
|
||||
return receiver.retrieveProfile(new SignalServiceAddress(number), unidentifiedAccess);
|
||||
}
|
||||
|
||||
private void setIdentityKey(Recipient recipient, String identityKeyValue) {
|
||||
@@ -143,6 +165,30 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private void setUnidentifiedAccessMode(Recipient recipient, String unidentifiedAccessVerifier, boolean unrestrictedUnidentifiedAccess) {
|
||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||
byte[] profileKey = recipient.getProfileKey();
|
||||
|
||||
// XXX Update UI
|
||||
if (unrestrictedUnidentifiedAccess) {
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED);
|
||||
} else if (profileKey == null || unidentifiedAccessVerifier == null) {
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED);
|
||||
} else {
|
||||
ProfileCipher profileCipher = new ProfileCipher(profileKey);
|
||||
boolean verifiedUnidentifiedAccess;
|
||||
|
||||
try {
|
||||
verifiedUnidentifiedAccess = profileCipher.verifyUnidentifiedAccess(Base64.decode(unidentifiedAccessVerifier));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
verifiedUnidentifiedAccess = false;
|
||||
}
|
||||
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, verifiedUnidentifiedAccess ? UnidentifiedAccessMode.ENABLED : UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
private void setProfileName(Recipient recipient, String profileName) {
|
||||
try {
|
||||
byte[] profileKey = recipient.getProfileKey();
|
||||
@@ -172,4 +218,14 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
.add(new RetrieveProfileAvatarJob(context, recipient, profileAvatar));
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<UnidentifiedAccess> getUnidentifiedAccess(@NonNull Recipient recipient) {
|
||||
Optional<UnidentifiedAccessPair> unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient);
|
||||
|
||||
if (unidentifiedAccess.isPresent()) {
|
||||
return unidentifiedAccess.get().getTargetUnidentifiedAccess();
|
||||
}
|
||||
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class RotateCertificateJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = RotateCertificateJob.class.getName();
|
||||
|
||||
@Inject transient SignalServiceAccountManager accountManager;
|
||||
|
||||
public RotateCertificateJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public RotateCertificateJob(Context context) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withGroupId("__ROTATE_SENDER_CERTIFICATE__")
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded() {}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException {
|
||||
byte[] certificate = accountManager.getSenderCertificate();
|
||||
TextSecurePreferences.setUnidentifiedAccessCertificate(context, certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetry(Exception e) {
|
||||
return e instanceof PushNetworkException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
Log.w(TAG, "Failed to rotate sender certificate!");
|
||||
}
|
||||
}
|
||||
100
src/org/thoughtcrime/securesms/jobs/SendDeliveryReceiptJob.java
Normal file
100
src/org/thoughtcrime/securesms/jobs/SendDeliveryReceiptJob.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
public class SendDeliveryReceiptJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String KEY_ADDRESS = "address";
|
||||
private static final String KEY_MESSAGE_ID = "message_id";
|
||||
private static final String KEY_TIMESTAMP = "timestamp";
|
||||
|
||||
private static final String TAG = SendReadReceiptJob.class.getSimpleName();
|
||||
|
||||
@Inject
|
||||
transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private String address;
|
||||
private long messageId;
|
||||
private long timestamp;
|
||||
|
||||
public SendDeliveryReceiptJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public SendDeliveryReceiptJob(Context context, Address address, long messageId) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
|
||||
this.address = address.serialize();
|
||||
this.messageId = messageId;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded() {}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.putString(KEY_ADDRESS, address)
|
||||
.putLong(KEY_MESSAGE_ID, messageId)
|
||||
.putLong(KEY_TIMESTAMP, timestamp)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) {
|
||||
this.address = data.getString(KEY_ADDRESS);
|
||||
this.messageId = data.getLong(KEY_MESSAGE_ID);
|
||||
this.timestamp = data.getLong(KEY_TIMESTAMP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
SignalServiceAddress remoteAddress = new SignalServiceAddress(address);
|
||||
SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.DELIVERY,
|
||||
Collections.singletonList(messageId),
|
||||
timestamp);
|
||||
|
||||
messageSender.sendReceipt(remoteAddress,
|
||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(address), false)),
|
||||
receiptMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetry(Exception e) {
|
||||
if (e instanceof PushNetworkException) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
Log.w(TAG, "Failed to send delivery receipt to: " + address);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,11 +4,13 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
@@ -86,7 +88,9 @@ public class SendReadReceiptJob extends ContextJob implements InjectableType {
|
||||
SignalServiceAddress remoteAddress = new SignalServiceAddress(address);
|
||||
SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ, messageIds, timestamp);
|
||||
|
||||
messageSender.sendReceipt(remoteAddress, receiptMessage);
|
||||
messageSender.sendReceipt(remoteAddress,
|
||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(address), false)),
|
||||
receiptMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user