Bump libsignal to v0.96.2

Co-authored-by: Cody Henthorne <cody@signal.org>
This commit is contained in:
andrew-signal 2026-06-23 11:45:52 -04:00 committed by jeffrey-signal
parent 7fdaf6f706
commit 9dac02fa1c
No known key found for this signature in database
30 changed files with 200 additions and 141 deletions

View File

@ -4,6 +4,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil;
import org.thoughtcrime.securesms.database.MessageTable;
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
@ -144,6 +145,8 @@ public class AutomaticSessionResetJob extends BaseJob {
messageSender.sendNullMessage(address, SealedSenderAccessUtil.getSealedSenderAccessFor(recipient));
} catch (UntrustedIdentityException e) {
Log.w(TAG, "Unable to send null message.");
} catch (NoSessionException e) {
Log.w(TAG, "Unable to send null message; no session to send over.", e);
}
}

View File

@ -4,8 +4,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.thoughtcrime.securesms.database.GroupTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.RecipientRecord;
@ -169,7 +169,7 @@ public class GroupCallUpdateSendJob extends BaseJob {
}
private @NonNull List<Recipient> deliver(@NonNull GroupId groupId, @NonNull List<Recipient> destinations)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder()
.withTimestamp(System.currentTimeMillis())

View File

@ -5,6 +5,7 @@ import androidx.annotation.WorkerThread
import okio.utf8Size
import org.signal.core.util.UuidUtil.parseOrThrow
import org.signal.core.util.logging.Log
import org.signal.libsignal.protocol.NoSessionException
import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil
import org.thoughtcrime.securesms.database.NoSuchMessageException
import org.thoughtcrime.securesms.database.RecipientTable.SealedSenderAccessMode
@ -163,7 +164,17 @@ class IndividualSendJob private constructor(parameters: Parameters, private val
val profileKey = recipient.profileKey
val accessMode = recipient.sealedSenderAccessMode
val unidentified = deliver(message, originalEditedMessage)
val unidentified = try {
deliver(message, originalEditedMessage)
} catch (e: NoSessionException) {
warn(TAG, message.sentTimeMillis.toString(), "Failed to send message, likely due to a missing or corrupt session. Archiving sessions and retrying.", e)
val recipientId = message.threadRecipient.id
AppDependencies.protocolStore.aci().sessions().archiveSessions(recipientId)
AppDependencies.protocolStore.pni().sessions().archiveSessions(recipientId)
throw RetryLaterException()
}
SignalDatabase.messages.markAsSent(messageId)
markAttachmentsUploaded(messageId, message)

View File

@ -5,6 +5,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
@ -13,12 +15,10 @@ import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
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;
import org.whispersystems.signalservice.api.messages.multidevice.ConfigurationMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import java.io.IOException;
@ -88,7 +88,7 @@ public class MultiDeviceConfigurationUpdateJob extends BaseJob {
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
public void onRun() throws IOException, UntrustedIdentityException, NoSessionException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}

View File

@ -14,6 +14,9 @@ import org.signal.core.ui.permissions.Permissions;
import org.signal.core.util.AppForegroundObserver;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.signal.network.service.CdnService;
import org.signal.network.exceptions.PushNetworkException;
import org.signal.network.service.CdnService;
import org.thoughtcrime.securesms.database.RecipientTable;
@ -118,7 +121,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
@Override
public void onRun()
throws IOException, UntrustedIdentityException, NetworkException
throws IOException, UntrustedIdentityException, NetworkException, NoSessionException
{
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
@ -139,7 +142,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
}
private void generateSingleContactUpdate(@NonNull RecipientId recipientId)
throws IOException, UntrustedIdentityException, NetworkException
throws IOException, UntrustedIdentityException, NetworkException, NoSessionException
{
WriteDetails writeDetails = createTempFile();
@ -190,7 +193,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
}
private void generateFullContactUpdate()
throws IOException, UntrustedIdentityException, NetworkException
throws IOException, UntrustedIdentityException, NetworkException, NoSessionException
{
boolean isAppVisible = AppForegroundObserver.isForegrounded();
long timeSinceLastSync = System.currentTimeMillis() - TextSecurePreferences.getLastFullContactSyncTime(context);
@ -277,7 +280,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
}
private void sendUpdate(SignalServiceMessageSender messageSender, InputStream stream, long length, boolean complete)
throws UntrustedIdentityException, NetworkException
throws UntrustedIdentityException, NetworkException, NoSessionException
{
if (length > 0) {
try {

View File

@ -5,6 +5,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.RecipientRecord;
@ -17,12 +19,10 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.multidevice.MessageRequestResponseMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import java.io.IOException;
@ -97,7 +97,7 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob {
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
public void onRun() throws IOException, UntrustedIdentityException, NoSessionException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}

View File

@ -5,9 +5,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.signal.network.service.CdnService;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
@ -18,15 +18,14 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
import org.whispersystems.signalservice.api.messages.multidevice.ContactsMessage;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceContact;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream;
import org.whispersystems.signalservice.internal.push.http.ResumableUploadSpec;
import java.io.ByteArrayInputStream;
@ -66,7 +65,7 @@ public class MultiDeviceProfileKeyUpdateJob extends BaseJob {
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
public void onRun() throws IOException, UntrustedIdentityException, NoSessionException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}

View File

@ -3,12 +3,14 @@ package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.signal.core.models.ServiceId;
import org.signal.core.util.JsonUtils;
import org.signal.core.util.ListUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId;
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
import org.thoughtcrime.securesms.database.SignalDatabase;
@ -23,13 +25,10 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.signal.core.util.JsonUtils;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.signal.core.models.ServiceId;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import java.io.IOException;
@ -37,6 +36,8 @@ import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class MultiDeviceReadUpdateJob extends BaseJob {
@ -106,7 +107,7 @@ public class MultiDeviceReadUpdateJob extends BaseJob {
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
public void onRun() throws IOException, UntrustedIdentityException, NoSessionException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}

View File

@ -8,6 +8,8 @@ import org.signal.core.util.Base64;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.thoughtcrime.securesms.database.IdentityTable.VerifiedStatus;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobmanager.Job;
@ -19,13 +21,11 @@ import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import java.io.IOException;
@ -90,7 +90,7 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob {
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
public void onRun() throws IOException, UntrustedIdentityException, NoSessionException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}

View File

@ -5,7 +5,10 @@ import androidx.annotation.Nullable;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.signal.core.util.JsonUtils;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId;
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
import org.thoughtcrime.securesms.database.SignalDatabase;
@ -19,13 +22,10 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.signal.core.util.JsonUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMessage;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import java.io.IOException;
@ -76,7 +76,7 @@ public class MultiDeviceViewOnceOpenJob extends BaseJob {
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
public void onRun() throws IOException, UntrustedIdentityException, NoSessionException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}

View File

@ -3,12 +3,13 @@ package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.signal.core.util.JsonUtils;
import org.signal.core.util.ListUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.network.exceptions.PushNetworkException;
import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId;
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
import org.thoughtcrime.securesms.database.SignalDatabase;
@ -23,13 +24,10 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.signal.core.util.JsonUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import java.io.IOException;
@ -37,6 +35,8 @@ import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class MultiDeviceViewedUpdateJob extends BaseJob {
@ -106,7 +106,7 @@ public class MultiDeviceViewedUpdateJob extends BaseJob {
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
public void onRun() throws IOException, UntrustedIdentityException, NoSessionException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}

View File

@ -5,6 +5,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.thoughtcrime.securesms.database.GroupTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.RecipientRecord;
@ -188,7 +189,7 @@ public class ProfileKeySendJob extends BaseJob {
}
private List<Recipient> deliver(@NonNull List<Recipient> destinations) throws IOException, UntrustedIdentityException {
private List<Recipient> deliver(@NonNull List<Recipient> destinations) throws IOException, UntrustedIdentityException, NoSessionException {
SignalServiceDataMessage.Builder dataMessage = SignalServiceDataMessage.newBuilder()
.asProfileKeyUpdate(true)
.withTimestamp(System.currentTimeMillis())

View File

@ -6,8 +6,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.core.util.Util;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.database.GroupReceiptTable;
@ -33,7 +34,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.stories.Stories;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.signal.core.util.Util;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.SendMessageResult;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
@ -189,7 +189,7 @@ public final class PushDistributionListSendJob extends PushSendJob {
PushGroupSendJob.processGroupMessageResults(context, messageId, -1, null, message, results, targets, skipped, existingNetworkFailures, existingIdentityMismatches);
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
} catch (UntrustedIdentityException | UndeliverableMessageException | NoSessionException e) {
warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
database.markAsSentFailed(messageId);
notifyMediaMessageDeliveryFailed(context, messageId);
@ -202,7 +202,7 @@ public final class PushDistributionListSendJob extends PushSendJob {
}
private List<SendMessageResult> deliver(@NonNull OutgoingMessage message, @NonNull List<Recipient> destinations)
throws IOException, UntrustedIdentityException, UndeliverableMessageException
throws IOException, UntrustedIdentityException, UndeliverableMessageException, NoSessionException
{
try {
List<Attachment> attachments = message.getAttachments().stream().filter(attachment -> !attachment.isSticker()).collect(Collectors.toList());

View File

@ -6,10 +6,11 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import java.util.stream.Collectors;
import org.signal.core.util.ByteUnit;
import org.signal.core.util.SetUtil;
import org.signal.core.util.Util;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.database.GroupReceiptTable;
import org.thoughtcrime.securesms.database.GroupReceiptTable.GroupReceiptInfo;
@ -44,12 +45,10 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.signal.core.util.ByteUnit;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.MessageUtil;
import org.thoughtcrime.securesms.util.RecipientAccessList;
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
import org.signal.core.util.Util;
import org.whispersystems.signalservice.api.crypto.ContentHint;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.SendMessageResult;
@ -74,9 +73,9 @@ import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import kotlin.Pair;
import okio.ByteString;
import okio.Utf8;
@ -250,7 +249,7 @@ public final class PushGroupSendJob extends PushSendJob {
ConversationShortcutRankingUpdateJob.enqueueForOutgoingIfNecessary(groupRecipient);
Log.i(TAG, JobLogger.format(this, "Finished send."));
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
} catch (UntrustedIdentityException | UndeliverableMessageException | NoSessionException e) {
warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
database.markAsSentFailed(messageId);
notifyMediaMessageDeliveryFailed(context, messageId);
@ -271,7 +270,7 @@ public final class PushGroupSendJob extends PushSendJob {
}
private List<SendMessageResult> deliver(OutgoingMessage message, @Nullable MessageRecord originalEditedMessage, @NonNull Recipient groupRecipient, @NonNull List<Recipient> destinations)
throws IOException, UntrustedIdentityException, UndeliverableMessageException
throws IOException, UntrustedIdentityException, UndeliverableMessageException, NoSessionException
{
if (Utf8.size(message.getBody()) > MessageUtil.MAX_INLINE_BODY_SIZE_BYTES) {
throw new UndeliverableMessageException("The total body size was greater than our limit of " + MessageUtil.MAX_INLINE_BODY_SIZE_BYTES + " bytes.");

View File

@ -10,6 +10,7 @@ import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.util.Base64;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.thoughtcrime.securesms.database.RecipientTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
@ -178,7 +179,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
}
private @NonNull List<Recipient> deliver(@NonNull List<Recipient> destinations, @NonNull GroupId.V2 groupId)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
SignalServiceGroupV2 group = SignalServiceGroupV2.fromProtobuf(groupContextV2);
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()

View File

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.thoughtcrime.securesms.database.GroupTable;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.ReactionTable;
@ -229,7 +230,7 @@ public class ReactionSendJob extends BaseJob {
}
private @NonNull List<Recipient> deliver(@NonNull RecipientRecord conversationRecipient, @NonNull List<Recipient> destinations, @NonNull Recipient targetAuthor, long targetSentTimestamp)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder()
.withTimestamp(System.currentTimeMillis())

View File

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.jobs
import org.signal.core.util.logging.Log
import org.signal.libsignal.protocol.NoSessionException
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.recipients.RecipientId
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException
@ -23,15 +24,15 @@ object ReceiptSender {
fun sendWithSessionRepair(recipientId: RecipientId, operation: ReceiptSendOperation): SendMessageResult? {
return try {
operation.send()
} catch (e: IllegalStateException) {
Log.w(TAG, "Failed to send receipt, likely due to a missing or corrupt session. Archiving sessions and retrying.", e)
} catch (e: NoSessionException) {
Log.w(TAG, "Failed to send receipt due to a missing session. Archiving sessions and retrying.", e)
AppDependencies.protocolStore.aci().sessions().archiveSessions(recipientId)
AppDependencies.protocolStore.pni().sessions().archiveSessions(recipientId)
try {
operation.send()
} catch (retryError: IllegalStateException) {
} catch (retryError: NoSessionException) {
Log.w(TAG, "Failed to send receipt even after archiving sessions. Dropping.", retryError)
null
}
@ -39,7 +40,7 @@ object ReceiptSender {
}
fun interface ReceiptSendOperation {
@Throws(IOException::class, UntrustedIdentityException::class)
@Throws(IOException::class, UntrustedIdentityException::class, NoSessionException::class)
fun send(): SendMessageResult
}
}

View File

@ -7,6 +7,7 @@ import androidx.annotation.WorkerThread;
import org.signal.core.util.SetUtil;
import org.signal.core.util.Util;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.thoughtcrime.securesms.database.GroupTable;
import org.thoughtcrime.securesms.database.MessageTable;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
@ -228,7 +229,7 @@ public class RemoteDeleteSendJob extends BaseJob {
long targetSentTimestamp,
boolean isForStory,
@Nullable DistributionListId distributionListId)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder()
.withTimestamp(System.currentTimeMillis())

View File

@ -5,6 +5,7 @@ import androidx.annotation.Nullable;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.message.SenderKeyDistributionMessage;
import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil;
@ -187,8 +188,8 @@ public class ResendMessageJob extends BaseJob {
try {
result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.ofNullable(groupId).map(GroupId::getDecodedId), urgent);
} catch (IllegalStateException e) {
Log.w(TAG, "Failed to resend content. Archiving session and trying again.", e);
} catch (NoSessionException e) {
Log.w(TAG, "Failed to resend content due to a missing session. Archiving session and trying again.", e);
AppDependencies.getProtocolStore().aci().sessions().archiveSessions(recipientId, SignalServiceAddress.DEFAULT_DEVICE_ID);
AppDependencies.getProtocolStore().aci().sessions().archiveSiblingSessions(recipient.getServiceId().toProtocolAddress(SignalServiceAddress.DEFAULT_DEVICE_ID));
AppDependencies.getProtocolStore().pni().sessions().archiveSessions(recipientId, SignalServiceAddress.DEFAULT_DEVICE_ID);

View File

@ -6,6 +6,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.core.models.ServiceId;
import org.signal.core.util.Util;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.metadata.certificate.SenderCertificate;
import org.signal.libsignal.protocol.InvalidKeyException;
@ -14,6 +16,7 @@ import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
import org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsement;
import org.signal.libsignal.zkgroup.groupsend.GroupSendFullToken;
import org.signal.network.util.Preconditions;
import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil;
import org.thoughtcrime.securesms.crypto.SenderKeyUtil;
import org.thoughtcrime.securesms.database.MessageSendLogTables;
@ -34,7 +37,6 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.RecipientAccessList;
import org.thoughtcrime.securesms.util.RemoteConfig;
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
import org.signal.core.util.Util;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.SignalServiceMessageSender.LegacyGroupEvents;
import org.whispersystems.signalservice.api.SignalServiceMessageSender.SenderKeyGroupEvents;
@ -51,10 +53,8 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessageRe
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.signal.core.models.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
import org.signal.network.util.Preconditions;
import org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException;
import org.whispersystems.signalservice.internal.push.http.CancelationSignal;
import org.whispersystems.signalservice.internal.push.http.PartialSendBatchCompleteListener;
@ -108,7 +108,7 @@ public final class GroupSendUtil {
boolean isForStory,
@Nullable SignalServiceEditMessage editMessage,
@Nullable CancelationSignal cancelationSignal)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Preconditions.checkArgument(groupId == null || distributionListId == null, "Cannot supply both a groupId and a distributionListId!");
@ -135,7 +135,7 @@ public final class GroupSendUtil {
@NonNull SignalServiceDataMessage message,
boolean urgent,
CancelationSignal cancelationSignal)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, isRecipientUpdate, false, DataSendOperation.unresendable(message, contentHint, urgent), cancelationSignal);
}
@ -152,7 +152,7 @@ public final class GroupSendUtil {
@NonNull List<Recipient> allTargets,
@NonNull SignalServiceTypingMessage message,
@Nullable CancelationSignal cancelationSignal)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, false, new TypingSendOperation(message), cancelationSignal);
}
@ -168,7 +168,7 @@ public final class GroupSendUtil {
@NonNull GroupId.V2 groupId,
@NonNull List<Recipient> allTargets,
@NonNull SignalServiceCallMessage message)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, false, new CallSendOperation(message), null);
}
@ -187,7 +187,7 @@ public final class GroupSendUtil {
long sentTimestamp,
@NonNull SignalServiceStoryMessage message,
@NonNull Set<SignalServiceStoryMessageRecipient> manifest)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
return sendMessage(
context,
@ -214,7 +214,7 @@ public final class GroupSendUtil {
@NonNull MessageId messageId,
long sentTimestamp,
@NonNull SignalServiceStoryMessage message)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
return sendMessage(
context,
@ -253,7 +253,7 @@ public final class GroupSendUtil {
boolean isStorySend,
@NonNull SendOperation sendOperation,
@Nullable CancelationSignal cancelationSignal)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Log.i(TAG, "Starting group send. GroupId: " + (groupId != null ? groupId.toString() : "none") + ", DistributionId: " + (distributionId != null ? distributionId.toString() : "none") + " RelatedMessageId: " + (relatedMessageId != null ? relatedMessageId.toString() : "none") + ", Targets: " + allTargets.size() + ", RecipientUpdate: " + isRecipientUpdate + ", Operation: " + sendOperation.getClass().getSimpleName());
@ -577,7 +577,7 @@ public final class GroupSendUtil {
boolean isRecipientUpdate,
@Nullable PartialSendCompleteListener partialListener,
@Nullable CancelationSignal cancelationSignal)
throws IOException, UntrustedIdentityException;
throws IOException, UntrustedIdentityException, NoSessionException;
@NonNull ContentHint getContentHint();
long getSentTimestamp();
@ -639,7 +639,7 @@ public final class GroupSendUtil {
boolean isRecipientUpdate,
@Nullable PartialSendCompleteListener partialListener,
@Nullable CancelationSignal cancelationSignal)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
// PniSignatures are only needed for 1:1 messages, but some message jobs use the GroupSendUtil methods to send 1:1
if (targets.size() == 1 && relatedMessageId == null) {
@ -877,7 +877,7 @@ public final class GroupSendUtil {
boolean isRecipientUpdate,
@Nullable PartialSendCompleteListener partialListener,
@Nullable CancelationSignal cancelationSignal)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
// We only allow legacy sends if you're sending to an empty group and just need to send a sync message.
if (targets.isEmpty()) {

View File

@ -13,16 +13,19 @@ import androidx.annotation.Nullable;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.util.AppForegroundObserver;
import org.signal.core.util.Util;
import org.signal.core.util.concurrent.KeyedSerialMonoLifoExecutor;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.zkgroup.GenericServerPublicParams;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.VerificationFailedException;
import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredentialPresentation;
import org.signal.libsignal.zkgroup.calllinks.CallLinkSecretParams;
import org.signal.libsignal.zkgroup.groups.GroupIdentifier;
import org.signal.network.NetworkResult;
import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallLinkRootKey;
@ -68,7 +71,6 @@ import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId;
import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkManager;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.signal.core.util.AppForegroundObserver;
import org.thoughtcrime.securesms.util.RecipientAccessList;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.rx.RxStore;
@ -76,7 +78,6 @@ import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.webrtc.PeerConnection;
import org.signal.network.NetworkResult;
import org.whispersystems.signalservice.api.NetworkResultUtil;
import org.whispersystems.signalservice.api.crypto.SealedSenderAccess;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
@ -902,6 +903,10 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
} catch (IOException e) {
Log.i(TAG, "onSendCallMessage onFailure: ", e);
process((s, p) -> p.handleGroupMessageSentError(s, Collections.singletonList(recipient.getId()), NETWORK_FAILURE));
} catch (NoSessionException e) {
Log.w(TAG, "onSendCallMessage onFailure: missing or corrupt session. Archiving sessions so the next send rebuilds.", e);
archiveSessions(recipient.getId());
process((s, p) -> p.handleGroupMessageSentError(s, Collections.singletonList(recipient.getId()), NETWORK_FAILURE));
}
});
}
@ -947,7 +952,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
RetrieveProfileJob.enqueue(identifyFailureRecipientIds, true);
}
} catch (UntrustedIdentityException | IOException | InvalidInputException e) {
} catch (UntrustedIdentityException | IOException | InvalidInputException | NoSessionException e) {
Log.w(TAG, "onSendCallMessageToGroup failed", e);
}
});
@ -1323,10 +1328,23 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
remotePeer.getCallId(),
e instanceof UnregisteredUserException ? NO_SUCH_USER : NETWORK_FAILURE,
Optional.empty()));
} catch (NoSessionException e) {
Log.w(TAG, "sendCallMessage: missing or corrupt session. Archiving sessions so the next send rebuilds.", e);
archiveSessions(recipient.getId());
processSendMessageFailureWithChangeDetection(remotePeer,
(s, p) -> p.handleMessageSentError(s,
remotePeer.getCallId(),
NETWORK_FAILURE,
Optional.empty()));
}
});
}
private void archiveSessions(@NonNull RecipientId recipientId) {
AppDependencies.getProtocolStore().aci().sessions().archiveSessions(recipientId);
AppDependencies.getProtocolStore().pni().sessions().archiveSessions(recipientId);
}
public void sendAcceptedCallEventSyncMessage(@NonNull RemotePeer remotePeer, boolean isOutgoing, boolean isVideoCall) {
SignalDatabase
.calls()
@ -1337,7 +1355,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
try {
SyncMessage.CallEvent callEvent = CallEventSyncMessageUtil.createAcceptedSyncMessage(remotePeer, System.currentTimeMillis(), isOutgoing, isVideoCall);
AppDependencies.getSignalServiceMessageSender().sendSyncMessage(SignalServiceSyncMessage.forCallEvent(callEvent));
} catch (IOException | UntrustedIdentityException e) {
} catch (IOException | UntrustedIdentityException | NoSessionException e) {
Log.w(TAG, "Unable to send call event sync message for " + remotePeer.getCallId().longValue(), e);
}
});
@ -1354,7 +1372,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
try {
SyncMessage.CallEvent callEvent = CallEventSyncMessageUtil.createNotAcceptedSyncMessage(remotePeer, System.currentTimeMillis(), isOutgoing, isVideoCall);
AppDependencies.getSignalServiceMessageSender().sendSyncMessage(SignalServiceSyncMessage.forCallEvent(callEvent));
} catch (IOException | UntrustedIdentityException e) {
} catch (IOException | UntrustedIdentityException | NoSessionException e) {
Log.w(TAG, "Unable to send call event sync message for " + remotePeer.getCallId().longValue(), e);
}
});
@ -1367,7 +1385,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
try {
SyncMessage.CallEvent callEvent = CallEventSyncMessageUtil.createNotAcceptedSyncMessage(remotePeer, System.currentTimeMillis(), isOutgoing, true);
AppDependencies.getSignalServiceMessageSender().sendSyncMessage(SignalServiceSyncMessage.forCallEvent(callEvent));
} catch (IOException | UntrustedIdentityException e) {
} catch (IOException | UntrustedIdentityException | NoSessionException e) {
Log.w(TAG, "Unable to send call event sync message for " + remotePeer.getCallId().longValue(), e);
}
});

