mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
fix: closed groups info messages work now
This commit is contained in:
parent
fd0596f9ea
commit
34fab9681c
@ -184,7 +184,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void create(@NonNull String groupId, @Nullable String title, @NonNull List<Address> members,
|
public long create(@NonNull String groupId, @Nullable String title, @NonNull List<Address> members,
|
||||||
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay, @Nullable List<Address> admins)
|
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay, @Nullable List<Address> admins)
|
||||||
{
|
{
|
||||||
Collections.sort(members);
|
Collections.sort(members);
|
||||||
@ -211,7 +211,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
contentValues.put(ADMINS, Address.Companion.toSerializedList(admins, ','));
|
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.applyCached(Address.Companion.fromSerialized(groupId), recipient -> {
|
||||||
recipient.setName(title);
|
recipient.setName(title);
|
||||||
@ -220,6 +220,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
});
|
});
|
||||||
|
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
|
return threadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean delete(@NonNull String groupId) {
|
public boolean delete(@NonNull String groupId) {
|
||||||
|
@ -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);
|
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
|
||||||
|
|
||||||
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null)) {
|
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null)) {
|
||||||
@ -96,8 +96,8 @@ public class MmsSmsDatabase extends Database {
|
|||||||
MessageRecord messageRecord;
|
MessageRecord messageRecord;
|
||||||
|
|
||||||
while ((messageRecord = reader.getNext()) != null) {
|
while ((messageRecord = reader.getNext()) != null) {
|
||||||
if ((Util.isOwnNumber(context, author.serialize()) && messageRecord.isOutgoing()) ||
|
if ((Util.isOwnNumber(context, serializedAuthor) && messageRecord.isOutgoing()) ||
|
||||||
(!Util.isOwnNumber(context, author.serialize()) && messageRecord.getIndividualRecipient().getAddress().equals(author)))
|
(!Util.isOwnNumber(context, serializedAuthor) && messageRecord.getIndividualRecipient().getAddress().equals(serializedAuthor)))
|
||||||
{
|
{
|
||||||
return messageRecord;
|
return messageRecord;
|
||||||
}
|
}
|
||||||
@ -107,6 +107,10 @@ public class MmsSmsDatabase extends Database {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable MessageRecord getMessageFor(long timestamp, Address author) {
|
||||||
|
return getMessageFor(timestamp, author.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
public Cursor getConversation(long threadId, long offset, long limit) {
|
public Cursor getConversation(long threadId, long offset, long limit) {
|
||||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
||||||
|
@ -8,7 +8,6 @@ import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
|||||||
import org.session.libsession.messaging.jobs.Job
|
import org.session.libsession.messaging.jobs.Job
|
||||||
import org.session.libsession.messaging.jobs.JobQueue
|
import org.session.libsession.messaging.jobs.JobQueue
|
||||||
import org.session.libsession.messaging.jobs.MessageSendJob
|
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.Attachment
|
||||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||||
import org.session.libsession.messaging.opengroups.OpenGroup
|
import org.session.libsession.messaging.opengroups.OpenGroup
|
||||||
@ -351,7 +350,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, System.currentTimeMillis(), 0, null, listOf(), listOf())
|
val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, 0, null, listOf(), listOf())
|
||||||
val mmsDB = DatabaseFactory.getMmsDatabase(context)
|
val mmsDB = DatabaseFactory.getMmsDatabase(context)
|
||||||
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null)
|
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null)
|
||||||
mmsDB.markAsSent(infoMessageID, true)
|
mmsDB.markAsSent(infoMessageID, true)
|
||||||
|
@ -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);
|
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);
|
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
|
||||||
|
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId);
|
||||||
|
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
|||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
||||||
import org.session.libsignal.utilities.logging.Log;
|
import org.session.libsignal.utilities.logging.Log;
|
||||||
@ -269,9 +270,16 @@ public class GroupMessageProcessor {
|
|||||||
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||||
Address address = Address.Companion.fromExternal(context, GroupUtil.getEncodedId(group));
|
Address address = Address.Companion.fromExternal(context, GroupUtil.getEncodedId(group));
|
||||||
Recipient recipient = Recipient.from(context, address, false);
|
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 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);
|
mmsDatabase.markAsSent(messageId, true);
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ import org.session.libsession.utilities.TextSecurePreferences;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.contactshare.ContactModelMapper;
|
import org.thoughtcrime.securesms.contactshare.ContactModelMapper;
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
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.SessionManagementProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
|
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.loki.utilities.MentionManagerUtilities;
|
||||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
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.IncomingEndSessionMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
|
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
|
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||||
import org.session.libsignal.utilities.Hex;
|
import org.session.libsignal.utilities.Hex;
|
||||||
import org.session.libsignal.libsignal.InvalidMessageException;
|
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,
|
private void handleGroupMessage(@NonNull SignalServiceContent content,
|
||||||
@NonNull SignalServiceDataMessage message,
|
@NonNull SignalServiceDataMessage message,
|
||||||
@NonNull Optional<Long> smsMessageId)
|
@NonNull Optional<Long> smsMessageId)
|
||||||
@ -484,83 +454,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSynchronizeStickerPackOperation(@NonNull List<StickerPackOperationMessage> 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,
|
public void handleMediaMessage(@NonNull SignalServiceContent content,
|
||||||
@NonNull SignalServiceDataMessage message,
|
@NonNull SignalServiceDataMessage message,
|
||||||
@NonNull Optional<Long> smsMessageId,
|
@NonNull Optional<Long> smsMessageId,
|
||||||
@ -1429,6 +1322,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
return true;
|
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);
|
Recipient sender = Recipient.from(context, Address.Companion.fromSerialized(content.getSender()), false);
|
||||||
|
|
||||||
if (content.getDeviceLink().isPresent()) {
|
if (content.getDeviceLink().isPresent()) {
|
||||||
|
@ -29,7 +29,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long? {
|
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
|
return if (message != null) getServerID(message.getId()) else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import org.session.libsignal.utilities.Hex
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
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 {
|
sealed class Kind {
|
||||||
class New(val publicKey: ByteArray, val name: String, val encryptionKeyPair: ECKeyPair, val members: Collection<ByteArray>, val admins: Collection<ByteArray>) : Kind()
|
class New(val publicKey: ByteArray, val name: String, val encryptionKeyPair: ECKeyPair, val members: Collection<ByteArray>, val admins: Collection<ByteArray>) : 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)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setQueue(KEY)
|
.setQueue(KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
.setMaxAttempts(20)
|
.setMaxAttempts(20)
|
||||||
.build(),
|
.build(),
|
||||||
destination,
|
destination,
|
||||||
kind)
|
kind,
|
||||||
|
sentTime)
|
||||||
|
|
||||||
override fun getFactoryKey(): String { return KEY }
|
override fun getFactoryKey(): String { return KEY }
|
||||||
|
|
||||||
override fun serialize(): Data {
|
override fun serialize(): Data {
|
||||||
val builder = Data.Builder()
|
val builder = Data.Builder()
|
||||||
builder.putString("destination", destination)
|
builder.putString("destination", destination)
|
||||||
|
builder.putLong("sentTime", sentTime)
|
||||||
when (kind) {
|
when (kind) {
|
||||||
is Kind.New -> {
|
is Kind.New -> {
|
||||||
builder.putString("kind", "New")
|
builder.putString("kind", "New")
|
||||||
@ -124,6 +126,7 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete
|
|||||||
override fun create(parameters: Parameters, data: Data): ClosedGroupUpdateMessageSendJobV2 {
|
override fun create(parameters: Parameters, data: Data): ClosedGroupUpdateMessageSendJobV2 {
|
||||||
val destination = data.getString("destination")
|
val destination = data.getString("destination")
|
||||||
val rawKind = data.getString("kind")
|
val rawKind = data.getString("kind")
|
||||||
|
val sentTime = data.getLong("sentTime")
|
||||||
val kind: Kind
|
val kind: Kind
|
||||||
when (rawKind) {
|
when (rawKind) {
|
||||||
"New" -> {
|
"New" -> {
|
||||||
@ -162,7 +165,7 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete
|
|||||||
}
|
}
|
||||||
else -> throw Exception("Invalid closed group update message kind: $rawKind.")
|
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 {
|
try {
|
||||||
// isClosedGroup can always be false as it's only used in the context of legacy closed groups
|
// isClosedGroup can always be false as it's only used in the context of legacy closed groups
|
||||||
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
|
||||||
Date().time, serializedContentMessage, false, ttl, false,
|
sentTime, serializedContentMessage, false, ttl, false,
|
||||||
true, false, false, Optional.absent())
|
true, false, false, Optional.absent())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.")
|
Log.d("Loki", "Failed to send closed group update message to: $destination due to error: $e.")
|
||||||
|
@ -285,7 +285,7 @@ object ClosedGroupsProtocol {
|
|||||||
.setName(name)
|
.setName(name)
|
||||||
.addAllMembers(members)
|
.addAllMembers(members)
|
||||||
.addAllAdmins(admins)
|
.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 mmsDB = DatabaseFactory.getMmsDatabase(context)
|
||||||
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null)
|
val infoMessageID = mmsDB.insertMessageOutbox(infoMessage, threadID, false, null)
|
||||||
mmsDB.markAsSent(infoMessageID, true)
|
mmsDB.markAsSent(infoMessageID, true)
|
||||||
@ -324,6 +324,6 @@ object ClosedGroupsProtocol {
|
|||||||
.setId(decodedGroupId)
|
.setId(decodedGroupId)
|
||||||
.setType(GroupContext.Type.QUIT)
|
.setType(GroupContext.Type.QUIT)
|
||||||
.build()
|
.build()
|
||||||
return OutgoingGroupMediaMessage(groupRecipient, groupContext, null, System.currentTimeMillis(), 0, null, emptyList(), emptyList())
|
return OutgoingGroupMediaMessage(groupRecipient, groupContext, null, 0, null, emptyList(), emptyList())
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -58,6 +58,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||||
// Generate the group's public key
|
// Generate the group's public key
|
||||||
val groupPublicKey = Curve.generateKeyPair().hexEncodedPublicKey // Includes the "05" prefix
|
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
|
// Generate the key pair that'll be used for encryption and decryption
|
||||||
val encryptionKeyPair = Curve.generateKeyPair()
|
val encryptionKeyPair = Curve.generateKeyPair()
|
||||||
// Create the group
|
// Create the group
|
||||||
@ -68,19 +69,20 @@ object ClosedGroupsProtocolV2 {
|
|||||||
null, null, LinkedList(admins.map { Address.fromSerialized(it!!) }))
|
null, null, LinkedList(admins.map { Address.fromSerialized(it!!) }))
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
|
||||||
// Send a closed group update message to all members individually
|
// 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
|
// Add the group to the user's set of public keys to poll for
|
||||||
apiDB.addClosedGroupPublicKey(groupPublicKey)
|
apiDB.addClosedGroupPublicKey(groupPublicKey)
|
||||||
// Store the encryption key pair
|
// Store the encryption key pair
|
||||||
apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
|
apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
|
||||||
// Notify the user
|
// Notify the user
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
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
|
// Notify the PN server
|
||||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||||
// Fulfill the promise
|
// Fulfill the promise
|
||||||
@ -102,13 +104,14 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val updatedMembers = group.members.map { it.serialize() }.toSet() - userPublicKey
|
val updatedMembers = group.members.map { it.serialize() }.toSet() - userPublicKey
|
||||||
val admins = group.admins.map { it.serialize() }
|
val admins = group.admins.map { it.serialize() }
|
||||||
val name = group.title
|
val name = group.title
|
||||||
|
val sentTime = System.currentTimeMillis()
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
Log.d("Loki", "Can't leave nonexistent closed group.")
|
Log.d("Loki", "Can't leave nonexistent closed group.")
|
||||||
return@queue deferred.reject(Error.NoThread)
|
return@queue deferred.reject(Error.NoThread)
|
||||||
}
|
}
|
||||||
// Send the update to the group
|
// Send the update to the group
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, ClosedGroupUpdateMessageSendJobV2.Kind.Leave)
|
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, ClosedGroupUpdateMessageSendJobV2.Kind.Leave, sentTime)
|
||||||
job.setContext(context)
|
job.setContext(context)
|
||||||
job.onRun() // Run the job immediately
|
job.onRun() // Run the job immediately
|
||||||
// Remove the group private key and unsubscribe from PNs
|
// Remove the group private key and unsubscribe from PNs
|
||||||
@ -116,7 +119,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
// Notify the user
|
// Notify the user
|
||||||
val infoType = GroupContext.Type.QUIT
|
val infoType = GroupContext.Type.QUIT
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
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)
|
deferred.resolve(Unit)
|
||||||
}
|
}
|
||||||
return deferred.promise
|
return deferred.promise
|
||||||
@ -140,6 +143,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val newMembersAsData = membersToAdd.map { Hex.fromStringCondensed(it) }
|
val newMembersAsData = membersToAdd.map { Hex.fromStringCondensed(it) }
|
||||||
val admins = group.admins.map { it.serialize() }
|
val admins = group.admins.map { it.serialize() }
|
||||||
val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
|
val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
|
||||||
|
val sentTime = System.currentTimeMillis()
|
||||||
val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
|
val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
|
||||||
if (encryptionKeyPair == null) {
|
if (encryptionKeyPair == null) {
|
||||||
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
|
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
|
||||||
@ -148,7 +152,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val name = group.title
|
val name = group.title
|
||||||
// Send the update to the group
|
// Send the update to the group
|
||||||
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.AddMembers(newMembersAsData)
|
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.AddMembers(newMembersAsData)
|
||||||
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind)
|
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
|
||||||
job.setContext(context)
|
job.setContext(context)
|
||||||
job.onRun() // Run the job immediately
|
job.onRun() // Run the job immediately
|
||||||
// Send closed group update messages to any new members individually
|
// Send closed group update messages to any new members individually
|
||||||
@ -156,13 +160,13 @@ object ClosedGroupsProtocolV2 {
|
|||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val closedGroupNewKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
|
val closedGroupNewKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val newMemberJob = ClosedGroupUpdateMessageSendJobV2(member, closedGroupNewKind)
|
val newMemberJob = ClosedGroupUpdateMessageSendJobV2(member, closedGroupNewKind, sentTime)
|
||||||
ApplicationContext.getInstance(context).jobManager.add(newMemberJob)
|
ApplicationContext.getInstance(context).jobManager.add(newMemberJob)
|
||||||
}
|
}
|
||||||
// Notify the user
|
// Notify the user
|
||||||
val infoType = GroupContext.Type.UPDATE
|
val infoType = GroupContext.Type.UPDATE
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
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) })
|
groupDB.updateMembers(groupID, updatedMembers.map { Address.fromSerialized(it) })
|
||||||
val removeMembersAsData = membersToRemove.map { Hex.fromStringCondensed(it) }
|
val removeMembersAsData = membersToRemove.map { Hex.fromStringCondensed(it) }
|
||||||
val admins = group.admins.map { it.serialize() }
|
val admins = group.admins.map { it.serialize() }
|
||||||
|
val sentTime = System.currentTimeMillis()
|
||||||
val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
|
val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
|
||||||
if (encryptionKeyPair == null) {
|
if (encryptionKeyPair == null) {
|
||||||
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
|
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
|
||||||
@ -195,7 +200,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val name = group.title
|
val name = group.title
|
||||||
// Send the update to the group
|
// Send the update to the group
|
||||||
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.RemoveMembers(removeMembersAsData)
|
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.RemoveMembers(removeMembersAsData)
|
||||||
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind)
|
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
|
||||||
job.setContext(context)
|
job.setContext(context)
|
||||||
job.onRun() // Run the job immediately
|
job.onRun() // Run the job immediately
|
||||||
val isCurrentUserAdmin = admins.contains(userPublicKey)
|
val isCurrentUserAdmin = admins.contains(userPublicKey)
|
||||||
@ -205,7 +210,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
// Notify the user
|
// Notify the user
|
||||||
val infoType = GroupContext.Type.UPDATE
|
val infoType = GroupContext.Type.UPDATE
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
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 group = groupDB.getGroup(groupID).orNull()
|
||||||
val members = group.members.map { it.serialize() }.toSet()
|
val members = group.members.map { it.serialize() }.toSet()
|
||||||
val admins = group.admins.map { it.serialize() }
|
val admins = group.admins.map { it.serialize() }
|
||||||
|
val sentTime = System.currentTimeMillis()
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
Log.d("Loki", "Can't leave nonexistent closed group.")
|
Log.d("Loki", "Can't leave nonexistent closed group.")
|
||||||
return@queue deferred.reject(Error.NoThread)
|
return@queue deferred.reject(Error.NoThread)
|
||||||
}
|
}
|
||||||
// Send the update to the group
|
// Send the update to the group
|
||||||
val kind = ClosedGroupUpdateMessageSendJobV2.Kind.NameChange(newName)
|
val kind = ClosedGroupUpdateMessageSendJobV2.Kind.NameChange(newName)
|
||||||
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, kind)
|
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, kind, sentTime)
|
||||||
job.setContext(context)
|
job.setContext(context)
|
||||||
job.onRun() // Run the job immediately
|
job.onRun() // Run the job immediately
|
||||||
// Update the group
|
// Update the group
|
||||||
@ -232,7 +238,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
// Notify the user
|
// Notify the user
|
||||||
val infoType = GroupContext.Type.UPDATE
|
val infoType = GroupContext.Type.UPDATE
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
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)
|
deferred.resolve(Unit)
|
||||||
}
|
}
|
||||||
return deferred.promise
|
return deferred.promise
|
||||||
@ -272,6 +278,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
Log.d("Loki", "Can't update nonexistent closed group.")
|
Log.d("Loki", "Can't update nonexistent closed group.")
|
||||||
return@queue deferred.reject(Error.NoThread)
|
return@queue deferred.reject(Error.NoThread)
|
||||||
}
|
}
|
||||||
|
val sentTime = System.currentTimeMillis()
|
||||||
val oldMembers = group.members.map { it.serialize() }.toSet()
|
val oldMembers = group.members.map { it.serialize() }.toSet()
|
||||||
val newMembers = members.minus(oldMembers)
|
val newMembers = members.minus(oldMembers)
|
||||||
val membersAsData = members.map { Hex.fromStringCondensed(it) }
|
val membersAsData = members.map { Hex.fromStringCondensed(it) }
|
||||||
@ -298,7 +305,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.Update(name, membersAsData)
|
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.Update(name, membersAsData)
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, closedGroupUpdateKind)
|
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, closedGroupUpdateKind, sentTime)
|
||||||
job.setContext(context)
|
job.setContext(context)
|
||||||
job.onRun() // Run the job immediately
|
job.onRun() // Run the job immediately
|
||||||
if (isUserLeaving) {
|
if (isUserLeaving) {
|
||||||
@ -322,7 +329,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
|
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val job = ClosedGroupUpdateMessageSendJobV2(member, closedGroupUpdateKind)
|
val job = ClosedGroupUpdateMessageSendJobV2(member, closedGroupUpdateKind, sentTime)
|
||||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,7 +342,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
// Notify the user
|
// Notify the user
|
||||||
val infoType = if (isUserLeaving) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
|
val infoType = if (isUserLeaving) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
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)
|
deferred.resolve(Unit)
|
||||||
}
|
}
|
||||||
return deferred.promise
|
return deferred.promise
|
||||||
@ -367,7 +374,7 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val ciphertext = SessionProtocolImpl(context).encrypt(plaintext, publicKey)
|
val ciphertext = SessionProtocolImpl(context).encrypt(plaintext, publicKey)
|
||||||
ClosedGroupUpdateMessageSendJobV2.KeyPairWrapper(publicKey, ciphertext)
|
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.setContext(context)
|
||||||
job.onRun() // Run the job immediately
|
job.onRun() // Run the job immediately
|
||||||
// Store it * after * having sent out the message to the group
|
// Store it * after * having sent out the message to the group
|
||||||
@ -376,9 +383,9 @@ object ClosedGroupsProtocolV2 {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun handleMessage(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
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) {
|
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_REMOVED -> handleClosedGroupMembersRemoved(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBERS_ADDED -> handleClosedGroupMembersAdded(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)
|
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) {
|
return when (closedGroupUpdate.type) {
|
||||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW -> {
|
SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW -> {
|
||||||
(!closedGroupUpdate.publicKey.isEmpty && !closedGroupUpdate.name.isNullOrEmpty() && !(closedGroupUpdate.encryptionKeyPair.privateKey ?: ByteString.copyFrom(ByteArray(0))).isEmpty
|
(!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
|
// Prepare
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
||||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||||
@ -426,7 +436,8 @@ object ClosedGroupsProtocolV2 {
|
|||||||
// Create the group
|
// Create the group
|
||||||
val groupID = doubleEncodeGroupID(groupPublicKey)
|
val groupID = doubleEncodeGroupID(groupPublicKey)
|
||||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||||
if (groupDB.getGroup(groupID).orNull() != null) {
|
val prevGroup = groupDB.getGroup(groupID).orNull()
|
||||||
|
if (prevGroup != null) {
|
||||||
// Update the group
|
// Update the group
|
||||||
groupDB.updateTitle(groupID, name)
|
groupDB.updateTitle(groupID, name)
|
||||||
groupDB.updateMembers(groupID, members.map { Address.fromSerialized(it) })
|
groupDB.updateMembers(groupID, members.map { Address.fromSerialized(it) })
|
||||||
@ -440,8 +451,14 @@ object ClosedGroupsProtocolV2 {
|
|||||||
// Store the encryption key pair
|
// Store the encryption key pair
|
||||||
val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray().removing05PrefixIfNeeded()), DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
|
val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray().removing05PrefixIfNeeded()), DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
|
||||||
apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
|
apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
|
||||||
// Notify the user
|
// 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)
|
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
|
// Notify the PN server
|
||||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||||
}
|
}
|
||||||
@ -451,8 +468,8 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||||
val groupID = doubleEncodeGroupID(groupPublicKey)
|
val groupID = doubleEncodeGroupID(groupPublicKey)
|
||||||
val group = groupDB.getGroup(groupID).orNull()
|
val group = groupDB.getGroup(groupID).orNull()
|
||||||
if (group == null) {
|
if (group == null || !group.isActive) {
|
||||||
Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
|
Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
||||||
@ -491,16 +508,21 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val (contextType, signalType) =
|
val (contextType, signalType) =
|
||||||
if (senderLeft) GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT
|
if (senderLeft) GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT
|
||||||
else GroupContext.Type.UPDATE to SignalServiceGroup.Type.UPDATE
|
else GroupContext.Type.UPDATE to SignalServiceGroup.Type.UPDATE
|
||||||
|
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)
|
insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun handleClosedGroupMembersAdded(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
fun handleClosedGroupMembersAdded(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||||
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||||
val groupID = doubleEncodeGroupID(groupPublicKey)
|
val groupID = doubleEncodeGroupID(groupPublicKey)
|
||||||
val group = groupDB.getGroup(groupID).orNull()
|
val group = groupDB.getGroup(groupID).orNull()
|
||||||
if (group == null) {
|
if (group == null || !group.isActive) {
|
||||||
Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
|
Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!isValidGroupUpdate(group, sentTimestamp, senderPublicKey)) {
|
if (!isValidGroupUpdate(group, sentTimestamp, senderPublicKey)) {
|
||||||
@ -517,16 +539,22 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val newMembers = members + updateMembers
|
val newMembers = members + updateMembers
|
||||||
groupDB.updateMembers(groupID, newMembers.map { Address.fromSerialized(it) })
|
groupDB.updateMembers(groupID, newMembers.map { Address.fromSerialized(it) })
|
||||||
|
|
||||||
|
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)
|
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) {
|
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)
|
// Check that the sender is a member of the group (before the update)
|
||||||
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||||
val groupID = doubleEncodeGroupID(groupPublicKey)
|
val groupID = doubleEncodeGroupID(groupPublicKey)
|
||||||
val group = groupDB.getGroup(groupID).orNull()
|
val group = groupDB.getGroup(groupID).orNull()
|
||||||
if (group == null) {
|
if (group == null || !group.isActive) {
|
||||||
Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
|
Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check common group update logic
|
// Check common group update logic
|
||||||
@ -538,21 +566,23 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val name = closedGroupUpdate.name
|
val name = closedGroupUpdate.name
|
||||||
groupDB.updateTitle(groupID, name)
|
groupDB.updateTitle(groupID, name)
|
||||||
|
|
||||||
|
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)
|
insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleClosedGroupMemberLeft(context: Context, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
private fun handleClosedGroupMemberLeft(context: Context, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||||
// Check the user leaving isn't us, will already be handled
|
// Check the user leaving isn't us, will already be handled
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
||||||
if (senderPublicKey == userPublicKey) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||||
val groupID = doubleEncodeGroupID(groupPublicKey)
|
val groupID = doubleEncodeGroupID(groupPublicKey)
|
||||||
val group = groupDB.getGroup(groupID).orNull()
|
val group = groupDB.getGroup(groupID).orNull()
|
||||||
if (group == null) {
|
if (group == null || !group.isActive) {
|
||||||
Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
|
Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val name = group.title
|
val name = group.title
|
||||||
@ -575,7 +605,12 @@ object ClosedGroupsProtocolV2 {
|
|||||||
generateAndSendNewEncryptionKeyPair(context, groupPublicKey, updatedMemberList)
|
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) {
|
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 groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||||
val groupID = doubleEncodeGroupID(groupPublicKey)
|
val groupID = doubleEncodeGroupID(groupPublicKey)
|
||||||
val group = groupDB.getGroup(groupID).orNull()
|
val group = groupDB.getGroup(groupID).orNull()
|
||||||
if (group == null) {
|
if (group == null || !group.isActive) {
|
||||||
Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
|
Log.d("Loki", "Ignoring closed group info message for nonexistent or inactive group.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val oldMembers = group.members.map { it.serialize() }
|
val oldMembers = group.members.map { it.serialize() }
|
||||||
@ -623,7 +658,13 @@ object ClosedGroupsProtocolV2 {
|
|||||||
val wasSenderRemoved = !members.contains(senderPublicKey)
|
val wasSenderRemoved = !members.contains(senderPublicKey)
|
||||||
val type0 = if (wasSenderRemoved) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
|
val type0 = if (wasSenderRemoved) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
|
||||||
val type1 = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.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) {
|
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,
|
private fun insertOutgoingInfoMessage(context: Context, groupID: String, type: GroupContext.Type, name: String,
|
||||||
members: Collection<String>, admins: Collection<String>, threadID: Long) {
|
members: Collection<String>, admins: Collection<String>, threadID: Long,
|
||||||
|
sentTime: Long) {
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
|
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
|
||||||
val groupContextBuilder = GroupContext.newBuilder()
|
val groupContextBuilder = GroupContext.newBuilder()
|
||||||
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
|
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
|
||||||
@ -707,9 +749,9 @@ object ClosedGroupsProtocolV2 {
|
|||||||
.setName(name)
|
.setName(name)
|
||||||
.addAllMembers(members)
|
.addAllMembers(members)
|
||||||
.addAllAdmins(admins)
|
.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 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)
|
mmsDB.markAsSent(infoMessageID, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
|||||||
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
|
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
|
||||||
@NonNull GroupContext group,
|
@NonNull GroupContext group,
|
||||||
@Nullable final Attachment avatar,
|
@Nullable final Attachment avatar,
|
||||||
long sentTimeMillis,
|
|
||||||
long expireIn,
|
long expireIn,
|
||||||
@Nullable QuoteModel quote,
|
@Nullable QuoteModel quote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
|
@ -1052,7 +1052,6 @@ public class SignalServiceMessageSender {
|
|||||||
Optional<String> syncTarget)
|
Optional<String> syncTarget)
|
||||||
throws IOException, UntrustedIdentityException
|
throws IOException, UntrustedIdentityException
|
||||||
{
|
{
|
||||||
if (recipient.getNumber().equals(userPublicKey) && !syncTarget.isPresent()) { return SendMessageResult.success(recipient, false, false); }
|
|
||||||
final SettableFuture<?>[] future = { new SettableFuture<Unit>() };
|
final SettableFuture<?>[] future = { new SettableFuture<Unit>() };
|
||||||
OutgoingPushMessageList messages = getSessionProtocolEncryptedMessage(recipient, timestamp, content);
|
OutgoingPushMessageList messages = getSessionProtocolEncryptedMessage(recipient, timestamp, content);
|
||||||
// Loki - Remove this when we have shared sender keys
|
// Loki - Remove this when we have shared sender keys
|
||||||
|
Loading…
Reference in New Issue
Block a user