Merge pull request #494 from hjubb/refactor-sending

Fix expiration timers updates for groups
This commit is contained in:
Niels Andriesse 2021-04-09 16:22:40 +10:00 committed by GitHub
commit 201dde7412
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 37 deletions

View File

@ -28,12 +28,14 @@ import com.annimon.stream.Collectors;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd; import com.google.android.mms.pdu_alt.NotificationInd;
import com.google.android.mms.pdu_alt.PduHeaders; import com.google.android.mms.pdu_alt.PduHeaders;
import com.google.protobuf.ByteString;
import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteDatabase;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.session.libsession.utilities.GroupUtil;
import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.attachments.MmsNotificationAttachment; import org.thoughtcrime.securesms.attachments.MmsNotificationAttachment;
import org.session.libsession.database.documents.IdentityKeyMismatch; import org.session.libsession.database.documents.IdentityKeyMismatch;
@ -686,8 +688,15 @@ public class MmsDatabase extends MessagingDatabase {
throws MmsException throws MmsException
{ {
if (threadId == -1) { if (threadId == -1) {
if(retrieved.isGroup()) {
ByteString decodedGroupId = ((OutgoingGroupMediaMessage)retrieved).getGroupContext().getId();
String groupId = GroupUtil.doubleEncodeGroupID(decodedGroupId.toByteArray());
Recipient group = Recipient.from(context, Address.fromSerialized(groupId), false);
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(group);
} else {
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(retrieved.getRecipient()); threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(retrieved.getRecipient());
} }
}
long messageId = insertMessageOutbox(retrieved, threadId, false, null, serverTimestamp); long messageId = insertMessageOutbox(retrieved, threadId, false, null, serverTimestamp);
if (messageId == -1) { if (messageId == -1) {
return Optional.absent(); return Optional.absent();

View File

@ -417,7 +417,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
.setName(name) .setName(name)
.addAllMembers(members) .addAllMembers(members)
.addAllAdmins(admins) .addAllAdmins(admins)
val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, sentTimestamp, 0, null, listOf(), listOf()) val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, sentTimestamp, 0, false, null, listOf(), listOf())
val mmsDB = DatabaseFactory.getMmsDatabase(context) val mmsDB = DatabaseFactory.getMmsDatabase(context)
val mmsSmsDB = DatabaseFactory.getMmsSmsDatabase(context) val mmsSmsDB = DatabaseFactory.getMmsSmsDatabase(context)
if (mmsSmsDB.getMessageFor(sentTimestamp,userPublicKey) != null) return if (mmsSmsDB.getMessageFor(sentTimestamp,userPublicKey) != null) return

View File

@ -2,9 +2,11 @@ package org.thoughtcrime.securesms.service;
import android.content.Context; import android.content.Context;
import com.google.protobuf.ByteString;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate; import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate;
import org.session.libsession.messaging.messages.signal.OutgoingGroupMediaMessage;
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage; import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage;
import org.session.libsession.messaging.threads.Address; import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.threads.DistributionTypes; import org.session.libsession.messaging.threads.DistributionTypes;
@ -73,32 +75,88 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
@Override @Override
public void setExpirationTimer(@NotNull ExpirationTimerUpdate message) { public void setExpirationTimer(@NotNull ExpirationTimerUpdate message) {
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
String userPublicKey = TextSecurePreferences.getLocalNumber(context); String userPublicKey = TextSecurePreferences.getLocalNumber(context);
String senderPublicKey = message.getSender(); String senderPublicKey = message.getSender();
int duration = message.getDuration();
String groupPK = message.getGroupPublicKey();
Long sentTimestamp = message.getSentTimestamp();
Optional<SignalServiceGroup> groupInfo = Optional.absent();
Address address;
try {
if (groupPK != null) {
String groupID = GroupUtil.doubleEncodeGroupID(groupPK);
groupInfo = Optional.of(new SignalServiceGroup(GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL));
address = Address.fromSerialized(groupID);
} else {
address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : senderPublicKey);
}
Recipient recipient = Recipient.from(context, address, false);
if (recipient.isBlocked()) return;
// Notify the user // Notify the user
if (userPublicKey.equals(senderPublicKey)) { if (userPublicKey.equals(senderPublicKey)) {
// sender is a linked device // sender is a linked device
insertOutgoingExpirationTimerMessage(message);
} else {
insertIncomingExpirationTimerMessage(message);
}
if (message.getId() != null) {
DatabaseFactory.getSmsDatabase(context).deleteMessage(message.getId());
}
}
private void insertIncomingExpirationTimerMessage(ExpirationTimerUpdate message) {
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
String senderPublicKey = message.getSender();
Long sentTimestamp = message.getSentTimestamp();
String groupId = message.getGroupPublicKey();
int duration = message.getDuration();
Optional<SignalServiceGroup> groupInfo = Optional.absent();
Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : senderPublicKey);
Recipient recipient = Recipient.from(context, address, false);
// if the sender is blocked, we don't display the update, except if it's in a closed group
if (recipient.isBlocked() && groupId == null) return;
try {
if (groupId != null) {
String groupID = GroupUtil.doubleEncodeGroupID(groupId);
groupInfo = Optional.of(new SignalServiceGroup(GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL));
Address groupAddress = Address.fromSerialized(groupID);
recipient = Recipient.from(context, groupAddress, false);
}
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, sentTimestamp, -1,
duration * 1000L, true,
false,
Optional.absent(),
groupInfo,
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
//insert the timer update message
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
//set the timer to the conversation
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, duration);
} catch (IOException | MmsException ioe) {
Log.e("Loki", "Failed to insert expiration update message.");
}
}
private void insertOutgoingExpirationTimerMessage(ExpirationTimerUpdate message) {
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
String senderPublicKey = message.getSender();
Long sentTimestamp = message.getSentTimestamp();
String groupId = message.getGroupPublicKey();
int duration = message.getDuration();
Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : senderPublicKey);
Recipient recipient = Recipient.from(context, address, false);
try {
if (groupId != null) {
// conversation is a closed group
GroupContext groupContext = SignalServiceProtos.GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupId))).build();
OutgoingGroupMediaMessage infoMessage = new OutgoingGroupMediaMessage(recipient, groupContext, null, sentTimestamp, duration * 1000L, true, null, Collections.emptyList(), Collections.emptyList());
database.insertSecureDecryptedMessageOutbox(infoMessage, -1, sentTimestamp);
// we need the group ID as recipient for setExpireMessages below
recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(groupId)), false);
} else {
// conversation is a 1-1
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipient, OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipient,
null, null,
Collections.emptyList(), Collections.emptyList(),
@ -113,29 +171,12 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
Collections.emptyList(), Collections.emptyList(),
Collections.emptyList()); Collections.emptyList());
database.insertSecureDecryptedMessageOutbox(mediaMessage, -1, sentTimestamp); database.insertSecureDecryptedMessageOutbox(mediaMessage, -1, sentTimestamp);
} else {
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, sentTimestamp, -1,
duration * 1000L, true,
false,
Optional.absent(),
groupInfo,
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
//insert the timer update message
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
} }
//set the timer to the conversation //set the timer to the conversation
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, duration); DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, duration);
if (message.getId() != null) { } catch (MmsException | IOException ioe) {
DatabaseFactory.getSmsDatabase(context).deleteMessage(message.getId());
}
} catch (MmsException e) {
Log.e("Loki", "Failed to insert expiration update message.");
} catch (IOException ioe) {
Log.e("Loki", "Failed to insert expiration update message."); Log.e("Loki", "Failed to insert expiration update message.");
} }
} }

