Compare commits

...

2 Commits

Author SHA1 Message Date
Greyson Parrelli
5cad031b28 Bump version to 5.24.7.1 2021-10-02 16:04:37 -04:00
Greyson Parrelli
761657ddc0 Improve handling of badly-serialized data.
h/t @i-infra
2021-10-02 16:04:37 -04:00
4 changed files with 61 additions and 47 deletions

View File

@@ -67,14 +67,14 @@ protobuf {
}
def canonicalVersionCode = 927
def canonicalVersionName = "5.24.7"
def canonicalVersionName = "5.24.7.1"
def postFixSize = 100
def abiPostFix = ['universal' : 0,
'armeabi-v7a' : 1,
'arm64-v8a' : 2,
'x86' : 3,
'x86_64' : 4]
def abiPostFix = ['universal' : 5,
'armeabi-v7a' : 6,
'arm64-v8a' : 7,
'x86' : 8,
'x86_64' : 9]
def keystores = [ 'debug' : loadKeystoreProperties('keystore.debug.properties') ]

View File

@@ -12,6 +12,7 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mobilecoin.lib.exceptions.SerializationException;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
@@ -30,6 +31,7 @@ import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.CursorUtil;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.signalservice.api.InvalidMessageStructureException;
import org.whispersystems.signalservice.api.payments.Money;
import java.util.Arrays;
@@ -105,7 +107,7 @@ public final class PaymentDatabase extends Database {
@NonNull Money amount,
@NonNull Money fee,
@NonNull byte[] receipt)
throws PublicKeyConflictException
throws PublicKeyConflictException, SerializationException
{
create(uuid, fromRecipient, null, timestamp, 0, note, Direction.RECEIVED, State.SUBMITTED, amount, fee, null, receipt, null, false);
}
@@ -122,7 +124,9 @@ public final class PaymentDatabase extends Database {
create(uuid, toRecipient, publicAddress, timestamp, 0, note, Direction.SENT, State.INITIAL, amount, amount.toZero(), null, null, null, true);
} catch (PublicKeyConflictException e) {
Log.w(TAG, "Tried to create payment but the public key appears already in the database", e);
throw new AssertionError(e);
throw new IllegalArgumentException(e);
} catch (SerializationException e) {
throw new IllegalArgumentException(e);
}
}
@@ -142,6 +146,7 @@ public final class PaymentDatabase extends Database {
@NonNull Money fee,
@NonNull byte[] receipt,
@NonNull PaymentMetaData metaData)
throws SerializationException
{
try {
create(uuid, toRecipient, publicAddress, timestamp, blockIndex, note, Direction.SENT, State.SUCCESSFUL, amount, fee, null, receipt, metaData, true);
@@ -165,6 +170,8 @@ public final class PaymentDatabase extends Database {
} catch (PublicKeyConflictException e) {
Log.w(TAG, "Tried to create payment but the public key appears already in the database", e);
throw new AssertionError(e);
} catch (SerializationException e) {
throw new IllegalArgumentException(e);
}
}
@@ -183,7 +190,7 @@ public final class PaymentDatabase extends Database {
@Nullable byte[] receipt,
@Nullable PaymentMetaData metaData,
boolean seen)
throws PublicKeyConflictException
throws PublicKeyConflictException, SerializationException
{
if (recipientId == null && publicAddress == null) {
throw new AssertionError();
@@ -403,8 +410,12 @@ public final class PaymentDatabase extends Database {
values.put(STATE, State.SUBMITTED.serialize());
values.put(TRANSACTION, transaction);
values.put(RECEIPT, receipt);
values.put(PUBLIC_KEY, Base64.encodeBytes(PaymentMetaDataUtil.receiptPublic(PaymentMetaDataUtil.fromReceipt(receipt))));
values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).toByteArray());
try {
values.put(PUBLIC_KEY, Base64.encodeBytes(PaymentMetaDataUtil.receiptPublic(PaymentMetaDataUtil.fromReceipt(receipt))));
values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).toByteArray());
} catch (SerializationException e) {
throw new IllegalArgumentException(e);
}
values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).toByteArray());
database.beginTransaction();

View File

