mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 10:05:15 +00:00
redesign of group update messages management
This commit is contained in:
parent
df0ca11ec5
commit
9cdcdc43a6
@ -89,7 +89,6 @@ import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate;
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage;
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
|
||||
import org.session.libsession.messaging.threads.DistributionTypes;
|
||||
import org.session.libsession.messaging.utilities.UpdateMessageBuilder;
|
||||
import org.session.libsession.utilities.GroupUtil;
|
||||
import org.session.libsession.utilities.MediaTypes;
|
||||
import org.session.libsignal.libsignal.InvalidMessageException;
|
||||
@ -159,7 +158,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.ImageSlide;
|
||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.session.libsession.messaging.messages.signal.OutgoingExpirationUpdateMessage;
|
||||
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage;
|
||||
import org.session.libsession.messaging.messages.signal.OutgoingSecureMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.QuoteId;
|
||||
@ -176,6 +174,7 @@ import org.session.libsession.messaging.threads.recipients.RecipientModifiedList
|
||||
import org.thoughtcrime.securesms.search.model.MessageResult;
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender;
|
||||
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
@ -807,16 +806,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient, expirationTime);
|
||||
ExpirationTimerUpdate message = new ExpirationTimerUpdate(null, expirationTime);
|
||||
ExpirationTimerUpdate message = new ExpirationTimerUpdate(expirationTime);
|
||||
message.setRecipient(recipient.getAddress().serialize()); // we need the recipient in ExpiringMessageManager.insertOutgoingExpirationTimerMessage
|
||||
message.setSentTimestamp(System.currentTimeMillis());
|
||||
String displayedMessage = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(getApplicationContext(), expirationTime, null, false);
|
||||
OutgoingExpirationUpdateMessage outgoingMessage = OutgoingExpirationUpdateMessage.from(message, recipient, displayedMessage);
|
||||
try {
|
||||
message.setId(DatabaseFactory.getMmsDatabase(ConversationActivity.this).insertMessageOutbox(outgoingMessage, getAllocatedThreadId(ConversationActivity.this), false, null));
|
||||
MessageSender.send(message, recipient.getAddress());
|
||||
} catch (MmsException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
ExpiringMessageManager expiringMessageManager = ApplicationContext.getInstance(getApplicationContext()).getExpiringMessageManager();
|
||||
expiringMessageManager.setExpirationTimer(message);
|
||||
MessageSender.send(message, recipient.getAddress());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -515,7 +515,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
|
||||
return new OutgoingGroupMediaMessage(recipient, body, attachments, timestamp, 0, quote, contacts, previews);
|
||||
return new OutgoingGroupMediaMessage(recipient, body, null, attachments, timestamp, 0, quote, contacts, previews);
|
||||
} else if (Types.isExpirationTimerUpdate(outboxType)) {
|
||||
return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
|
||||
}
|
||||
@ -689,8 +689,14 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
{
|
||||
if (threadId == -1) {
|
||||
if(retrieved.isGroup()) {
|
||||
ByteString decodedGroupId = ((OutgoingGroupMediaMessage)retrieved).getGroupContext().getId();
|
||||
String groupId = GroupUtil.doubleEncodeGroupID(decodedGroupId.toByteArray());
|
||||
String decodedGroupId = ((OutgoingGroupMediaMessage)retrieved).getGroupId();
|
||||
String groupId;
|
||||
try {
|
||||
groupId = GroupUtil.doubleEncodeGroupID(decodedGroupId);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Couldn't encrypt group ID");
|
||||
throw new MmsException(e);
|
||||
}
|
||||
Recipient group = Recipient.from(context, Address.fromSerialized(groupId), false);
|
||||
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(group);
|
||||
} else {
|
||||
@ -746,8 +752,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT;
|
||||
|
||||
if (message.isGroup()) {
|
||||
if (((OutgoingGroupMediaMessage)message).isGroupUpdate()) type |= Types.GROUP_UPDATE_BIT;
|
||||
else if (((OutgoingGroupMediaMessage)message).isGroupQuit()) type |= Types.GROUP_QUIT_BIT;
|
||||
type |= Types.GROUP_UPDATE_BIT;
|
||||
}
|
||||
|
||||
if (message.isExpirationUpdate()) {
|
||||
|
@ -347,8 +347,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
type |= Types.SECURE_MESSAGE_BIT;
|
||||
} else if (message.isGroup()) {
|
||||
type |= Types.SECURE_MESSAGE_BIT;
|
||||
if (((IncomingGroupMessage)message).isUpdate()) type |= Types.GROUP_UPDATE_BIT;
|
||||
else if (((IncomingGroupMessage)message).isQuit()) type |= Types.GROUP_QUIT_BIT;
|
||||
type |= Types.GROUP_UPDATE_BIT;
|
||||
}
|
||||
|
||||
if (message.isPush()) type |= Types.PUSH_MESSAGE_BIT;
|
||||
|
@ -400,31 +400,22 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
DatabaseFactory.getGroupDatabase(context).updateMembers(groupID, members)
|
||||
}
|
||||
|
||||
override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type0: SignalServiceProtos.GroupContext.Type, type1: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long) {
|
||||
val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder()
|
||||
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
|
||||
.setType(type0)
|
||||
.setName(name)
|
||||
.addAllMembers(members)
|
||||
.addAllAdmins(admins)
|
||||
val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
|
||||
override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long) {
|
||||
val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
|
||||
val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), 0, true)
|
||||
val messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, senderPublicKey)
|
||||
val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), messageBody)
|
||||
val infoMessage = IncomingGroupMessage(m, groupID, messageBody)
|
||||
val smsDB = DatabaseFactory.getSmsDatabase(context)
|
||||
smsDB.insertMessageInbox(infoMessage)
|
||||
}
|
||||
|
||||
override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceProtos.GroupContext.Type, name: String, members: Collection<String>, admins: Collection<String>, threadID: Long, sentTimestamp: Long) {
|
||||
override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, threadID: Long, sentTimestamp: Long) {
|
||||
val userPublicKey = getUserPublicKey()
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
|
||||
val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder()
|
||||
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
|
||||
.setType(type)
|
||||
.setName(name)
|
||||
.addAllMembers(members)
|
||||
.addAllAdmins(admins)
|
||||
val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, sentTimestamp, 0, false, null, listOf(), listOf())
|
||||
|
||||
val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
|
||||
val messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, null, true)
|
||||
val infoMessage = OutgoingGroupMediaMessage(recipient, messageBody, groupID, null, sentTimestamp, 0, false, null, listOf(), listOf())
|
||||
val mmsDB = DatabaseFactory.getMmsDatabase(context)
|
||||
val mmsSmsDB = DatabaseFactory.getMmsSmsDatabase(context)
|
||||
if (mmsSmsDB.getMessageFor(sentTimestamp,userPublicKey) != null) return
|
||||
|
@ -24,6 +24,8 @@ import android.text.style.RelativeSizeSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
|
||||
import network.loki.messenger.R;
|
||||
|
||||
import org.session.libsession.messaging.utilities.UpdateMessageBuilder;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.session.libsession.database.documents.IdentityKeyMismatch;
|
||||
|
@ -9,7 +9,6 @@ import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||
import org.session.libsignal.service.api.messages.SignalServiceGroup
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext
|
||||
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
|
||||
import org.session.libsignal.service.loki.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
@ -26,7 +25,6 @@ import org.session.libsession.messaging.sending_receiving.sendEncryptionKeyPair
|
||||
import org.session.libsession.messaging.threads.Address
|
||||
import org.session.libsession.messaging.threads.GroupRecord
|
||||
import org.session.libsession.messaging.threads.recipients.Recipient
|
||||
import org.session.libsession.messaging.utilities.UpdateMessageBuilder
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
|
||||
@ -105,11 +103,11 @@ object ClosedGroupsProtocolV2 {
|
||||
apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
|
||||
// Notify the user (if we didn't make the group)
|
||||
if (userPublicKey != senderPublicKey) {
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.NEW_GROUP, name, members, admins, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp)
|
||||
} else if (prevGroup == null) {
|
||||
// only notify if we created this group
|
||||
val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
|
||||
}
|
||||
// Notify the PN server
|
||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||
@ -157,14 +155,14 @@ object ClosedGroupsProtocolV2 {
|
||||
MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey, newMembers)
|
||||
}
|
||||
}
|
||||
val (contextType, signalType) =
|
||||
if (senderLeft) GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT
|
||||
else GroupContext.Type.UPDATE to SignalServiceGroup.Type.MEMBER_REMOVED
|
||||
val type =
|
||||
if (senderLeft) SignalServiceGroup.Type.QUIT
|
||||
else SignalServiceGroup.Type.UPDATE
|
||||
if (userPublicKey == senderPublicKey) {
|
||||
val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, contextType, name, members, admins, threadID, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, type, name, members, admins, threadID, sentTimestamp)
|
||||
} else {
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, members, admins, sentTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,9 +190,9 @@ object ClosedGroupsProtocolV2 {
|
||||
groupDB.updateMembers(groupID, newMembers.map { Address.fromSerialized(it) })
|
||||
if (userPublicKey == senderPublicKey) {
|
||||
val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
|
||||
} else {
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.MEMBER_ADDED, name, members, admins, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp)
|
||||
}
|
||||
if (userPublicKey in admins) {
|
||||
// send current encryption key to the latest added members
|
||||
@ -231,9 +229,9 @@ object ClosedGroupsProtocolV2 {
|
||||
// Notify the user
|
||||
if (userPublicKey == senderPublicKey) {
|
||||
val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, threadID, sentTimestamp)
|
||||
} else {
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,9 +271,9 @@ object ClosedGroupsProtocolV2 {
|
||||
// Notify user
|
||||
if (userLeft) {
|
||||
val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.QUIT, name, members, admins, threadID, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, threadID, sentTimestamp)
|
||||
} else {
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.QUIT, SignalServiceGroup.Type.QUIT, name, members, admins, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, sentTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,14 +384,13 @@ object ClosedGroupsProtocolV2 {
|
||||
}
|
||||
// Notify the user
|
||||
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
|
||||
val type = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.UPDATE
|
||||
val admins = group.admins.map { it.toString() }
|
||||
if (userPublicKey == senderPublicKey) {
|
||||
val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, type0, name, members, admins, threadID, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, type, name, members, admins, threadID, sentTimestamp)
|
||||
} else {
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, type0, type1, name, members, admins, sentTimestamp)
|
||||
DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, members, admins, sentTimestamp)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
@ -78,8 +78,8 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
|
||||
String senderPublicKey = message.getSender();
|
||||
|
||||
// Notify the user
|
||||
if (userPublicKey.equals(senderPublicKey)) {
|
||||
// sender is a linked device
|
||||
if (senderPublicKey == null || userPublicKey.equals(senderPublicKey)) {
|
||||
// sender is self or a linked device
|
||||
insertOutgoingExpirationTimerMessage(message);
|
||||
} else {
|
||||
insertIncomingExpirationTimerMessage(message);
|
||||
@ -97,9 +97,10 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
|
||||
Long sentTimestamp = message.getSentTimestamp();
|
||||
String groupId = message.getGroupPublicKey();
|
||||
int duration = message.getDuration();
|
||||
String messageBody = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, duration, senderPublicKey, false);
|
||||
|
||||
Optional<SignalServiceGroup> groupInfo = Optional.absent();
|
||||
Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : senderPublicKey);
|
||||
Address address = Address.fromSerialized(senderPublicKey);
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
|
||||
// if the sender is blocked, we don't display the update, except if it's in a closed group
|
||||
@ -117,7 +118,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, sentTimestamp, -1,
|
||||
duration * 1000L, true,
|
||||
false,
|
||||
Optional.absent(),
|
||||
Optional.of(messageBody),
|
||||
groupInfo,
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
@ -137,27 +138,25 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
|
||||
private void insertOutgoingExpirationTimerMessage(ExpirationTimerUpdate message) {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
|
||||
String senderPublicKey = message.getSender();
|
||||
Long sentTimestamp = message.getSentTimestamp();
|
||||
String groupId = message.getGroupPublicKey();
|
||||
int duration = message.getDuration();
|
||||
String messageBody = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, duration, null, true);
|
||||
|
||||
Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : senderPublicKey);
|
||||
Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : message.getRecipient());
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
|
||||
try {
|
||||
if (groupId != null) {
|
||||
// conversation is a closed group
|
||||
GroupContext groupContext = SignalServiceProtos.GroupContext.newBuilder()
|
||||
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupId))).build();
|
||||
OutgoingGroupMediaMessage infoMessage = new OutgoingGroupMediaMessage(recipient, groupContext, null, sentTimestamp, duration * 1000L, true, null, Collections.emptyList(), Collections.emptyList());
|
||||
OutgoingGroupMediaMessage infoMessage = new OutgoingGroupMediaMessage(recipient, messageBody, groupId, null, sentTimestamp, duration * 1000L, true, null, Collections.emptyList(), Collections.emptyList());
|
||||
database.insertSecureDecryptedMessageOutbox(infoMessage, -1, sentTimestamp);
|
||||
// we need the group ID as recipient for setExpireMessages below
|
||||
recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(groupId)), false);
|
||||
} else {
|
||||
// conversation is a 1-1
|
||||
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipient,
|
||||
null,
|
||||
messageBody,
|
||||
Collections.emptyList(),
|
||||
message.getSentTimestamp(),
|
||||
-1,
|
||||
|
@ -117,9 +117,9 @@ interface StorageProtocol {
|
||||
fun removeClosedGroupPublicKey(groupPublicKey: String)
|
||||
fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String)
|
||||
fun removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String)
|
||||
fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type0: SignalServiceProtos.GroupContext.Type, type1: SignalServiceGroup.Type,
|
||||
fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type,
|
||||
name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long)
|
||||
fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceProtos.GroupContext.Type, name: String,
|
||||
fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String,
|
||||
members: Collection<String>, admins: Collection<String>, threadID: Long, sentTimestamp: Long)
|
||||
fun isClosedGroup(publicKey: String): Boolean
|
||||
fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList<ECKeyPair>
|
||||
|
@ -33,6 +33,11 @@ class ExpirationTimerUpdate() : ControlMessage() {
|
||||
this.duration = duration
|
||||
}
|
||||
|
||||
internal constructor(duration: Int) : this() {
|
||||
this.syncTarget = null
|
||||
this.duration = duration
|
||||
}
|
||||
|
||||
// validation
|
||||
override fun isValid(): Boolean {
|
||||
if (!super.isValid()) return false
|
||||
|
@ -4,11 +4,11 @@ import static org.session.libsignal.service.internal.push.SignalServiceProtos.Gr
|
||||
|
||||
public class IncomingGroupMessage extends IncomingTextMessage {
|
||||
|
||||
private final GroupContext groupContext;
|
||||
private final String groupID;
|
||||
|
||||
public IncomingGroupMessage(IncomingTextMessage base, GroupContext groupContext, String body) {
|
||||
public IncomingGroupMessage(IncomingTextMessage base, String groupID, String body) {
|
||||
super(base, body);
|
||||
this.groupContext = groupContext;
|
||||
this.groupID = groupID;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -16,12 +16,4 @@ public class IncomingGroupMessage extends IncomingTextMessage {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isUpdate() {
|
||||
return groupContext.getType().getNumber() == GroupContext.Type.UPDATE_VALUE;
|
||||
}
|
||||
|
||||
public boolean isQuit() {
|
||||
return groupContext.getType().getNumber() == GroupContext.Type.QUIT_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,17 +8,18 @@ import org.session.libsession.messaging.threads.recipients.Recipient;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
// TODO this class could be deleted if its usage in MmsDatabase.getOutgoingMessage is replaced by something elsex
|
||||
public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage {
|
||||
|
||||
public OutgoingExpirationUpdateMessage(Recipient recipient, String body, long sentTimeMillis, long expiresIn) {
|
||||
public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) {
|
||||
super(recipient, "", new LinkedList<Attachment>(), sentTimeMillis,
|
||||
DistributionTypes.CONVERSATION, expiresIn, true, null, Collections.emptyList(),
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
public static OutgoingExpirationUpdateMessage from(ExpirationTimerUpdate message,
|
||||
Recipient recipient, String body) {
|
||||
return new OutgoingExpirationUpdateMessage(recipient, body, message.getSentTimestamp(), message.getDuration() * 1000);
|
||||
Recipient recipient) {
|
||||
return new OutgoingExpirationUpdateMessage(recipient, message.getSentTimestamp(), message.getDuration() * 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,10 +19,11 @@ import java.util.List;
|
||||
|
||||
public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
||||
|
||||
private final GroupContext group;
|
||||
private final String groupID;
|
||||
|
||||
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
|
||||
@NonNull String encodedGroupContext,
|
||||
@NonNull String body,
|
||||
@Nullable String groupId,
|
||||
@NonNull List<Attachment> avatar,
|
||||
long sentTimeMillis,
|
||||
long expiresIn,
|
||||
@ -31,30 +32,15 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
||||
@NonNull List<LinkPreview> previews)
|
||||
throws IOException
|
||||
{
|
||||
super(recipient, encodedGroupContext, avatar, sentTimeMillis,
|
||||
super(recipient, body, avatar, sentTimeMillis,
|
||||
DistributionTypes.CONVERSATION, expiresIn, false, quote, contacts, previews);
|
||||
|
||||
this.group = GroupContext.parseFrom(Base64.decode(encodedGroupContext));
|
||||
this.groupID = groupId;
|
||||
}
|
||||
|
||||
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
|
||||
@NonNull GroupContext group,
|
||||
@Nullable final Attachment avatar,
|
||||
long expireIn,
|
||||
@Nullable QuoteModel quote,
|
||||
@NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> previews)
|
||||
{
|
||||
super(recipient, Base64.encodeBytes(group.toByteArray()),
|
||||
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
|
||||
System.currentTimeMillis(),
|
||||
DistributionTypes.CONVERSATION, expireIn, false, quote, contacts, previews);
|
||||
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
|
||||
@NonNull GroupContext group,
|
||||
@NonNull String body,
|
||||
@Nullable String groupId,
|
||||
@Nullable final Attachment avatar,
|
||||
long sentTime,
|
||||
long expireIn,
|
||||
@ -63,12 +49,12 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
||||
@NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> previews)
|
||||
{
|
||||
super(recipient, Base64.encodeBytes(group.toByteArray()),
|
||||
super(recipient, body,
|
||||
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
|
||||
sentTime,
|
||||
DistributionTypes.CONVERSATION, expireIn, expirationUpdate, quote, contacts, previews);
|
||||
|
||||
this.group = group;
|
||||
this.groupID = groupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,15 +62,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isGroupUpdate() {
|
||||
return group.getType().getNumber() == GroupContext.Type.UPDATE_VALUE;
|
||||
}
|
||||
|
||||
public boolean isGroupQuit() {
|
||||
return group.getType().getNumber() == GroupContext.Type.QUIT_VALUE;
|
||||
}
|
||||
|
||||
public GroupContext getGroupContext() {
|
||||
return group;
|
||||
public String getGroupId() {
|
||||
return groupID;
|
||||
}
|
||||
}
|
||||
|
@ -243,8 +243,15 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
|
||||
} else {
|
||||
storage.createGroup(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }),
|
||||
null, null, LinkedList(admins.map { Address.fromSerialized(it) }), formationTimestamp)
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
// Notify the user
|
||||
storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.NEW_GROUP, name, members, admins, sentTimestamp)
|
||||
if (userPublicKey == sender) {
|
||||
// sender is a linked device
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, threadID, sentTimestamp)
|
||||
} else {
|
||||
storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, sentTimestamp)
|
||||
}
|
||||
}
|
||||
storage.setProfileSharing(Address.fromSerialized(groupID), true)
|
||||
// Add the group to the user's set of public keys to poll for
|
||||
@ -304,9 +311,8 @@ private fun MessageReceiver.handleClosedGroupUpdated(message: ClosedGroupControl
|
||||
}
|
||||
// Notify the user
|
||||
val wasSenderRemoved = !members.contains(senderPublicKey)
|
||||
val type0 = if (wasSenderRemoved) SignalServiceProtos.GroupContext.Type.QUIT else SignalServiceProtos.GroupContext.Type.UPDATE
|
||||
val type1 = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.UPDATE
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type0, type1, name, members, group.admins.map { it.toString() }, message.sentTimestamp!!)
|
||||
val type = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.MEMBER_REMOVED
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, members, group.admins.map { it.toString() }, message.sentTimestamp!!)
|
||||
}
|
||||
|
||||
private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGroupControlMessage) {
|
||||
@ -378,9 +384,9 @@ private fun MessageReceiver.handleClosedGroupNameChanged(message: ClosedGroupCon
|
||||
if (userPublicKey == senderPublicKey) {
|
||||
// sender is a linked device
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, name, members, admins, threadID, message.sentTimestamp!!)
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, threadID, message.sentTimestamp!!)
|
||||
} else {
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, message.sentTimestamp!!)
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, message.sentTimestamp!!)
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,9 +419,9 @@ private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupCo
|
||||
if (userPublicKey == senderPublicKey) {
|
||||
// sender is a linked device
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, name, members, admins, threadID, message.sentTimestamp!!)
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.MEMBER_ADDED, name, updateMembers, admins, threadID, message.sentTimestamp!!)
|
||||
} else {
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.MEMBER_ADDED, name, members, admins, message.sentTimestamp!!)
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.MEMBER_ADDED, name, updateMembers, admins, message.sentTimestamp!!)
|
||||
}
|
||||
if (userPublicKey in admins) {
|
||||
// send current encryption key to the latest added members
|
||||
@ -477,17 +483,16 @@ private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroup
|
||||
MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey, newMembers)
|
||||
}
|
||||
}
|
||||
val (contextType, signalType) =
|
||||
if (senderLeft) SignalServiceProtos.GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT
|
||||
else SignalServiceProtos.GroupContext.Type.UPDATE to SignalServiceGroup.Type.MEMBER_REMOVED
|
||||
val type = if (senderLeft) SignalServiceGroup.Type.QUIT
|
||||
else SignalServiceGroup.Type.MEMBER_REMOVED
|
||||
|
||||
// Notify the user
|
||||
if (userPublicKey == senderPublicKey) {
|
||||
// sender is a linked device
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, contextType, name, members, admins, threadID, message.sentTimestamp!!)
|
||||
storage.insertOutgoingInfoMessage(context, groupID, type, name, updateMembers, admins, threadID, message.sentTimestamp!!)
|
||||
} else {
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins, message.sentTimestamp!!)
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, updateMembers, admins, message.sentTimestamp!!)
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,9 +538,9 @@ private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupCont
|
||||
if (userLeft) {
|
||||
//sender is a linked device
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceProtos.GroupContext.Type.QUIT, name, members, admins, threadID, message.sentTimestamp!!)
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, threadID, message.sentTimestamp!!)
|
||||
} else {
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.QUIT, SignalServiceGroup.Type.QUIT, name, members, admins, message.sentTimestamp!!)
|
||||
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, message.sentTimestamp!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.libsignal.ecc.Curve
|
||||
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||
import org.session.libsignal.libsignal.util.guava.Optional
|
||||
import org.session.libsignal.service.api.messages.SignalServiceGroup
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||
import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
|
||||
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
|
||||
@ -60,7 +61,7 @@ fun MessageSender.create(name: String, members: Collection<String>): Promise<Str
|
||||
storage.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey)
|
||||
// Notify the user
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, name, members, admins, threadID, sentTime)
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, threadID, sentTime)
|
||||
// Notify the PN server
|
||||
PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||
// Fulfill the promise
|
||||
@ -107,7 +108,7 @@ fun MessageSender.setName(groupPublicKey: String, newName: String) {
|
||||
// Update the group
|
||||
storage.updateTitle(groupID, newName)
|
||||
// Notify the user
|
||||
val infoType = SignalServiceProtos.GroupContext.Type.UPDATE
|
||||
val infoType = SignalServiceGroup.Type.NAME_CHANGE
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, infoType, newName, members, admins, threadID, sentTime)
|
||||
}
|
||||
@ -150,9 +151,9 @@ fun MessageSender.addMembers(groupPublicKey: String, membersToAdd: List<String>)
|
||||
send(closedGroupControlMessage, Address.fromSerialized(member))
|
||||
}
|
||||
// Notify the user
|
||||
val infoType = SignalServiceProtos.GroupContext.Type.UPDATE
|
||||
val infoType = SignalServiceGroup.Type.MEMBER_ADDED
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
|
||||
storage.insertOutgoingInfoMessage(context, groupID, infoType, name, membersToAdd, admins, threadID, sentTime)
|
||||
}
|
||||
|
||||
fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List<String>) {
|
||||
@ -189,9 +190,9 @@ fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List<St
|
||||
generateAndSendNewEncryptionKeyPair(groupPublicKey, updatedMembers)
|
||||
}
|
||||
// Notify the user
|
||||
val infoType = SignalServiceProtos.GroupContext.Type.UPDATE
|
||||
val infoType = SignalServiceGroup.Type.MEMBER_REMOVED
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
|
||||
storage.insertOutgoingInfoMessage(context, groupID, infoType, name, membersToRemove, admins, threadID, sentTime)
|
||||
}
|
||||
|
||||
fun MessageSender.leave(groupPublicKey: String, notifyUser: Boolean = true): Promise<Unit, Exception> {
|
||||
@ -212,7 +213,7 @@ fun MessageSender.leave(groupPublicKey: String, notifyUser: Boolean = true): Pro
|
||||
storage.setActive(groupID, false)
|
||||
sendNonDurably(closedGroupControlMessage, Address.fromSerialized(groupID)).success {
|
||||
// Notify the user
|
||||
val infoType = SignalServiceProtos.GroupContext.Type.QUIT
|
||||
val infoType = SignalServiceGroup.Type.QUIT
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
if (notifyUser) {
|
||||
storage.insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
|
||||
|
@ -19,7 +19,7 @@ object UpdateMessageBuilder {
|
||||
} else { sender }
|
||||
|
||||
when (updateType) {
|
||||
SignalServiceGroup.Type.NEW_GROUP -> {
|
||||
SignalServiceGroup.Type.CREATION -> {
|
||||
message = if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_you_created_a_new_group)
|
||||
} else {
|
||||
@ -79,24 +79,29 @@ object UpdateMessageBuilder {
|
||||
return message
|
||||
}
|
||||
|
||||
fun buildExpirationTimerMessage(context: Context, duration: Int, sender: String? = null, isOutgoing: Boolean = false): String {
|
||||
val seconds = (duration!! / 1000)
|
||||
fun buildExpirationTimerMessage(context: Context, duration: Long, sender: String? = null, isOutgoing: Boolean = false): String {
|
||||
if (!isOutgoing && sender == null) return ""
|
||||
val senderName: String? = if (!isOutgoing) {
|
||||
MessagingConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender
|
||||
} else { sender }
|
||||
return if (seconds <= 0) {
|
||||
return if (duration <= 0) {
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_you_disabled_disappearing_messages)
|
||||
else context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, senderName)
|
||||
} else {
|
||||
val time = ExpirationUtil.getExpirationDisplayValue(context, seconds)
|
||||
val time = ExpirationUtil.getExpirationDisplayValue(context, duration.toInt())
|
||||
if (isOutgoing)context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time)
|
||||
else context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, senderName, time)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO one this is merged in
|
||||
fun buildDataExtractionMessage(): String {
|
||||
return ""
|
||||
}
|
||||
|
||||
/*TODO retro compatibilite old update messages (MessageRecord)
|
||||
ThreadRecord to display specific messages? (hard unless we can get the incoming / outgoing messages)
|
||||
Clean code (comments, logs...)
|
||||
Delete OutgoingExpirationUpdateMessage (check how its used in MmsDatabase l.520 to save messages and how to do the same when getting messages from db without breaking it)
|
||||
*/
|
||||
}
|
@ -38,7 +38,7 @@ public class SignalServiceGroup {
|
||||
DELIVER,
|
||||
QUIT,
|
||||
REQUEST_INFO,
|
||||
NEW_GROUP,
|
||||
CREATION,
|
||||
NAME_CHANGE,
|
||||
MEMBER_ADDED,
|
||||
MEMBER_REMOVED
|
||||
|
Loading…
Reference in New Issue
Block a user