View File

@ -27,7 +27,7 @@ androidx-navigation3-core = "1.0.0"
androidx-core-telecom = "1.1.0-alpha04"
androidx-window = "1.3.0"
glide = "4.15.1"
libsignal-client = "0.94.5"
libsignal-client = "0.96.2"
mp4parser = "1.9.39"
accompanist = "0.28.0"
nanohttpd = "2.3.1"

View File

@ -21596,20 +21596,20 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="57b3cf8f247f1990211110734a7d1af413db145c8f17eb1b2cdc9b9321188c2b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.signal" name="libsignal-android" version="0.94.5">
<artifact name="libsignal-android-0.94.5.aar">
<sha256 value="ec333b33aa9acc58d5e6dd9b0492497d4ceb978cd99658b9147be64cca2c61dd" origin="Generated by Gradle"/>
<component group="org.signal" name="libsignal-android" version="0.96.2">
<artifact name="libsignal-android-0.96.2.aar">
<sha256 value="ea4d9e881537325ea9b8ed222664e5c47514f3c0d5ffe8ec7f4d43fda56a352c" origin="Generated by Gradle"/>
</artifact>
<artifact name="libsignal-android-0.94.5.module">
<sha256 value="a2880e5eb149d57b383bd0a00d98b187370b9b61a6857326578a3f4b661fbf17" origin="Generated by Gradle"/>
<artifact name="libsignal-android-0.96.2.module">
<sha256 value="45cab6585d6acc231b81b53628dc5097118eddc50c75b2955c42d4ed8f0edb97" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.signal" name="libsignal-client" version="0.94.5">
<artifact name="libsignal-client-0.94.5.jar">
<sha256 value="33fcf541fe94dcf770f4934552e87e7280bf2d2c22b372159ee1d80accfdb09b" origin="Generated by Gradle"/>
<component group="org.signal" name="libsignal-client" version="0.96.2">
<artifact name="libsignal-client-0.96.2.jar">
<sha256 value="0e3cb1c5a5cdd7d8fe696de7d82ad42785a9fef51b014c6bedd2f9ce0d5471af" origin="Generated by Gradle"/>
</artifact>
<artifact name="libsignal-client-0.94.5.module">
<sha256 value="752f2d2ec20d7f56eb4503a58ce6786bdfd946dce7557134900855b042957c3e" origin="Generated by Gradle"/>
<artifact name="libsignal-client-0.96.2.module">
<sha256 value="d6742b8d7f365639abe694773fc154dee4868b0fb0b202fa2dbfbeb9b8985e6f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.signal" name="ringrtc-android" version="2.69.3">

