mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Ensure that incoming messages are expected in the current state
Previously, the introducer would process and forward invalid messages by the introducees. This commit adds the necessary checks and tests.
This commit is contained in:
@@ -200,21 +200,21 @@ class IntroducerProtocolEngine
|
||||
@Nullable String message, long timestamp) throws DbException {
|
||||
// Send REQUEST messages
|
||||
long localTimestamp =
|
||||
Math.max(timestamp, getLocalTimestamp(s, s.getIntroducee1()));
|
||||
Message sent1 = sendRequestMessage(txn, s.getIntroducee1(),
|
||||
localTimestamp, s.getIntroducee2().author, message
|
||||
Math.max(timestamp, getLocalTimestamp(s, s.getIntroduceeA()));
|
||||
Message sentA = sendRequestMessage(txn, s.getIntroduceeA(),
|
||||
localTimestamp, s.getIntroduceeB().author, message
|
||||
);
|
||||
Message sent2 = sendRequestMessage(txn, s.getIntroducee2(),
|
||||
localTimestamp, s.getIntroducee1().author, message
|
||||
Message sentB = sendRequestMessage(txn, s.getIntroduceeB(),
|
||||
localTimestamp, s.getIntroduceeA().author, message
|
||||
);
|
||||
// Track the messages
|
||||
messageTracker.trackOutgoingMessage(txn, sent1);
|
||||
messageTracker.trackOutgoingMessage(txn, sent2);
|
||||
messageTracker.trackOutgoingMessage(txn, sentA);
|
||||
messageTracker.trackOutgoingMessage(txn, sentB);
|
||||
// Move to the AWAIT_RESPONSES state
|
||||
Introducee introducee1 = new Introducee(s.getIntroducee1(), sent1);
|
||||
Introducee introducee2 = new Introducee(s.getIntroducee2(), sent2);
|
||||
Introducee introduceeA = new Introducee(s.getIntroduceeA(), sentA);
|
||||
Introducee introduceeB = new Introducee(s.getIntroduceeB(), sentB);
|
||||
return new IntroducerSession(s.getSessionId(), AWAIT_RESPONSES,
|
||||
localTimestamp, introducee1, introducee2);
|
||||
localTimestamp, introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private IntroducerSession onRemoteAccept(Transaction txn,
|
||||
@@ -225,6 +225,14 @@ class IntroducerProtocolEngine
|
||||
// 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 (s.getState() != AWAIT_RESPONSES) {
|
||||
if (senderIsAlice && s.getState() != AWAIT_RESPONSE_A)
|
||||
return abort(txn, s);
|
||||
else if (!senderIsAlice && s.getState() != AWAIT_RESPONSE_B)
|
||||
return abort(txn, s);
|
||||
}
|
||||
|
||||
// Mark the response visible in the UI
|
||||
markMessageVisibleInUi(txn, m.getMessageId());
|
||||
@@ -240,27 +248,24 @@ class IntroducerProtocolEngine
|
||||
m.getAcceptTimestamp(), m.getTransportProperties(),
|
||||
false);
|
||||
|
||||
// Move to the next state
|
||||
// Create the next state
|
||||
IntroducerState state = AWAIT_AUTHS;
|
||||
Introducee introducee1, introducee2;
|
||||
Contact c;
|
||||
if (i.equals(s.getIntroducee1())) {
|
||||
if (s.getState() == AWAIT_RESPONSES) state = AWAIT_RESPONSE_A;
|
||||
introducee1 = new Introducee(s.getIntroducee1(), sent);
|
||||
introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId());
|
||||
c = contactManager
|
||||
.getContact(txn, s.getIntroducee2().author.getId(),
|
||||
identityManager.getLocalAuthor(txn).getId());
|
||||
} else if (i.equals(s.getIntroducee2())) {
|
||||
Introducee introduceeA, introduceeB;
|
||||
if (senderIsAlice) {
|
||||
if (s.getState() == AWAIT_RESPONSES) state = AWAIT_RESPONSE_B;
|
||||
introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId());
|
||||
introducee2 = new Introducee(s.getIntroducee2(), sent);
|
||||
c = contactManager
|
||||
.getContact(txn, s.getIntroducee1().author.getId(),
|
||||
identityManager.getLocalAuthor(txn).getId());
|
||||
} else throw new AssertionError();
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), sent);
|
||||
} else {
|
||||
if (s.getState() == AWAIT_RESPONSES) state = AWAIT_RESPONSE_A;
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), sent);
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
||||
}
|
||||
|
||||
// Broadcast IntroductionResponseReceivedEvent
|
||||
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
|
||||
Contact c = contactManager.getContact(txn,
|
||||
senderIsAlice ? introduceeA.author.getId() :
|
||||
introduceeB.author.getId(), localAuthorId);
|
||||
IntroductionResponse request =
|
||||
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
||||
m.getGroupId(), INTRODUCER, m.getTimestamp(), false,
|
||||
@@ -269,8 +274,14 @@ class IntroducerProtocolEngine
|
||||
new IntroductionResponseReceivedEvent(c.getId(), request);
|
||||
txn.attach(e);
|
||||
|
||||
// Move to the next state
|
||||
return new IntroducerSession(s.getSessionId(), state,
|
||||
s.getRequestTimestamp(), introducee1, introducee2);
|
||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private boolean senderIsAlice(IntroducerSession s,
|
||||
AbstractIntroductionMessage m) {
|
||||
return m.getGroupId().equals(s.getIntroduceeA().groupId);
|
||||
}
|
||||
|
||||
private IntroducerSession onRemoteDecline(Transaction txn,
|
||||
@@ -281,6 +292,14 @@ class IntroducerProtocolEngine
|
||||
// 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 (s.getState() != AWAIT_RESPONSES) {
|
||||
if (senderIsAlice && s.getState() != AWAIT_RESPONSE_A)
|
||||
return abort(txn, s);
|
||||
else if (!senderIsAlice && s.getState() != AWAIT_RESPONSE_B)
|
||||
return abort(txn, s);
|
||||
}
|
||||
|
||||
// Mark the response visible in the UI
|
||||
markMessageVisibleInUi(txn, m.getMessageId());
|
||||
@@ -293,25 +312,21 @@ class IntroducerProtocolEngine
|
||||
long timestamp = getLocalTimestamp(s, i);
|
||||
Message sent = sendDeclineMessage(txn, i, timestamp, false);
|
||||
|
||||
// Move to the START state
|
||||
Introducee introducee1, introducee2;
|
||||
AuthorId localAuthorId =identityManager.getLocalAuthor(txn).getId();
|
||||
Contact c;
|
||||
if (i.equals(s.getIntroducee1())) {
|
||||
introducee1 = new Introducee(s.getIntroducee1(), sent);
|
||||
introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId());
|
||||
c = contactManager
|
||||
.getContact(txn, s.getIntroducee2().author.getId(),
|
||||
localAuthorId);
|
||||
} else if (i.equals(s.getIntroducee2())) {
|
||||
introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId());
|
||||
introducee2 = new Introducee(s.getIntroducee2(), sent);
|
||||
c = contactManager
|
||||
.getContact(txn, s.getIntroducee1().author.getId(),
|
||||
localAuthorId);
|
||||
} else throw new AssertionError();
|
||||
// Update introducee state
|
||||
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
|
||||
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
|
||||
Contact c = contactManager.getContact(txn,
|
||||
senderIsAlice ? introduceeA.author.getId() :
|
||||
introduceeB.author.getId(), localAuthorId);
|
||||
IntroductionResponse request =
|
||||
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
||||
m.getGroupId(), INTRODUCER, m.getTimestamp(), false,
|
||||
@@ -321,7 +336,7 @@ class IntroducerProtocolEngine
|
||||
txn.attach(e);
|
||||
|
||||
return new IntroducerSession(s.getSessionId(), START,
|
||||
s.getRequestTimestamp(), introducee1, introducee2);
|
||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private IntroducerSession onRemoteResponseInStart(Transaction txn,
|
||||
@@ -341,20 +356,20 @@ class IntroducerProtocolEngine
|
||||
.trackMessage(txn, m.getGroupId(), m.getTimestamp(), false);
|
||||
|
||||
Introducee i = getIntroducee(s, m.getGroupId());
|
||||
Introducee introducee1, introducee2;
|
||||
Introducee introduceeA, introduceeB;
|
||||
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
|
||||
Contact c;
|
||||
if (i.equals(s.getIntroducee1())) {
|
||||
introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId());
|
||||
introducee2 = s.getIntroducee2();
|
||||
if (i.equals(s.getIntroduceeA())) {
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
||||
introduceeB = s.getIntroduceeB();
|
||||
c = contactManager
|
||||
.getContact(txn, s.getIntroducee1().author.getId(),
|
||||
.getContact(txn, s.getIntroduceeA().author.getId(),
|
||||
localAuthorId);
|
||||
} else if (i.equals(s.getIntroducee2())) {
|
||||
introducee1 = s.getIntroducee1();
|
||||
introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId());
|
||||
} else if (i.equals(s.getIntroduceeB())) {
|
||||
introduceeA = s.getIntroduceeA();
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
||||
c = contactManager
|
||||
.getContact(txn, s.getIntroducee2().author.getId(),
|
||||
.getContact(txn, s.getIntroduceeB().author.getId(),
|
||||
localAuthorId);
|
||||
} else throw new AssertionError();
|
||||
|
||||
@@ -369,7 +384,7 @@ class IntroducerProtocolEngine
|
||||
txn.attach(e);
|
||||
|
||||
return new IntroducerSession(s.getSessionId(), START,
|
||||
s.getRequestTimestamp(), introducee1, introducee2);
|
||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private IntroducerSession onRemoteAuth(Transaction txn,
|
||||
@@ -377,6 +392,14 @@ class IntroducerProtocolEngine
|
||||
// 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 (s.getState() != AWAIT_AUTHS) {
|
||||
if (senderIsAlice && s.getState() != AWAIT_AUTH_A)
|
||||
return abort(txn, s);
|
||||
else if (!senderIsAlice && s.getState() != AWAIT_AUTH_B)
|
||||
return abort(txn, s);
|
||||
}
|
||||
|
||||
// Forward AUTH message
|
||||
Introducee i = getOtherIntroducee(s, m.getGroupId());
|
||||
@@ -386,18 +409,18 @@ class IntroducerProtocolEngine
|
||||
|
||||
// Move to the next state
|
||||
IntroducerState state = AWAIT_ACTIVATES;
|
||||
Introducee introducee1, introducee2;
|
||||
if (i.equals(s.getIntroducee1())) {
|
||||
if (s.getState() == AWAIT_AUTHS) state = AWAIT_AUTH_A;
|
||||
introducee1 = new Introducee(s.getIntroducee1(), sent);
|
||||
introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId());
|
||||
} else if (i.equals(s.getIntroducee2())) {
|
||||
Introducee introduceeA, introduceeB;
|
||||
if (senderIsAlice) {
|
||||
if (s.getState() == AWAIT_AUTHS) state = AWAIT_AUTH_B;
|
||||
introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId());
|
||||
introducee2 = new Introducee(s.getIntroducee2(), sent);
|
||||
} else throw new AssertionError();
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), sent);
|
||||
} else {
|
||||
if (s.getState() == AWAIT_AUTHS) state = AWAIT_AUTH_A;
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), sent);
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
||||
}
|
||||
return new IntroducerSession(s.getSessionId(), state,
|
||||
s.getRequestTimestamp(), introducee1, introducee2);
|
||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private IntroducerSession onRemoteActivate(Transaction txn,
|
||||
@@ -405,26 +428,34 @@ class IntroducerProtocolEngine
|
||||
// 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 (s.getState() != AWAIT_ACTIVATES) {
|
||||
if (senderIsAlice && s.getState() != AWAIT_ACTIVATE_A)
|
||||
return abort(txn, s);
|
||||
else if (!senderIsAlice && s.getState() != AWAIT_ACTIVATE_B)
|
||||
return abort(txn, s);
|
||||
}
|
||||
|
||||
// Forward AUTH message
|
||||
// Forward ACTIVATE message
|
||||
Introducee i = getOtherIntroducee(s, m.getGroupId());
|
||||
long timestamp = getLocalTimestamp(s, i);
|
||||
Message sent = sendActivateMessage(txn, i, timestamp);
|
||||
|
||||
// Move to the next state
|
||||
IntroducerState state = START;
|
||||
Introducee introducee1, introducee2;
|
||||
if (i.equals(s.getIntroducee1())) {
|
||||
if (s.getState() == AWAIT_ACTIVATES) state = AWAIT_ACTIVATE_A;
|
||||
introducee1 = new Introducee(s.getIntroducee1(), sent);
|
||||
introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId());
|
||||
} else if (i.equals(s.getIntroducee2())) {
|
||||
Introducee introduceeA, introduceeB;
|
||||
if (senderIsAlice) {
|
||||
if (s.getState() == AWAIT_ACTIVATES) state = AWAIT_ACTIVATE_B;
|
||||
introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId());
|
||||
introducee2 = new Introducee(s.getIntroducee2(), sent);
|
||||
} else throw new AssertionError();
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), sent);
|
||||
} else {
|
||||
if (s.getState() == AWAIT_ACTIVATES) state = AWAIT_ACTIVATE_A;
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), sent);
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
||||
}
|
||||
return new IntroducerSession(s.getSessionId(), state,
|
||||
s.getRequestTimestamp(), introducee1, introducee2);
|
||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private IntroducerSession onRemoteAbort(Transaction txn,
|
||||
@@ -438,16 +469,16 @@ class IntroducerProtocolEngine
|
||||
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
|
||||
|
||||
// Reset the session back to initial state
|
||||
Introducee introducee1, introducee2;
|
||||
if (i.equals(s.getIntroducee1())) {
|
||||
introducee1 = new Introducee(s.getIntroducee1(), sent);
|
||||
introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId());
|
||||
} else if (i.equals(s.getIntroducee2())) {
|
||||
introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId());
|
||||
introducee2 = new Introducee(s.getIntroducee2(), sent);
|
||||
Introducee introduceeA, introduceeB;
|
||||
if (i.equals(s.getIntroduceeA())) {
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), sent);
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
||||
} else if (i.equals(s.getIntroduceeB())) {
|
||||
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
||||
introduceeB = new Introducee(s.getIntroduceeB(), sent);
|
||||
} else throw new AssertionError();
|
||||
return new IntroducerSession(s.getSessionId(), START,
|
||||
s.getRequestTimestamp(), introducee1, introducee2);
|
||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private IntroducerSession abort(Transaction txn,
|
||||
@@ -456,28 +487,28 @@ class IntroducerProtocolEngine
|
||||
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
|
||||
|
||||
// Send an ABORT message to both introducees
|
||||
long timestamp1 = getLocalTimestamp(s, s.getIntroducee1());
|
||||
Message sent1 = sendAbortMessage(txn, s.getIntroducee1(), timestamp1);
|
||||
long timestamp2 = getLocalTimestamp(s, s.getIntroducee2());
|
||||
Message sent2 = sendAbortMessage(txn, s.getIntroducee2(), timestamp2);
|
||||
long timestampA = getLocalTimestamp(s, s.getIntroduceeA());
|
||||
Message sentA = sendAbortMessage(txn, s.getIntroduceeA(), timestampA);
|
||||
long timestampB = getLocalTimestamp(s, s.getIntroduceeB());
|
||||
Message sentB = sendAbortMessage(txn, s.getIntroduceeB(), timestampB);
|
||||
// Reset the session back to initial state
|
||||
Introducee introducee1 = new Introducee(s.getIntroducee1(), sent1);
|
||||
Introducee introducee2 = new Introducee(s.getIntroducee2(), sent2);
|
||||
Introducee introduceeA = new Introducee(s.getIntroduceeA(), sentA);
|
||||
Introducee introduceeB = new Introducee(s.getIntroduceeB(), sentB);
|
||||
return new IntroducerSession(s.getSessionId(), START,
|
||||
s.getRequestTimestamp(), introducee1, introducee2);
|
||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private Introducee getIntroducee(IntroducerSession s, GroupId g) {
|
||||
if (s.getIntroducee1().groupId.equals(g)) return s.getIntroducee1();
|
||||
else if (s.getIntroducee2().groupId.equals(g))
|
||||
return s.getIntroducee2();
|
||||
if (s.getIntroduceeA().groupId.equals(g)) return s.getIntroduceeA();
|
||||
else if (s.getIntroduceeB().groupId.equals(g))
|
||||
return s.getIntroduceeB();
|
||||
else throw new AssertionError();
|
||||
}
|
||||
|
||||
private Introducee getOtherIntroducee(IntroducerSession s, GroupId g) {
|
||||
if (s.getIntroducee1().groupId.equals(g)) return s.getIntroducee2();
|
||||
else if (s.getIntroducee2().groupId.equals(g))
|
||||
return s.getIntroducee1();
|
||||
if (s.getIntroduceeA().groupId.equals(g)) return s.getIntroduceeB();
|
||||
else if (s.getIntroduceeB().groupId.equals(g))
|
||||
return s.getIntroduceeA();
|
||||
else throw new AssertionError();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,21 +17,21 @@ import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
|
||||
@NotNullByDefault
|
||||
class IntroducerSession extends Session<IntroducerState> {
|
||||
|
||||
private final Introducee introducee1, introducee2;
|
||||
private final Introducee introduceeA, introduceeB;
|
||||
|
||||
IntroducerSession(SessionId sessionId, IntroducerState state,
|
||||
long requestTimestamp, Introducee introducee1,
|
||||
Introducee introducee2) {
|
||||
long requestTimestamp, Introducee introduceeA,
|
||||
Introducee introduceeB) {
|
||||
super(sessionId, state, requestTimestamp);
|
||||
this.introducee1 = introducee1;
|
||||
this.introducee2 = introducee2;
|
||||
this.introduceeA = introduceeA;
|
||||
this.introduceeB = introduceeB;
|
||||
}
|
||||
|
||||
IntroducerSession(SessionId sessionId, GroupId groupId1, Author author1,
|
||||
GroupId groupId2, Author author2) {
|
||||
IntroducerSession(SessionId sessionId, GroupId groupIdA, Author authorA,
|
||||
GroupId groupIdB, Author authorB) {
|
||||
this(sessionId, IntroducerState.START, -1,
|
||||
new Introducee(sessionId, groupId1, author1),
|
||||
new Introducee(sessionId, groupId2, author2));
|
||||
new Introducee(sessionId, groupIdA, authorA),
|
||||
new Introducee(sessionId, groupIdB, authorB));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,12 +39,12 @@ class IntroducerSession extends Session<IntroducerState> {
|
||||
return INTRODUCER;
|
||||
}
|
||||
|
||||
Introducee getIntroducee1() {
|
||||
return introducee1;
|
||||
Introducee getIntroduceeA() {
|
||||
return introduceeA;
|
||||
}
|
||||
|
||||
Introducee getIntroducee2() {
|
||||
return introducee2;
|
||||
Introducee getIntroduceeB() {
|
||||
return introduceeB;
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
||||
@@ -23,8 +23,8 @@ interface IntroductionConstants {
|
||||
String SESSION_KEY_LAST_REMOTE_MESSAGE_ID = "lastRemoteMessageId";
|
||||
|
||||
// Session Keys Introducer
|
||||
String SESSION_KEY_INTRODUCEE_1 = "introducee1";
|
||||
String SESSION_KEY_INTRODUCEE_2 = "introducee2";
|
||||
String SESSION_KEY_INTRODUCEE_A = "introduceeA";
|
||||
String SESSION_KEY_INTRODUCEE_B = "introduceeB";
|
||||
String SESSION_KEY_GROUP_ID = "groupId";
|
||||
String SESSION_KEY_AUTHOR = "author";
|
||||
|
||||
|
||||
@@ -308,8 +308,15 @@ class IntroductionManagerImpl extends ConversationClientImpl
|
||||
// This is the first request - create a new session
|
||||
GroupId groupId1 = getContactGroup(c1).getId();
|
||||
GroupId groupId2 = getContactGroup(c2).getId();
|
||||
session = new IntroducerSession(sessionId, groupId1,
|
||||
c1.getAuthor(), groupId2, c2.getAuthor());
|
||||
boolean alice = crypto.isAlice(c1.getAuthor().getId(),
|
||||
c2.getAuthor().getId());
|
||||
// use fixed deterministic roles for the introducees
|
||||
session = new IntroducerSession(sessionId,
|
||||
alice ? groupId1 : groupId2,
|
||||
alice ? c1.getAuthor() : c2.getAuthor(),
|
||||
alice ? groupId2 : groupId1,
|
||||
alice ? c2.getAuthor() : c1.getAuthor()
|
||||
);
|
||||
storageId = createStorageId(txn);
|
||||
} else {
|
||||
// An earlier request exists, so we already have a session
|
||||
@@ -425,10 +432,10 @@ class IntroductionManagerImpl extends ConversationClientImpl
|
||||
IntroducerSession session =
|
||||
sessionParser.parseIntroducerSession(bdfSession);
|
||||
sessionId = session.getSessionId();
|
||||
if (contactGroupId.equals(session.getIntroducee1().groupId)) {
|
||||
author = session.getIntroducee2().author;
|
||||
if (contactGroupId.equals(session.getIntroduceeA().groupId)) {
|
||||
author = session.getIntroduceeB().author;
|
||||
} else {
|
||||
author = session.getIntroducee1().author;
|
||||
author = session.getIntroduceeA().author;
|
||||
}
|
||||
} else if (role == INTRODUCEE) {
|
||||
IntroduceeSession session = sessionParser
|
||||
@@ -465,10 +472,10 @@ class IntroductionManagerImpl extends ConversationClientImpl
|
||||
sessionParser.parseIntroducerSession(bdfSession);
|
||||
sessionId = session.getSessionId();
|
||||
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
||||
if (localAuthor.equals(session.getIntroducee1().author)) {
|
||||
author = session.getIntroducee2().author;
|
||||
if (localAuthor.equals(session.getIntroduceeA().author)) {
|
||||
author = session.getIntroduceeB().author;
|
||||
} else {
|
||||
author = session.getIntroducee1().author;
|
||||
author = session.getIntroduceeA().author;
|
||||
}
|
||||
} else if (role == INTRODUCEE) {
|
||||
IntroduceeSession session = sessionParser
|
||||
@@ -516,12 +523,12 @@ class IntroductionManagerImpl extends ConversationClientImpl
|
||||
} catch (FormatException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
if (s.getIntroducee1().author.equals(c.getAuthor())) {
|
||||
if (s.getIntroduceeA().author.equals(c.getAuthor())) {
|
||||
abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(),
|
||||
s.getIntroducee2(), localAuthor);
|
||||
} else if (s.getIntroducee2().author.equals(c.getAuthor())) {
|
||||
s.getIntroduceeB(), localAuthor);
|
||||
} else if (s.getIntroduceeB().author.equals(c.getAuthor())) {
|
||||
abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(),
|
||||
s.getIntroducee1(), localAuthor);
|
||||
s.getIntroduceeA(), localAuthor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_GROUP_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_1;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_2;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_A;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_B;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
|
||||
@@ -72,8 +72,8 @@ class SessionEncoderImpl implements SessionEncoder {
|
||||
@Override
|
||||
public BdfDictionary encodeIntroducerSession(IntroducerSession s) {
|
||||
BdfDictionary d = encodeSession(s);
|
||||
d.put(SESSION_KEY_INTRODUCEE_1, encodeIntroducee(s.getIntroducee1()));
|
||||
d.put(SESSION_KEY_INTRODUCEE_2, encodeIntroducee(s.getIntroducee2()));
|
||||
d.put(SESSION_KEY_INTRODUCEE_A, encodeIntroducee(s.getIntroduceeA()));
|
||||
d.put(SESSION_KEY_INTRODUCEE_B, encodeIntroducee(s.getIntroduceeB()));
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_GROUP_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_1;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_2;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_A;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_B;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
|
||||
@@ -75,12 +75,12 @@ class SessionParserImpl implements SessionParser {
|
||||
SessionId sessionId = getSessionId(d);
|
||||
IntroducerState state = IntroducerState.fromValue(getState(d));
|
||||
long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP);
|
||||
Introducee introducee1 = parseIntroducee(sessionId,
|
||||
d.getDictionary(SESSION_KEY_INTRODUCEE_1));
|
||||
Introducee introducee2 = parseIntroducee(sessionId,
|
||||
d.getDictionary(SESSION_KEY_INTRODUCEE_2));
|
||||
Introducee introduceeA = parseIntroducee(sessionId,
|
||||
d.getDictionary(SESSION_KEY_INTRODUCEE_A));
|
||||
Introducee introduceeB = parseIntroducee(sessionId,
|
||||
d.getDictionary(SESSION_KEY_INTRODUCEE_B));
|
||||
return new IntroducerSession(sessionId, state, requestTimestamp,
|
||||
introducee1, introducee2);
|
||||
introduceeA, introduceeB);
|
||||
}
|
||||
|
||||
private Introducee parseIntroducee(SessionId sessionId, BdfDictionary d)
|
||||
|
||||
@@ -54,11 +54,12 @@ import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT
|
||||
import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_AUTHOR;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_1;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_2;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_A;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_B;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID;
|
||||
import static org.briarproject.briar.introduction.MessageType.ACCEPT;
|
||||
import static org.briarproject.briar.introduction.MessageType.AUTH;
|
||||
import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -610,6 +611,123 @@ public class IntroductionIntegrationTest
|
||||
assertFalse(listener2.aborted);
|
||||
}
|
||||
|
||||
/**
|
||||
* One introducee illegally sends two ACCEPT messages in a row.
|
||||
* The introducer should notice this and ABORT the session.
|
||||
*/
|
||||
@Test
|
||||
public void testDoubleAccept() throws Exception {
|
||||
addListeners(true, true);
|
||||
|
||||
// make the introduction
|
||||
long time = clock.currentTimeMillis();
|
||||
introductionManager0
|
||||
.makeIntroduction(contact1From0, contact2From0, null, time);
|
||||
|
||||
// sync REQUEST to introducee1
|
||||
sync0To1(1, true);
|
||||
|
||||
// save ACCEPT from introducee1
|
||||
AcceptMessage m = (AcceptMessage) getMessageFor(c1.getClientHelper(),
|
||||
contact0From1, ACCEPT);
|
||||
|
||||
// sync ACCEPT back to introducer
|
||||
sync1To0(1, true);
|
||||
|
||||
// fake a second ACCEPT message from introducee1
|
||||
Message msg = c1.getMessageEncoder()
|
||||
.encodeAcceptMessage(m.getGroupId(), clock.currentTimeMillis(),
|
||||
m.getMessageId(), m.getSessionId(),
|
||||
m.getEphemeralPublicKey(), m.getAcceptTimestamp(),
|
||||
m.getTransportProperties());
|
||||
c1.getClientHelper().addLocalMessage(msg, new BdfDictionary(), true);
|
||||
|
||||
// sync fake ACCEPT back to introducer
|
||||
sync1To0(1, true);
|
||||
|
||||
assertTrue(listener0.aborted);
|
||||
}
|
||||
|
||||
/**
|
||||
* One introducee sends an ACCEPT and then another DECLINE message.
|
||||
* The introducer should notice this and ABORT the session.
|
||||
*/
|
||||
@Test
|
||||
public void testAcceptAndDecline() throws Exception {
|
||||
addListeners(true, true);
|
||||
|
||||
// make the introduction
|
||||
long time = clock.currentTimeMillis();
|
||||
introductionManager0
|
||||
.makeIntroduction(contact1From0, contact2From0, null, time);
|
||||
|
||||
// sync REQUEST to introducee1
|
||||
sync0To1(1, true);
|
||||
|
||||
// save ACCEPT from introducee1
|
||||
AcceptMessage m = (AcceptMessage) getMessageFor(c1.getClientHelper(),
|
||||
contact0From1, ACCEPT);
|
||||
|
||||
// sync ACCEPT back to introducer
|
||||
sync1To0(1, true);
|
||||
|
||||
// fake a second DECLINE message also from introducee1
|
||||
Message msg = c1.getMessageEncoder()
|
||||
.encodeDeclineMessage(m.getGroupId(), clock.currentTimeMillis(),
|
||||
m.getMessageId(), m.getSessionId());
|
||||
c1.getClientHelper().addLocalMessage(msg, new BdfDictionary(), true);
|
||||
|
||||
// sync fake DECLINE back to introducer
|
||||
sync1To0(1, true);
|
||||
|
||||
assertTrue(listener0.aborted);
|
||||
}
|
||||
|
||||
/**
|
||||
* One introducee sends two AUTH messages.
|
||||
* The introducer should notice this and ABORT the session.
|
||||
*/
|
||||
@Test
|
||||
public void testDoubleAuth() throws Exception {
|
||||
addListeners(true, true);
|
||||
|
||||
// make the introduction
|
||||
long time = clock.currentTimeMillis();
|
||||
introductionManager0
|
||||
.makeIntroduction(contact1From0, contact2From0, null, time);
|
||||
|
||||
// sync REQUEST messages
|
||||
sync0To1(1, true);
|
||||
sync0To2(1, true);
|
||||
|
||||
// sync ACCEPT messages
|
||||
sync1To0(1, true);
|
||||
sync2To0(1, true);
|
||||
|
||||
// sync forwarded ACCEPT messages to introducees
|
||||
sync0To1(1, true);
|
||||
sync0To2(1, true);
|
||||
|
||||
// save AUTH from introducee1
|
||||
AuthMessage m = (AuthMessage) getMessageFor(c1.getClientHelper(),
|
||||
contact0From1, AUTH);
|
||||
|
||||
// sync first AUTH message
|
||||
sync1To0(1, true);
|
||||
|
||||
// fake a second AUTH message also from introducee1
|
||||
Message msg = c1.getMessageEncoder()
|
||||
.encodeAuthMessage(m.getGroupId(), clock.currentTimeMillis(),
|
||||
m.getMessageId(), m.getSessionId(), m.getMac(),
|
||||
m.getSignature());
|
||||
c1.getClientHelper().addLocalMessage(msg, new BdfDictionary(), true);
|
||||
|
||||
// sync second AUTH message
|
||||
sync1To0(1, true);
|
||||
|
||||
assertTrue(listener0.aborted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntroducerRemovedCleanup() throws Exception {
|
||||
addListeners(true, true);
|
||||
@@ -955,8 +1073,8 @@ public class IntroductionIntegrationTest
|
||||
|
||||
private void replacePreviousLocalMessageId(Author author,
|
||||
BdfDictionary d, MessageId id) throws FormatException {
|
||||
BdfDictionary i1 = d.getDictionary(SESSION_KEY_INTRODUCEE_1);
|
||||
BdfDictionary i2 = d.getDictionary(SESSION_KEY_INTRODUCEE_2);
|
||||
BdfDictionary i1 = d.getDictionary(SESSION_KEY_INTRODUCEE_A);
|
||||
BdfDictionary i2 = d.getDictionary(SESSION_KEY_INTRODUCEE_B);
|
||||
Author a1 = clientHelper
|
||||
.parseAndValidateAuthor(i1.getList(SESSION_KEY_AUTHOR));
|
||||
Author a2 = clientHelper
|
||||
@@ -964,10 +1082,10 @@ public class IntroductionIntegrationTest
|
||||
|
||||
if (a1.equals(author)) {
|
||||
i1.put(SESSION_KEY_LAST_LOCAL_MESSAGE_ID, id);
|
||||
d.put(SESSION_KEY_INTRODUCEE_1, i1);
|
||||
d.put(SESSION_KEY_INTRODUCEE_A, i1);
|
||||
} else if (a2.equals(author)) {
|
||||
i2.put(SESSION_KEY_LAST_LOCAL_MESSAGE_ID, id);
|
||||
d.put(SESSION_KEY_INTRODUCEE_2, i2);
|
||||
d.put(SESSION_KEY_INTRODUCEE_B, i2);
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
@@ -986,8 +1104,13 @@ public class IntroductionIntegrationTest
|
||||
MessageId id = map.entrySet().iterator().next().getKey();
|
||||
Message m = ch.getMessage(id);
|
||||
BdfList body = ch.getMessageAsList(id);
|
||||
//noinspection ConstantConditions
|
||||
return c0.getMessageParser().parseAcceptMessage(m, body);
|
||||
if (type == ACCEPT) {
|
||||
//noinspection ConstantConditions
|
||||
return c0.getMessageParser().parseAcceptMessage(m, body);
|
||||
} else if (type == AUTH) {
|
||||
//noinspection ConstantConditions
|
||||
return c0.getMessageParser().parseAuthMessage(m, body);
|
||||
} else throw new AssertionError("Not implemented");
|
||||
}
|
||||
|
||||
private IntroductionRequest getIntroductionRequest(
|
||||
@@ -1002,6 +1125,15 @@ public class IntroductionIntegrationTest
|
||||
throw new AssertionError("No IntroductionRequest found");
|
||||
}
|
||||
|
||||
private IntroducerSession getIntroducerSession()
|
||||
throws DbException, FormatException {
|
||||
Map<MessageId, BdfDictionary> dicts = c0.getClientHelper()
|
||||
.getMessageMetadataAsDictionary(getLocalGroup().getId());
|
||||
assertEquals(1, dicts.size());
|
||||
BdfDictionary d = dicts.values().iterator().next();
|
||||
return c0.getSessionParser().parseIntroducerSession(d);
|
||||
}
|
||||
|
||||
private IntroduceeSession getIntroduceeSession(ClientHelper ch,
|
||||
GroupId introducerGroup) throws DbException, FormatException {
|
||||
Map<MessageId, BdfDictionary> dicts =
|
||||
|
||||
@@ -102,8 +102,8 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
assertEquals(s1.getSessionId(), s2.getSessionId());
|
||||
assertEquals(AWAIT_AUTHS, s1.getState());
|
||||
assertEquals(s1.getState(), s2.getState());
|
||||
assertIntroduceeEquals(s1.getIntroducee1(), s2.getIntroducee1());
|
||||
assertIntroduceeEquals(s1.getIntroducee2(), s2.getIntroducee2());
|
||||
assertIntroduceeEquals(s1.getIntroduceeA(), s2.getIntroduceeA());
|
||||
assertIntroduceeEquals(s1.getIntroduceeB(), s2.getIntroduceeB());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,19 +121,19 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
BdfDictionary d = sessionEncoder.encodeIntroducerSession(s1);
|
||||
IntroducerSession s2 = sessionParser.parseIntroducerSession(d);
|
||||
|
||||
assertNull(s1.getIntroducee1().lastLocalMessageId);
|
||||
assertEquals(s1.getIntroducee1().lastLocalMessageId,
|
||||
s2.getIntroducee1().lastLocalMessageId);
|
||||
assertNull(s1.getIntroducee1().lastRemoteMessageId);
|
||||
assertEquals(s1.getIntroducee1().lastRemoteMessageId,
|
||||
s2.getIntroducee1().lastRemoteMessageId);
|
||||
assertNull(s1.getIntroduceeA().lastLocalMessageId);
|
||||
assertEquals(s1.getIntroduceeA().lastLocalMessageId,
|
||||
s2.getIntroduceeA().lastLocalMessageId);
|
||||
assertNull(s1.getIntroduceeA().lastRemoteMessageId);
|
||||
assertEquals(s1.getIntroduceeA().lastRemoteMessageId,
|
||||
s2.getIntroduceeA().lastRemoteMessageId);
|
||||
|
||||
assertNull(s1.getIntroducee2().lastLocalMessageId);
|
||||
assertEquals(s1.getIntroducee2().lastLocalMessageId,
|
||||
s2.getIntroducee2().lastLocalMessageId);
|
||||
assertNull(s1.getIntroducee2().lastRemoteMessageId);
|
||||
assertEquals(s1.getIntroducee2().lastRemoteMessageId,
|
||||
s2.getIntroducee2().lastRemoteMessageId);
|
||||
assertNull(s1.getIntroduceeB().lastLocalMessageId);
|
||||
assertEquals(s1.getIntroduceeB().lastLocalMessageId,
|
||||
s2.getIntroduceeB().lastLocalMessageId);
|
||||
assertNull(s1.getIntroduceeB().lastRemoteMessageId);
|
||||
assertEquals(s1.getIntroduceeB().lastRemoteMessageId,
|
||||
s2.getIntroduceeB().lastRemoteMessageId);
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
|
||||
Reference in New Issue
Block a user