mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-11 17:27:42 +00:00
WIP: clean up signal protocol
This commit is contained in:
@@ -27,6 +27,7 @@ import org.session.libsignal.metadata.ProtocolLegacyMessageException;
|
||||
import org.session.libsignal.metadata.ProtocolNoSessionException;
|
||||
import org.session.libsignal.metadata.ProtocolUntrustedIdentityException;
|
||||
import org.session.libsignal.metadata.SelfSendException;
|
||||
import org.session.libsignal.service.api.crypto.SignalServiceCipher;
|
||||
import org.session.libsignal.service.loki.api.crypto.SessionProtocol;
|
||||
import org.session.libsignal.utilities.PromiseUtilities;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
@@ -108,12 +109,8 @@ import org.session.libsignal.service.api.messages.SignalServiceEnvelope;
|
||||
import org.session.libsignal.service.api.messages.SignalServiceGroup;
|
||||
import org.session.libsignal.service.api.messages.SignalServiceReceiptMessage;
|
||||
import org.session.libsignal.service.api.messages.SignalServiceTypingMessage;
|
||||
import org.session.libsignal.service.api.messages.multidevice.SentTranscriptMessage;
|
||||
import org.session.libsignal.service.api.messages.multidevice.StickerPackOperationMessage;
|
||||
import org.session.libsignal.service.api.messages.shared.SharedContact;
|
||||
import org.session.libsignal.service.api.push.SignalServiceAddress;
|
||||
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI;
|
||||
import org.session.libsignal.service.loki.crypto.LokiServiceCipher;
|
||||
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager;
|
||||
import org.session.libsignal.service.loki.utilities.PublicKeyValidation;
|
||||
|
||||
@@ -248,7 +245,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
SessionResetProtocol sessionResetProtocol = new SessionResetImplementation(context);
|
||||
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
|
||||
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(context);
|
||||
LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, new SessionProtocolImpl(context), sessionResetProtocol, apiDB, UnidentifiedAccessUtil.getCertificateValidator());
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore, sessionResetProtocol, new SessionProtocolImpl(context), apiDB);
|
||||
|
||||
SignalServiceContent content = cipher.decrypt(envelope);
|
||||
|
||||
@@ -265,14 +262,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
MultiDeviceProtocol.handleConfigurationMessage(context, content.configurationMessageProto.get(), content.getSender(), content.getTimestamp());
|
||||
} else if (content.getDataMessage().isPresent()) {
|
||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent() || message.getSticker().isPresent();
|
||||
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent();
|
||||
|
||||
if (message.getClosedGroupUpdateV2().isPresent()) {
|
||||
ClosedGroupsProtocolV2.handleMessage(context, message.getClosedGroupUpdateV2().get(), message.getTimestamp(), envelope.getSource(), content.getSender());
|
||||
if (message.getClosedGroupControlMessage().isPresent()) {
|
||||
ClosedGroupsProtocolV2.handleMessage(context, message.getClosedGroupControlMessage().get(), message.getTimestamp(), envelope.getSource(), content.getSender());
|
||||
}
|
||||
if (message.isEndSession()) {
|
||||
handleEndSessionMessage(content, smsMessageId);
|
||||
} else if (message.isGroupUpdate()) {
|
||||
if (message.isGroupUpdate()) {
|
||||
handleGroupMessage(content, message, smsMessageId);
|
||||
} else if (message.isExpirationUpdate()) {
|
||||
handleExpirationUpdate(content, message, smsMessageId);
|
||||
@@ -293,8 +288,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
if (SessionMetaProtocol.shouldSendDeliveryReceipt(message, Address.fromSerialized(content.getSender()))) {
|
||||
handleNeedsDeliveryReceipt(content, message);
|
||||
}
|
||||
} else if (content.getSyncMessage().isPresent()) {
|
||||
throw new UnsupportedOperationException("Device link operations are not supported!");
|
||||
} else if (content.getReceiptMessage().isPresent()) {
|
||||
SignalServiceReceiptMessage message = content.getReceiptMessage().get();
|
||||
|
||||
@@ -311,37 +304,16 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
// if (envelope.isPreKeySignalMessage()) {
|
||||
// ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob());
|
||||
// }
|
||||
} catch (ProtocolInvalidVersionException e) {
|
||||
Log.w(TAG, e);
|
||||
handleInvalidVersionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolInvalidMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
if (!isPushNotification) { // This can be triggered if a PN encrypted with an old session comes in after the user performed a session reset
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId, e);
|
||||
}
|
||||
} catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
|
||||
}catch (StorageFailedException e) {
|
||||
Log.w(TAG, e);
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId, e);
|
||||
} catch (StorageFailedException e) {
|
||||
} catch (InvalidMetadataMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId, e);
|
||||
} catch (ProtocolNoSessionException e) {
|
||||
Log.w(TAG, e);
|
||||
handleNoSessionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolLegacyMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleLegacyMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolDuplicateMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleDuplicateMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (InvalidMetadataVersionException | InvalidMetadataMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (SelfSendException e) {
|
||||
Log.i(TAG, "Dropping UD message from self.");
|
||||
} catch (IOException e) {
|
||||
Log.i(TAG, "IOException during message decryption.");
|
||||
} catch (SessionProtocol.Exception e) {
|
||||
Log.i(TAG, "Couldn't handle message due to error: " + e.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +389,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
|
||||
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
@@ -448,7 +419,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getQuote());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getSharedContacts());
|
||||
Optional<List<LinkPreview>> linkPreviews = getLinkPreviews(message.getPreviews(), message.getBody().or(""));
|
||||
Optional<Attachment> sticker = getStickerAttachment(message.getSticker());
|
||||
|
||||
Address masterAddress = masterRecipient.getAddress();
|
||||
|
||||
@@ -523,7 +493,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
} else {
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterAddress, message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, false, content.isNeedsReceipt(), message.getBody(), message.getGroupInfo(), message.getAttachments(),
|
||||
quote, sharedContacts, linkPreviews, sticker);
|
||||
quote, sharedContacts, linkPreviews);
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
database.beginTransaction();
|
||||
|
||||
@@ -594,110 +564,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private long handleSynchronizeSentExpirationUpdate(@NonNull SentTranscriptMessage message) throws MmsException {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getSyncMessageMasterDestination(message);
|
||||
|
||||
OutgoingExpirationUpdateMessage expirationUpdateMessage = new OutgoingExpirationUpdateMessage(recipient,
|
||||
message.getTimestamp(),
|
||||
message.getMessage().getExpiresInSeconds() * 1000L);
|
||||
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||
long messageId = database.insertMessageOutbox(expirationUpdateMessage, threadId, false, null);
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, message.getMessage().getExpiresInSeconds());
|
||||
|
||||
return threadId;
|
||||
}
|
||||
|
||||
public long handleSynchronizeSentMediaMessage(@NonNull SentTranscriptMessage message)
|
||||
throws MmsException
|
||||
{
|
||||
if (SessionMetaProtocol.shouldIgnoreMessage(message.getTimestamp())) { return -1; }
|
||||
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipients = getSyncMessageMasterDestination(message);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getMessage().getQuote());
|
||||
Optional<Attachment> sticker = getStickerAttachment(message.getMessage().getSticker());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getMessage().getSharedContacts());
|
||||
Optional<List<LinkPreview>> previews = getLinkPreviews(message.getMessage().getPreviews(), message.getMessage().getBody().or(""));
|
||||
List<Attachment> syncAttachments = PointerAttachment.forPointers(message.getMessage().getAttachments());
|
||||
|
||||
if (sticker.isPresent()) {
|
||||
syncAttachments.add(sticker.get());
|
||||
}
|
||||
|
||||
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipients, message.getMessage().getBody().orNull(),
|
||||
syncAttachments,
|
||||
message.getTimestamp(), -1,
|
||||
message.getMessage().getExpiresInSeconds() * 1000,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
|
||||
sharedContacts.or(Collections.emptyList()),
|
||||
previews.or(Collections.emptyList()),
|
||||
Collections.emptyList(), Collections.emptyList());
|
||||
|
||||
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
|
||||
|
||||
if (recipients.getExpireMessages() != message.getMessage().getExpiresInSeconds()) {
|
||||
handleSynchronizeSentExpirationUpdate(message);
|
||||
}
|
||||
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipients);
|
||||
|
||||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
long messageId = database.insertMessageOutbox(mediaMessage, threadId, false, null);
|
||||
if (message.messageServerID >= 0) { DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageId, message.messageServerID); }
|
||||
|
||||
if (recipients.getAddress().isGroup()) {
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipients.getAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient member : members) {
|
||||
receiptDatabase.setUnidentified(member.getAddress(), messageId, message.isUnidentified(member.getAddress().serialize()));
|
||||
}
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipients.getAddress().serialize()));
|
||||
|
||||
List<DatabaseAttachment> allAttachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(messageId);
|
||||
List<DatabaseAttachment> stickerAttachments = Stream.of(allAttachments).filter(Attachment::isSticker).toList();
|
||||
List<DatabaseAttachment> attachments = Stream.of(allAttachments).filterNot(Attachment::isSticker).toList();
|
||||
|
||||
forceStickerDownloadIfNecessary(stickerAttachments);
|
||||
|
||||
for (DatabaseAttachment attachment : attachments) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(messageId, attachment.getAttachmentId(), false));
|
||||
}
|
||||
|
||||
if (message.getMessage().getExpiresInSeconds() > 0) {
|
||||
database.markExpireStarted(messageId, message.getExpirationStartTimestamp());
|
||||
ApplicationContext.getInstance(context)
|
||||
.getExpiringMessageManager()
|
||||
.scheduleDeletion(messageId, true,
|
||||
message.getExpirationStartTimestamp(),
|
||||
message.getMessage().getExpiresInSeconds() * 1000L);
|
||||
}
|
||||
|
||||
if (recipients.isLocalNumber()) {
|
||||
SyncMessageId id = new SyncMessageId(recipients.getAddress(), message.getTimestamp());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
return threadId;
|
||||
}
|
||||
|
||||
public void handleTextMessage(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message,
|
||||
@NonNull Optional<Long> smsMessageId,
|
||||
@@ -824,86 +690,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
public long handleSynchronizeSentTextMessage(@NonNull SentTranscriptMessage message)
|
||||
throws MmsException
|
||||
{
|
||||
if (SessionMetaProtocol.shouldIgnoreMessage(message.getTimestamp())) { return -1; }
|
||||
|
||||
Recipient recipient = getSyncMessageMasterDestination(message);
|
||||
String body = message.getMessage().getBody().or("");
|
||||
long expiresInMillis = message.getMessage().getExpiresInSeconds() * 1000L;
|
||||
|
||||
// Ignore the message if it has no body
|
||||
if (body.isEmpty()) { return -1; }
|
||||
|
||||
if (recipient.getExpireMessages() != message.getMessage().getExpiresInSeconds()) {
|
||||
handleSynchronizeSentExpirationUpdate(message);
|
||||
}
|
||||
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||
boolean isGroup = recipient.getAddress().isGroup();
|
||||
|
||||
MessagingDatabase database;
|
||||
long messageId;
|
||||
|
||||
if (isGroup) {
|
||||
OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient, new SlideDeck(), body, message.getMessage().getTimestamp(), -1, expiresInMillis, ThreadDatabase.DistributionTypes.DEFAULT, null, Collections.emptyList(), Collections.emptyList());
|
||||
outgoingMediaMessage = new OutgoingSecureMediaMessage(outgoingMediaMessage);
|
||||
|
||||
messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, null,message.getTimestamp());
|
||||
if (message.messageServerID >= 0) { DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageId, message.messageServerID); }
|
||||
|
||||
database = DatabaseFactory.getMmsDatabase(context);
|
||||
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient member : members) {
|
||||
receiptDatabase.setUnidentified(member.getAddress(), messageId, message.isUnidentified(member.getAddress().serialize()));
|
||||
}
|
||||
} else {
|
||||
OutgoingTextMessage outgoingTextMessage = new OutgoingEncryptedMessage(recipient, body, expiresInMillis);
|
||||
|
||||
messageId = DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoingTextMessage, false, message.getTimestamp(), null);
|
||||
database = DatabaseFactory.getSmsDatabase(context);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipient.getAddress().serialize()));
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
|
||||
if (expiresInMillis > 0) {
|
||||
database.markExpireStarted(messageId, message.getExpirationStartTimestamp());
|
||||
ApplicationContext.getInstance(context)
|
||||
.getExpiringMessageManager()
|
||||
.scheduleDeletion(messageId, isGroup, message.getExpirationStartTimestamp(), expiresInMillis);
|
||||
}
|
||||
|
||||
if (recipient.isLocalNumber()) {
|
||||
SyncMessageId id = new SyncMessageId(recipient.getAddress(), message.getTimestamp());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
return threadId;
|
||||
}
|
||||
|
||||
private void handleInvalidVersionMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
|
||||
if (!smsMessageId.isPresent()) {
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsInvalidVersionKeyExchange(insertResult.get().getMessageId());
|
||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
} else {
|
||||
smsDatabase.markAsInvalidVersionKeyExchange(smsMessageId.get());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCorruptMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId, @NonNull Throwable e)
|
||||
{
|
||||
@@ -1059,17 +845,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
long threadId;
|
||||
|
||||
if (typingMessage.getGroupId().isPresent()) {
|
||||
// Typing messages should only apply to closed groups, thus we use `getEncodedId`
|
||||
Address groupAddress = Address.fromSerialized(GroupUtil.getEncodedClosedGroupID(typingMessage.getGroupId().get()));
|
||||
Recipient groupRecipient = Recipient.from(context, groupAddress, false);
|
||||
|
||||
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(groupRecipient);
|
||||
} else {
|
||||
// See if we need to redirect the message
|
||||
author = getMessageMasterDestination(content.getSender());
|
||||
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(author);
|
||||
}
|
||||
author = getMessageMasterDestination(content.getSender());
|
||||
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(author);
|
||||
|
||||
if (threadId <= 0) {
|
||||
Log.w(TAG, "Couldn't find a matching thread for a typing message.");
|
||||
@@ -1211,28 +988,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
return database.insertMessageInbox(textMessage);
|
||||
}
|
||||
|
||||
private Recipient getSyncMessageDestination(SentTranscriptMessage message) {
|
||||
if (message.getMessage().isGroupMessage()) {
|
||||
return Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get())), false);
|
||||
} else {
|
||||
return Recipient.from(context, Address.fromSerialized(message.getDestination().get()), false);
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getSyncMessageMasterDestination(SentTranscriptMessage message) {
|
||||
if (message.getMessage().isGroupMessage()) {
|
||||
return Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get())), false);
|
||||
} else {
|
||||
String publicKey = message.getDestination().get();
|
||||
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
if (publicKey.equals(userPublicKey)) {
|
||||
return Recipient.from(context, Address.fromSerialized(userPublicKey), false);
|
||||
} else {
|
||||
return Recipient.from(context, Address.fromSerialized(publicKey), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
if (message.getGroupInfo().isPresent()) {
|
||||
return Recipient.from(context, Address.fromExternal(context, GroupUtil.getEncodedClosedGroupID(message.getGroupInfo().get().getGroupId())), false);
|
||||
@@ -1309,8 +1064,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
} else {
|
||||
return sender.isBlocked();
|
||||
}
|
||||
} else if (content.getSyncMessage().isPresent()) {
|
||||
throw new UnsupportedOperationException("Device link operations are not supported!");
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@@ -21,7 +21,6 @@ import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
|
||||
import org.session.libsignal.service.api.messages.SignalServiceContent
|
||||
import org.session.libsignal.service.api.messages.SignalServiceDataMessage
|
||||
import org.session.libsignal.service.api.messages.SignalServiceGroup
|
||||
import org.session.libsignal.service.api.messages.multidevice.SentTranscriptMessage
|
||||
import org.session.libsignal.service.api.push.SignalServiceAddress
|
||||
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI
|
||||
import org.session.libsignal.service.loki.api.opengroups.PublicChat
|
||||
@@ -222,16 +221,6 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
|
||||
FileServerAPI.configure(userHexEncodedPublicKey, userPrivateKey, apiDB)
|
||||
// Kovenant propagates a context to chained promises, so LokiPublicChatAPI.sharedContext should be used for all of the below
|
||||
val promise = api.getMessages(group.channel, group.server).bind(PublicChatAPI.sharedContext) { messages ->
|
||||
/*
|
||||
if (messages.isNotEmpty()) {
|
||||
// We need to fetch the device mapping for any devices we don't have
|
||||
uniqueDevices = messages.map { it.senderPublicKey }.toSet()
|
||||
val devicesToUpdate = uniqueDevices.filter { !userDevices.contains(it) && FileServerAPI.shared.hasDeviceLinkCacheExpired(publicKey = it) }
|
||||
if (devicesToUpdate.isNotEmpty()) {
|
||||
return@bind FileServerAPI.shared.getDeviceLinks(devicesToUpdate.toSet()).then { messages }
|
||||
}
|
||||
}
|
||||
*/
|
||||
Promise.of(messages)
|
||||
}
|
||||
promise.successBackground { messages ->
|
||||
|
@@ -13,6 +13,7 @@ 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.internal.push.SignalServiceProtos.DataMessage
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext
|
||||
import org.session.libsignal.utilities.ThreadUtils
|
||||
import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
|
||||
@@ -402,48 +403,48 @@ object ClosedGroupsProtocolV2 {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun handleMessage(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
fun handleMessage(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
if (!isValid(context, closedGroupUpdate, senderPublicKey, sentTimestamp)) { return }
|
||||
when (closedGroupUpdate.type) {
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW -> handleNewClosedGroup(context, closedGroupUpdate, senderPublicKey, sentTimestamp)
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBERS_REMOVED -> handleClosedGroupMembersRemoved(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBERS_ADDED -> handleClosedGroupMembersAdded(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.NAME_CHANGE -> handleClosedGroupNameChange(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBER_LEFT -> handleClosedGroupMemberLeft(context, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.UPDATE -> handleClosedGroupUpdate(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.ENCRYPTION_KEY_PAIR -> handleGroupEncryptionKeyPair(context, closedGroupUpdate, groupPublicKey, senderPublicKey)
|
||||
DataMessage.ClosedGroupControlMessage.Type.NEW -> handleNewClosedGroup(context, closedGroupUpdate, senderPublicKey, sentTimestamp)
|
||||
DataMessage.ClosedGroupControlMessage.Type.MEMBERS_REMOVED -> handleClosedGroupMembersRemoved(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
DataMessage.ClosedGroupControlMessage.Type.MEMBERS_ADDED -> handleClosedGroupMembersAdded(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
DataMessage.ClosedGroupControlMessage.Type.NAME_CHANGE -> handleClosedGroupNameChange(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
DataMessage.ClosedGroupControlMessage.Type.MEMBER_LEFT -> handleClosedGroupMemberLeft(context, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
DataMessage.ClosedGroupControlMessage.Type.UPDATE -> handleClosedGroupUpdate(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
|
||||
DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR -> handleGroupEncryptionKeyPair(context, closedGroupUpdate, groupPublicKey, senderPublicKey)
|
||||
else -> {
|
||||
Log.d("Loki","Can't handle closed group update of unknown type: ${closedGroupUpdate.type}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValid(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, senderPublicKey: String, sentTimestamp: Long): Boolean {
|
||||
private fun isValid(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, senderPublicKey: String, sentTimestamp: Long): Boolean {
|
||||
val record = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(sentTimestamp, senderPublicKey)
|
||||
if (record != null) return false
|
||||
|
||||
return when (closedGroupUpdate.type) {
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW -> {
|
||||
DataMessage.ClosedGroupControlMessage.Type.NEW -> {
|
||||
(!closedGroupUpdate.publicKey.isEmpty && !closedGroupUpdate.name.isNullOrEmpty() && !(closedGroupUpdate.encryptionKeyPair.privateKey ?: ByteString.copyFrom(ByteArray(0))).isEmpty
|
||||
&& !(closedGroupUpdate.encryptionKeyPair.publicKey ?: ByteString.copyFrom(ByteArray(0))).isEmpty && closedGroupUpdate.membersCount > 0 && closedGroupUpdate.adminsCount > 0)
|
||||
}
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBERS_ADDED,
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBERS_REMOVED -> {
|
||||
DataMessage.ClosedGroupControlMessage.Type.MEMBERS_ADDED,
|
||||
DataMessage.ClosedGroupControlMessage.Type.MEMBERS_REMOVED -> {
|
||||
closedGroupUpdate.membersCount > 0
|
||||
}
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.MEMBER_LEFT -> {
|
||||
DataMessage.ClosedGroupControlMessage.Type.MEMBER_LEFT -> {
|
||||
senderPublicKey.isNotEmpty()
|
||||
}
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.UPDATE,
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.NAME_CHANGE -> {
|
||||
DataMessage.ClosedGroupControlMessage.Type.UPDATE,
|
||||
DataMessage.ClosedGroupControlMessage.Type.NAME_CHANGE -> {
|
||||
!closedGroupUpdate.name.isNullOrEmpty()
|
||||
}
|
||||
SignalServiceProtos.ClosedGroupUpdateV2.Type.ENCRYPTION_KEY_PAIR -> true
|
||||
DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
public fun handleNewClosedGroup(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, senderPublicKey: String, sentTimestamp: Long) {
|
||||
public fun handleNewClosedGroup(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, senderPublicKey: String, sentTimestamp: Long) {
|
||||
// Prepare
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||
@@ -483,7 +484,7 @@ object ClosedGroupsProtocolV2 {
|
||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||
}
|
||||
|
||||
fun handleClosedGroupMembersRemoved(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
fun handleClosedGroupMembersRemoved(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
|
||||
@@ -536,7 +537,7 @@ object ClosedGroupsProtocolV2 {
|
||||
}
|
||||
}
|
||||
|
||||
fun handleClosedGroupMembersAdded(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
fun handleClosedGroupMembersAdded(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||
@@ -578,7 +579,7 @@ object ClosedGroupsProtocolV2 {
|
||||
}
|
||||
}
|
||||
|
||||
fun handleClosedGroupNameChange(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
fun handleClosedGroupNameChange(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
// Check that the sender is a member of the group (before the update)
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
||||
@@ -646,7 +647,7 @@ object ClosedGroupsProtocolV2 {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleClosedGroupUpdate(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
private fun handleClosedGroupUpdate(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
|
||||
// Prepare
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||
@@ -728,7 +729,7 @@ object ClosedGroupsProtocolV2 {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun handleGroupEncryptionKeyPair(context: Context, closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdateV2, groupPublicKey: String, senderPublicKey: String) {
|
||||
private fun handleGroupEncryptionKeyPair(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, groupPublicKey: String, senderPublicKey: String) {
|
||||
// Prepare
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||
|
@@ -70,8 +70,7 @@ public class IncomingMediaMessage {
|
||||
Optional<List<SignalServiceAttachment>> attachments,
|
||||
Optional<QuoteModel> quote,
|
||||
Optional<List<Contact>> sharedContacts,
|
||||
Optional<List<LinkPreview>> linkPreviews,
|
||||
Optional<Attachment> sticker)
|
||||
Optional<List<LinkPreview>> linkPreviews)
|
||||
{
|
||||
this.push = true;
|
||||
this.from = from;
|
||||
@@ -89,10 +88,6 @@ public class IncomingMediaMessage {
|
||||
this.attachments.addAll(PointerAttachment.forPointers(attachments));
|
||||
this.sharedContacts.addAll(sharedContacts.or(Collections.emptyList()));
|
||||
this.linkPreviews.addAll(linkPreviews.or(Collections.emptyList()));
|
||||
|
||||
if (sticker.isPresent()) {
|
||||
this.attachments.add(sticker.get());
|
||||
}
|
||||
}
|
||||
|
||||
public static IncomingMediaMessage from(VisibleMessage message,
|
||||
@@ -104,7 +99,7 @@ public class IncomingMediaMessage {
|
||||
Optional<List<LinkPreview>> linkPreviews)
|
||||
{
|
||||
return new IncomingMediaMessage(from, message.getReceivedTimestamp(), -1, expiresIn, false,
|
||||
false, Optional.fromNullable(message.getText()), group, attachments, quote, Optional.absent(), linkPreviews, Optional.absent());
|
||||
false, Optional.fromNullable(message.getText()), group, attachments, quote, Optional.absent(), linkPreviews);
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
|
Reference in New Issue
Block a user