mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 14:19:53 +01:00
Properly handle DECLINE messages in START state
Previously, DECLINE messages let directly to the START state for introducer and introducees. So incoming ACCEPT and DECLINE messages needed to be ignored in START state introducing undefined behavior into the protocol. This is fixed with this commit by adding two additional states to the introducer state machine as well as making use of the existing LOCAL_DECLINED state for the introducees.
This commit is contained in:
@@ -3,12 +3,14 @@ package org.briarproject.briar.introduction;
|
|||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
@@ -18,6 +20,8 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.client.SessionId;
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
|
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
||||||
|
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -141,6 +145,21 @@ abstract class AbstractProtocolEngine<S extends Session>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void broadcastIntroductionResponseReceivedEvent(Transaction txn,
|
||||||
|
Session s, AuthorId sender, AbstractIntroductionMessage m)
|
||||||
|
throws DbException {
|
||||||
|
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
|
||||||
|
Contact c = contactManager.getContact(txn, sender, localAuthorId);
|
||||||
|
IntroductionResponse response =
|
||||||
|
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
||||||
|
m.getGroupId(), s.getRole(), m.getTimestamp(), false,
|
||||||
|
false, false, false, c.getAuthor().getName(),
|
||||||
|
m instanceof AcceptMessage);
|
||||||
|
IntroductionResponseReceivedEvent e =
|
||||||
|
new IntroductionResponseReceivedEvent(c.getId(), response);
|
||||||
|
txn.attach(e);
|
||||||
|
}
|
||||||
|
|
||||||
void markMessageVisibleInUi(Transaction txn, MessageId m)
|
void markMessageVisibleInUi(Transaction txn, MessageId m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
BdfDictionary meta = new BdfDictionary();
|
BdfDictionary meta = new BdfDictionary();
|
||||||
|
|||||||
@@ -27,10 +27,8 @@ import org.briarproject.briar.api.client.MessageTracker;
|
|||||||
import org.briarproject.briar.api.client.ProtocolStateException;
|
import org.briarproject.briar.api.client.ProtocolStateException;
|
||||||
import org.briarproject.briar.api.client.SessionId;
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
|
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
|
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
|
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
@@ -44,7 +42,9 @@ import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
|
|||||||
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH;
|
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH;
|
||||||
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_RESPONSES;
|
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_RESPONSES;
|
||||||
import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_ACCEPTED;
|
import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_ACCEPTED;
|
||||||
|
import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_DECLINED;
|
||||||
import static org.briarproject.briar.introduction.IntroduceeState.REMOTE_ACCEPTED;
|
import static org.briarproject.briar.introduction.IntroduceeState.REMOTE_ACCEPTED;
|
||||||
|
import static org.briarproject.briar.introduction.IntroduceeState.START;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -142,12 +142,12 @@ class IntroduceeProtocolEngine
|
|||||||
public IntroduceeSession onAcceptMessage(Transaction txn,
|
public IntroduceeSession onAcceptMessage(Transaction txn,
|
||||||
IntroduceeSession session, AcceptMessage m) throws DbException {
|
IntroduceeSession session, AcceptMessage m) throws DbException {
|
||||||
switch (session.getState()) {
|
switch (session.getState()) {
|
||||||
case START:
|
case LOCAL_DECLINED:
|
||||||
return onRemoteResponseInStart(txn, session, m);
|
return onRemoteResponseWhenDeclined(txn, session, m);
|
||||||
case AWAIT_RESPONSES:
|
case AWAIT_RESPONSES:
|
||||||
case LOCAL_ACCEPTED:
|
case LOCAL_ACCEPTED:
|
||||||
return onRemoteAccept(txn, session, m);
|
return onRemoteAccept(txn, session, m);
|
||||||
case LOCAL_DECLINED:
|
case START:
|
||||||
case REMOTE_ACCEPTED:
|
case REMOTE_ACCEPTED:
|
||||||
case AWAIT_AUTH:
|
case AWAIT_AUTH:
|
||||||
case AWAIT_ACTIVATE:
|
case AWAIT_ACTIVATE:
|
||||||
@@ -161,12 +161,12 @@ class IntroduceeProtocolEngine
|
|||||||
public IntroduceeSession onDeclineMessage(Transaction txn,
|
public IntroduceeSession onDeclineMessage(Transaction txn,
|
||||||
IntroduceeSession session, DeclineMessage m) throws DbException {
|
IntroduceeSession session, DeclineMessage m) throws DbException {
|
||||||
switch (session.getState()) {
|
switch (session.getState()) {
|
||||||
case START:
|
|
||||||
return onRemoteResponseInStart(txn, session, m);
|
|
||||||
case AWAIT_RESPONSES:
|
|
||||||
case LOCAL_DECLINED:
|
case LOCAL_DECLINED:
|
||||||
|
return onRemoteResponseWhenDeclined(txn, session, m);
|
||||||
|
case AWAIT_RESPONSES:
|
||||||
case LOCAL_ACCEPTED:
|
case LOCAL_ACCEPTED:
|
||||||
return onRemoteDecline(txn, session, m);
|
return onRemoteDecline(txn, session, m);
|
||||||
|
case START:
|
||||||
case REMOTE_ACCEPTED:
|
case REMOTE_ACCEPTED:
|
||||||
case AWAIT_AUTH:
|
case AWAIT_AUTH:
|
||||||
case AWAIT_ACTIVATE:
|
case AWAIT_ACTIVATE:
|
||||||
@@ -255,8 +255,7 @@ class IntroduceeProtocolEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession onLocalAccept(Transaction txn,
|
private IntroduceeSession onLocalAccept(Transaction txn,
|
||||||
IntroduceeSession s, long timestamp)
|
IntroduceeSession s, long timestamp) throws DbException {
|
||||||
throws DbException {
|
|
||||||
// Mark the request message unavailable to answer
|
// Mark the request message unavailable to answer
|
||||||
markRequestsUnavailableToAnswer(txn, s);
|
markRequestsUnavailableToAnswer(txn, s);
|
||||||
|
|
||||||
@@ -291,20 +290,23 @@ class IntroduceeProtocolEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession onLocalDecline(Transaction txn,
|
private IntroduceeSession onLocalDecline(Transaction txn,
|
||||||
IntroduceeSession s, long timestamp)
|
IntroduceeSession s, long timestamp) throws DbException {
|
||||||
throws DbException {
|
|
||||||
// Mark the request message unavailable to answer
|
// Mark the request message unavailable to answer
|
||||||
markRequestsUnavailableToAnswer(txn, s);
|
markRequestsUnavailableToAnswer(txn, s);
|
||||||
|
|
||||||
// Send a DECLINE message
|
// Send a DECLINE message
|
||||||
long localTimestamp = Math.max(timestamp + 1, getLocalTimestamp(s));
|
long localTimestamp = Math.max(timestamp + 1, getLocalTimestamp(s));
|
||||||
Message sent = sendDeclineMessage(txn, s, localTimestamp, true);
|
Message sent = sendDeclineMessage(txn, s, localTimestamp, true);
|
||||||
|
|
||||||
// Track the message
|
// Track the message
|
||||||
messageTracker.trackOutgoingMessage(txn, sent);
|
messageTracker.trackOutgoingMessage(txn, sent);
|
||||||
|
|
||||||
// Move to the START state
|
// Move to the START or LOCAL_DECLINED state, if still awaiting response
|
||||||
return IntroduceeSession.clear(s, sent.getId(), sent.getTimestamp(),
|
IntroduceeState state =
|
||||||
s.getLastRemoteMessageId());
|
s.getState() == REMOTE_ACCEPTED ? START : LOCAL_DECLINED;
|
||||||
|
return IntroduceeSession
|
||||||
|
.clear(s, state, sent.getId(), sent.getTimestamp(),
|
||||||
|
s.getLastRemoteMessageId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession onRemoteAccept(Transaction txn,
|
private IntroduceeSession onRemoteAccept(Transaction txn,
|
||||||
@@ -347,25 +349,17 @@ class IntroduceeProtocolEngine
|
|||||||
.trackMessage(txn, m.getGroupId(), m.getTimestamp(), false);
|
.trackMessage(txn, m.getGroupId(), m.getTimestamp(), false);
|
||||||
|
|
||||||
// Broadcast IntroductionResponseReceivedEvent
|
// Broadcast IntroductionResponseReceivedEvent
|
||||||
Contact c = contactManager.getContact(txn, s.getIntroducer().getId(),
|
broadcastIntroductionResponseReceivedEvent(txn, s,
|
||||||
identityManager.getLocalAuthor(txn).getId());
|
s.getIntroducer().getId(), m);
|
||||||
IntroductionResponse request =
|
|
||||||
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
|
||||||
m.getGroupId(), INTRODUCEE, m.getTimestamp(), false,
|
|
||||||
false, false, false, s.getRemote().author.getName(),
|
|
||||||
false);
|
|
||||||
IntroductionResponseReceivedEvent e =
|
|
||||||
new IntroductionResponseReceivedEvent(c.getId(), request);
|
|
||||||
txn.attach(e);
|
|
||||||
|
|
||||||
// Move back to START state
|
// Move back to START state
|
||||||
return IntroduceeSession
|
return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(),
|
||||||
.clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(),
|
s.getLocalTimestamp(), m.getMessageId());
|
||||||
m.getMessageId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession onRemoteResponseInStart(Transaction txn,
|
private IntroduceeSession onRemoteResponseWhenDeclined(Transaction txn,
|
||||||
IntroduceeSession s, AbstractIntroductionMessage m) throws DbException {
|
IntroduceeSession s, AbstractIntroductionMessage m)
|
||||||
|
throws DbException {
|
||||||
// The timestamp must be higher than the last request message
|
// The timestamp must be higher than the last request message
|
||||||
if (m.getTimestamp() <= s.getRequestTimestamp())
|
if (m.getTimestamp() <= s.getRequestTimestamp())
|
||||||
return abort(txn, s);
|
return abort(txn, s);
|
||||||
@@ -373,10 +367,9 @@ class IntroduceeProtocolEngine
|
|||||||
if (isInvalidDependency(s, m.getPreviousMessageId()))
|
if (isInvalidDependency(s, m.getPreviousMessageId()))
|
||||||
return abort(txn, s);
|
return abort(txn, s);
|
||||||
|
|
||||||
// Stay in START state
|
// Move to START state
|
||||||
return IntroduceeSession
|
return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(),
|
||||||
.clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(),
|
s.getLocalTimestamp(), m.getMessageId());
|
||||||
m.getMessageId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession onLocalAuth(Transaction txn, IntroduceeSession s)
|
private IntroduceeSession onLocalAuth(Transaction txn, IntroduceeSession s)
|
||||||
@@ -479,9 +472,8 @@ class IntroduceeProtocolEngine
|
|||||||
keyManager.activateKeys(txn, s.getTransportKeys());
|
keyManager.activateKeys(txn, s.getTransportKeys());
|
||||||
|
|
||||||
// Move back to START state
|
// Move back to START state
|
||||||
return IntroduceeSession
|
return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(),
|
||||||
.clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(),
|
s.getLocalTimestamp(), m.getMessageId());
|
||||||
m.getMessageId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession onRemoteAbort(Transaction txn,
|
private IntroduceeSession onRemoteAbort(Transaction txn,
|
||||||
@@ -494,9 +486,8 @@ class IntroduceeProtocolEngine
|
|||||||
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
|
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
|
||||||
|
|
||||||
// Reset the session back to initial state
|
// Reset the session back to initial state
|
||||||
return IntroduceeSession
|
return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(),
|
||||||
.clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(),
|
s.getLocalTimestamp(), m.getMessageId());
|
||||||
m.getMessageId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession abort(Transaction txn, IntroduceeSession s)
|
private IntroduceeSession abort(Transaction txn, IntroduceeSession s)
|
||||||
@@ -511,8 +502,9 @@ class IntroduceeProtocolEngine
|
|||||||
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
|
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
|
||||||
|
|
||||||
// Reset the session back to initial state
|
// Reset the session back to initial state
|
||||||
return IntroduceeSession.clear(s, sent.getId(), sent.getTimestamp(),
|
return IntroduceeSession
|
||||||
s.getLastRemoteMessageId());
|
.clear(s, START, sent.getId(), sent.getTimestamp(),
|
||||||
|
s.getLastRemoteMessageId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isInvalidDependency(IntroduceeSession s,
|
private boolean isInvalidDependency(IntroduceeSession s,
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class IntroduceeSession extends Session<IntroduceeState>
|
|||||||
remote, null, transportKeys);
|
remote, null, transportKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
static IntroduceeSession clear(IntroduceeSession s,
|
static IntroduceeSession clear(IntroduceeSession s, IntroduceeState state,
|
||||||
@Nullable MessageId lastLocalMessageId, long localTimestamp,
|
@Nullable MessageId lastLocalMessageId, long localTimestamp,
|
||||||
@Nullable MessageId lastRemoteMessageId) {
|
@Nullable MessageId lastRemoteMessageId) {
|
||||||
Local local =
|
Local local =
|
||||||
@@ -130,7 +130,7 @@ class IntroduceeSession extends Session<IntroduceeState>
|
|||||||
Remote remote =
|
Remote remote =
|
||||||
new Remote(s.remote.alice, s.remote.author, lastRemoteMessageId,
|
new Remote(s.remote.alice, s.remote.author, lastRemoteMessageId,
|
||||||
null, null, -1, null);
|
null, null, -1, null);
|
||||||
return new IntroduceeSession(s.getSessionId(), START,
|
return new IntroduceeSession(s.getSessionId(), state,
|
||||||
s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
|
s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
|
||||||
remote, null, null);
|
remote, null, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ package org.briarproject.briar.introduction;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
@@ -16,16 +15,13 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.client.ProtocolStateException;
|
import org.briarproject.briar.api.client.ProtocolStateException;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
|
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
|
|
||||||
import org.briarproject.briar.introduction.IntroducerSession.Introducee;
|
import org.briarproject.briar.introduction.IntroducerSession.Introducee;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
|
|
||||||
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATES;
|
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATES;
|
||||||
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_A;
|
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_A;
|
||||||
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_B;
|
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_B;
|
||||||
@@ -35,6 +31,8 @@ import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTH_B;
|
|||||||
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSES;
|
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSES;
|
||||||
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSE_A;
|
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSE_A;
|
||||||
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSE_B;
|
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSE_B;
|
||||||
|
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;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -68,6 +66,8 @@ class IntroducerProtocolEngine
|
|||||||
case AWAIT_RESPONSES:
|
case AWAIT_RESPONSES:
|
||||||
case AWAIT_RESPONSE_A:
|
case AWAIT_RESPONSE_A:
|
||||||
case AWAIT_RESPONSE_B:
|
case AWAIT_RESPONSE_B:
|
||||||
|
case A_DECLINED:
|
||||||
|
case B_DECLINED:
|
||||||
case AWAIT_AUTHS:
|
case AWAIT_AUTHS:
|
||||||
case AWAIT_AUTH_A:
|
case AWAIT_AUTH_A:
|
||||||
case AWAIT_AUTH_B:
|
case AWAIT_AUTH_B:
|
||||||
@@ -111,8 +111,10 @@ class IntroducerProtocolEngine
|
|||||||
case AWAIT_RESPONSE_A:
|
case AWAIT_RESPONSE_A:
|
||||||
case AWAIT_RESPONSE_B:
|
case AWAIT_RESPONSE_B:
|
||||||
return onRemoteAccept(txn, s, m);
|
return onRemoteAccept(txn, s, m);
|
||||||
|
case A_DECLINED:
|
||||||
|
case B_DECLINED:
|
||||||
|
return onRemoteResponseWhenDeclined(txn, s, m);
|
||||||
case START:
|
case START:
|
||||||
return onRemoteResponseInStart(txn, s, m);
|
|
||||||
case AWAIT_AUTHS:
|
case AWAIT_AUTHS:
|
||||||
case AWAIT_AUTH_A:
|
case AWAIT_AUTH_A:
|
||||||
case AWAIT_AUTH_B:
|
case AWAIT_AUTH_B:
|
||||||
@@ -133,8 +135,10 @@ class IntroducerProtocolEngine
|
|||||||
case AWAIT_RESPONSE_A:
|
case AWAIT_RESPONSE_A:
|
||||||
case AWAIT_RESPONSE_B:
|
case AWAIT_RESPONSE_B:
|
||||||
return onRemoteDecline(txn, s, m);
|
return onRemoteDecline(txn, s, m);
|
||||||
|
case A_DECLINED:
|
||||||
|
case B_DECLINED:
|
||||||
|
return onRemoteResponseWhenDeclined(txn, s, m);
|
||||||
case START:
|
case START:
|
||||||
return onRemoteResponseInStart(txn, s, m);
|
|
||||||
case AWAIT_AUTHS:
|
case AWAIT_AUTHS:
|
||||||
case AWAIT_AUTH_A:
|
case AWAIT_AUTH_A:
|
||||||
case AWAIT_AUTH_B:
|
case AWAIT_AUTH_B:
|
||||||
@@ -159,6 +163,8 @@ class IntroducerProtocolEngine
|
|||||||
case AWAIT_RESPONSES:
|
case AWAIT_RESPONSES:
|
||||||
case AWAIT_RESPONSE_A:
|
case AWAIT_RESPONSE_A:
|
||||||
case AWAIT_RESPONSE_B:
|
case AWAIT_RESPONSE_B:
|
||||||
|
case A_DECLINED:
|
||||||
|
case B_DECLINED:
|
||||||
case AWAIT_ACTIVATES:
|
case AWAIT_ACTIVATES:
|
||||||
case AWAIT_ACTIVATE_A:
|
case AWAIT_ACTIVATE_A:
|
||||||
case AWAIT_ACTIVATE_B:
|
case AWAIT_ACTIVATE_B:
|
||||||
@@ -180,6 +186,8 @@ class IntroducerProtocolEngine
|
|||||||
case AWAIT_RESPONSES:
|
case AWAIT_RESPONSES:
|
||||||
case AWAIT_RESPONSE_A:
|
case AWAIT_RESPONSE_A:
|
||||||
case AWAIT_RESPONSE_B:
|
case AWAIT_RESPONSE_B:
|
||||||
|
case A_DECLINED:
|
||||||
|
case B_DECLINED:
|
||||||
case AWAIT_AUTHS:
|
case AWAIT_AUTHS:
|
||||||
case AWAIT_AUTH_A:
|
case AWAIT_AUTH_A:
|
||||||
case AWAIT_AUTH_B:
|
case AWAIT_AUTH_B:
|
||||||
@@ -262,17 +270,8 @@ class IntroducerProtocolEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast IntroductionResponseReceivedEvent
|
// Broadcast IntroductionResponseReceivedEvent
|
||||||
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
|
Author sender = senderIsAlice ? introduceeA.author : introduceeB.author;
|
||||||
Contact c = contactManager.getContact(txn,
|
broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), m);
|
||||||
senderIsAlice ? introduceeA.author.getId() :
|
|
||||||
introduceeB.author.getId(), localAuthorId);
|
|
||||||
IntroductionResponse request =
|
|
||||||
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
|
||||||
m.getGroupId(), INTRODUCER, m.getTimestamp(), false,
|
|
||||||
false, false, false, c.getAuthor().getName(), true);
|
|
||||||
IntroductionResponseReceivedEvent e =
|
|
||||||
new IntroductionResponseReceivedEvent(c.getId(), request);
|
|
||||||
txn.attach(e);
|
|
||||||
|
|
||||||
// Move to the next state
|
// Move to the next state
|
||||||
return new IntroducerSession(s.getSessionId(), state,
|
return new IntroducerSession(s.getSessionId(), state,
|
||||||
@@ -312,34 +311,28 @@ class IntroducerProtocolEngine
|
|||||||
long timestamp = getLocalTimestamp(s, i);
|
long timestamp = getLocalTimestamp(s, i);
|
||||||
Message sent = sendDeclineMessage(txn, i, timestamp, false);
|
Message sent = sendDeclineMessage(txn, i, timestamp, false);
|
||||||
|
|
||||||
// Update introducee state
|
// Create the next state
|
||||||
|
IntroducerState state = START;
|
||||||
Introducee introduceeA, introduceeB;
|
Introducee introduceeA, introduceeB;
|
||||||
if (senderIsAlice) {
|
if (senderIsAlice) {
|
||||||
|
if (s.getState() == AWAIT_RESPONSES) state = A_DECLINED;
|
||||||
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
||||||
introduceeB = new Introducee(s.getIntroduceeB(), sent);
|
introduceeB = new Introducee(s.getIntroduceeB(), sent);
|
||||||
} else {
|
} else {
|
||||||
|
if (s.getState() == AWAIT_RESPONSES) state = B_DECLINED;
|
||||||
introduceeA = new Introducee(s.getIntroduceeA(), sent);
|
introduceeA = new Introducee(s.getIntroduceeA(), sent);
|
||||||
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast IntroductionResponseReceivedEvent
|
// Broadcast IntroductionResponseReceivedEvent
|
||||||
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
|
Author sender = senderIsAlice ? introduceeA.author : introduceeB.author;
|
||||||
Contact c = contactManager.getContact(txn,
|
broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), m);
|
||||||
senderIsAlice ? introduceeA.author.getId() :
|
|
||||||
introduceeB.author.getId(), localAuthorId);
|
|
||||||
IntroductionResponse request =
|
|
||||||
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
|
||||||
m.getGroupId(), INTRODUCER, m.getTimestamp(), false,
|
|
||||||
false, false, false, c.getAuthor().getName(), false);
|
|
||||||
IntroductionResponseReceivedEvent e =
|
|
||||||
new IntroductionResponseReceivedEvent(c.getId(), request);
|
|
||||||
txn.attach(e);
|
|
||||||
|
|
||||||
return new IntroducerSession(s.getSessionId(), START,
|
return new IntroducerSession(s.getSessionId(), state,
|
||||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntroducerSession onRemoteResponseInStart(Transaction txn,
|
private IntroducerSession onRemoteResponseWhenDeclined(Transaction txn,
|
||||||
IntroducerSession s, AbstractIntroductionMessage m)
|
IntroducerSession s, AbstractIntroductionMessage m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
// The timestamp must be higher than the last request message
|
// The timestamp must be higher than the last request message
|
||||||
@@ -355,33 +348,19 @@ class IntroducerProtocolEngine
|
|||||||
messageTracker
|
messageTracker
|
||||||
.trackMessage(txn, m.getGroupId(), m.getTimestamp(), false);
|
.trackMessage(txn, m.getGroupId(), m.getTimestamp(), false);
|
||||||
|
|
||||||
Introducee i = getIntroducee(s, m.getGroupId());
|
boolean senderIsAlice = senderIsAlice(s, m);
|
||||||
Introducee introduceeA, introduceeB;
|
Introducee introduceeA, introduceeB;
|
||||||
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
|
if (senderIsAlice) {
|
||||||
Contact c;
|
|
||||||
if (i.equals(s.getIntroduceeA())) {
|
|
||||||
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
introduceeA = new Introducee(s.getIntroduceeA(), m.getMessageId());
|
||||||
introduceeB = s.getIntroduceeB();
|
introduceeB = s.getIntroduceeB();
|
||||||
c = contactManager
|
} else {
|
||||||
.getContact(txn, s.getIntroduceeA().author.getId(),
|
|
||||||
localAuthorId);
|
|
||||||
} else if (i.equals(s.getIntroduceeB())) {
|
|
||||||
introduceeA = s.getIntroduceeA();
|
introduceeA = s.getIntroduceeA();
|
||||||
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
introduceeB = new Introducee(s.getIntroduceeB(), m.getMessageId());
|
||||||
c = contactManager
|
}
|
||||||
.getContact(txn, s.getIntroduceeB().author.getId(),
|
|
||||||
localAuthorId);
|
|
||||||
} else throw new AssertionError();
|
|
||||||
|
|
||||||
// Broadcast IntroductionResponseReceivedEvent
|
// Broadcast IntroductionResponseReceivedEvent
|
||||||
IntroductionResponse request =
|
Author sender = senderIsAlice ? introduceeA.author : introduceeB.author;
|
||||||
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
broadcastIntroductionResponseReceivedEvent(txn, s, sender.getId(), m);
|
||||||
m.getGroupId(), INTRODUCER, m.getTimestamp(), false,
|
|
||||||
false, false, false, c.getAuthor().getName(),
|
|
||||||
m instanceof AcceptMessage);
|
|
||||||
IntroductionResponseReceivedEvent e =
|
|
||||||
new IntroductionResponseReceivedEvent(c.getId(), request);
|
|
||||||
txn.attach(e);
|
|
||||||
|
|
||||||
return new IntroducerSession(s.getSessionId(), START,
|
return new IntroducerSession(s.getSessionId(), START,
|
||||||
s.getRequestTimestamp(), introduceeA, introduceeB);
|
s.getRequestTimestamp(), introduceeA, introduceeB);
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ enum IntroducerState implements State {
|
|||||||
START(0),
|
START(0),
|
||||||
AWAIT_RESPONSES(1),
|
AWAIT_RESPONSES(1),
|
||||||
AWAIT_RESPONSE_A(2), AWAIT_RESPONSE_B(3),
|
AWAIT_RESPONSE_A(2), AWAIT_RESPONSE_B(3),
|
||||||
AWAIT_AUTHS(4),
|
A_DECLINED(4), B_DECLINED(5),
|
||||||
AWAIT_AUTH_A(5), AWAIT_AUTH_B(6),
|
AWAIT_AUTHS(6),
|
||||||
AWAIT_ACTIVATES(7),
|
AWAIT_AUTH_A(7), AWAIT_AUTH_B(8),
|
||||||
AWAIT_ACTIVATE_A(8), AWAIT_ACTIVATE_B(9);
|
AWAIT_ACTIVATES(9),
|
||||||
|
AWAIT_ACTIVATE_A(10), AWAIT_ACTIVATE_B(11);
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.sync.Group;
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.test.TestDatabaseModule;
|
import org.briarproject.bramble.test.TestDatabaseModule;
|
||||||
@@ -52,6 +51,10 @@ import static org.briarproject.bramble.test.TestUtils.getTransportProperties;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap;
|
import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap;
|
||||||
import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID;
|
import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID;
|
||||||
import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
|
import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION;
|
||||||
|
import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_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.IntroductionConstants.MSG_KEY_MESSAGE_TYPE;
|
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_AUTHOR;
|
||||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_A;
|
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_A;
|
||||||
@@ -171,8 +174,7 @@ public class IntroductionIntegrationTest
|
|||||||
sync0To2(1, true);
|
sync0To2(1, true);
|
||||||
|
|
||||||
// assert that introducee2 did add the transport keys
|
// assert that introducee2 did add the transport keys
|
||||||
IntroduceeSession session2 = getIntroduceeSession(c2.getClientHelper(),
|
IntroduceeSession session2 = getIntroduceeSession(c2);
|
||||||
introductionManager2.getContactGroup(contact0From2).getId());
|
|
||||||
assertNotNull(session2.getTransportKeys());
|
assertNotNull(session2.getTransportKeys());
|
||||||
assertFalse(session2.getTransportKeys().isEmpty());
|
assertFalse(session2.getTransportKeys().isEmpty());
|
||||||
|
|
||||||
@@ -181,8 +183,7 @@ public class IntroductionIntegrationTest
|
|||||||
sync0To1(2, true);
|
sync0To1(2, true);
|
||||||
|
|
||||||
// assert that introducee1 really purged the key material
|
// assert that introducee1 really purged the key material
|
||||||
IntroduceeSession session1 = getIntroduceeSession(c1.getClientHelper(),
|
IntroduceeSession session1 = getIntroduceeSession(c1);
|
||||||
introductionManager1.getContactGroup(contact0From1).getId());
|
|
||||||
assertNull(session1.getMasterKey());
|
assertNull(session1.getMasterKey());
|
||||||
assertNull(session1.getLocal().ephemeralPrivateKey);
|
assertNull(session1.getLocal().ephemeralPrivateKey);
|
||||||
assertNull(session1.getTransportKeys());
|
assertNull(session1.getTransportKeys());
|
||||||
@@ -240,16 +241,32 @@ public class IntroductionIntegrationTest
|
|||||||
assertTrue(listener1.requestReceived);
|
assertTrue(listener1.requestReceived);
|
||||||
assertTrue(listener2.requestReceived);
|
assertTrue(listener2.requestReceived);
|
||||||
|
|
||||||
|
// assert that introducee is in correct state
|
||||||
|
IntroduceeSession introduceeSession = getIntroduceeSession(c1);
|
||||||
|
assertEquals(LOCAL_DECLINED, introduceeSession.getState());
|
||||||
|
|
||||||
// sync first response
|
// sync first response
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
eventWaiter.await(TIMEOUT, 1);
|
eventWaiter.await(TIMEOUT, 1);
|
||||||
assertTrue(listener0.response1Received);
|
assertTrue(listener0.response1Received);
|
||||||
|
|
||||||
|
// assert that introducer is in correct state
|
||||||
|
boolean alice = c0.getIntroductionCrypto()
|
||||||
|
.isAlice(introducee1.getAuthor().getId(),
|
||||||
|
introducee2.getAuthor().getId());
|
||||||
|
IntroducerSession introducerSession = getIntroducerSession();
|
||||||
|
assertEquals(alice ? A_DECLINED : B_DECLINED,
|
||||||
|
introducerSession.getState());
|
||||||
|
|
||||||
// sync second response
|
// sync second response
|
||||||
sync2To0(1, true);
|
sync2To0(1, true);
|
||||||
eventWaiter.await(TIMEOUT, 1);
|
eventWaiter.await(TIMEOUT, 1);
|
||||||
assertTrue(listener0.response2Received);
|
assertTrue(listener0.response2Received);
|
||||||
|
|
||||||
|
// assert that introducer now moved to START state
|
||||||
|
introducerSession = getIntroducerSession();
|
||||||
|
assertEquals(START, introducerSession.getState());
|
||||||
|
|
||||||
// sync first forwarded response
|
// sync first forwarded response
|
||||||
sync0To2(1, true);
|
sync0To2(1, true);
|
||||||
|
|
||||||
@@ -1114,13 +1131,17 @@ public class IntroductionIntegrationTest
|
|||||||
return c0.getSessionParser().parseIntroducerSession(d);
|
return c0.getSessionParser().parseIntroducerSession(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntroduceeSession getIntroduceeSession(ClientHelper ch,
|
private IntroduceeSession getIntroduceeSession(
|
||||||
GroupId introducerGroup) throws DbException, FormatException {
|
IntroductionIntegrationTestComponent c)
|
||||||
Map<MessageId, BdfDictionary> dicts =
|
throws DbException, FormatException {
|
||||||
ch.getMessageMetadataAsDictionary(getLocalGroup().getId());
|
Map<MessageId, BdfDictionary> dicts = c.getClientHelper()
|
||||||
|
.getMessageMetadataAsDictionary(getLocalGroup().getId());
|
||||||
assertEquals(1, dicts.size());
|
assertEquals(1, dicts.size());
|
||||||
BdfDictionary d = dicts.values().iterator().next();
|
BdfDictionary d = dicts.values().iterator().next();
|
||||||
return c0.getSessionParser().parseIntroduceeSession(introducerGroup, d);
|
Group introducerGroup =
|
||||||
|
introductionManager2.getContactGroup(contact0From2);
|
||||||
|
return c.getSessionParser()
|
||||||
|
.parseIntroduceeSession(introducerGroup.getId(), d);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Group getLocalGroup() {
|
private Group getLocalGroup() {
|
||||||
|
|||||||
@@ -62,5 +62,6 @@ interface IntroductionIntegrationTestComponent
|
|||||||
MessageEncoder getMessageEncoder();
|
MessageEncoder getMessageEncoder();
|
||||||
MessageParser getMessageParser();
|
MessageParser getMessageParser();
|
||||||
SessionParser getSessionParser();
|
SessionParser getSessionParser();
|
||||||
|
IntroductionCrypto getIntroductionCrypto();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user