Merge branch '1514-introduction-message' into 'master'

Fix Introduction Issues

Closes #1516 and #1514

See merge request briar/briar!1067
This commit is contained in:
akwizgran
2019-04-04 16:47:09 +00:00
7 changed files with 89 additions and 32 deletions

View File

@@ -252,12 +252,12 @@ class ConversationVisitor implements
if (r.isLocal()) { if (r.isLocal()) {
String text; String text;
if (r.wasAccepted()) { if (r.wasAccepted()) {
String suffix = r.canSucceed() ? "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
introducedAuthor) : "";
text = ctx.getString( text = ctx.getString(
R.string.introduction_response_accepted_sent, R.string.introduction_response_accepted_sent,
introducedAuthor) introducedAuthor) + suffix;
+ "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
introducedAuthor);
} else { } else {
text = ctx.getString( text = ctx.getString(
R.string.introduction_response_declined_sent, R.string.introduction_response_declined_sent,

View File

@@ -20,16 +20,18 @@ public class IntroductionResponse extends ConversationResponse {
private final Author introducedAuthor; private final Author introducedAuthor;
private final AuthorInfo introducedAuthorInfo; private final AuthorInfo introducedAuthorInfo;
private final Role ourRole; private final Role ourRole;
private final boolean canSucceed;
public IntroductionResponse(MessageId messageId, GroupId groupId, long time, public IntroductionResponse(MessageId messageId, GroupId groupId, long time,
boolean local, boolean read, boolean sent, boolean seen, boolean local, boolean read, boolean sent, boolean seen,
SessionId sessionId, boolean accepted, Author author, SessionId sessionId, boolean accepted, Author author,
AuthorInfo introducedAuthorInfo, Role role) { AuthorInfo introducedAuthorInfo, Role role, boolean canSucceed) {
super(messageId, groupId, time, local, read, sent, seen, sessionId, super(messageId, groupId, time, local, read, sent, seen, sessionId,
accepted); accepted);
this.introducedAuthor = author; this.introducedAuthor = author;
this.introducedAuthorInfo = introducedAuthorInfo; this.introducedAuthorInfo = introducedAuthorInfo;
this.ourRole = role; this.ourRole = role;
this.canSucceed = canSucceed;
} }
public Author getIntroducedAuthor() { public Author getIntroducedAuthor() {
@@ -40,6 +42,10 @@ public class IntroductionResponse extends ConversationResponse {
return introducedAuthorInfo; return introducedAuthorInfo;
} }
public boolean canSucceed() {
return canSucceed;
}
public boolean isIntroducer() { public boolean isIntroducer() {
return ourRole == INTRODUCER; return ourRole == INTRODUCER;
} }
@@ -48,4 +54,5 @@ public class IntroductionResponse extends ConversationResponse {
public <T> T accept(ConversationMessageVisitor<T> v) { public <T> T accept(ConversationMessageVisitor<T> v) {
return v.visitIntroductionResponse(this); return v.visitIntroductionResponse(this);
} }
} }

View File

@@ -146,8 +146,8 @@ abstract class AbstractProtocolEngine<S extends Session>
} }
void broadcastIntroductionResponseReceivedEvent(Transaction txn, Session s, void broadcastIntroductionResponseReceivedEvent(Transaction txn, Session s,
AuthorId sender, Author otherAuthor, AbstractIntroductionMessage m) AuthorId sender, Author otherAuthor, AbstractIntroductionMessage m,
throws DbException { boolean canSucceed) throws DbException {
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId(); AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
Contact c = contactManager.getContact(txn, sender, localAuthorId); Contact c = contactManager.getContact(txn, sender, localAuthorId);
AuthorInfo otherAuthorInfo = AuthorInfo otherAuthorInfo =
@@ -156,7 +156,7 @@ abstract class AbstractProtocolEngine<S extends Session>
new IntroductionResponse(m.getMessageId(), m.getGroupId(), new IntroductionResponse(m.getMessageId(), m.getGroupId(),
m.getTimestamp(), false, false, false, false, m.getTimestamp(), false, false, false, false,
s.getSessionId(), m instanceof AcceptMessage, s.getSessionId(), m instanceof AcceptMessage,
otherAuthor, otherAuthorInfo, s.getRole()); otherAuthor, otherAuthorInfo, s.getRole(), canSucceed);
IntroductionResponseReceivedEvent e = IntroductionResponseReceivedEvent e =
new IntroductionResponseReceivedEvent(response, c.getId()); new IntroductionResponseReceivedEvent(response, c.getId());
txn.attach(e); txn.attach(e);

View File

@@ -363,12 +363,15 @@ class IntroduceeProtocolEngine
// Broadcast IntroductionResponseReceivedEvent // Broadcast IntroductionResponseReceivedEvent
broadcastIntroductionResponseReceivedEvent(txn, s, broadcastIntroductionResponseReceivedEvent(txn, s,
s.getIntroducer().getId(), s.getRemote().author, m); s.getIntroducer().getId(), s.getRemote().author, m, false);
// Move to REMOTE_DECLINED state // Determine next state
return IntroduceeSession.clear(s, REMOTE_DECLINED, IntroduceeState state =
s.getLastLocalMessageId(), s.getLocalTimestamp(), s.getState() == AWAIT_RESPONSES ? REMOTE_DECLINED : START;
m.getMessageId());
// Move to the next state
return IntroduceeSession.clear(s, state, s.getLastLocalMessageId(),
s.getLocalTimestamp(), m.getMessageId());
} }
private IntroduceeSession onRemoteResponseWhenDeclined(Transaction txn, private IntroduceeSession onRemoteResponseWhenDeclined(Transaction txn,
@@ -381,17 +384,6 @@ class IntroduceeProtocolEngine
if (isInvalidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abort(txn, s); 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);
// Broadcast IntroductionResponseReceivedEvent
broadcastIntroductionResponseReceivedEvent(txn, s,
s.getIntroducer().getId(), s.getRemote().author, m);
// Move to START state // Move to START state
return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(), return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(),
s.getLocalTimestamp(), m.getMessageId()); s.getLocalTimestamp(), m.getMessageId());

View File

@@ -294,7 +294,7 @@ class IntroducerProtocolEngine
// Broadcast IntroductionResponseReceivedEvent // Broadcast IntroductionResponseReceivedEvent
broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(),
other, m); other, m, true);
// Move to the next state // Move to the next state
return new IntroducerSession(s.getSessionId(), state, return new IntroducerSession(s.getSessionId(), state,
@@ -349,7 +349,7 @@ class IntroducerProtocolEngine
// Broadcast IntroductionResponseReceivedEvent // Broadcast IntroductionResponseReceivedEvent
broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(),
other, m); other, m, false);
return new IntroducerSession(s.getSessionId(), START, return new IntroducerSession(s.getSessionId(), START,
s.getRequestTimestamp(), introduceeA, introduceeB); s.getRequestTimestamp(), introduceeA, introduceeB);
@@ -403,7 +403,7 @@ class IntroducerProtocolEngine
// Broadcast IntroductionResponseReceivedEvent // Broadcast IntroductionResponseReceivedEvent
broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(),
other, m); other, m, false);
return new IntroducerSession(s.getSessionId(), state, return new IntroducerSession(s.getSessionId(), state,
s.getRequestTimestamp(), introduceeA, introduceeB); s.getRequestTimestamp(), introduceeA, introduceeB);
@@ -451,7 +451,7 @@ class IntroducerProtocolEngine
// Broadcast IntroductionResponseReceivedEvent // Broadcast IntroductionResponseReceivedEvent
broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(),
other, m); other, m, false);
return new IntroducerSession(s.getSessionId(), START, return new IntroducerSession(s.getSessionId(), START,
s.getRequestTimestamp(), introduceeA, introduceeB); s.getRequestTimestamp(), introduceeA, introduceeB);