@@ -23,11 +23,11 @@ public final class PaymentMetaDataUtil {
try {
return PaymentMetaData.parseFrom(requireBlob);
} catch (InvalidProtocolBufferException e) {
throw new AssertionError(e);
throw new IllegalStateException(e);
}
}
public static @NonNull PaymentMetaData fromReceipt(@Nullable byte[] receipt) {
public static @NonNull PaymentMetaData fromReceipt(@Nullable byte[] receipt) throws SerializationException {
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder();
if (receipt != null) {
@@ -46,7 +46,7 @@ public final class PaymentMetaDataUtil {
return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build();
}
public static @NonNull PaymentMetaData fromReceiptAndTransaction(@Nullable byte[] receipt, @Nullable byte[] transaction) {
public static @NonNull PaymentMetaData fromReceiptAndTransaction(@Nullable byte[] receipt, @Nullable byte[] transaction) throws SerializationException {
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder();
if (transaction != null) {
@@ -58,27 +58,19 @@ public final class PaymentMetaDataUtil {
return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build();
}
private static void addReceiptData(@NonNull byte[] receipt, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) {
try {
RistrettoPublic publicKey = Receipt.fromBytes(receipt).getPublicKey();
addPublicKey(builder, publicKey);
} catch (SerializationException e) {
throw new AssertionError(e);
}
private static void addReceiptData(@NonNull byte[] receipt, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) throws SerializationException {
RistrettoPublic publicKey = Receipt.fromBytes(receipt).getPublicKey();
addPublicKey(builder, publicKey);
}
private static void addTransactionData(@NonNull byte[] transactionBytes, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) {
try {
Transaction transaction = Transaction.fromBytes(transactionBytes);
Set<KeyImage> keyImages = transaction.getKeyImages();
for (KeyImage keyImage : keyImages) {
builder.addKeyImages(ByteString.copyFrom(keyImage.getData()));
}
for (RistrettoPublic publicKey : transaction.getOutputPublicKeys()) {
addPublicKey(builder, publicKey);
}
} catch (SerializationException e) {
throw new AssertionError(e);
private static void addTransactionData(@NonNull byte[] transactionBytes, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) throws SerializationException {
Transaction transaction = Transaction.fromBytes(transactionBytes);
Set<KeyImage> keyImages = transaction.getKeyImages();
for (KeyImage keyImage : keyImages) {
builder.addKeyImages(ByteString.copyFrom(keyImage.getData()));
}
for (RistrettoPublic publicKey : transaction.getOutputPublicKeys()) {
addPublicKey(builder, publicKey);
}
}

View File

@@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.mobilecoin.lib.exceptions.SerializationException;
import org.signal.core.util.logging.Log;
import org.signal.ringrtc.CallId;
@@ -309,7 +310,7 @@ public final class MessageContentProcessor {
else if (syncMessage.getBlockedList().isPresent()) handleSynchronizeBlockedListMessage(syncMessage.getBlockedList().get());
else if (syncMessage.getFetchType().isPresent()) handleSynchronizeFetchMessage(syncMessage.getFetchType().get());
else if (syncMessage.getMessageRequestResponse().isPresent()) handleSynchronizeMessageRequestResponse(syncMessage.getMessageRequestResponse().get());
else if (syncMessage.getOutgoingPaymentMessage().isPresent()) handleSynchronizeOutgoingPayment(syncMessage.getOutgoingPaymentMessage().get());
else if (syncMessage.getOutgoingPaymentMessage().isPresent()) handleSynchronizeOutgoingPayment(content, syncMessage.getOutgoingPaymentMessage().get());
else warn(String.valueOf(content.getTimestamp()), "Contains no known sync types...");
} else if (content.getCallMessage().isPresent()) {
log(String.valueOf(content.getTimestamp()), "Got call message...");
@@ -410,6 +411,8 @@ public final class MessageContentProcessor {
} catch (PaymentDatabase.PublicKeyConflictException e) {
warn(content.getTimestamp(), "Ignoring payment with public key already in database");
return;
} catch (SerializationException e) {
warn(content.getTimestamp(), "Ignoring payment with bad data.", e);
}
ApplicationDependencies.getJobManager()
@@ -1016,7 +1019,7 @@ public final class MessageContentProcessor {
}
}
private void handleSynchronizeOutgoingPayment(@NonNull OutgoingPaymentMessage outgoingPaymentMessage) {
private void handleSynchronizeOutgoingPayment(@NonNull SignalServiceContent content, @NonNull OutgoingPaymentMessage outgoingPaymentMessage) {
RecipientId recipientId = outgoingPaymentMessage.getRecipient()
.transform(uuid -> RecipientId.from(uuid, null))
.orNull();
@@ -1027,23 +1030,27 @@ public final class MessageContentProcessor {
Optional<MobileCoinPublicAddress> address = outgoingPaymentMessage.getAddress().transform(MobileCoinPublicAddress::fromBytes);
if (!address.isPresent() && recipientId == null) {
log("Inserting defrag");
log(content.getTimestamp(), "Inserting defrag");
address = Optional.of(ApplicationDependencies.getPayments().getWallet().getMobileCoinPublicAddress());
recipientId = Recipient.self().getId();
}
UUID uuid = UUID.randomUUID();
DatabaseFactory.getPaymentDatabase(context)
.createSuccessfulPayment(uuid,
recipientId,
address.get(),
timestamp,
outgoingPaymentMessage.getBlockIndex(),
outgoingPaymentMessage.getNote().or(""),
outgoingPaymentMessage.getAmount(),
outgoingPaymentMessage.getFee(),
outgoingPaymentMessage.getReceipt().toByteArray(),
PaymentMetaDataUtil.fromKeysAndImages(outgoingPaymentMessage.getPublicKeys(), outgoingPaymentMessage.getKeyImages()));
try {
DatabaseFactory.getPaymentDatabase(context)
.createSuccessfulPayment(uuid,
recipientId,
address.get(),
timestamp,
outgoingPaymentMessage.getBlockIndex(),
outgoingPaymentMessage.getNote().or(""),
outgoingPaymentMessage.getAmount(),
outgoingPaymentMessage.getFee(),
outgoingPaymentMessage.getReceipt().toByteArray(),
PaymentMetaDataUtil.fromKeysAndImages(outgoingPaymentMessage.getPublicKeys(), outgoingPaymentMessage.getKeyImages()));
} catch (SerializationException e) {
warn(content.getTimestamp(), "Ignoring synchronized outgoing payment with bad data.", e);
}
log("Inserted synchronized payment " + uuid);
}
@@ -2254,6 +2261,10 @@ public final class MessageContentProcessor {
warn(String.valueOf(timestamp), message);
}
protected void warn(long timestamp, @NonNull String message, @Nullable Throwable t) {
warn(String.valueOf(timestamp), message, t);
}
protected void warn(@NonNull String message, @Nullable Throwable t) {
warn("", message, t);
}