diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java
index f17e6aca8c..164172aba1 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java
@@ -184,7 +184,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
}
}
- public void create(@NonNull String groupId, @Nullable String title, @NonNull List
members,
+ public long create(@NonNull String groupId, @Nullable String title, @NonNull List members,
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay, @Nullable List admins)
{
Collections.sort(members);
@@ -211,7 +211,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
contentValues.put(ADMINS, Address.Companion.toSerializedList(admins, ','));
}
- databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
+ long threadId = databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
Recipient.applyCached(Address.Companion.fromSerialized(groupId), recipient -> {
recipient.setName(title);
@@ -220,6 +220,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
});
notifyConversationListListeners();
+ return threadId;
}
public boolean delete(@NonNull String groupId) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
index 0ddf142866..159d961816 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
@@ -87,7 +87,7 @@ public class MmsSmsDatabase extends Database {
}
}
- public @Nullable MessageRecord getMessageFor(long timestamp, Address author) {
+ public @Nullable MessageRecord getMessageFor(long timestamp, String serializedAuthor) {
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null)) {
@@ -96,8 +96,8 @@ public class MmsSmsDatabase extends Database {
MessageRecord messageRecord;
while ((messageRecord = reader.getNext()) != null) {
- if ((Util.isOwnNumber(context, author.serialize()) && messageRecord.isOutgoing()) ||
- (!Util.isOwnNumber(context, author.serialize()) && messageRecord.getIndividualRecipient().getAddress().equals(author)))
+ if ((Util.isOwnNumber(context, serializedAuthor) && messageRecord.isOutgoing()) ||
+ (!Util.isOwnNumber(context, serializedAuthor) && messageRecord.getIndividualRecipient().getAddress().equals(serializedAuthor)))
{
return messageRecord;
}
@@ -107,6 +107,10 @@ public class MmsSmsDatabase extends Database {
return null;
}
+ public @Nullable MessageRecord getMessageFor(long timestamp, Address author) {
+ return getMessageFor(timestamp, author.serialize());
+ }
+
public Cursor getConversation(long threadId, long offset, long limit) {
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
index 3f34547fde..984f9fb82c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
@@ -8,7 +8,6 @@ import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.Job
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageSendJob
-import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.messages.visible.Attachment
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.opengroups.OpenGroup
@@ -351,7 +350,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
.setName(name)
.addAllMembers(members)
.addAllAdmins(admins)
- val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, System.currentTimeMillis(), 0, null, listOf(), listOf())
+ val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, 0, null, listOf(), listOf())
val mmsDB = DatabaseFactory.getMmsDatabase(context)
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null)
mmsDB.markAsSent(infoMessageID, true)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java
index 6d9ac5e29a..af11e476c4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java
@@ -194,7 +194,7 @@ public class GroupManager {
avatarAttachment = new UriAttachment(avatarUri, MediaTypes.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false, null, null);
}
- OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, null, Collections.emptyList(), Collections.emptyList());
+ OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, 0, null, Collections.emptyList(), Collections.emptyList());
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
return new GroupActionResult(groupRecipient, threadId);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java
index e6d9090021..e6474ce4b7 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java
@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
+import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
import org.session.libsignal.utilities.logging.Log;
@@ -269,9 +270,16 @@ public class GroupMessageProcessor {
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
Address address = Address.Companion.fromExternal(context, GroupUtil.getEncodedId(group));
Recipient recipient = Recipient.from(context, address, false);
- OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, null, Collections.emptyList(), Collections.emptyList());
+ OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, 0, null, Collections.emptyList(), Collections.emptyList());
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
- long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
+ Address senderAddress = Address.Companion.fromExternal(context, content.getSender());
+ MessageRecord existingMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(content.getTimestamp(), senderAddress);
+ long messageId;
+ if (existingMessage != null) {
+ messageId = existingMessage.getId();
+ } else {
+ messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
+ }
mmsDatabase.markAsSent(messageId, true);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
index 40cfb1fdc2..85b27d315e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
@@ -47,7 +47,6 @@ import org.session.libsession.utilities.TextSecurePreferences;
import org.thoughtcrime.securesms.contactshare.ContactModelMapper;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
-import org.thoughtcrime.securesms.crypto.SecurityEvent;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
@@ -83,7 +82,6 @@ import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2;
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
-import org.thoughtcrime.securesms.loki.utilities.DatabaseUtilitiesKt;
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MmsException;
@@ -97,7 +95,6 @@ import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
-import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.session.libsignal.utilities.Hex;
import org.session.libsignal.libsignal.InvalidMessageException;
@@ -399,33 +396,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
}
- private long handleSynchronizeSentEndSessionMessage(@NonNull SentTranscriptMessage message)
- {
- SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
- Recipient recipient = getSyncMessageDestination(message);
- OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipient, "", -1);
- OutgoingEndSessionMessage outgoingEndSessionMessage = new OutgoingEndSessionMessage(outgoingTextMessage);
-
- long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
-
- if (!recipient.isGroupRecipient()) {
- // TODO: Handle session reset on sync messages
- /*
- SessionStore sessionStore = new TextSecureSessionStore(context);
- sessionStore.deleteAllSessions(recipient.getAddress().toPhoneString());
- */
-
- SecurityEvent.broadcastSecurityUpdateEvent(context);
-
- long messageId = database.insertMessageOutbox(threadId, outgoingEndSessionMessage,
- false, message.getTimestamp(),
- null);
- database.markAsSent(messageId, true);
- }
-
- return threadId;
- }
-
private void handleGroupMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional smsMessageId)
@@ -484,83 +454,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
}
- private void handleSynchronizeStickerPackOperation(@NonNull List stickerPackOperations) {
- JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
-
- for (StickerPackOperationMessage operation : stickerPackOperations) {
- if (operation.getPackId().isPresent() && operation.getPackKey().isPresent() && operation.getType().isPresent()) {
- String packId = Hex.toStringCondensed(operation.getPackId().get());
- String packKey = Hex.toStringCondensed(operation.getPackKey().get());
-
- switch (operation.getType().get()) {
- case INSTALL:
- jobManager.add(new StickerPackDownloadJob(packId, packKey, false));
- break;
- case REMOVE:
- DatabaseFactory.getStickerDatabase(context).uninstallPack(packId);
- break;
- }
- } else {
- Log.w(TAG, "Received incomplete sticker pack operation sync.");
- }
- }
- }
-
- private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content,
- @NonNull SentTranscriptMessage message)
- throws StorageFailedException
-
- {
- try {
- GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
-
- Long threadId;
-
- if (message.getMessage().isEndSession()) {
- threadId = handleSynchronizeSentEndSessionMessage(message);
- } else if (message.getMessage().isGroupUpdate()) {
- threadId = GroupMessageProcessor.process(context, content, message.getMessage(), true);
- } else if (message.getMessage().isExpirationUpdate()) {
- threadId = handleSynchronizeSentExpirationUpdate(message);
- } else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent() || message.getMessage().getPreviews().isPresent() || message.getMessage().getSticker().isPresent()) {
- threadId = handleSynchronizeSentMediaMessage(message);
- } else {
- threadId = handleSynchronizeSentTextMessage(message);
- }
-
- if (threadId == -1L) { threadId = null; }
-
- if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get()))) {
- handleUnknownGroupMessage(content, message.getMessage().getGroupInfo().get());
- }
-
- if (message.getMessage().getProfileKey().isPresent()) {
- Recipient recipient = null;
-
- if (message.getDestination().isPresent()) recipient = Recipient.from(context, Address.Companion.fromSerialized(message.getDestination().get()), false);
- else if (message.getMessage().getGroupInfo().isPresent()) recipient = Recipient.from(context, Address.Companion.fromSerialized(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get())), false);
-
-
- if (recipient != null && !recipient.isSystemContact() && !recipient.isProfileSharing()) {
- DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
- }
-
- SessionMetaProtocol.handleProfileKeyUpdate(context, content);
- }
-
- SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content);
-
- if (threadId != null) {
- DatabaseFactory.getThreadDatabase(context).setRead(threadId, true);
- messageNotifier.updateNotification(context);
- }
-
- messageNotifier.setLastDesktopActivityTimestamp(message.getTimestamp());
- } catch (MmsException e) {
- throw new StorageFailedException(e, content.getSender(), content.getSenderDevice());
- }
- }
-
public void handleMediaMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional smsMessageId,
@@ -1429,6 +1322,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return true;
}
+ if (content.getSender().equals(TextSecurePreferences.getLocalNumber(context)) &&
+ DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(content.getTimestamp(), content.getSender()) != null) {
+ Log.d("Loki", "Skipping message from self we already have");
+ return true;
+ }
+
Recipient sender = Recipient.from(context, Address.Companion.fromSerialized(content.getSender()), false);
if (content.getDeviceLink().isPresent()) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt
index 108783a51f..66c1907405 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt
@@ -29,7 +29,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
}
override fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long? {
- val message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quoteID, Address.fromSerialized(quoteePublicKey))
+ val message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quoteID, quoteePublicKey)
return if (message != null) getServerID(message.getId()) else null
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt
index 8ae19749e5..6b4060aa17 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt
@@ -27,7 +27,7 @@ import org.session.libsignal.utilities.Hex
import java.util.*
import java.util.concurrent.TimeUnit
-class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Parameters, private val destination: String, private val kind: Kind) : BaseJob(parameters) {
+class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Parameters, private val destination: String, private val kind: Kind, private val sentTime: Long) : BaseJob(parameters) {
sealed class Kind {
class New(val publicKey: ByteArray, val name: String, val encryptionKeyPair: ECKeyPair, val members: Collection, val admins: Collection) : Kind()
@@ -61,20 +61,22 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete
}
}
- constructor(destination: String, kind: Kind) : this(Parameters.Builder()
+ constructor(destination: String, kind: Kind, sentTime: Long) : this(Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.setQueue(KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(20)
.build(),
destination,
- kind)
+ kind,
+ sentTime)
override fun getFactoryKey(): String { return KEY }
override fun serialize(): Data {
val builder = Data.Builder()
builder.putString("destination", destination)
+ builder.putLong("sentTime", sentTime)
when (kind) {
is Kind.New -> {
builder.putString("kind", "New")
@@ -124,6 +126,7 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete
override fun create(parameters: Parameters, data: Data): ClosedGroupUpdateMessageSendJobV2 {
val destination = data.getString("destination")
val rawKind = data.getString("kind")
+ val sentTime = data.getLong("sentTime")
val kind: Kind
when (rawKind) {
"New" -> {
@@ -162,7 +165,7 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete
}
else -> throw Exception("Invalid closed group update message kind: $rawKind.")
}
- return ClosedGroupUpdateMessageSendJobV2(parameters, destination, kind)
+ return ClosedGroupUpdateMessageSendJobV2(parameters, destination, kind, sentTime)
}
}
@@ -221,7 +224,7 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete
try {
// isClosedGroup can always be false as it's only used in the context of legacy closed groups
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
- Date().time, serializedContentMessage, false, ttl, false,
+ sentTime, serializedContentMessage, false, ttl, false,
true, false, false, Optional.absent())
} catch (e: Exception) {
Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.")
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt
index 3dd347472c..6c47269505 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt
@@ -285,7 +285,7 @@ object ClosedGroupsProtocol {
.setName(name)
.addAllMembers(members)
.addAllAdmins(admins)
- val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, System.currentTimeMillis(), 0, null, listOf(), listOf())
+ val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, 0, null, listOf(), listOf())
val mmsDB = DatabaseFactory.getMmsDatabase(context)
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null)
mmsDB.markAsSent(infoMessageID, true)
@@ -324,6 +324,6 @@ object ClosedGroupsProtocol {
.setId(decodedGroupId)
.setType(GroupContext.Type.QUIT)
.build()
- return OutgoingGroupMediaMessage(groupRecipient, groupContext, null, System.currentTimeMillis(), 0, null, emptyList(), emptyList())
+ return OutgoingGroupMediaMessage(groupRecipient, groupContext, null, 0, null, emptyList(), emptyList())
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt
index c97591b879..7395fd2b9c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt
@@ -58,6 +58,7 @@ object ClosedGroupsProtocolV2 {
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
// Generate the group's public key
val groupPublicKey = Curve.generateKeyPair().hexEncodedPublicKey // Includes the "05" prefix
+ val sentTime = System.currentTimeMillis()
// Generate the key pair that'll be used for encryption and decryption
val encryptionKeyPair = Curve.generateKeyPair()
// Create the group
@@ -68,19 +69,20 @@ object ClosedGroupsProtocolV2 {
null, null, LinkedList(admins.map { Address.fromSerialized(it!!) }))
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
// Send a closed group update message to all members individually
- val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
- for (member in members) {
- val job = ClosedGroupUpdateMessageSendJobV2(member, closedGroupUpdateKind)
- job.setContext(context)
- job.onRun() // Run the job immediately to make all of this sync
- }
// Add the group to the user's set of public keys to poll for
apiDB.addClosedGroupPublicKey(groupPublicKey)
// Store the encryption key pair
apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
// Notify the user
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
- insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID)
+ insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTime)
+
+ val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
+ for (member in members) {
+ val job = ClosedGroupUpdateMessageSendJobV2(member, closedGroupUpdateKind, sentTime)
+ job.setContext(context)
+ job.onRun() // Run the job immediately to make all of this sync
+ }
// Notify the PN server
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
// Fulfill the promise
@@ -102,13 +104,14 @@ object ClosedGroupsProtocolV2 {
val updatedMembers = group.members.map { it.serialize() }.toSet() - userPublicKey
val admins = group.admins.map { it.serialize() }
val name = group.title
+ val sentTime = System.currentTimeMillis()
if (group == null) {
Log.d("Loki", "Can't leave nonexistent closed group.")
return@queue deferred.reject(Error.NoThread)
}
// Send the update to the group
@Suppress("NAME_SHADOWING")
- val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, ClosedGroupUpdateMessageSendJobV2.Kind.Leave)
+ val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, ClosedGroupUpdateMessageSendJobV2.Kind.Leave, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
// Remove the group private key and unsubscribe from PNs
@@ -116,7 +119,7 @@ object ClosedGroupsProtocolV2 {
// Notify the user
val infoType = GroupContext.Type.QUIT
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
- insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID)
+ insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
deferred.resolve(Unit)
}
return deferred.promise
@@ -140,6 +143,7 @@ object ClosedGroupsProtocolV2 {
val newMembersAsData = membersToAdd.map { Hex.fromStringCondensed(it) }
val admins = group.admins.map { it.serialize() }
val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
+ val sentTime = System.currentTimeMillis()
val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
if (encryptionKeyPair == null) {
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
@@ -148,7 +152,7 @@ object ClosedGroupsProtocolV2 {
val name = group.title
// Send the update to the group
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.AddMembers(newMembersAsData)
- val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind)
+ val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
// Send closed group update messages to any new members individually
@@ -156,13 +160,13 @@ object ClosedGroupsProtocolV2 {
@Suppress("NAME_SHADOWING")
val closedGroupNewKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
@Suppress("NAME_SHADOWING")
- val newMemberJob = ClosedGroupUpdateMessageSendJobV2(member, closedGroupNewKind)
+ val newMemberJob = ClosedGroupUpdateMessageSendJobV2(member, closedGroupNewKind, sentTime)
ApplicationContext.getInstance(context).jobManager.add(newMemberJob)
}
// Notify the user
val infoType = GroupContext.Type.UPDATE
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
- insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID)
+ insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
}
}
@@ -183,6 +187,7 @@ object ClosedGroupsProtocolV2 {
groupDB.updateMembers(groupID, updatedMembers.map { Address.fromSerialized(it) })
val removeMembersAsData = membersToRemove.map { Hex.fromStringCondensed(it) }
val admins = group.admins.map { it.serialize() }
+ val sentTime = System.currentTimeMillis()
val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
if (encryptionKeyPair == null) {
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
@@ -195,7 +200,7 @@ object ClosedGroupsProtocolV2 {
val name = group.title
// Send the update to the group
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.RemoveMembers(removeMembersAsData)
- val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind)
+ val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
val isCurrentUserAdmin = admins.contains(userPublicKey)
@@ -205,7 +210,7 @@ object ClosedGroupsProtocolV2 {
// Notify the user
val infoType = GroupContext.Type.UPDATE
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
- insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID)
+ insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
}
}
@@ -218,13 +223,14 @@ object ClosedGroupsProtocolV2 {
val group = groupDB.getGroup(groupID).orNull()
val members = group.members.map { it.serialize() }.toSet()
val admins = group.admins.map { it.serialize() }
+ val sentTime = System.currentTimeMillis()
if (group == null) {
Log.d("Loki", "Can't leave nonexistent closed group.")
return@queue deferred.reject(Error.NoThread)
}
// Send the update to the group
val kind = ClosedGroupUpdateMessageSendJobV2.Kind.NameChange(newName)
- val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, kind)
+ val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, kind, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
// Update the group
@@ -232,7 +238,7 @@ object ClosedGroupsProtocolV2 {
// Notify the user
val infoType = GroupContext.Type.UPDATE
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
- insertOutgoingInfoMessage(context, groupID, infoType, newName, members, admins, threadID)
+ insertOutgoingInfoMessage(context, groupID, infoType, newName, members, admins, threadID, sentTime)
deferred.resolve(Unit)
}
return deferred.promise
@@ -272,6 +278,7 @@ object ClosedGroupsProtocolV2 {
Log.d("Loki", "Can't update nonexistent closed group.")
return@queue deferred.reject(Error.NoThread)
}
+ val sentTime = System.currentTimeMillis()
val oldMembers = group.members.map { it.serialize() }.toSet()
val newMembers = members.minus(oldMembers)
val membersAsData = members.map { Hex.fromStringCondensed(it) }
@@ -298,7 +305,7 @@ object ClosedGroupsProtocolV2 {
@Suppress("NAME_SHADOWING")
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.Update(name, membersAsData)
@Suppress("NAME_SHADOWING")
- val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, closedGroupUpdateKind)
+ val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, closedGroupUpdateKind, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
if (isUserLeaving) {
@@ -322,7 +329,7 @@ object ClosedGroupsProtocolV2 {
@Suppress("NAME_SHADOWING")
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
@Suppress("NAME_SHADOWING")
- val job = ClosedGroupUpdateMessageSendJobV2(member, closedGroupUpdateKind)
+ val job = ClosedGroupUpdateMessageSendJobV2(member, closedGroupUpdateKind, sentTime)
ApplicationContext.getInstance(context).jobManager.add(job)
}
}
@@ -335,7 +342,7 @@ object ClosedGroupsProtocolV2 {
// Notify the user
val infoType = if (isUserLeaving) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
- insertOutgoingInfoMessage(context, groupID, infoType, name, members, admins, threadID)
+ insertOutgoingInfoMessage(context, groupID, infoType, name, members, admins, threadID, sentTime)
deferred.resolve(Unit)
}
return deferred.promise
@@ -367,7 +374,7 @@ object ClosedGroupsProtocolV2 {
val ciphertext = SessionProtocolImpl(context).encrypt(plaintext, publicKey)
ClosedGroupUpdateMessageSendJobV2.KeyPairWrapper(publicKey, ciphertext)
}
- val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, ClosedGroupUpdateMessageSendJobV2.Kind.EncryptionKeyPair(wrappers))
+ val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, ClosedGroupUpdateMessageSendJobV2.Kind.EncryptionKeyPair(wrappers), System.currentTimeMillis())
job.setContext(context)
job.onRun() // Run the job immediately
// Store it * after * having sent out the message to the group
@@ -376,9 +383,9 @@ object ClosedGroupsProtocolV2 {
@JvmStatic
fun handleMessage(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
- if (!isValid(closedGroupUpdate, senderPublicKey)) { return }
+ if (!isValid(context, closedGroupUpdate, senderPublicKey, sentTimestamp)) { return }
when (closedGroupUpdate.type) {
- SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW -> handleNewClosedGroup(context, closedGroupUpdate, senderPublicKey)
+ SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW -> handleNewClosedGroup(context, closedGroupUpdate, senderPublicKey, sentTimestamp)
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBERS_REMOVED -> handleClosedGroupMembersRemoved(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBERS_ADDED -> handleClosedGroupMembersAdded(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
SignalServiceProtos.ClosedGroupUpdateV2.Type.NAME_CHANGE -> handleClosedGroupNameChange(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
@@ -391,7 +398,10 @@ object ClosedGroupsProtocolV2 {
}
}
- private fun isValid(closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, senderPublicKey: String): Boolean {
+ private fun isValid(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, senderPublicKey: String, sentTimestamp: Long): Boolean {
+ val record = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(sentTimestamp, senderPublicKey)
+ if (record != null) return false
+
return when (closedGroupUpdate.type) {
SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW -> {
(!closedGroupUpdate.publicKey.isEmpty && !closedGroupUpdate.name.isNullOrEmpty() && !(closedGroupUpdate.encryptionKeyPair.privateKey ?: ByteString.copyFrom(ByteArray(0))).isEmpty
@@ -413,7 +423,7 @@ object ClosedGroupsProtocolV2 {
}
}
- public fun handleNewClosedGroup(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, senderPublicKey: String) {
+ public fun handleNewClosedGroup(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, senderPublicKey: String, sentTimestamp: Long) {
// Prepare
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
@@ -426,7 +436,8 @@ object ClosedGroupsProtocolV2 {
// Create the group
val groupID = doubleEncodeGroupID(groupPublicKey)
val groupDB = DatabaseFactory.getGroupDatabase(context)
- if (groupDB.getGroup(groupID).orNull() != null) {
+ val prevGroup = groupDB.getGroup(groupID).orNull()
+ if (prevGroup != null) {
// Update the group
groupDB.updateTitle(groupID, name)
groupDB.updateMembers(groupID, members.map { Address.fromSerialized(it) })
@@ -440,8 +451,14 @@ object ClosedGroupsProtocolV2 {
// Store the encryption key pair
val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray().removing05PrefixIfNeeded()), DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
- // Notify the user
- insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
+ // Notify the user (if we didn't make the group)
+ if (userPublicKey != senderPublicKey) {
+ insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
+ } else if (prevGroup == null) {
+ // only notify if we created this group
+ val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
+ insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
+ }
// Notify the PN server
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
}
@@ -451,8 +468,8 @@ object ClosedGroupsProtocolV2 {
val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupID = doubleEncodeGroupID(groupPublicKey)
val group = groupDB.getGroup(groupID).orNull()
- if (group == null) {
- Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
+ if (group == null || !group.isActive) {
+ Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
return
}
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
@@ -491,16 +508,21 @@ object ClosedGroupsProtocolV2 {
val (contextType, signalType) =
if (senderLeft) GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT
else GroupContext.Type.UPDATE to SignalServiceGroup.Type.UPDATE
-
- insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins)
+ if (userPublicKey == senderPublicKey) {
+ val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
+ insertOutgoingInfoMessage(context, groupID, contextType, name, members, admins, threadID, sentTimestamp)
+ } else {
+ insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins)
+ }
}
fun handleClosedGroupMembersAdded(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
+ val userPublicKey = TextSecurePreferences.getLocalNumber(context)
val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupID = doubleEncodeGroupID(groupPublicKey)
val group = groupDB.getGroup(groupID).orNull()
- if (group == null) {
- Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
+ if (group == null || !group.isActive) {
+ Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
return
}
if (!isValidGroupUpdate(group, sentTimestamp, senderPublicKey)) {
@@ -517,16 +539,22 @@ object ClosedGroupsProtocolV2 {
val newMembers = members + updateMembers
groupDB.updateMembers(groupID, newMembers.map { Address.fromSerialized(it) })
- insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
+ if (userPublicKey == senderPublicKey) {
+ val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
+ insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
+ } else {
+ insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
+ }
}
fun handleClosedGroupNameChange(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
// Check that the sender is a member of the group (before the update)
+ val userPublicKey = TextSecurePreferences.getLocalNumber(context)
val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupID = doubleEncodeGroupID(groupPublicKey)
val group = groupDB.getGroup(groupID).orNull()
- if (group == null) {
- Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
+ if (group == null || !group.isActive) {
+ Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
return
}
// Check common group update logic
@@ -538,21 +566,23 @@ object ClosedGroupsProtocolV2 {
val name = closedGroupUpdate.name
groupDB.updateTitle(groupID, name)
- insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
+ if (userPublicKey == senderPublicKey) {
+ val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
+ insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
+ } else {
+ insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
+ }
}
private fun handleClosedGroupMemberLeft(context: Context, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
// Check the user leaving isn't us, will already be handled
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
- if (senderPublicKey == userPublicKey) {
- return
- }
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupID = doubleEncodeGroupID(groupPublicKey)
val group = groupDB.getGroup(groupID).orNull()
- if (group == null) {
- Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
+ if (group == null || !group.isActive) {
+ Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
return
}
val name = group.title
@@ -575,7 +605,12 @@ object ClosedGroupsProtocolV2 {
generateAndSendNewEncryptionKeyPair(context, groupPublicKey, updatedMemberList)
}
}
- insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.QUIT, SignalServiceGroup.Type.QUIT, name, members, admins)
+ if (userPublicKey == senderPublicKey) {
+ val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
+ insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
+ } else {
+ insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
+ }
}
private fun handleClosedGroupUpdate(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
@@ -588,8 +623,8 @@ object ClosedGroupsProtocolV2 {
val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupID = doubleEncodeGroupID(groupPublicKey)
val group = groupDB.getGroup(groupID).orNull()
- if (group == null) {
- Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
+ if (group == null || !group.isActive) {
+ Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
return
}
val oldMembers = group.members.map { it.serialize() }
@@ -623,7 +658,13 @@ object ClosedGroupsProtocolV2 {
val wasSenderRemoved = !members.contains(senderPublicKey)
val type0 = if (wasSenderRemoved) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
val type1 = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.UPDATE
- insertIncomingInfoMessage(context, senderPublicKey, groupID, type0, type1, name, members, group.admins.map { it.toString() })
+ val admins = group.admins.map { it.toString() }
+ if (userPublicKey == senderPublicKey) {
+ val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
+ insertOutgoingInfoMessage(context, groupID, type0, name, members, admins, threadID, sentTimestamp)
+ } else {
+ insertIncomingInfoMessage(context, senderPublicKey, groupID, type0, type1, name, members, admins)
+ }
}
private fun disableLocalGroupAndUnsubscribe(context: Context, apiDB: LokiAPIDatabase, groupPublicKey: String, groupDB: GroupDatabase, groupID: String, userPublicKey: String) {
@@ -699,7 +740,8 @@ object ClosedGroupsProtocolV2 {
}
private fun insertOutgoingInfoMessage(context: Context, groupID: String, type: GroupContext.Type, name: String,
- members: Collection, admins: Collection, threadID: Long) {
+ members: Collection, admins: Collection, threadID: Long,
+ sentTime: Long) {
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
val groupContextBuilder = GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
@@ -707,9 +749,9 @@ object ClosedGroupsProtocolV2 {
.setName(name)
.addAllMembers(members)
.addAllAdmins(admins)
- val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, System.currentTimeMillis(), 0, null, listOf(), listOf())
+ val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, 0, null, listOf(), listOf())
val mmsDB = DatabaseFactory.getMmsDatabase(context)
- val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null)
+ val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null, sentTime)
mmsDB.markAsSent(infoMessageID, true)
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java
index d34a14909c..4b1fbfb257 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java
@@ -40,7 +40,6 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
@NonNull GroupContext group,
@Nullable final Attachment avatar,
- long sentTimeMillis,
long expireIn,
@Nullable QuoteModel quote,
@NonNull List contacts,
diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java b/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java
index 263b9276bf..be28948a3c 100644
--- a/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java
+++ b/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java
@@ -1052,7 +1052,6 @@ public class SignalServiceMessageSender {
Optional syncTarget)
throws IOException, UntrustedIdentityException
{
- if (recipient.getNumber().equals(userPublicKey) && !syncTarget.isPresent()) { return SendMessageResult.success(recipient, false, false); }
final SettableFuture>[] future = { new SettableFuture() };
OutgoingPushMessageList messages = getSessionProtocolEncryptedMessage(recipient, timestamp, content);
// Loki - Remove this when we have shared sender keys