View File

@@ -52,6 +52,9 @@ import javax.inject.Inject;
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
import static org.briarproject.briar.api.introduction.Role.INTRODUCER; import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
import static org.briarproject.briar.introduction.IntroduceeState.REMOTE_DECLINED;
import static org.briarproject.briar.introduction.IntroducerState.A_DECLINED;
import static org.briarproject.briar.introduction.IntroducerState.B_DECLINED;
import static org.briarproject.briar.introduction.IntroducerState.START; import static org.briarproject.briar.introduction.IntroducerState.START;
import static org.briarproject.briar.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.briar.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ABORT;
@@ -466,6 +469,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
Role role = sessionParser.getRole(bdfSession); Role role = sessionParser.getRole(bdfSession);
SessionId sessionId; SessionId sessionId;
Author author; Author author;
boolean canSucceed;
if (role == INTRODUCER) { if (role == INTRODUCER) {
IntroducerSession session = IntroducerSession session =
sessionParser.parseIntroducerSession(bdfSession); sessionParser.parseIntroducerSession(bdfSession);
@@ -475,11 +479,15 @@ class IntroductionManagerImpl extends ConversationClientImpl
} else { } else {
author = session.getIntroduceeA().author; author = session.getIntroduceeA().author;
} }
IntroducerState s = session.getState();
canSucceed = s != START && s != A_DECLINED && s != B_DECLINED;
} else if (role == INTRODUCEE) { } else if (role == INTRODUCEE) {
IntroduceeSession session = sessionParser IntroduceeSession session = sessionParser
.parseIntroduceeSession(contactGroupId, bdfSession); .parseIntroduceeSession(contactGroupId, bdfSession);
sessionId = session.getSessionId(); sessionId = session.getSessionId();
author = session.getRemote().author; author = session.getRemote().author;
IntroduceeState s = session.getState();
canSucceed = s != IntroduceeState.START && s != REMOTE_DECLINED;
} else throw new AssertionError(); } else throw new AssertionError();
AuthorInfo authorInfo = authorInfos.get(author.getId()); AuthorInfo authorInfo = authorInfos.get(author.getId());
if (authorInfo == null) { if (authorInfo == null) {
@@ -488,7 +496,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
} }
return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(), return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(),
meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(),
sessionId, accept, author, authorInfo, role); sessionId, accept, author, authorInfo, role, canSucceed);
} }
private void removeSessionWithIntroducer(Transaction txn, private void removeSessionWithIntroducer(Transaction txn,

View File

@@ -185,6 +185,7 @@ public class IntroductionIntegrationTest
assertEquals(introducee2.getAuthor().getName(), assertEquals(introducee2.getAuthor().getName(),
listener0.getResponse().getIntroducedAuthor().getName()); listener0.getResponse().getIntroducedAuthor().getName());
assertGroupCount(messageTracker0, g1.getId(), 2, 1); assertGroupCount(messageTracker0, g1.getId(), 2, 1);
assertTrue(listener0.getResponse().canSucceed());
// sync second ACCEPT message // sync second ACCEPT message
sync2To0(1, true); sync2To0(1, true);
@@ -193,6 +194,7 @@ public class IntroductionIntegrationTest
assertEquals(introducee1.getAuthor().getName(), assertEquals(introducee1.getAuthor().getName(),
listener0.getResponse().getIntroducedAuthor().getName()); listener0.getResponse().getIntroducedAuthor().getName());
assertGroupCount(messageTracker0, g2.getId(), 2, 1); assertGroupCount(messageTracker0, g2.getId(), 2, 1);
assertTrue(listener0.getResponse().canSucceed());
// sync forwarded ACCEPT messages to introducees // sync forwarded ACCEPT messages to introducees
sync0To1(1, true); sync0To1(1, true);
@@ -290,6 +292,7 @@ public class IntroductionIntegrationTest
// assert that the name on the decline event is correct // assert that the name on the decline event is correct
assertEquals(introducee2.getAuthor().getName(), assertEquals(introducee2.getAuthor().getName(),
listener0.getResponse().getIntroducedAuthor().getName()); listener0.getResponse().getIntroducedAuthor().getName());
assertFalse(listener0.getResponse().canSucceed());
// sync second response // sync second response
sync2To0(1, true); sync2To0(1, true);
@@ -307,6 +310,7 @@ public class IntroductionIntegrationTest
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertEquals(introducee1.getAuthor().getName(), assertEquals(introducee1.getAuthor().getName(),
listener2.getResponse().getIntroducedAuthor().getName()); listener2.getResponse().getIntroducedAuthor().getName());
assertFalse(listener2.getResponse().canSucceed());
// note how the introducer does not forward the second response, // note how the introducer does not forward the second response,
// because after the first decline the protocol finished // because after the first decline the protocol finished
@@ -381,6 +385,7 @@ public class IntroductionIntegrationTest
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertEquals(contact2From0.getAuthor().getName(), assertEquals(contact2From0.getAuthor().getName(),
listener1.getResponse().getIntroducedAuthor().getName()); listener1.getResponse().getIntroducedAuthor().getName());
assertFalse(listener1.getResponse().canSucceed());
assertFalse(contactManager1 assertFalse(contactManager1
.contactExists(author2.getId(), author1.getId())); .contactExists(author2.getId(), author1.getId()));
@@ -399,7 +404,52 @@ public class IntroductionIntegrationTest
assertEquals(3, messages.size()); assertEquals(3, messages.size());
messages = db2.transactionWithResult(true, txn -> messages = db2.transactionWithResult(true, txn ->
introductionManager2.getMessageHeaders(txn, contactId0From2)); introductionManager2.getMessageHeaders(txn, contactId0From2));
assertEquals(3, messages.size()); assertEquals(2, messages.size());
assertFalse(listener0.aborted);
assertFalse(listener1.aborted);
assertFalse(listener2.aborted);
}
@Test
public void testNewIntroductionAfterDecline() throws Exception {
addListeners(false, true);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
// sync request messages
sync0To1(1, true);
sync0To2(1, true);
eventWaiter.await(TIMEOUT, 2);
// sync first response
sync1To0(1, true);
eventWaiter.await(TIMEOUT, 1);
// sync second response
sync2To0(1, true);
eventWaiter.await(TIMEOUT, 1);
// sync both forwarded response
sync0To2(1, true);
sync0To1(1, true);
eventWaiter.await(TIMEOUT, 1);
assertFalse(listener0.aborted);
assertFalse(listener1.aborted);
assertFalse(listener2.aborted);
time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
// sync request messages
sync0To1(1, true);
sync0To2(1, true);
eventWaiter.await(TIMEOUT, 2);
assertFalse(listener0.aborted); assertFalse(listener0.aborted);
assertFalse(listener1.aborted); assertFalse(listener1.aborted);
assertFalse(listener2.aborted); assertFalse(listener2.aborted);
@@ -553,10 +603,10 @@ public class IntroductionIntegrationTest
introductionManager0.getMessageHeaders(txn, contactId2From0)) introductionManager0.getMessageHeaders(txn, contactId2From0))
.size()); .size());
assertGroupCount(messageTracker0, g2.getId(), 2, 1); assertGroupCount(messageTracker0, g2.getId(), 2, 1);
assertEquals(3, db1.transactionWithResult(true, txn -> assertEquals(2, db1.transactionWithResult(true, txn ->
introductionManager1.getMessageHeaders(txn, contactId0From1)) introductionManager1.getMessageHeaders(txn, contactId0From1))
.size()); .size());
assertGroupCount(messageTracker1, g1.getId(), 3, 2); assertGroupCount(messageTracker1, g1.getId(), 2, 1);
assertEquals(3, db2.transactionWithResult(true, txn -> assertEquals(3, db2.transactionWithResult(true, txn ->
introductionManager2.getMessageHeaders(txn, contactId0From2)) introductionManager2.getMessageHeaders(txn, contactId0From2))
.size()); .size());