mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-24 11:29:06 +00:00
Support for sealed sender - Part 2
This commit is contained in:
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
@@ -13,6 +14,8 @@ import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage;
|
||||
@@ -61,6 +64,11 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
||||
public void onRun(MasterSecret masterSecret)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||
|
||||
try (RecipientReader reader = database.readerForBlocked(database.getBlocked())) {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
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;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ConfigurationMessage;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
public class MultiDeviceConfigurationUpdateJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = MultiDeviceConfigurationUpdateJob.class.getSimpleName();
|
||||
|
||||
private static final String KEY_READ_RECEIPTS_ENABLED = "read_receipts_enabled";
|
||||
private static final String KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED = "unidentified_delivery_indicators_enabled";
|
||||
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private boolean readReceiptsEnabled;
|
||||
private boolean unidentifiedDeliveryIndicatorsEnabled;
|
||||
|
||||
public MultiDeviceConfigurationUpdateJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public MultiDeviceConfigurationUpdateJob(Context context, boolean readReceiptsEnabled, boolean unidentifiedDeliveryIndicatorsEnabled) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withGroupId("__MULTI_DEVICE_CONFIGURATION_UPDATE_JOB__")
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
|
||||
this.readReceiptsEnabled = readReceiptsEnabled;
|
||||
this.unidentifiedDeliveryIndicatorsEnabled = unidentifiedDeliveryIndicatorsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) {
|
||||
readReceiptsEnabled = data.getBoolean(KEY_READ_RECEIPTS_ENABLED);
|
||||
unidentifiedDeliveryIndicatorsEnabled = data.getBoolean(KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.putBoolean(KEY_READ_RECEIPTS_ENABLED, readReceiptsEnabled)
|
||||
.putBoolean(KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED, unidentifiedDeliveryIndicatorsEnabled)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(readReceiptsEnabled), Optional.of(unidentifiedDeliveryIndicatorsEnabled))),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetry(Exception e) {
|
||||
return e instanceof PushNetworkException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
Log.w(TAG, "**** Failed to synchronize read receipts state!");
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
||||
throws IOException, UntrustedIdentityException, NetworkException
|
||||
{
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.w(TAG, "Not multi device, aborting...");
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
@@ -67,6 +68,11 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject
|
||||
|
||||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws Exception {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||
GroupDatabase.Reader reader = null;
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I
|
||||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException {
|
||||
if (!TextSecurePreferences.isMultiDevice(getContext())) {
|
||||
Log.w(TAG, "Not multi device...");
|
||||
Log.i(TAG, "Not multi device...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ 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.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
@@ -22,6 +23,10 @@ import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
/**
|
||||
* Use {@link MultiDeviceConfigurationUpdateJob}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class MultiDeviceReadReceiptUpdateJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -59,7 +64,12 @@ public class MultiDeviceReadReceiptUpdateJob extends ContextJob implements Injec
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled))),
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled), Optional.absent())),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
|
||||
@@ -91,7 +92,7 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
||||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.w(TAG, "Not multi device...");
|
||||
Log.i(TAG, "Not multi device...");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,8 +102,7 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
||||
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages), UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,7 +91,7 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
try {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.w(TAG, "Not multi device...");
|
||||
Log.i(TAG, "Not multi device...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ 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.signal.libsignal.metadata.SelfSendException;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -36,6 +37,7 @@ import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
@@ -242,6 +244,8 @@ public class PushDecryptJob extends ContextJob {
|
||||
handleNeedsDeliveryReceipt(content, message);
|
||||
}
|
||||
} else if (content.getSyncMessage().isPresent()) {
|
||||
TextSecurePreferences.setMultiDevice(context, true);
|
||||
|
||||
SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
|
||||
|
||||
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get());
|
||||
@@ -273,7 +277,11 @@ public class PushDecryptJob extends ContextJob {
|
||||
} catch (ProtocolInvalidVersionException e) {
|
||||
Log.w(TAG, e);
|
||||
handleInvalidVersionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolInvalidMessageException | ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
|
||||
} catch (ProtocolInvalidMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
}
|
||||
catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
|
||||
Log.w(TAG, e);
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (StorageFailedException e) {
|
||||
@@ -290,6 +298,8 @@ public class PushDecryptJob extends ContextJob {
|
||||
handleDuplicateMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (InvalidMetadataVersionException | InvalidMetadataMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (SelfSendException e) {
|
||||
Log.i(TAG, "Dropping UD message from self.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +552,10 @@ public class PushDecryptJob extends ContextJob {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceContactUpdateJob(getContext(), true));
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RefreshUnidentifiedDeliveryAbilityJob(context));
|
||||
}
|
||||
|
||||
if (message.isGroupsRequest()) {
|
||||
@@ -559,7 +573,9 @@ public class PushDecryptJob extends ContextJob {
|
||||
if (message.isConfigurationRequest()) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceReadReceiptUpdateJob(getContext(), TextSecurePreferences.isReadReceiptsEnabled(getContext())));
|
||||
.add(new MultiDeviceConfigurationUpdateJob(getContext(),
|
||||
TextSecurePreferences.isReadReceiptsEnabled(getContext()),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,7 +686,17 @@ public class PushDecryptJob extends ContextJob {
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
long messageId = database.insertMessageOutbox(mediaMessage, threadId, false, null);
|
||||
|
||||
if (recipients.getAddress().isGroup()) {
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipients.getAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient member : members) {
|
||||
receiptDatabase.setUnidentified(member.getAddress(), messageId, message.isUnidentified(member.getAddress().serialize()));
|
||||
}
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipients.getAddress().serialize()));
|
||||
|
||||
for (DatabaseAttachment attachment : DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(messageId)) {
|
||||
ApplicationContext.getInstance(context)
|
||||
@@ -753,11 +779,19 @@ public class PushDecryptJob extends ContextJob {
|
||||
|
||||
messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, null);
|
||||
database = DatabaseFactory.getMmsDatabase(context);
|
||||
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient member : members) {
|
||||
receiptDatabase.setUnidentified(member.getAddress(), messageId, message.isUnidentified(member.getAddress().serialize()));
|
||||
}
|
||||
} else {
|
||||
OutgoingTextMessage outgoingTextMessage = new OutgoingEncryptedMessage(recipient, body, expiresInMillis);
|
||||
|
||||
messageId = DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoingTextMessage, false, message.getTimestamp(), null);
|
||||
database = DatabaseFactory.getSmsDatabase(context);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipient.getAddress().serialize()));
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -99,6 +100,11 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdded() {
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSending(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPushSend()
|
||||
throws IOException, MmsException, NoSuchMessageException, RetryLaterException
|
||||
@@ -110,6 +116,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Sending message: " + messageId);
|
||||
|
||||
List<Address> target;
|
||||
|
||||
if (filterAddress != null) target = Collections.singletonList(Address.fromSerialized(filterAddress));
|
||||
|
||||
@@ -10,16 +10,19 @@ 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.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||
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;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
@@ -68,6 +71,11 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
return dataBuilder.putLong(KEY_MESSAGE_ID, messageId).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdded() {
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSending(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPushSend()
|
||||
throws RetryLaterException, MmsException, NoSuchMessageException,
|
||||
@@ -85,6 +93,19 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
markAttachmentsUploaded(messageId, message.getAttachments());
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
|
||||
if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) {
|
||||
Recipient recipient = message.getRecipient().resolve();
|
||||
UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode();
|
||||
|
||||
if (unidentified && (accessMode == UnidentifiedAccessMode.UNKNOWN || accessMode == UnidentifiedAccessMode.DISABLED)) {
|
||||
Log.i(TAG, "Marking recipient as UD-enabled following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED);
|
||||
} else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) {
|
||||
Log.i(TAG, "Marking recipient as UD-disabled following a non-UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
|
||||
database.markExpireStarted(messageId);
|
||||
expirationManager.scheduleDeletion(messageId, true, message.getExpiresIn());
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
@@ -19,11 +20,11 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
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;
|
||||
@@ -68,6 +69,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
@Override
|
||||
public void onAdded() {
|
||||
Log.i(TAG, "onAdded() messageId: " + messageId);
|
||||
DatabaseFactory.getSmsDatabase(context).markAsSending(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,6 +85,19 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
|
||||
if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) {
|
||||
Recipient recipient = record.getRecipient().resolve();
|
||||
UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode();
|
||||
|
||||
if (unidentified && (accessMode == UnidentifiedAccessMode.UNKNOWN || accessMode == UnidentifiedAccessMode.DISABLED)) {
|
||||
Log.i(TAG, "Marking recipient as UD-enabled following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED);
|
||||
} else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) {
|
||||
Log.i(TAG, "Marking recipient as UD-disabled following a non-UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (record.getExpiresIn() > 0) {
|
||||
database.markExpireStarted(messageId);
|
||||
expirationManager.scheduleDeletion(record.getId(), record.isMms(), record.getExpiresIn());
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
@@ -10,10 +11,6 @@ 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;
|
||||
@@ -63,6 +60,10 @@ public class RefreshAttributesJob extends ContextJob implements InjectableType {
|
||||
|
||||
signalAccountManager.setAccountAttributes(signalingKey, registrationId, fetchesMessages, pin,
|
||||
unidentifiedAccessKey, universalUnidentifiedAccess);
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RefreshUnidentifiedDeliveryAbilityJob(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
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.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
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.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
public class RefreshUnidentifiedDeliveryAbilityJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final String TAG = RefreshUnidentifiedDeliveryAbilityJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalServiceMessageReceiver receiver;
|
||||
|
||||
public RefreshUnidentifiedDeliveryAbilityJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public RefreshUnidentifiedDeliveryAbilityJob(Context context) {
|
||||
super(context, new JobParameters.Builder()
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) { }
|
||||
|
||||
@Override
|
||||
protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun() throws Exception {
|
||||
byte[] profileKey = ProfileKeyUtil.getProfileKey(context);
|
||||
SignalServiceProfile profile = retrieveProfile(TextSecurePreferences.getLocalNumber(context));
|
||||
|
||||
boolean enabled = profile.getUnidentifiedAccess() != null && isValidVerifier(profileKey, profile.getUnidentifiedAccess());
|
||||
|
||||
TextSecurePreferences.setIsUnidentifiedDeliveryEnabled(context, enabled);
|
||||
Log.i(TAG, "Set UD status to: " + enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCanceled() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onShouldRetry(Exception exception) {
|
||||
return exception instanceof PushNetworkException;
|
||||
}
|
||||
|
||||
private SignalServiceProfile retrieveProfile(@NonNull String number) throws IOException {
|
||||
SignalServiceMessagePipe pipe = IncomingMessageObserver.getPipe();
|
||||
|
||||
if (pipe != null) {
|
||||
try {
|
||||
return pipe.getProfile(new SignalServiceAddress(number), Optional.absent());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
return receiver.retrieveProfile(new SignalServiceAddress(number), Optional.absent());
|
||||
}
|
||||
|
||||
private boolean isValidVerifier(@NonNull byte[] profileKey, @NonNull String verifier) {
|
||||
ProfileCipher profileCipher = new ProfileCipher(profileKey);
|
||||
try {
|
||||
return profileCipher.verifyUnidentifiedAccess(Base64.decode(verifier));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ 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.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -101,9 +101,8 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
|
||||
try {
|
||||
profile = retrieveProfile(number, unidentifiedAccess);
|
||||
} catch (AuthorizationFailedException e) {
|
||||
} catch (NonSuccessfulResponseCodeException e) {
|
||||
if (unidentifiedAccess.isPresent()) {
|
||||
// XXX Update UI
|
||||
profile = retrieveProfile(number, Optional.absent());
|
||||
} else {
|
||||
throw e;
|
||||
@@ -129,7 +128,10 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
private SignalServiceProfile retrieveProfile(@NonNull String number, Optional<UnidentifiedAccess> unidentifiedAccess)
|
||||
throws IOException
|
||||
{
|
||||
SignalServiceMessagePipe pipe = IncomingMessageObserver.getPipe();
|
||||
SignalServiceMessagePipe authPipe = IncomingMessageObserver.getPipe();
|
||||
SignalServiceMessagePipe unidentifiedPipe = IncomingMessageObserver.getUnidentifiedPipe();
|
||||
SignalServiceMessagePipe pipe = unidentifiedPipe != null && unidentifiedAccess.isPresent() ? unidentifiedPipe
|
||||
: authPipe;
|
||||
|
||||
if (pipe != null) {
|
||||
try {
|
||||
@@ -169,10 +171,11 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||
byte[] profileKey = recipient.getProfileKey();
|
||||
|
||||
// XXX Update UI
|
||||
if (unrestrictedUnidentifiedAccess) {
|
||||
Log.i(TAG, "Marking recipient UD status as unrestricted.");
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED);
|
||||
} else if (profileKey == null || unidentifiedAccessVerifier == null) {
|
||||
Log.i(TAG, "Marking recipient UD status as disabled.");
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED);
|
||||
} else {
|
||||
ProfileCipher profileCipher = new ProfileCipher(profileKey);
|
||||
@@ -185,7 +188,9 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
||||
verifiedUnidentifiedAccess = false;
|
||||
}
|
||||
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, verifiedUnidentifiedAccess ? UnidentifiedAccessMode.ENABLED : UnidentifiedAccessMode.DISABLED);
|
||||
UnidentifiedAccessMode mode = verifiedUnidentifiedAccess ? UnidentifiedAccessMode.ENABLED : UnidentifiedAccessMode.DISABLED;
|
||||
Log.i(TAG, "Marking recipient UD status as " + mode.name() + " after verification.");
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
88
src/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java
Normal file
88
src/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
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.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
import org.whispersystems.signalservice.api.util.StreamDetails;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
public class RotateProfileKeyJob extends ContextJob implements InjectableType {
|
||||
|
||||
@Inject SignalServiceAccountManager accountManager;
|
||||
|
||||
public RotateProfileKeyJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public RotateProfileKeyJob(Context context) {
|
||||
super(context, new JobParameters.Builder()
|
||||
.withGroupId("__ROTATE_PROFILE_KEY__")
|
||||
.withDuplicatesIgnored(true)
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun() throws Exception {
|
||||
byte[] profileKey = ProfileKeyUtil.rotateProfileKey(context);
|
||||
|
||||
accountManager.setProfileName(profileKey, TextSecurePreferences.getProfileName(context));
|
||||
accountManager.setProfileAvatar(profileKey, getProfileAvatar());
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RefreshAttributesJob(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCanceled() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onShouldRetry(Exception exception) {
|
||||
return exception instanceof PushNetworkException;
|
||||
}
|
||||
|
||||
private @Nullable StreamDetails getProfileAvatar() {
|
||||
try {
|
||||
Address localAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(context));
|
||||
File avatarFile = AvatarHelper.getAvatarFile(context, localAddress);
|
||||
|
||||
if (avatarFile.exists()) {
|
||||
return new StreamDetails(new FileInputStream(avatarFile), "image/jpeg", avatarFile.length());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user