From c0dfe3e85a44657394480dab2d23f399f9f38405 Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Fri, 27 Apr 2018 15:57:56 +0100 Subject: [PATCH] Sent automatic decline when other introducee declines. --- .../android/contact/ConversationActivity.java | 87 ++++++++++--------- .../introduction/AbstractProtocolEngine.java | 3 +- .../IntroduceeProtocolEngine.java | 22 ++++- .../IntroducerProtocolEngine.java | 66 ++++++++++++-- 4 files changed, 121 insertions(+), 57 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java index 2af7fb8e54..67572ff2bd 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java @@ -575,6 +575,10 @@ public class ConversationActivity extends BriarActivity @Override public void onSuccess(String contactName) { runOnUiThreadUnlessDestroyed(() -> { + // If the other introducee declined, we can no longer + // respond to the request + if (!m.isIntroducer() && !m.wasAccepted()) + markRequestAnswered(m.getSessionId()); ConversationItem item = ConversationItem .from(ConversationActivity.this, contactName, m); addConversationItem(item); @@ -627,6 +631,26 @@ public class ConversationActivity extends BriarActivity }); } + private void markRequestAnswered(SessionId sessionId) { + int size = adapter.getItemCount(); + for (int i = 0; i < size; i++) { + ConversationItem item = adapter.getItemAt(i); + if (item instanceof ConversationRequestItem) { + ConversationRequestItem req = (ConversationRequestItem) item; + if (req.getSessionId().equals(sessionId) + && !req.wasAnswered()) { + LOG.info("Marking request answered"); + req.setAnswered(true); + int position = adapter.findItemPosition(req); + if (position != INVALID_POSITION) + adapter.notifyItemChanged(position, req); + // There shouldn't be more than one unanswered request + return; + } + } + } + } + private void markMessages(Collection<MessageId> messageIds, boolean sent, boolean seen) { runOnUiThreadUnlessDestroyed(() -> { @@ -781,25 +805,18 @@ public class ConversationActivity extends BriarActivity return; } - PromptStateChangeListener listener = new PromptStateChangeListener() { - @Override - public void onPromptStateChanged( - MaterialTapTargetPrompt prompt, int state) { - if (state == STATE_DISMISSED || - state == STATE_FINISHED) { -introductionOnboardingSeen(); - } - } - - }; - new MaterialTapTargetPrompt.Builder(ConversationActivity.this, - R.style.OnboardingDialogTheme).setTarget(target) - .setPrimaryText(R.string.introduction_onboarding_title) - .setSecondaryText(R.string.introduction_onboarding_text) - .setIcon(R.drawable.ic_more_vert_accent) - .setPromptStateChangeListener(listener) - .show(); - + PromptStateChangeListener listener = (prompt, state) -> { + if (state == STATE_DISMISSED || state == STATE_FINISHED) { + introductionOnboardingSeen(); + } + }; + new MaterialTapTargetPrompt.Builder(ConversationActivity.this, + R.style.OnboardingDialogTheme).setTarget(target) + .setPrimaryText(R.string.introduction_onboarding_title) + .setSecondaryText(R.string.introduction_onboarding_text) + .setIcon(R.drawable.ic_more_vert_accent) + .setPromptStateChangeListener(listener) + .show(); }); } @@ -865,11 +882,12 @@ introductionOnboardingSeen(); "Unknown Request Type"); } loadMessages(); + } catch (ProtocolStateException e) { + // Action is no longer valid - reloading should solve the issue + if (LOG.isLoggable(INFO)) LOG.log(INFO, e.toString(), e); } catch (DbException e) { - // TODO use more generic error message - introductionResponseError(); - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); + // TODO show an error message + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } }); } @@ -900,14 +918,8 @@ introductionOnboardingSeen(); @DatabaseExecutor private void respondToIntroductionRequest(SessionId sessionId, boolean accept, long time) throws DbException { - try { - introductionManager - .respondToIntroduction(contactId, sessionId, time, accept); - } catch (ProtocolStateException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - introductionResponseError(); - } + introductionManager.respondToIntroduction(contactId, sessionId, time, + accept); } @DatabaseExecutor @@ -925,18 +937,7 @@ introductionOnboardingSeen(); @DatabaseExecutor private void respondToGroupRequest(SessionId id, boolean accept) throws DbException { - try { - groupInvitationManager.respondToInvitation(contactId, id, accept); - } catch (ProtocolStateException e) { - // this action is no longer possible - } - } - - private void introductionResponseError() { - runOnUiThreadUnlessDestroyed(() -> - Toast.makeText(ConversationActivity.this, - R.string.introduction_response_error, - Toast.LENGTH_SHORT).show()); + groupInvitationManager.respondToInvitation(contactId, id, accept); } private ListenableFutureTask<String> getContactNameTask() { diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java index c9002bb0e6..ae395b5969 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java @@ -84,8 +84,7 @@ abstract class AbstractProtocolEngine<S extends Session> Message sendAcceptMessage(Transaction txn, PeerSession s, long timestamp, byte[] ephemeralPublicKey, long acceptTimestamp, Map<TransportId, TransportProperties> transportProperties, - boolean visible) - throws DbException { + boolean visible) throws DbException { Message m = messageEncoder .encodeAcceptMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index c0cf65a073..c1bab31a8a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -357,9 +357,25 @@ class IntroduceeProtocolEngine broadcastIntroductionResponseReceivedEvent(txn, s, s.getIntroducer().getId(), m); - // Move back to START state - return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(), - s.getLocalTimestamp(), m.getMessageId()); + if (s.getState() == AWAIT_RESPONSES) { + // Mark the request message unavailable to answer + markRequestsUnavailableToAnswer(txn, s); + + // Send a DECLINE message + Message sent = + sendDeclineMessage(txn, s, getLocalTimestamp(s), false); + + // Track the message + messageTracker.trackOutgoingMessage(txn, sent); + + // Move back to START state + return IntroduceeSession.clear(s, START, sent.getId(), + sent.getTimestamp(), m.getMessageId()); + } else { + // Move back to START state + return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(), + s.getLocalTimestamp(), m.getMessageId()); + } } private IntroduceeSession onRemoteResponseWhenDeclined(Transaction txn, diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java index ed19fe651a..50b9d01a94 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java @@ -113,7 +113,7 @@ class IntroducerProtocolEngine return onRemoteAccept(txn, s, m); case A_DECLINED: case B_DECLINED: - return onRemoteResponseWhenDeclined(txn, s, m); + return onRemoteAcceptWhenDeclined(txn, s, m); case START: case AWAIT_AUTHS: case AWAIT_AUTH_A: @@ -137,7 +137,7 @@ class IntroducerProtocolEngine return onRemoteDecline(txn, s, m); case A_DECLINED: case B_DECLINED: - return onRemoteResponseWhenDeclined(txn, s, m); + return onRemoteDeclineWhenDeclined(txn, s, m); case START: case AWAIT_AUTHS: case AWAIT_AUTH_A: @@ -204,8 +204,8 @@ class IntroducerProtocolEngine } private IntroducerSession onLocalRequest(Transaction txn, - IntroducerSession s, - @Nullable String message, long timestamp) throws DbException { + IntroducerSession s, @Nullable String message, long timestamp) + throws DbException { // Send REQUEST messages long maxIntroduceeTimestamp = Math.max(getLocalTimestamp(s, s.getIntroduceeA()), @@ -285,6 +285,50 @@ class IntroducerProtocolEngine return m.getGroupId().equals(s.getIntroduceeA().groupId); } + private IntroducerSession onRemoteAcceptWhenDeclined(Transaction txn, + IntroducerSession s, AcceptMessage m) throws DbException { + // The timestamp must be higher than the last request message + if (m.getTimestamp() <= s.getRequestTimestamp()) + return abort(txn, s); + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s, m.getGroupId(), m.getPreviousMessageId())) + return abort(txn, s); + // The message must be expected in the current state + boolean senderIsAlice = senderIsAlice(s, m); + if (senderIsAlice && s.getState() != B_DECLINED) + return abort(txn, s); + else if (!senderIsAlice && s.getState() != A_DECLINED) + return abort(txn, s); + + // Mark the response visible in the UI + markMessageVisibleInUi(txn, m.getMessageId()); + // Track the incoming message + messageTracker + .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + + // Forward ACCEPT message + Introducee i = getOtherIntroducee(s, m.getGroupId()); + Message sent = sendAcceptMessage(txn, i, getLocalTimestamp(s, i), + m.getEphemeralPublicKey(), m.getAcceptTimestamp(), + m.getTransportProperties(), false); + + Introducee introduceeA, introduceeB; + if (senderIsAlice) { + introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId()); + introduceeB = new Introducee(s.getIntroduceeB(), sent); + } else { + introduceeA = new Introducee(s.getIntroduceeA(), sent); + introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId()); + } + + // Broadcast IntroductionResponseReceivedEvent + Author sender = senderIsAlice ? introduceeA.author : introduceeB.author; + broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), m); + + return new IntroducerSession(s.getSessionId(), START, + s.getRequestTimestamp(), introduceeA, introduceeB); + } + private IntroducerSession onRemoteDecline(Transaction txn, IntroducerSession s, DeclineMessage m) throws DbException { // The timestamp must be higher than the last request message @@ -334,9 +378,8 @@ class IntroducerProtocolEngine s.getRequestTimestamp(), introduceeA, introduceeB); } - private IntroducerSession onRemoteResponseWhenDeclined(Transaction txn, - IntroducerSession s, AbstractIntroductionMessage m) - throws DbException { + private IntroducerSession onRemoteDeclineWhenDeclined(Transaction txn, + IntroducerSession s, DeclineMessage m) throws DbException { // The timestamp must be higher than the last request message if (m.getTimestamp() <= s.getRequestTimestamp()) return abort(txn, s); @@ -356,12 +399,17 @@ class IntroducerProtocolEngine messageTracker .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + // Forward DECLINE message + Introducee i = getOtherIntroducee(s, m.getGroupId()); + long timestamp = getLocalTimestamp(s, i); + Message sent = sendDeclineMessage(txn, i, timestamp, false); + Introducee introduceeA, introduceeB; if (senderIsAlice) { introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId()); - introduceeB = s.getIntroduceeB(); + introduceeB = new Introducee(s.getIntroduceeB(), sent); } else { - introduceeA = s.getIntroduceeA(); + introduceeA = new Introducee(s.getIntroduceeA(), sent); introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId()); } -- GitLab