mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 00:37:47 +00:00
Simplify PushDecryptJob a bit
This commit is contained in:
parent
27fdfe4ee8
commit
9c71a4c3cd
@ -290,13 +290,14 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
|
||||
// Loki - Handle friend request acceptance if needed
|
||||
acceptFriendRequestIfNeeded(content);
|
||||
if (!content.isFriendRequest() && !isGroupChatMessage(content)) {
|
||||
becomeFriendsWithContactIfNeeded(content.getSender(), true, false);
|
||||
}
|
||||
|
||||
// Loki - Session requests
|
||||
// Loki - Handle session request if needed
|
||||
handleSessionRequestIfNeeded(content);
|
||||
|
||||
// Loki - Store pre key bundle
|
||||
// We shouldn't store it if it's a pairing message
|
||||
// Loki - Store pre key bundle if needed
|
||||
if (!content.getDeviceLink().isPresent()) {
|
||||
storePreKeyBundleIfNeeded(content);
|
||||
}
|
||||
@ -311,29 +312,29 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
// Loki - Store the sender display name if needed
|
||||
Optional<String> rawSenderDisplayName = content.senderDisplayName;
|
||||
if (rawSenderDisplayName.isPresent() && rawSenderDisplayName.get().length() > 0) {
|
||||
// If we got a name from our primary device then we set our profile name to match it
|
||||
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourPrimaryDevice != null && content.getSender().equals(ourPrimaryDevice)) {
|
||||
// If we got a name from our master device then set our display name to match
|
||||
String ourMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourMasterDevice != null && content.getSender().equals(ourMasterDevice)) {
|
||||
TextSecurePreferences.setProfileName(context, rawSenderDisplayName.get());
|
||||
}
|
||||
|
||||
// If we receive a message from our device then don't set the display name in the database (as we probably have a alias set for them)
|
||||
MultiDeviceUtilities.isOneOfOurDevices(context, Address.fromSerialized(content.getSender())).success(isOneOfOurDevice -> {
|
||||
if (!isOneOfOurDevice) { setDisplayName(content.getSender(), rawSenderDisplayName.get()); }
|
||||
MultiDeviceUtilities.isOneOfOurDevices(context, Address.fromSerialized(content.getSender())).success( isOneOfOurDevices -> {
|
||||
if (!isOneOfOurDevices) { setDisplayName(content.getSender(), rawSenderDisplayName.get()); }
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
if (content.getDeviceLink().isPresent()) {
|
||||
handlePairingMessage(content.getDeviceLink().get(), content);
|
||||
handleDeviceLinkMessage(content.getDeviceLink().get(), content);
|
||||
} 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();
|
||||
|
||||
if (!content.isFriendRequest() && message.isUnlinkingRequest()) {
|
||||
// Make sure we got the request from our primary device
|
||||
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourPrimaryDevice != null && ourPrimaryDevice.equals(content.getSender())) {
|
||||
// Make sure we got the request from our master device
|
||||
String ourMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourMasterDevice != null && ourMasterDevice.equals(content.getSender())) {
|
||||
TextSecurePreferences.setDatabaseResetFromUnpair(context, true);
|
||||
MultiDeviceUtilities.checkForRevocation(context);
|
||||
}
|
||||
@ -376,7 +377,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp());
|
||||
else if (syncMessage.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get());
|
||||
else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get());
|
||||
else if (syncMessage.getContacts().isPresent()) handleSynchronizeContactMessage(syncMessage.getContacts().get());
|
||||
else if (syncMessage.getContacts().isPresent()) handleContactSyncMessage(syncMessage.getContacts().get());
|
||||
else Log.w(TAG, "Contains no known sync types...");
|
||||
} else if (content.getCallMessage().isPresent()) {
|
||||
Log.i(TAG, "Got call message...");
|
||||
@ -594,7 +595,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
{
|
||||
GroupMessageProcessor.process(context, content, message, false);
|
||||
|
||||
if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getMessageDestination(content, message).getExpireMessages()) {
|
||||
if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getRecipientForMessage(content, message).getExpireMessages()) {
|
||||
handleExpirationUpdate(content, message, Optional.absent());
|
||||
}
|
||||
|
||||
@ -620,7 +621,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
{
|
||||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getMessageDestination(content, message);
|
||||
Recipient recipient = getRecipientForMessage(content, message);
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromSerialized(content.getSender()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, true,
|
||||
@ -671,45 +672,44 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSynchronizeContactMessage(@NonNull ContactsMessage contactsMessage) {
|
||||
if (contactsMessage.getContactsStream().isStream()) {
|
||||
Log.d("Loki", "Received contact sync message");
|
||||
private void handleContactSyncMessage(@NonNull ContactsMessage contactsMessage) {
|
||||
if (!contactsMessage.getContactsStream().isStream()) { return; }
|
||||
Log.d("Loki", "Received contact sync message.");
|
||||
|
||||
try {
|
||||
InputStream in = contactsMessage.getContactsStream().asStream().getInputStream();
|
||||
DeviceContactsInputStream contactsInputStream = new DeviceContactsInputStream(in);
|
||||
List<DeviceContact> devices = contactsInputStream.readAll();
|
||||
for (DeviceContact deviceContact : devices) {
|
||||
// Check if we have the contact as a friend and that we're not trying to sync our own device
|
||||
String pubKey = deviceContact.getNumber();
|
||||
Address address = Address.fromSerialized(pubKey);
|
||||
if (!address.isPhone() || address.toPhoneString().equals(TextSecurePreferences.getLocalNumber(context))) { continue; }
|
||||
try {
|
||||
InputStream in = contactsMessage.getContactsStream().asStream().getInputStream();
|
||||
DeviceContactsInputStream contactsInputStream = new DeviceContactsInputStream(in);
|
||||
List<DeviceContact> deviceContacts = contactsInputStream.readAll();
|
||||
for (DeviceContact deviceContact : deviceContacts) {
|
||||
// Check if we have the contact as a friend and that we're not trying to sync our own device
|
||||
String hexEncodedPublicKey = deviceContact.getNumber();
|
||||
Address address = Address.fromSerialized(hexEncodedPublicKey);
|
||||
if (!address.isPhone() || address.toPhoneString().equals(TextSecurePreferences.getLocalNumber(context))) { continue; }
|
||||
|
||||
/*
|
||||
If we're not friends with the contact we received or our friend request expired then we should send them a friend request
|
||||
otherwise if we have received a friend request with from them then we should automatically accept the friend request
|
||||
*/
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
LokiThreadFriendRequestStatus status = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
||||
if (status == LokiThreadFriendRequestStatus.NONE || status == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
|
||||
MessageSender.sendBackgroundFriendRequest(context, pubKey, "Please accept to enable messages to be synced across devices");
|
||||
Log.d("Loki", "Sent friend request to " + pubKey);
|
||||
} else if (status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
||||
// Accept the incoming friend request
|
||||
becomeFriendsWithContact(pubKey, false, false);
|
||||
// Send them an accept message back
|
||||
MessageSender.sendBackgroundMessage(context, pubKey);
|
||||
Log.d("Loki", "Became friends with " + deviceContact.getNumber());
|
||||
}
|
||||
|
||||
// TODO: Handle blocked - If user is not blocked then we should do the friend request logic otherwise add them to our block list
|
||||
// TODO: Handle expiration timer - Update expiration timer?
|
||||
// TODO: Handle avatar - Download and set avatar?
|
||||
/*
|
||||
If we're not friends with the contact we received or our friend request expired then we should send them a friend request.
|
||||
Otherwise, if we have received a friend request from them, automatically accept the friend request.
|
||||
*/
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
LokiThreadFriendRequestStatus status = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
||||
if (status == LokiThreadFriendRequestStatus.NONE || status == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
|
||||
MessageSender.sendBackgroundFriendRequest(context, hexEncodedPublicKey, "Please accept to enable messages to be synced across devices");
|
||||
Log.d("Loki", "Sent friend request to " + hexEncodedPublicKey);
|
||||
} else if (status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
||||
// Accept the incoming friend request
|
||||
becomeFriendsWithContactIfNeeded(hexEncodedPublicKey, false, false);
|
||||
// Send them an accept message back
|
||||
MessageSender.sendBackgroundMessage(context, hexEncodedPublicKey);
|
||||
Log.d("Loki", "Became friends with " + deviceContact.getNumber());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("Loki", "Failed to sync contact: " + e);
|
||||
|
||||
// TODO: Handle blocked - If user is not blocked then we should do the friend request logic otherwise add them to our block list
|
||||
// TODO: Handle expiration timer - Update expiration timer?
|
||||
// TODO: Handle avatar - Download and set avatar?
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("Loki", "Failed to sync contact: " + e + ".");
|
||||
}
|
||||
}
|
||||
|
||||
@ -752,7 +752,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
|
||||
}
|
||||
|
||||
// Loki - If we received a sync message from our master device then we need to extract the avatar url
|
||||
// Loki - If we received a sync message from our master device then we need to extract the profile picture url
|
||||
if (isSenderMasterDevice) {
|
||||
handleProfileKey(content, message.getMessage());
|
||||
}
|
||||
@ -842,21 +842,21 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
@NonNull Optional<Long> messageServerIDOrNull)
|
||||
throws StorageFailedException
|
||||
{
|
||||
Recipient originalRecipient = getMessageDestination(content, message);
|
||||
Recipient primaryDeviceRecipient = getMessagePrimaryDestination(content, message);
|
||||
Recipient originalRecipient = getRecipientForMessage(content, message);
|
||||
Recipient masterRecipient = getMasterRecipientForMessage(content, message);
|
||||
|
||||
notifyTypingStoppedFromIncomingMessage(primaryDeviceRecipient, content.getSender(), content.getSenderDevice());
|
||||
notifyTypingStoppedFromIncomingMessage(masterRecipient, content.getSender(), content.getSenderDevice());
|
||||
|
||||
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 sender = primaryDeviceRecipient.getAddress();
|
||||
Address sender = masterRecipient.getAddress();
|
||||
|
||||
// If message is from group then we need to map it to get the sender of the message
|
||||
if (message.isGroupMessage()) {
|
||||
sender = getPrimaryDeviceRecipient(content.getSender()).getAddress();
|
||||
sender = getMasterRecipient(content.getSender()).getAddress();
|
||||
}
|
||||
|
||||
// Ignore messages from ourselves
|
||||
@ -1031,8 +1031,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
{
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
String body = message.getBody().isPresent() ? message.getBody().get() : "";
|
||||
Recipient originalRecipient = getMessageDestination(content, message);
|
||||
Recipient primaryDeviceRecipient = getMessagePrimaryDestination(content, message);
|
||||
Recipient originalRecipient = getRecipientForMessage(content, message);
|
||||
Recipient masterRecipient = getMasterRecipientForMessage(content, message);
|
||||
|
||||
if (message.getExpiresInSeconds() != originalRecipient.getExpireMessages()) {
|
||||
handleExpirationUpdate(content, message, Optional.absent());
|
||||
@ -1043,13 +1043,13 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
if (smsMessageId.isPresent() && !message.getGroupInfo().isPresent()) {
|
||||
threadId = database.updateBundleMessageBody(smsMessageId.get(), body).second;
|
||||
} else {
|
||||
notifyTypingStoppedFromIncomingMessage(primaryDeviceRecipient, content.getSender(), content.getSenderDevice());
|
||||
notifyTypingStoppedFromIncomingMessage(masterRecipient, content.getSender(), content.getSenderDevice());
|
||||
|
||||
Address sender = primaryDeviceRecipient.getAddress();
|
||||
Address sender = masterRecipient.getAddress();
|
||||
|
||||
// If message is from group then we need to map it to get the sender of the message
|
||||
if (message.isGroupMessage()) {
|
||||
sender = getPrimaryDeviceRecipient(content.getSender()).getAddress();
|
||||
sender = getMasterRecipient(content.getSender()).getAddress();
|
||||
}
|
||||
|
||||
// Ignore messages from ourselves
|
||||
@ -1103,7 +1103,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidPairingMessage(@NonNull DeviceLink authorisation) {
|
||||
private boolean isValidDeviceLinkMessage(@NonNull DeviceLink authorisation) {
|
||||
boolean isSecondaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context) != null;
|
||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
boolean isRequest = (authorisation.getType() == DeviceLink.Type.REQUEST);
|
||||
@ -1123,74 +1123,66 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
return authorisation.verify();
|
||||
}
|
||||
|
||||
private void handleProfileAvatar(SignalServiceContent content, String url) {
|
||||
Recipient primaryDevice = getPrimaryDeviceRecipient(content.getSender());
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new RetrieveProfileAvatarJob(primaryDevice, url));
|
||||
}
|
||||
|
||||
private void handlePairingMessage(@NonNull DeviceLink authorisation, @NonNull SignalServiceContent content) {
|
||||
private void handleDeviceLinkMessage(@NonNull DeviceLink deviceLink, @NonNull SignalServiceContent content) {
|
||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
if (authorisation.getType() == DeviceLink.Type.REQUEST) {
|
||||
handlePairingRequestMessage(authorisation, content);
|
||||
} else if (authorisation.getSlaveHexEncodedPublicKey().equals(userHexEncodedPublicKey)) {
|
||||
handlePairingAuthorisationMessage(authorisation, content);
|
||||
if (deviceLink.getType() == DeviceLink.Type.REQUEST) {
|
||||
handleDeviceLinkRequestMessage(deviceLink, content);
|
||||
} else if (deviceLink.getSlaveHexEncodedPublicKey().equals(userHexEncodedPublicKey)) {
|
||||
handleDeviceLinkAuthorizedMessage(deviceLink, content);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePairingRequestMessage(@NonNull DeviceLink authorisation, @NonNull SignalServiceContent content) {
|
||||
boolean isValid = isValidPairingMessage(authorisation);
|
||||
private void handleDeviceLinkRequestMessage(@NonNull DeviceLink deviceLink, @NonNull SignalServiceContent content) {
|
||||
boolean isValid = isValidDeviceLinkMessage(deviceLink);
|
||||
DeviceLinkingSession linkingSession = DeviceLinkingSession.Companion.getShared();
|
||||
if (isValid && linkingSession.isListeningForLinkingRequests()) {
|
||||
// Loki - If we successfully received a request then we should store the PreKeyBundle
|
||||
storePreKeyBundleIfNeeded(content);
|
||||
linkingSession.processLinkingRequest(authorisation);
|
||||
}
|
||||
if (!isValid || !linkingSession.isListeningForLinkingRequests()) { return; }
|
||||
storePreKeyBundleIfNeeded(content);
|
||||
linkingSession.processLinkingRequest(deviceLink);
|
||||
}
|
||||
|
||||
private void handlePairingAuthorisationMessage(@NonNull DeviceLink authorisation, @NonNull SignalServiceContent content) {
|
||||
// Prepare
|
||||
boolean isSecondaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context) != null;
|
||||
if (isSecondaryDevice) {
|
||||
Log.d("Loki", "Ignoring unexpected pairing authorisation message (the device is already paired as a secondary device).");
|
||||
private void handleDeviceLinkAuthorizedMessage(@NonNull DeviceLink deviceLink, @NonNull SignalServiceContent content) {
|
||||
// Check preconditions
|
||||
boolean hasExistingDeviceLink = TextSecurePreferences.getMasterHexEncodedPublicKey(context) != null;
|
||||
if (hasExistingDeviceLink) {
|
||||
Log.d("Loki", "Ignoring unexpected device link message (the device is already linked as a slave device).");
|
||||
return;
|
||||
}
|
||||
boolean isValid = isValidPairingMessage(authorisation);
|
||||
boolean isValid = isValidDeviceLinkMessage(deviceLink);
|
||||
if (!isValid) {
|
||||
Log.d("Loki", "Ignoring invalid pairing authorisation message.");
|
||||
Log.d("Loki", "Ignoring invalid device link message.");
|
||||
return;
|
||||
}
|
||||
if (!DeviceLinkingSession.Companion.getShared().isListeningForLinkingRequests()) {
|
||||
Log.d("Loki", "Ignoring pairing authorisation message.");
|
||||
Log.d("Loki", "Ignoring device link message.");
|
||||
return;
|
||||
}
|
||||
if (authorisation.getType() != DeviceLink.Type.AUTHORIZATION) { return; }
|
||||
Log.d("Loki", "Received pairing authorisation message from: " + authorisation.getMasterHexEncodedPublicKey() + ".");
|
||||
// Save PreKeyBundle if for whatever reason we got one
|
||||
if (deviceLink.getType() != DeviceLink.Type.AUTHORIZATION) { return; }
|
||||
Log.d("Loki", "Received device link authorized message from: " + deviceLink.getMasterHexEncodedPublicKey() + ".");
|
||||
// Save pre key bundle if we somehow got one
|
||||
storePreKeyBundleIfNeeded(content);
|
||||
// Process
|
||||
DeviceLinkingSession.Companion.getShared().processLinkingAuthorization(authorisation);
|
||||
// Store the primary device's public key
|
||||
DeviceLinkingSession.Companion.getShared().processLinkingAuthorization(deviceLink);
|
||||
// Store the master device's ID
|
||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
DatabaseFactory.getLokiAPIDatabase(context).clearDeviceLinks(userHexEncodedPublicKey);
|
||||
DatabaseFactory.getLokiAPIDatabase(context).addDeviceLink(authorisation);
|
||||
TextSecurePreferences.setMasterHexEncodedPublicKey(context, authorisation.getMasterHexEncodedPublicKey());
|
||||
DatabaseFactory.getLokiAPIDatabase(context).addDeviceLink(deviceLink);
|
||||
TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.getMasterHexEncodedPublicKey());
|
||||
TextSecurePreferences.setMultiDevice(context, true);
|
||||
// Send a background message to the primary device
|
||||
MessageSender.sendBackgroundMessage(context, authorisation.getMasterHexEncodedPublicKey());
|
||||
// Send a background message to the master device
|
||||
MessageSender.sendBackgroundMessage(context, deviceLink.getMasterHexEncodedPublicKey());
|
||||
// Propagate the updates to the file server
|
||||
LokiFileServerAPI storageAPI = LokiFileServerAPI.Companion.getShared();
|
||||
storageAPI.updateUserDeviceLinks();
|
||||
// Update display names
|
||||
LokiFileServerAPI.Companion.getShared().updateUserDeviceLinks();
|
||||
// Update display name if needed
|
||||
if (content.senderDisplayName.isPresent() && content.senderDisplayName.get().length() > 0) {
|
||||
TextSecurePreferences.setProfileName(context, content.senderDisplayName.get());
|
||||
}
|
||||
// Profile avatar updates
|
||||
// Update profile picture if needed
|
||||
if (content.getDataMessage().isPresent()) {
|
||||
handleProfileKey(content, content.getDataMessage().get());
|
||||
}
|
||||
// Contact sync
|
||||
// Handle contact sync if needed
|
||||
if (content.getSyncMessage().isPresent() && content.getSyncMessage().get().getContacts().isPresent()) {
|
||||
handleSynchronizeContactMessage(content.getSyncMessage().get().getContacts().get());
|
||||
handleContactSyncMessage(content.getSyncMessage().get().getContacts().get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1200,95 +1192,79 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
|
||||
private void updateGroupChatMessageServerID(Optional<Long> messageServerIDOrNull, Optional<InsertResult> insertResult) {
|
||||
if (insertResult.isPresent() && messageServerIDOrNull.isPresent()) {
|
||||
long messageID = insertResult.get().getMessageId();
|
||||
long messageServerID = messageServerIDOrNull.get();
|
||||
DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageID, messageServerID);
|
||||
}
|
||||
if (!insertResult.isPresent() || !messageServerIDOrNull.isPresent()) { return; }
|
||||
long messageID = insertResult.get().getMessageId();
|
||||
long messageServerID = messageServerIDOrNull.get();
|
||||
DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageID, messageServerID);
|
||||
}
|
||||
|
||||
private void storePreKeyBundleIfNeeded(@NonNull SignalServiceContent content) {
|
||||
Recipient sender = Recipient.from(context, Address.fromSerialized(content.getSender()), false);
|
||||
if (!sender.isGroupRecipient() && content.lokiServiceMessage.isPresent()) {
|
||||
LokiServiceMessage lokiMessage = content.lokiServiceMessage.get();
|
||||
if (lokiMessage.getPreKeyBundleMessage() != null) {
|
||||
int registrationID = TextSecurePreferences.getLocalRegistrationId(context);
|
||||
LokiPreKeyBundleDatabase lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context);
|
||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context);
|
||||
|
||||
// Loki - Store the latest pre key bundle
|
||||
if (registrationID > 0) {
|
||||
Log.d("Loki", "Received a pre key bundle from: " + content.getSender() + ".");
|
||||
PreKeyBundle preKeyBundle = lokiMessage.getPreKeyBundleMessage().getPreKeyBundle(registrationID);
|
||||
lokiPreKeyBundleDatabase.setPreKeyBundle(content.getSender(), preKeyBundle);
|
||||
|
||||
// Loki - If we received a friend request, but we were already friends with this user, then reset the session
|
||||
if (content.isFriendRequest()) {
|
||||
long threadID = threadDatabase.getThreadIdIfExistsFor(sender);
|
||||
if (lokiThreadDatabase.getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS) {
|
||||
resetSession(content.getSender(), threadID);
|
||||
// Let our other devices know that we have reset the session
|
||||
MessageSender.syncContact(context, sender.getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sender.isGroupRecipient() || !content.lokiServiceMessage.isPresent()) { return; }
|
||||
LokiServiceMessage lokiMessage = content.lokiServiceMessage.get();
|
||||
if (lokiMessage.getPreKeyBundleMessage() == null) { return; }
|
||||
int registrationID = TextSecurePreferences.getLocalRegistrationId(context);
|
||||
LokiPreKeyBundleDatabase lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context);
|
||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context);
|
||||
if (registrationID <= 0) { return; }
|
||||
Log.d("Loki", "Received a pre key bundle from: " + content.getSender() + ".");
|
||||
PreKeyBundle preKeyBundle = lokiMessage.getPreKeyBundleMessage().getPreKeyBundle(registrationID);
|
||||
lokiPreKeyBundleDatabase.setPreKeyBundle(content.getSender(), preKeyBundle);
|
||||
// If we received a friend request, but we were already friends with the user, reset the session
|
||||
if (content.isFriendRequest()) {
|
||||
long threadID = threadDatabase.getThreadIdIfExistsFor(sender);
|
||||
if (lokiThreadDatabase.getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS) {
|
||||
resetSession(content.getSender(), threadID);
|
||||
// Let our other devices know that we have reset the session
|
||||
MessageSender.syncContact(context, sender.getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void acceptFriendRequestIfNeeded(@NonNull SignalServiceContent content) {
|
||||
// If we get anything other than a friend request, we can assume that we have a session with the other user
|
||||
if (content.isFriendRequest() || isGroupChatMessage(content)) { return; }
|
||||
becomeFriendsWithContact(content.getSender(), true, false);
|
||||
}
|
||||
|
||||
private void handleSessionRequestIfNeeded(@NonNull SignalServiceContent content) {
|
||||
if (content.isFriendRequest() && isSessionRequest(content)) {
|
||||
// Check if the session request from a member in one of our groups or our friend
|
||||
LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(content.getSender()).success(primaryDevicePublicKey -> {
|
||||
String sender = primaryDevicePublicKey != null ? primaryDevicePublicKey : content.getSender();
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(sender), false));
|
||||
LokiThreadFriendRequestStatus threadFriendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
||||
boolean isOurFriend = threadFriendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS;
|
||||
boolean isInOneOfOurGroups = DatabaseFactory.getGroupDatabase(context).signalGroupsHaveMember(sender);
|
||||
boolean shouldAcceptSessionRequest = isOurFriend || isInOneOfOurGroups;
|
||||
if (shouldAcceptSessionRequest) {
|
||||
// Send a background message to acknowledge session request
|
||||
MessageSender.sendBackgroundMessage(context, content.getSender());
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
if (!content.isFriendRequest() || !isSessionRequest(content)) { return; }
|
||||
// Check if the session request came from a member in one of our groups or one of our friends
|
||||
LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(content.getSender()).success( masterHexEncodedPublicKey -> {
|
||||
String sender = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : content.getSender();
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(sender), false));
|
||||
LokiThreadFriendRequestStatus threadFriendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
||||
boolean isOurFriend = threadFriendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS;
|
||||
boolean isInOneOfOurGroups = DatabaseFactory.getGroupDatabase(context).signalGroupsHaveMember(sender);
|
||||
boolean shouldAcceptSessionRequest = isOurFriend || isInOneOfOurGroups;
|
||||
if (shouldAcceptSessionRequest) {
|
||||
MessageSender.sendBackgroundMessage(context, content.getSender()); // Send a background message to acknowledge
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
private void becomeFriendsWithContact(String pubKey, boolean syncContact, boolean force) {
|
||||
private void becomeFriendsWithContactIfNeeded(String hexEncodedPublicKey, boolean requiresContactSync, boolean canSkip) {
|
||||
// Ignore friend requests to group recipients
|
||||
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context);
|
||||
Recipient contactID = Recipient.from(context, Address.fromSerialized(pubKey), false);
|
||||
Recipient contactID = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false);
|
||||
if (contactID.isGroupRecipient()) return;
|
||||
|
||||
// Ignore friend requests to recipients we're already friends with
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(contactID);
|
||||
LokiThreadFriendRequestStatus threadFriendRequestStatus = lokiThreadDatabase.getFriendRequestStatus(threadID);
|
||||
if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS) { return; }
|
||||
|
||||
// We shouldn't be able to skip from None -> Friends in normal circumstances.
|
||||
// Multi-device is the exception to this rule because we want to automatically be friends with a secondary device
|
||||
if (!force && threadFriendRequestStatus == LokiThreadFriendRequestStatus.NONE) { return; }
|
||||
|
||||
// If the thread's friend request status is not `FRIENDS`, but we're receiving a message,
|
||||
// We shouldn't be able to skip from NONE to FRIENDS under normal circumstances.
|
||||
// Multi-device is the one exception to this rule because we want to automatically become friends with slave devices.
|
||||
if (!canSkip && threadFriendRequestStatus == LokiThreadFriendRequestStatus.NONE) { return; }
|
||||
// If the thread's friend request status is not `FRIENDS` or `NONE`, but we're receiving a message,
|
||||
// it must be a friend request accepted message. Declining a friend request doesn't send a message.
|
||||
lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS);
|
||||
// Send out a contact sync message
|
||||
if (syncContact) {
|
||||
// Send out a contact sync message if needed
|
||||
if (requiresContactSync) {
|
||||
MessageSender.syncContact(context, contactID.getAddress());
|
||||
}
|
||||
// Allow profile sharing with contact
|
||||
// Enable profile sharing with the recipient
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(contactID, true);
|
||||
// Update the last message if needed
|
||||
LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(pubKey).success(primaryDevice -> {
|
||||
LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(hexEncodedPublicKey).success( masterHexEncodedPublicKey -> {
|
||||
Util.runOnMain(() -> {
|
||||
long primaryDeviceThreadID = primaryDevice == null ? threadID : DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(primaryDevice), false));
|
||||
FriendRequestHandler.updateLastFriendRequestMessage(context, primaryDeviceThreadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
|
||||
long masterThreadID = (masterHexEncodedPublicKey == null) ? threadID : DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(masterHexEncodedPublicKey), false));
|
||||
FriendRequestHandler.updateLastFriendRequestMessage(context, masterThreadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
@ -1296,25 +1272,24 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
private void updateFriendRequestStatusIfNeeded(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) {
|
||||
if (!content.isFriendRequest() || message.isGroupMessage() || message.isSessionRequest()) { return; }
|
||||
// This handles the case where another user sends us a regular message without authorisation
|
||||
Promise<Boolean, Exception> promise = PromiseUtil.timeout(MultiDeviceUtilities.shouldAutomaticallyBecomeFriendsWithDevice(content.getSender(), context), 8000);
|
||||
boolean shouldBecomeFriends = PromiseUtil.get(promise, false);
|
||||
if (shouldBecomeFriends) {
|
||||
// Become friends AND update the message they sent
|
||||
becomeFriendsWithContact(content.getSender(), true, true);
|
||||
becomeFriendsWithContactIfNeeded(content.getSender(), true, true);
|
||||
// Send them an accept message back
|
||||
MessageSender.sendBackgroundMessage(context, content.getSender());
|
||||
} else {
|
||||
// Do regular friend request logic checks
|
||||
Recipient originalRecipient = getMessageDestination(content, message);
|
||||
Recipient primaryDeviceRecipient = getMessagePrimaryDestination(content, message);
|
||||
Recipient originalRecipient = getRecipientForMessage(content, message);
|
||||
Recipient masterRecipient = getMasterRecipientForMessage(content, message);
|
||||
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context);
|
||||
|
||||
// Loki - Friend requests only work in direct chats
|
||||
if (!originalRecipient.getAddress().isPhone()) { return; }
|
||||
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(originalRecipient);
|
||||
long primaryDeviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDeviceRecipient);
|
||||
long primaryDeviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(masterRecipient);
|
||||
LokiThreadFriendRequestStatus threadFriendRequestStatus = lokiThreadDatabase.getFriendRequestStatus(threadID);
|
||||
|
||||
if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) {
|
||||
@ -1483,7 +1458,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
|
||||
private void triggerSessionRestorePrompt(@NonNull String sender) {
|
||||
Recipient primaryRecipient = getPrimaryDeviceRecipient(sender);
|
||||
Recipient primaryRecipient = getMasterRecipient(sender);
|
||||
if (!primaryRecipient.isGroupRecipient()) {
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(primaryRecipient);
|
||||
DatabaseFactory.getLokiThreadDatabase(context).addSessionRestoreDevice(threadID, sender);
|
||||
@ -1560,11 +1535,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
private void handleDeliveryReceipt(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceReceiptMessage message)
|
||||
{
|
||||
// Redirect message to primary device conversation
|
||||
// Redirect message to master device conversation
|
||||
Address sender = Address.fromSerialized(content.getSender());
|
||||
if (sender.isPhone()) {
|
||||
Recipient primaryDevice = getPrimaryDeviceRecipient(content.getSender());
|
||||
sender = primaryDevice.getAddress();
|
||||
Recipient masterDevice = getMasterRecipient(content.getSender());
|
||||
sender = masterDevice.getAddress();
|
||||
}
|
||||
|
||||
for (long timestamp : message.getTimestamps()) {
|
||||
@ -1580,11 +1555,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
{
|
||||
if (TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
|
||||
// Redirect message to primary device conversation
|
||||
// Redirect message to master device conversation
|
||||
Address sender = Address.fromSerialized(content.getSender());
|
||||
if (sender.isPhone()) {
|
||||
Recipient primaryDevice = getPrimaryDeviceRecipient(content.getSender());
|
||||
sender = primaryDevice.getAddress();
|
||||
Recipient masterDevice = getMasterRecipient(content.getSender());
|
||||
sender = masterDevice.getAddress();
|
||||
}
|
||||
|
||||
for (long timestamp : message.getTimestamps()) {
|
||||
@ -1615,7 +1590,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(groupRecipient);
|
||||
} else {
|
||||
// See if we need to redirect the message
|
||||
author = getPrimaryDeviceRecipient(content.getSender());
|
||||
author = getMasterRecipient(content.getSender());
|
||||
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(author);
|
||||
}
|
||||
|
||||
@ -1749,9 +1724,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
|
||||
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp) {
|
||||
Recipient primaryDevice = getPrimaryDeviceRecipient(sender);
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(primaryDevice.getAddress(),
|
||||
Recipient masterDevice = getMasterRecipient(sender);
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(masterDevice.getAddress(),
|
||||
senderDevice, timestamp, "",
|
||||
Optional.absent(), 0, false);
|
||||
|
||||
@ -1771,11 +1746,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
if (message.getMessage().isGroupMessage()) {
|
||||
return getSyncMessageDestination(message);
|
||||
} else {
|
||||
return getPrimaryDeviceRecipient(message.getDestination().get());
|
||||
return getMasterRecipient(message.getDestination().get());
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
private Recipient getRecipientForMessage(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
if (message.isGroupMessage()) {
|
||||
return Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(message.getGroupInfo().get())), false);
|
||||
} else {
|
||||
@ -1783,34 +1758,34 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getMessagePrimaryDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
private Recipient getMasterRecipientForMessage(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
if (message.isGroupMessage()) {
|
||||
return getMessageDestination(content, message);
|
||||
return getRecipientForMessage(content, message);
|
||||
} else {
|
||||
return getPrimaryDeviceRecipient(content.getSender());
|
||||
return getMasterRecipient(content.getSender());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary device recipient of the passed in device.
|
||||
* Get the master device recipient of the provided device.
|
||||
*
|
||||
* If the device doesn't have a primary device then it will return the same device.
|
||||
* If the device is our primary device then it will return our current device.
|
||||
* Otherwise it will return the primary device.
|
||||
* If the device doesn't have a master device this will return the same device.
|
||||
* If the device is our master device then it will return our current device.
|
||||
* Otherwise it will return the master device.
|
||||
*/
|
||||
private Recipient getPrimaryDeviceRecipient(String pubKey) {
|
||||
private Recipient getMasterRecipient(String hexEncodedPublicKey) {
|
||||
try {
|
||||
String primaryDevice = PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(pubKey), 5000).get();
|
||||
String publicKey = (primaryDevice != null) ? primaryDevice : pubKey;
|
||||
// If the public key matches our primary device then we need to forward the message to ourselves (Note to self)
|
||||
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourPrimaryDevice != null && ourPrimaryDevice.equals(publicKey)) {
|
||||
publicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
String masterHexEncodedPublicKey = PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(hexEncodedPublicKey), 5000).get();
|
||||
String targetHexEncodedPublicKey = (masterHexEncodedPublicKey != null) ? masterHexEncodedPublicKey : hexEncodedPublicKey;
|
||||
// If the public key matches our master device then we need to forward the message to ourselves (note to self)
|
||||
String ourMasterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourMasterHexEncodedPublicKey != null && ourMasterHexEncodedPublicKey.equals(targetHexEncodedPublicKey)) {
|
||||
targetHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
}
|
||||
return Recipient.from(context, Address.fromSerialized(publicKey), false);
|
||||
return Recipient.from(context, Address.fromSerialized(targetHexEncodedPublicKey), false);
|
||||
} catch (Exception e) {
|
||||
Log.d("Loki", "Failed to get primary device public key for " + pubKey + ". " + e.getMessage());
|
||||
return Recipient.from(context, Address.fromSerialized(pubKey), false);
|
||||
Log.d("Loki", "Failed to get master device for: " + hexEncodedPublicKey + ". " + e.getMessage());
|
||||
return Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1836,7 +1811,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
return false;
|
||||
} else if (content.getDataMessage().isPresent()) {
|
||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||
Recipient conversation = getMessageDestination(content, message);
|
||||
Recipient conversation = getRecipientForMessage(content, message);
|
||||
|
||||
if (conversation.isGroupRecipient() && conversation.isBlocked()) {
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user