Skip sends to users with prekey failures.

This commit is contained in:
Greyson Parrelli
2023-05-24 22:45:02 -04:00
committed by Cody Henthorne
parent 6b91e525db
commit 3e21fb77c7
4 changed files with 61 additions and 21 deletions

View File

@@ -0,0 +1,18 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.signalservice.api
import org.signal.libsignal.protocol.InvalidKeyException
import org.signal.libsignal.protocol.SignalProtocolAddress
import java.io.IOException
/**
* Wraps an [InvalidKeyException] in an [IOException] with a nicer message.
*/
class InvalidPreKeyException(
address: SignalProtocolAddress,
invalidKeyException: InvalidKeyException
) : IOException("Invalid prekey for $address", invalidKeyException)

View File

@@ -1849,24 +1849,28 @@ public class SignalServiceMessageSender {
results.add(futureResult.get());
} catch (ExecutionException e) {
if (e.getCause() instanceof UntrustedIdentityException) {
Log.w(TAG, e);
Log.w(TAG, "[" + timestamp + "] Hit identity mismatch: " + recipient.getIdentifier(), e);
results.add(SendMessageResult.identityFailure(recipient, ((UntrustedIdentityException) e.getCause()).getIdentityKey()));
} else if (e.getCause() instanceof UnregisteredUserException) {
Log.w(TAG, "[" + timestamp + "] Found unregistered user.");
Log.w(TAG, "[" + timestamp + "] Hit unregistered user: " + recipient.getIdentifier());
results.add(SendMessageResult.unregisteredFailure(recipient));
} else if (e.getCause() instanceof PushNetworkException) {
Log.w(TAG, e);
Log.w(TAG, "[" + timestamp + "] Hit network failure: " + recipient.getIdentifier(), e);
results.add(SendMessageResult.networkFailure(recipient));
} else if (e.getCause() instanceof ServerRejectedException) {
Log.w(TAG, e);
Log.w(TAG, "[" + timestamp + "] Hit server rejection: " + recipient.getIdentifier(), e);
throw ((ServerRejectedException) e.getCause());
} else if (e.getCause() instanceof ProofRequiredException) {
Log.w(TAG, e);
Log.w(TAG, "[" + timestamp + "] Hit proof required: " + recipient.getIdentifier(), e);
results.add(SendMessageResult.proofRequiredFailure(recipient, (ProofRequiredException) e.getCause()));
} else if (e.getCause() instanceof RateLimitException) {
Log.w(TAG, e);
Log.w(TAG, "[" + timestamp + "] Hit rate limit: " + recipient.getIdentifier(), e);
results.add(SendMessageResult.rateLimitFailure(recipient, (RateLimitException) e.getCause()));
} else if (e.getCause() instanceof InvalidPreKeyException) {
Log.w(TAG, "[" + timestamp + "] Hit invalid prekey: " + recipient.getIdentifier(), e);
results.add(SendMessageResult.invalidPreKeyFailure(recipient));
} else {
Log.w(TAG, "[" + timestamp + "] Hit unknown exception: " + recipient.getIdentifier(), e);
throw new IOException(e);
}
} catch (InterruptedException e) {
@@ -2317,10 +2321,10 @@ public class SignalServiceMessageSender {
// Visible for testing only
public OutgoingPushMessage getEncryptedMessage(SignalServiceAddress recipient,
Optional<UnidentifiedAccess> unidentifiedAccess,
int deviceId,
EnvelopeContent plaintext,
boolean story)
Optional<UnidentifiedAccess> unidentifiedAccess,
int deviceId,
EnvelopeContent plaintext,
boolean story)
throws IOException, InvalidKeyException, UntrustedIdentityException
{
SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(recipient.getIdentifier(), deviceId);
@@ -2331,6 +2335,8 @@ public class SignalServiceMessageSender {
List<PreKeyBundle> preKeys = getPreKeys(recipient, unidentifiedAccess, deviceId, story);
for (PreKeyBundle preKey : preKeys) {
Log.d(TAG, "Initializing prekey session for " + signalProtocolAddress);
try {
SignalProtocolAddress preKeyAddress = new SignalProtocolAddress(recipient.getIdentifier(), preKey.getDeviceId());
SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(aciStore, preKeyAddress));
@@ -2344,7 +2350,7 @@ public class SignalServiceMessageSender {
eventListener.get().onSecurityEvent(recipient);
}
} catch (InvalidKeyException e) {
throw new IOException(e);
throw new InvalidPreKeyException(signalProtocolAddress, e);
}
}

View File

@@ -19,29 +19,34 @@ public class SendMessageResult {
private final IdentityFailure identityFailure;
private final ProofRequiredException proofRequiredFailure;
private final RateLimitException rateLimitFailure;
private final boolean invalidPreKeyFailure;
public static SendMessageResult success(SignalServiceAddress address, List<Integer> devices, boolean unidentified, boolean needsSync, long duration, Optional<Content> content) {
return new SendMessageResult(address, new Success(unidentified, needsSync, duration, content, devices), false, false, null, null, null);
return new SendMessageResult(address, new Success(unidentified, needsSync, duration, content, devices), false, false, null, null, null, false);
}
public static SendMessageResult networkFailure(SignalServiceAddress address) {
return new SendMessageResult(address, null, true, false, null, null, null);
return new SendMessageResult(address, null, true, false, null, null, null, false);
}
public static SendMessageResult unregisteredFailure(SignalServiceAddress address) {
return new SendMessageResult(address, null, false, true, null, null, null);
return new SendMessageResult(address, null, false, true, null, null, null, false);
}
public static SendMessageResult identityFailure(SignalServiceAddress address, IdentityKey identityKey) {
return new SendMessageResult(address, null, false, false, new IdentityFailure(identityKey), null, null);
return new SendMessageResult(address, null, false, false, new IdentityFailure(identityKey), null, null, false);
}
public static SendMessageResult proofRequiredFailure(SignalServiceAddress address, ProofRequiredException proofRequiredException) {
return new SendMessageResult(address, null, false, false, null, proofRequiredException, null);
return new SendMessageResult(address, null, false, false, null, proofRequiredException, null, false);
}
public static SendMessageResult rateLimitFailure(SignalServiceAddress address, RateLimitException rateLimitException) {
return new SendMessageResult(address, null, false, false, null, null, rateLimitException);
return new SendMessageResult(address, null, false, false, null, null, rateLimitException, false);
}
public static SendMessageResult invalidPreKeyFailure(SignalServiceAddress address) {
return new SendMessageResult(address, null, false, false, null, null, null, true);
}
public SignalServiceAddress getAddress() {
@@ -76,13 +81,18 @@ public class SendMessageResult {
return rateLimitFailure;
}
public boolean isInvalidPreKeyFailure() {
return invalidPreKeyFailure;
}
private SendMessageResult(SignalServiceAddress address,
Success success,
boolean networkFailure,
boolean unregisteredFailure,
IdentityFailure identityFailure,
ProofRequiredException proofRequiredFailure,
RateLimitException rateLimitFailure)
RateLimitException rateLimitFailure,
boolean invalidPreKeyFailure)
{
this.address = address;
this.success = success;
@@ -91,6 +101,7 @@ public class SendMessageResult {
this.identityFailure = identityFailure;
this.proofRequiredFailure = proofRequiredFailure;
this.rateLimitFailure = rateLimitFailure;
this.invalidPreKeyFailure = invalidPreKeyFailure;
}
public static class Success {