Merge pull request #2 from loki-project/friend-request-handling

Friend Request Handling V2
This commit is contained in:
gamabuntan 2019-07-24 12:49:00 +10:00 committed by GitHub
commit 4374a902be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 48 deletions

View File

@ -2716,11 +2716,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
String contactID = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(this.threadId).getAddress().toString(); String contactID = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(this.threadId).getAddress().toString();
SignalServiceMessageSender messageSender = ApplicationContext.getInstance(this).communicationModule.provideSignalMessageSender(); SignalServiceMessageSender messageSender = ApplicationContext.getInstance(this).communicationModule.provideSignalMessageSender();
SignalServiceAddress address = new SignalServiceAddress(contactID); SignalServiceAddress address = new SignalServiceAddress(contactID);
SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), ""); SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), null);
try { try {
messageSender.sendMessage(0, address, Optional.absent(), message); // The message ID doesn't matter messageSender.sendMessage(0, address, Optional.absent(), message); // The message ID doesn't matter
} catch (Exception e) { } catch (Exception e) {
Log.d("Loki", "Failed to send empty message to: " + contactID + "."); Log.d("Loki", "Failed to send background message to: " + contactID + ".");
} }
} }

View File

@ -257,6 +257,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return; return;
} }
// Loki - Handle friend request acceptance if needed
acceptFriendRequestIfNeeded(envelope, content);
// Loki - Store pre key bundle if needed // Loki - Store pre key bundle if needed
if (content.lokiMessage.isPresent()) { if (content.lokiMessage.isPresent()) {
LokiServiceMessage lokiMessage = content.lokiMessage.get(); LokiServiceMessage lokiMessage = content.lokiMessage.get();
@ -302,8 +305,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
handleNeedsDeliveryReceipt(content, message); handleNeedsDeliveryReceipt(content, message);
} }
// Loki - Handle friend request logic // Loki - Handle friend request logic if needed
handleFriendRequestIfNeeded(envelope, content, message); updateFriendRequestStatusIfNeeded(envelope, content, message);
} else if (content.getSyncMessage().isPresent()) { } else if (content.getSyncMessage().isPresent()) {
TextSecurePreferences.setMultiDevice(context, true); TextSecurePreferences.setMultiDevice(context, true);
@ -347,11 +350,10 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} catch (ProtocolInvalidVersionException e) { } catch (ProtocolInvalidVersionException e) {
Log.w(TAG, e); Log.w(TAG, e);
handleInvalidVersionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId); handleInvalidVersionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
} catch (ProtocolInvalidMessageException e) { } catch (ProtocolInvalidMessageException e) {
Log.w(TAG, e); Log.w(TAG, e);
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId); handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
} } catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
Log.w(TAG, e); Log.w(TAG, e);
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId); handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
} catch (StorageFailedException e) { } catch (StorageFailedException e) {
@ -489,11 +491,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
String contactID = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId).getAddress().toString(); String contactID = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId).getAddress().toString();
SignalServiceMessageSender messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender(); SignalServiceMessageSender messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender();
SignalServiceAddress address = new SignalServiceAddress(contactID); SignalServiceAddress address = new SignalServiceAddress(contactID);
SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), ""); SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), null);
try { try {
messageSender.sendMessage(0, address, Optional.absent(), message); // The message ID doesn't matter messageSender.sendMessage(0, address, Optional.absent(), message); // The message ID doesn't matter
} catch (Exception e) { } catch (Exception e) {
Log.d("Loki", "Failed to send empty message to: " + contactID + "."); Log.d("Loki", "Failed to send background message to: " + contactID + ".");
} }
SecurityEvent.broadcastSecurityUpdateEvent(context); SecurityEvent.broadcastSecurityUpdateEvent(context);
@ -860,59 +862,69 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} }
} }
private void handleFriendRequestIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) { private void acceptFriendRequestIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content) {
Recipient contactID = getMessageDestination(content, message); // If we get anything other than a friend request, we can assume that we have a session with the other user
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context); if (envelope.isFriendRequest()) { return; }
Recipient contactID = Recipient.from(context, Address.fromSerialized(content.getSender()), false);
LokiThreadDatabase threadDatabase = DatabaseFactory.getLokiThreadDatabase(context);
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(contactID); long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(contactID);
LokiThreadFriendRequestStatus threadFriendRequestStatus = lokiThreadDatabase.getFriendRequestStatus(threadID); LokiThreadFriendRequestStatus threadFriendRequestStatus = threadDatabase.getFriendRequestStatus(threadID);
if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS) { return; }
SmsDatabase messageDatabase = DatabaseFactory.getSmsDatabase(context); SmsDatabase messageDatabase = DatabaseFactory.getSmsDatabase(context);
LokiMessageFriendRequestDatabase messageFriendRequestDatabase = DatabaseFactory.getLokiMessageFriendRequestDatabase(context); LokiMessageFriendRequestDatabase messageFriendRequestDatabase = DatabaseFactory.getLokiMessageFriendRequestDatabase(context);
int messageCount = messageDatabase.getMessageCountForThread(threadID); int messageCount = messageDatabase.getMessageCountForThread(threadID);
if (envelope.isFriendRequest()) { // If the thread's friend request status is not `FRIENDS`, but we're receiving a message,
if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) { // it must be a friend request accepted message. Declining a friend request doesn't send a message.
// This can happen if Alice sent Bob a friend request, Bob declined, but then Bob changed his threadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS);
// mind and sent a friend request to Alice. In this case we want Alice to auto-accept the request long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 1);
// and send a friend request accepted message back to Bob. We don't check that sending the messageFriendRequestDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
// friend request accepted message succeeded. Even if it doesn't, the thread's current friend }
// request status will be set to `FRIENDS` for Alice making it possible
// for Alice to send messages to Bob. When Bob receives a message, his thread's friend request status private void updateFriendRequestStatusIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) {
// will then be set to `FRIENDS`. If we do check for a successful send if (!envelope.isFriendRequest()) { return; }
// before updating Alice's thread's friend request status to `FRIENDS`, Recipient contactID = getMessageDestination(content, message);
// we can end up in a deadlock where both users' threads' friend request statuses are LokiThreadDatabase threadDatabase = DatabaseFactory.getLokiThreadDatabase(context);
// `REQUEST_SENT`. long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(contactID);
lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS); LokiThreadFriendRequestStatus threadFriendRequestStatus = threadDatabase.getFriendRequestStatus(threadID);
long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 2); // The message before the one that was just received SmsDatabase messageDatabase = DatabaseFactory.getSmsDatabase(context);
messageFriendRequestDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); LokiMessageFriendRequestDatabase messageFriendRequestDatabase = DatabaseFactory.getLokiMessageFriendRequestDatabase(context);
// Accept the friend request int messageCount = messageDatabase.getMessageCountForThread(threadID);
sendEmptyMessage(envelope.getSource()); if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) {
} else if (threadFriendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS) { // This can happen if Alice sent Bob a friend request, Bob declined, but then Bob changed his
// Checking that the sender of the message isn't already a friend is necessary because otherwise // mind and sent a friend request to Alice. In this case we want Alice to auto-accept the request
// the following situation can occur: Alice and Bob are friends. Bob loses his database and his // and send a friend request accepted message back to Bob. We don't check that sending the
// friend request status is reset to `NONE`. Bob now sends Alice a friend // friend request accepted message succeeded. Even if it doesn't, the thread's current friend
// request. Alice's thread's friend request status is reset to // request status will be set to `FRIENDS` for Alice making it possible
// `REQUEST_RECEIVED`. // for Alice to send messages to Bob. When Bob receives a message, his thread's friend request status
lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED); // will then be set to `FRIENDS`. If we do check for a successful send
long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 1); // The message that was just received // before updating Alice's thread's friend request status to `FRIENDS`,
messageFriendRequestDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING); // we can end up in a deadlock where both users' threads' friend request statuses are
} // `REQUEST_SENT`.
} else if (threadFriendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS) { threadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS);
// If the thread's friend request status is not `FRIENDS`, 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);
long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 2); // The message before the one that was just received long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 2); // The message before the one that was just received
messageFriendRequestDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); messageFriendRequestDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
// TODO: Send p2p details here // Accept the friend request
sendBackgroundMessage(content.getSender());
} else if (threadFriendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS) {
// Checking that the sender of the message isn't already a friend is necessary because otherwise
// the following situation can occur: Alice and Bob are friends. Bob loses his database and his
// friend request status is reset to `NONE`. Bob now sends Alice a friend
// request. Alice's thread's friend request status is reset to
// `REQUEST_RECEIVED`.
threadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED);
long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 1); // The message that was just received
messageFriendRequestDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING);
} }
} }
public void sendEmptyMessage(String contactHexEncodedPublicKey) { private void sendBackgroundMessage(String contactHexEncodedPublicKey) {
try { try {
SignalServiceAddress address = new SignalServiceAddress(contactHexEncodedPublicKey); SignalServiceAddress address = new SignalServiceAddress(contactHexEncodedPublicKey);
SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), ""); SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), null);
Optional<UnidentifiedAccessPair> access = Optional.absent(); Optional<UnidentifiedAccessPair> access = Optional.absent();
messageSender.sendMessage(0, address, access, message); // The message ID doesn't matter messageSender.sendMessage(0, address, access, message); // The message ID doesn't matter
} catch (Exception e) { } catch (Exception e) {
Log.d("Loki", "Failed to send empty message to: " + contactHexEncodedPublicKey + "."); Log.d("Loki", "Failed to send background message to: " + contactHexEncodedPublicKey + ".");
} }
} }