View File

@ -5,13 +5,14 @@
*/
package org.whispersystems.signalservice.api;
import org.signal.network.NetworkResult;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.Base64;
import org.signal.core.util.ProtoUtil;
import org.signal.core.util.Uint64RangeException;
import org.signal.core.util.Uint64Util;
import org.signal.core.util.UuidUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.metadata.certificate.SenderCertificate;
import org.signal.libsignal.net.MismatchedDeviceException;
import org.signal.libsignal.net.MultiRecipientMessageResponse;
@ -28,13 +29,16 @@ import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SessionBuilder;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.groups.GroupSessionBuilder;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.message.DecryptionErrorMessage;
import org.signal.libsignal.protocol.message.PlaintextContent;
import org.signal.libsignal.protocol.message.SenderKeyDistributionMessage;
import org.signal.libsignal.protocol.state.PreKeyBundle;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.zkgroup.groupsend.GroupSendFullToken;
import org.signal.network.NetworkResult;
import org.signal.network.exceptions.NonSuccessfulResponseCodeException;
import org.signal.network.exceptions.PushNetworkException;
import org.signal.network.util.Preconditions;
import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil;
import org.whispersystems.signalservice.api.crypto.ContentHint;
import org.whispersystems.signalservice.api.crypto.EnvelopeContent;
@ -84,9 +88,7 @@ import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
import org.signal.network.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException;
import org.signal.network.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.RateLimitException;
import org.whispersystems.signalservice.api.push.exceptions.RetryNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
@ -94,9 +96,6 @@ import org.whispersystems.signalservice.api.push.exceptions.UnknownGroupSendExce
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.api.util.AttachmentPointerUtil;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.signal.network.util.Preconditions;
import org.signal.core.util.Uint64RangeException;
import org.signal.core.util.Uint64Util;
import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException;
import org.whispersystems.signalservice.internal.crypto.AttachmentDigest;
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream;
@ -234,7 +233,7 @@ public class SignalServiceMessageSender {
@Nullable SealedSenderAccess sealedSenderAccess,
SignalServiceReceiptMessage message,
boolean includePniSignature)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Log.d(TAG, "[" + message.getWhen() + "] Sending a receipt.");
@ -258,7 +257,7 @@ public class SignalServiceMessageSender {
@Nullable SealedSenderAccess sealedSenderAccess,
Optional<byte[]> groupId,
DecryptionErrorMessage errorMessage)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
long timestamp = System.currentTimeMillis();
@ -312,7 +311,7 @@ public class SignalServiceMessageSender {
long timestamp,
boolean isRecipientUpdate,
Set<SignalServiceStoryMessageRecipient> manifest)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Log.d(TAG, "[" + timestamp + "] Sending a story sync message.");
@ -368,7 +367,7 @@ public class SignalServiceMessageSender {
public void sendCallMessage(SignalServiceAddress recipient,
@Nullable SealedSenderAccess sealedSenderAccess,
SignalServiceCallMessage message)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
long timestamp = System.currentTimeMillis();
Log.d(TAG, "[" + timestamp + "] Sending a call message (single recipient).");
@ -429,7 +428,7 @@ public class SignalServiceMessageSender {
IndividualSendEvents sendEvents,
boolean urgent,
boolean includePniSignature)
throws UntrustedIdentityException, IOException
throws UntrustedIdentityException, IOException, NoSessionException
{
Log.d(TAG, "[" + message.getTimestamp() + "] Sending a data message.");
@ -448,7 +447,7 @@ public class SignalServiceMessageSender {
IndividualSendEvents sendEvents,
boolean urgent,
long targetSentTimestamp)
throws UntrustedIdentityException, IOException
throws UntrustedIdentityException, IOException, NoSessionException
{
Log.d(TAG, "[" + message.getTimestamp() + "] Sending an edit message for " + targetSentTimestamp + ".");
@ -468,7 +467,7 @@ public class SignalServiceMessageSender {
boolean urgent,
boolean includePniSignature,
Content content)
throws UntrustedIdentityException, IOException
throws UntrustedIdentityException, IOException, NoSessionException
{
if (includePniSignature) {
Log.d(TAG, "[" + message.getTimestamp() + "] Including PNI signature.");
@ -537,7 +536,7 @@ public class SignalServiceMessageSender {
ContentHint contentHint,
Optional<byte[]> groupId,
boolean urgent)
throws UntrustedIdentityException, IOException
throws UntrustedIdentityException, IOException, NoSessionException
{
Log.d(TAG, "[" + timestamp + "] Resending content.");
@ -613,7 +612,7 @@ public class SignalServiceMessageSender {
PartialSendCompleteListener partialListener,
CancelationSignal cancelationSignal,
boolean urgent)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Log.d(TAG, "[" + message.getTimestamp() + "] Sending a data message to " + recipients.size() + " recipients.");
@ -665,7 +664,7 @@ public class SignalServiceMessageSender {
CancelationSignal cancelationSignal,
boolean urgent,
long targetSentTimestamp)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Log.d(TAG, "[" + message.getTimestamp() + "] Sending a edit message to " + recipients.size() + " recipients.");
@ -702,21 +701,21 @@ public class SignalServiceMessageSender {
}
public SendMessageResult sendSyncMessage(SignalServiceDataMessage dataMessage)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Log.d(TAG, "[" + dataMessage.getTimestamp() + "] Sending self-sync message.");
return sendSyncMessage(createSelfSendSyncMessage(dataMessage));
}
public SendMessageResult sendSelfSyncEditMessage(SignalServiceEditMessage editMessage)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Log.d(TAG, "[" + editMessage.getDataMessage().getTimestamp() + "] Sending self-sync edit message for " + editMessage.getTargetSentTimestamp() + ".");
return sendSyncMessage(createSelfSendSyncEditMessage(editMessage));
}
public SendMessageResult sendSyncMessage(SignalServiceSyncMessage message)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
Content content;
boolean urgent = false;
@ -779,7 +778,7 @@ public class SignalServiceMessageSender {
}
public @Nonnull SendMessageResult sendSyncMessage(Content content, boolean urgent, Optional<Long> sent)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
long timestamp = sent.orElseGet(System::currentTimeMillis);
@ -797,7 +796,7 @@ public class SignalServiceMessageSender {
* @return Encrypted {@link OutgoingPushMessage} to be included in the change number request sent to the server
*/
public @Nonnull OutgoingPushMessage getEncryptedSyncPniInitializeDeviceMessage(int deviceId, @Nonnull SyncMessage.PniChangeNumber pniChangeNumber)
throws UntrustedIdentityException, IOException, InvalidKeyException
throws UntrustedIdentityException, IOException, InvalidKeyException, NoSessionException
{
SyncMessage.Builder syncMessage = createSyncMessageBuilder().pniChangeNumber(pniChangeNumber);
Content.Builder content = new Content.Builder().syncMessage(syncMessage.build());
@ -856,7 +855,7 @@ public class SignalServiceMessageSender {
}
private SendMessageResult sendVerifiedSyncMessage(VerifiedMessage message)
throws IOException, UntrustedIdentityException
throws IOException, UntrustedIdentityException, NoSessionException
{
byte[] nullMessageBody = new DataMessage.Builder()
.body(Base64.encodeWithPadding(Util.getRandomLengthSecretBytes(140)))
@ -886,7 +885,7 @@ public class SignalServiceMessageSender {
}
public SendMessageResult sendNullMessage(SignalServiceAddress address, @Nullable SealedSenderAccess sealedSenderAccess)
throws UntrustedIdentityException, IOException
throws UntrustedIdentityException, IOException, NoSessionException
{
byte[] nullMessageBody = new DataMessage.Builder()
.body(Base64.encodeWithPadding(Util.getRandomLengthSecretBytes(140)))
@ -1968,7 +1967,7 @@ public class SignalServiceMessageSender {
SendEvents sendEvents,
boolean urgent,
boolean story)
throws UntrustedIdentityException, IOException
throws UntrustedIdentityException, IOException, NoSessionException
{
enforceMaxEnvelopeContentSize(content);
@ -2827,7 +2826,7 @@ public class SignalServiceMessageSender {
boolean online,
boolean urgent,
boolean story)
throws IOException, InvalidKeyException, UntrustedIdentityException
throws IOException, InvalidKeyException, UntrustedIdentityException, NoSessionException
{
List<OutgoingPushMessage> messages = new LinkedList<>();
List<Integer> subDevices = aciStore.getSubDeviceSessions(recipient.getIdentifier());
@ -2858,7 +2857,7 @@ public class SignalServiceMessageSender {
int deviceId,
EnvelopeContent plaintext,
boolean story)
throws IOException, InvalidKeyException, UntrustedIdentityException
throws IOException, InvalidKeyException, UntrustedIdentityException, NoSessionException
{
SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(recipient.getIdentifier(), deviceId);
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, localDeviceId, aciStore, sessionLock, null);

View File

@ -138,7 +138,7 @@ public interface EnvelopeContent {
SignalSealedSessionCipher sealedSessionCipher,
SignalProtocolAddress destination,
SenderCertificate senderCertificate)
throws UntrustedIdentityException, InvalidKeyException
throws UntrustedIdentityException, InvalidKeyException, NoSessionException
{
UnidentifiedSenderMessageContent messageContent = new UnidentifiedSenderMessageContent(plaintextContent,
senderCertificate,

View File

@ -20,12 +20,10 @@ import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.UntrustedIdentityException;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignalProtocolStore;
import org.whispersystems.signalservice.api.SignalSessionLock;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@ -59,7 +57,13 @@ public class SignalSealedSessionCipher {
throw new NoSessionException("No session for some recipients");
}
return cipher.multiRecipientEncrypt(recipients, recipientSessions, content);
try {
return cipher.multiRecipientEncrypt(recipients, recipientSessions, content);
} catch (IllegalStateException e) {
NoSessionException nse = new NoSessionException(e.getMessage());
nse.initCause(e);
throw nse;
}
}
}
@ -69,13 +73,13 @@ public class SignalSealedSessionCipher {
}
}
public int getSessionVersion(SignalProtocolAddress remoteAddress) {
public int getSessionVersion(SignalProtocolAddress remoteAddress) throws NoSessionException {
try (SignalSessionLock.Lock unused = lock.acquire()) {
return cipher.getSessionVersion(remoteAddress);
}
}
public int getRemoteRegistrationId(SignalProtocolAddress remoteAddress) {
public int getRemoteRegistrationId(SignalProtocolAddress remoteAddress) throws NoSessionException {
try (SignalSessionLock.Lock unused = lock.acquire()) {
return cipher.getRemoteRegistrationId(remoteAddress);
}

View File

@ -6,6 +6,10 @@
package org.whispersystems.signalservice.api.crypto;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.util.UuidUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.metadata.InvalidMetadataMessageException;
import org.signal.libsignal.metadata.InvalidMetadataVersionException;
import org.signal.libsignal.metadata.ProtocolDuplicateMessageException;
@ -27,7 +31,6 @@ import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.InvalidKeyIdException;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.protocol.InvalidRegistrationIdException;
import org.signal.libsignal.protocol.InvalidSessionException;
import org.signal.libsignal.protocol.InvalidVersionException;
import org.signal.libsignal.protocol.LegacyMessageException;
import org.signal.libsignal.protocol.NoSessionException;
@ -35,7 +38,6 @@ import org.signal.libsignal.protocol.SessionCipher;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.UntrustedIdentityException;
import org.signal.libsignal.protocol.groups.GroupCipher;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.message.CiphertextMessage;
import org.signal.libsignal.protocol.message.PlaintextContent;
import org.signal.libsignal.protocol.message.PreKeySignalMessage;
@ -46,10 +48,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountDataStore;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.messages.SignalServiceMetadata;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.Content;
import org.whispersystems.signalservice.internal.push.Envelope;
import org.whispersystems.signalservice.internal.push.OutgoingPushMessage;
@ -115,21 +114,17 @@ public class SignalServiceCipher {
public OutgoingPushMessage encrypt(SignalProtocolAddress destination,
@Nullable SealedSenderAccess sealedSenderAccess,
EnvelopeContent content)
throws UntrustedIdentityException, InvalidKeyException
throws UntrustedIdentityException, InvalidKeyException, NoSessionException
{
try {
SignalProtocolAddress localProtocolAddress = new SignalProtocolAddress(localAddress.getIdentifier(), localDeviceId);
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, localProtocolAddress, destination));
if (sealedSenderAccess != null) {
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber()
.orElse(null), localDeviceId));
SignalProtocolAddress localProtocolAddress = new SignalProtocolAddress(localAddress.getIdentifier(), localDeviceId);
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, localProtocolAddress, destination));
if (sealedSenderAccess != null) {
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber()
.orElse(null), localDeviceId));
return content.processSealedSender(sessionCipher, sealedSessionCipher, destination, sealedSenderAccess.getSenderCertificate());
} else {
return content.processUnsealedSender(sessionCipher, destination);
}
} catch (NoSessionException e) {
throw new InvalidSessionException("Session not found: " + destination);
return content.processSealedSender(sessionCipher, sealedSessionCipher, destination, sealedSenderAccess.getSenderCertificate());
} else {
return content.processUnsealedSender(sessionCipher, destination);
}
}

View File

@ -55,7 +55,7 @@ public class SignalSessionCipher {
}
}
public int getSessionVersion() {
public int getSessionVersion() throws NoSessionException {
try (SignalSessionLock.Lock unused = lock.acquire()) {
return cipher.getSessionVersion();
}

View File

@ -29,6 +29,7 @@ import org.signal.libsignal.net.UserBasedAuthorization
import org.signal.libsignal.net.UserBasedSendAuthorization
import org.signal.libsignal.protocol.IdentityKey
import org.signal.libsignal.protocol.InvalidKeyException
import org.signal.libsignal.protocol.NoSessionException
import org.signal.libsignal.protocol.SessionBuilder
import org.signal.libsignal.protocol.SignalProtocolAddress
import org.signal.libsignal.protocol.UntrustedIdentityException
@ -388,6 +389,10 @@ open class MessageService(
raise(SendError.IdentityMismatch(serviceId, e))
} catch (e: InvalidKeyException) {
raise(SendError.ApplicationError(e))
} catch (e: NoSessionException) {
Log.w(TAG, "Missing or corrupt session for $address. Archiving so the next attempt rebuilds it.", e)
protocolStore.archiveSession(address)
raise(SendError.ApplicationError(e))
}
private fun OutgoingPushMessage.toUnsealedMessage(): SingleOutboundUnsealedMessage {

View File

@ -28,6 +28,7 @@ import org.signal.libsignal.net.ServiceIdNotFoundException
import org.signal.libsignal.net.UserBasedAuthorization
import org.signal.libsignal.net.UserBasedSendAuthorization
import org.signal.libsignal.protocol.IdentityKeyPair
import org.signal.libsignal.protocol.NoSessionException
import org.signal.libsignal.protocol.SessionBuilder
import org.signal.libsignal.protocol.SessionCipher
import org.signal.libsignal.protocol.SignalProtocolAddress
@ -440,6 +441,21 @@ class MessageServiceTest {
assertThat(mismatch.exception).isEqualTo(untrusted)
}
@Test
fun `NoSessionException during encryption archives the session and surfaces a retryable error`() = runTest {
val service = newService()
every { protocolStore.getSubDeviceSessions(recipientAci.toString()) } returns emptyList()
val noSession = NoSessionException("missing session")
every { cipher.encrypt(any(), any(), any()) } throws noSession
val result = service.sendMessage(recipientAci, envelopeContent, timestamp, sealedSenderAccess = null, story = true, isOnline = false)
verify { protocolStore.archiveSession(SignalProtocolAddress(recipientAci.libSignalServiceId, SignalServiceAddress.DEFAULT_DEVICE_ID)) }
val app = (result as Either.Left).value as MessageService.SendError.ApplicationError
assertThat(app.exception).isEqualTo(noSession)
coVerify(exactly = 0) { messageApi.sendSealedSenderMessage(any(), any(), any(), any(), any(), any()) }
}
@Test
fun `content larger than max returns ContentTooLarge before encryption`() = runTest {
val largeContent: EnvelopeContent = mockk {