View File

@ -58,6 +58,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
@Nullable final Attachment avatar, @Nullable final Attachment avatar,
long sentTime, long sentTime,
long expireIn, long expireIn,
boolean expirationUpdate,
@Nullable QuoteModel quote, @Nullable QuoteModel quote,
@NonNull List<Contact> contacts, @NonNull List<Contact> contacts,
@NonNull List<LinkPreview> previews) @NonNull List<LinkPreview> previews)
@ -65,7 +66,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
super(recipient, Base64.encodeBytes(group.toByteArray()), super(recipient, Base64.encodeBytes(group.toByteArray()),
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}}, new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
sentTime, sentTime,
DistributionTypes.CONVERSATION, expireIn, false, quote, contacts, previews); DistributionTypes.CONVERSATION, expireIn, expirationUpdate, quote, contacts, previews);
this.group = group; this.group = group;
} }

View File

@ -78,6 +78,11 @@ object GroupUtil {
return getEncodedClosedGroupID(getEncodedClosedGroupID(Hex.fromStringCondensed(groupPublicKey)).toByteArray()) return getEncodedClosedGroupID(getEncodedClosedGroupID(Hex.fromStringCondensed(groupPublicKey)).toByteArray())
} }
@JvmStatic
fun doubleEncodeGroupID(groupID: ByteArray): String {
return getEncodedClosedGroupID(getEncodedClosedGroupID(groupID).toByteArray())
}
@JvmStatic @JvmStatic
@Throws(IOException::class) @Throws(IOException::class)
fun doubleDecodeGroupID(groupID: String): ByteArray { fun doubleDecodeGroupID(groupID: String): ByteArray {