Address first round of review comments for new IntroductionClient

This commit is contained in:
Torsten Grote
2018-04-25 10:12:49 -03:00
parent a9b678df32
commit 72e9a9d807
17 changed files with 208 additions and 239 deletions

View File

@@ -8,7 +8,6 @@ import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
// TODO still needed?
public class IntroductionSucceededEvent extends Event { public class IntroductionSucceededEvent extends Event {
private final Contact contact; private final Contact contact;

View File

@@ -57,19 +57,14 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook {
public boolean incomingMessage(Transaction txn, Message m, Metadata meta) public boolean incomingMessage(Transaction txn, Message m, Metadata meta)
throws DbException, InvalidMessageException { throws DbException, InvalidMessageException {
try { try {
return incomingMessage(txn, m, meta, MESSAGE_HEADER_LENGTH); byte[] raw = m.getRaw();
BdfList body = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
BdfDictionary metaDictionary = metadataParser.parse(meta);
return incomingMessage(txn, m, body, metaDictionary);
} catch (FormatException e) { } catch (FormatException e) {
throw new InvalidMessageException(e); throw new InvalidMessageException(e);
} }
} }
private boolean incomingMessage(Transaction txn, Message m, Metadata meta,
int headerLength) throws DbException, FormatException {
byte[] raw = m.getRaw();
BdfList body = clientHelper.toList(raw, headerLength,
raw.length - headerLength);
BdfDictionary metaDictionary = metadataParser.parse(meta);
return incomingMessage(txn, m, body, metaDictionary);
}
} }

View File

@@ -13,7 +13,6 @@ 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;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.Group;
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.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
@@ -25,8 +24,6 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
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.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ABORT;
import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACCEPT;
import static org.briarproject.briar.introduction.MessageType.ACTIVATE; import static org.briarproject.briar.introduction.MessageType.ACTIVATE;
@@ -155,28 +152,6 @@ abstract class AbstractProtocolEngine<S extends Session>
} }
} }
void markRequestUnavailableToAnswer(Transaction txn, MessageId m)
throws DbException {
BdfDictionary meta = new BdfDictionary();
messageEncoder.setAvailableToAnswer(meta, false);
try {
clientHelper.mergeMessageMetadata(txn, m, meta);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
Map<MessageId, BdfDictionary> getSessions(Transaction txn,
BdfDictionary query) throws DbException, FormatException {
return clientHelper
.getMessageMetadataAsDictionary(txn, getLocalGroup().getId(),
query);
}
private Group getLocalGroup() {
return contactGroupFactory.createLocalGroup(CLIENT_ID, CLIENT_VERSION);
}
boolean isInvalidDependency(@Nullable MessageId lastRemoteMessageId, boolean isInvalidDependency(@Nullable MessageId lastRemoteMessageId,
@Nullable MessageId dependency) { @Nullable MessageId dependency) {
if (dependency == null) return lastRemoteMessageId != null; if (dependency == null) return lastRemoteMessageId != null;

View File

@@ -124,8 +124,7 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onRequestMessage(Transaction txn, public IntroduceeSession onRequestMessage(Transaction txn,
IntroduceeSession session, RequestMessage m) IntroduceeSession session, RequestMessage m) throws DbException {
throws DbException, FormatException {
switch (session.getState()) { switch (session.getState()) {
case START: case START:
return onRemoteRequest(txn, session, m); return onRemoteRequest(txn, session, m);
@@ -143,8 +142,7 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onAcceptMessage(Transaction txn, public IntroduceeSession onAcceptMessage(Transaction txn,
IntroduceeSession session, AcceptMessage m) IntroduceeSession session, AcceptMessage m) throws DbException {
throws DbException, FormatException {
switch (session.getState()) { switch (session.getState()) {
case START: case START:
return onRemoteResponseInStart(txn, session, m); return onRemoteResponseInStart(txn, session, m);
@@ -163,8 +161,7 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onDeclineMessage(Transaction txn, public IntroduceeSession onDeclineMessage(Transaction txn,
IntroduceeSession session, DeclineMessage m) IntroduceeSession session, DeclineMessage m) throws DbException {
throws DbException, FormatException {
switch (session.getState()) { switch (session.getState()) {
case START: case START:
return onRemoteResponseInStart(txn, session, m); return onRemoteResponseInStart(txn, session, m);
@@ -183,8 +180,7 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onAuthMessage(Transaction txn, public IntroduceeSession onAuthMessage(Transaction txn,
IntroduceeSession session, AuthMessage m) IntroduceeSession session, AuthMessage m) throws DbException {
throws DbException, FormatException {
switch (session.getState()) { switch (session.getState()) {
case AWAIT_AUTH: case AWAIT_AUTH:
return onRemoteAuth(txn, session, m); return onRemoteAuth(txn, session, m);
@@ -202,8 +198,7 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onActivateMessage(Transaction txn, public IntroduceeSession onActivateMessage(Transaction txn,
IntroduceeSession session, ActivateMessage m) IntroduceeSession session, ActivateMessage m) throws DbException {
throws DbException, FormatException {
switch (session.getState()) { switch (session.getState()) {
case AWAIT_ACTIVATE: case AWAIT_ACTIVATE:
return onRemoteActivate(txn, session, m); return onRemoteActivate(txn, session, m);
@@ -221,8 +216,7 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onAbortMessage(Transaction txn, public IntroduceeSession onAbortMessage(Transaction txn,
IntroduceeSession session, AbortMessage m) IntroduceeSession session, AbortMessage m) throws DbException {
throws DbException, FormatException {
return onRemoteAbort(txn, session, m); return onRemoteAbort(txn, session, m);
} }
@@ -232,8 +226,9 @@ class IntroduceeProtocolEngine
if (isInvalidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abort(txn, s); return abort(txn, s);
// Mark the request visible in the UI // Mark the request visible in the UI and available to answer
markMessageVisibleInUi(txn, m.getMessageId()); markMessageVisibleInUi(txn, m.getMessageId());
markRequestAvailableToAnswer(txn, m.getMessageId(), true);
// Add SessionId to message metadata // Add SessionId to message metadata
addSessionId(txn, m.getMessageId(), s.getSessionId()); addSessionId(txn, m.getMessageId(), s.getSessionId());
@@ -243,9 +238,11 @@ class IntroduceeProtocolEngine
.trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false);
// Broadcast IntroductionRequestReceivedEvent // Broadcast IntroductionRequestReceivedEvent
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
Contact c = contactManager.getContact(txn, s.getIntroducer().getId(), Contact c = contactManager.getContact(txn, s.getIntroducer().getId(),
identityManager.getLocalAuthor(txn).getId()); localAuthor.getId());
boolean contactExists = false; // TODO boolean contactExists = contactManager
.contactExists(txn, m.getAuthor().getId(), localAuthor.getId());
IntroductionRequest request = IntroductionRequest request =
new IntroductionRequest(s.getSessionId(), m.getMessageId(), new IntroductionRequest(s.getSessionId(), m.getMessageId(),
m.getGroupId(), INTRODUCEE, m.getTimestamp(), false, m.getGroupId(), INTRODUCEE, m.getTimestamp(), false,
@@ -260,11 +257,10 @@ class IntroduceeProtocolEngine
} }
private IntroduceeSession onLocalAccept(Transaction txn, private IntroduceeSession onLocalAccept(Transaction txn,
IntroduceeSession s, long timestamp) throws DbException { IntroduceeSession s, long timestamp)
throws DbException {
// Mark the request message unavailable to answer // Mark the request message unavailable to answer
MessageId requestId = s.getLastRemoteMessageId(); markRequestsUnavailableToAnswer(txn, s);
if (requestId == null) throw new IllegalStateException();
markRequestUnavailableToAnswer(txn, requestId);
// Create ephemeral key pair and get local transport properties // Create ephemeral key pair and get local transport properties
KeyPair keyPair = crypto.generateKeyPair(); KeyPair keyPair = crypto.generateKeyPair();
@@ -275,7 +271,7 @@ class IntroduceeProtocolEngine
// Send a ACCEPT message // Send a ACCEPT message
long localTimestamp = long localTimestamp =
Math.max(timestamp, getLocalTimestamp(s)); Math.max(timestamp + 1, getLocalTimestamp(s));
Message sent = sendAcceptMessage(txn, s, localTimestamp, publicKey, Message sent = sendAcceptMessage(txn, s, localTimestamp, publicKey,
localTimestamp, transportProperties, true); localTimestamp, transportProperties, true);
// Track the message // Track the message
@@ -297,14 +293,13 @@ class IntroduceeProtocolEngine
} }
private IntroduceeSession onLocalDecline(Transaction txn, private IntroduceeSession onLocalDecline(Transaction txn,
IntroduceeSession s, long timestamp) throws DbException { IntroduceeSession s, long timestamp)
throws DbException {
// Mark the request message unavailable to answer // Mark the request message unavailable to answer
MessageId requestId = s.getLastRemoteMessageId(); markRequestsUnavailableToAnswer(txn, s);
if (requestId == null) throw new IllegalStateException();
markRequestUnavailableToAnswer(txn, requestId);
// Send a DECLINE message // Send a DECLINE message
long localTimestamp = Math.max(timestamp, 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);
@@ -316,7 +311,7 @@ class IntroduceeProtocolEngine
private IntroduceeSession onRemoteAccept(Transaction txn, private IntroduceeSession onRemoteAccept(Transaction txn,
IntroduceeSession s, AcceptMessage m) IntroduceeSession s, AcceptMessage m)
throws DbException, FormatException { 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);
@@ -346,7 +341,7 @@ class IntroduceeProtocolEngine
if (isInvalidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abort(txn, s); return abort(txn, s);
// Mark the request visible in the UI // Mark the response visible in the UI
markMessageVisibleInUi(txn, m.getMessageId()); markMessageVisibleInUi(txn, m.getMessageId());
// Track the incoming message // Track the incoming message
@@ -401,8 +396,6 @@ class IntroduceeProtocolEngine
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
// TODO // TODO
return abort(txn, s); return abort(txn, s);
} catch (FormatException e) {
throw new AssertionError(e);
} }
if (s.getState() != AWAIT_AUTH) throw new AssertionError(); if (s.getState() != AWAIT_AUTH) throw new AssertionError();
Message sent = sendAuthMessage(txn, s, getLocalTimestamp(s), mac, Message sent = sendAuthMessage(txn, s, getLocalTimestamp(s), mac,
@@ -411,8 +404,7 @@ class IntroduceeProtocolEngine
} }
private IntroduceeSession onRemoteAuth(Transaction txn, private IntroduceeSession onRemoteAuth(Transaction txn,
IntroduceeSession s, AuthMessage m) IntroduceeSession s, AuthMessage m) throws DbException {
throws DbException, FormatException {
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (isInvalidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abort(txn, s); return abort(txn, s);
@@ -479,9 +471,7 @@ class IntroduceeProtocolEngine
IntroduceeSession s, AbortMessage m) IntroduceeSession s, AbortMessage m)
throws DbException { throws DbException {
// Mark the request message unavailable to answer // Mark the request message unavailable to answer
MessageId requestId = s.getLastRemoteMessageId(); markRequestsUnavailableToAnswer(txn, s);
if (requestId == null) throw new IllegalStateException();
markRequestUnavailableToAnswer(txn, requestId);
// Broadcast abort event for testing // Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId())); txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
@@ -495,9 +485,7 @@ class IntroduceeProtocolEngine
private IntroduceeSession abort(Transaction txn, IntroduceeSession s) private IntroduceeSession abort(Transaction txn, IntroduceeSession s)
throws DbException { throws DbException {
// Mark the request message unavailable to answer // Mark the request message unavailable to answer
MessageId requestId = s.getLastRemoteMessageId(); markRequestsUnavailableToAnswer(txn, s);
if (requestId == null) throw new IllegalStateException();
markRequestUnavailableToAnswer(txn, requestId);
// Send an ABORT message // Send an ABORT message
Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s)); Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s));
@@ -537,4 +525,30 @@ class IntroduceeProtocolEngine
} }
} }
private void markRequestsUnavailableToAnswer(Transaction txn,
IntroduceeSession s) throws DbException {
BdfDictionary query = messageParser
.getRequestsAvailableToAnswerQuery(s.getSessionId());
try {
Map<MessageId, BdfDictionary> results =
clientHelper.getMessageMetadataAsDictionary(txn,
s.getContactGroupId(), query);
for (MessageId m : results.keySet())
markRequestAvailableToAnswer(txn, m, false);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
private void markRequestAvailableToAnswer(Transaction txn, MessageId m,
boolean available) throws DbException {
BdfDictionary meta = new BdfDictionary();
messageEncoder.setAvailableToAnswer(meta, available);
try {
clientHelper.mergeMessageMetadata(txn, m, meta);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
} }

View File

@@ -1,11 +1,9 @@
package org.briarproject.briar.introduction; package org.briarproject.briar.introduction;
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.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.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;
@@ -23,8 +21,6 @@ import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent; import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.introduction.IntroducerSession.Introducee; import org.briarproject.briar.introduction.IntroducerSession.Introducee;
import java.util.Map;
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;
@@ -97,21 +93,19 @@ class IntroducerProtocolEngine
} }
IntroducerSession onAbortAction(Transaction txn, IntroducerSession s) IntroducerSession onAbortAction(Transaction txn, IntroducerSession s)
throws DbException, FormatException { throws DbException {
return abort(txn, s); return abort(txn, s);
} }
@Override @Override
public IntroducerSession onRequestMessage(Transaction txn, public IntroducerSession onRequestMessage(Transaction txn,
IntroducerSession s, RequestMessage m) IntroducerSession s, RequestMessage m) throws DbException {
throws DbException, FormatException {
return abort(txn, s); // Invalid in this role return abort(txn, s); // Invalid in this role
} }
@Override @Override
public IntroducerSession onAcceptMessage(Transaction txn, public IntroducerSession onAcceptMessage(Transaction txn,
IntroducerSession s, AcceptMessage m) IntroducerSession s, AcceptMessage m) throws DbException {
throws DbException, FormatException {
switch (s.getState()) { switch (s.getState()) {
case AWAIT_RESPONSES: case AWAIT_RESPONSES:
case AWAIT_RESPONSE_A: case AWAIT_RESPONSE_A:
@@ -133,8 +127,7 @@ class IntroducerProtocolEngine
@Override @Override
public IntroducerSession onDeclineMessage(Transaction txn, public IntroducerSession onDeclineMessage(Transaction txn,
IntroducerSession s, DeclineMessage m) IntroducerSession s, DeclineMessage m) throws DbException {
throws DbException, FormatException {
switch (s.getState()) { switch (s.getState()) {
case AWAIT_RESPONSES: case AWAIT_RESPONSES:
case AWAIT_RESPONSE_A: case AWAIT_RESPONSE_A:
@@ -156,7 +149,7 @@ class IntroducerProtocolEngine
@Override @Override
public IntroducerSession onAuthMessage(Transaction txn, IntroducerSession s, public IntroducerSession onAuthMessage(Transaction txn, IntroducerSession s,
AuthMessage m) throws DbException, FormatException { AuthMessage m) throws DbException {
switch (s.getState()) { switch (s.getState()) {
case AWAIT_AUTHS: case AWAIT_AUTHS:
case AWAIT_AUTH_A: case AWAIT_AUTH_A:
@@ -177,8 +170,7 @@ class IntroducerProtocolEngine
@Override @Override
public IntroducerSession onActivateMessage(Transaction txn, public IntroducerSession onActivateMessage(Transaction txn,
IntroducerSession s, ActivateMessage m) IntroducerSession s, ActivateMessage m) throws DbException {
throws DbException, FormatException {
switch (s.getState()) { switch (s.getState()) {
case AWAIT_ACTIVATES: case AWAIT_ACTIVATES:
case AWAIT_ACTIVATE_A: case AWAIT_ACTIVATE_A:
@@ -199,8 +191,7 @@ class IntroducerProtocolEngine
@Override @Override
public IntroducerSession onAbortMessage(Transaction txn, public IntroducerSession onAbortMessage(Transaction txn,
IntroducerSession s, AbortMessage m) IntroducerSession s, AbortMessage m) throws DbException {
throws DbException, FormatException {
return onRemoteAbort(txn, s, m); return onRemoteAbort(txn, s, m);
} }
@@ -227,8 +218,7 @@ class IntroducerProtocolEngine
} }
private IntroducerSession onRemoteAccept(Transaction txn, private IntroducerSession onRemoteAccept(Transaction txn,
IntroducerSession s, AcceptMessage m) IntroducerSession s, AcceptMessage m) throws DbException {
throws DbException, FormatException {
// 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);
@@ -284,8 +274,7 @@ class IntroducerProtocolEngine
} }
private IntroducerSession onRemoteDecline(Transaction txn, private IntroducerSession onRemoteDecline(Transaction txn,
IntroducerSession s, DeclineMessage m) IntroducerSession s, DeclineMessage m) throws DbException {
throws DbException, FormatException {
// 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);
@@ -337,7 +326,7 @@ class IntroducerProtocolEngine
private IntroducerSession onRemoteResponseInStart(Transaction txn, private IntroducerSession onRemoteResponseInStart(Transaction txn,
IntroducerSession s, AbstractIntroductionMessage m) IntroducerSession s, AbstractIntroductionMessage m)
throws DbException, FormatException { 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);
@@ -384,8 +373,7 @@ class IntroducerProtocolEngine
} }
private IntroducerSession onRemoteAuth(Transaction txn, private IntroducerSession onRemoteAuth(Transaction txn,
IntroducerSession s, AuthMessage m) IntroducerSession s, AuthMessage m) throws DbException {
throws DbException, FormatException {
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (isInvalidDependency(s, m.getGroupId(), m.getPreviousMessageId())) if (isInvalidDependency(s, m.getGroupId(), m.getPreviousMessageId()))
return abort(txn, s); return abort(txn, s);
@@ -413,8 +401,7 @@ class IntroducerProtocolEngine
} }
private IntroducerSession onRemoteActivate(Transaction txn, private IntroducerSession onRemoteActivate(Transaction txn,
IntroducerSession s, ActivateMessage m) IntroducerSession s, ActivateMessage m) throws DbException {
throws DbException, FormatException {
// The dependency, if any, must be the last remote message // The dependency, if any, must be the last remote message
if (isInvalidDependency(s, m.getGroupId(), m.getPreviousMessageId())) if (isInvalidDependency(s, m.getGroupId(), m.getPreviousMessageId()))
return abort(txn, s); return abort(txn, s);
@@ -441,11 +428,7 @@ class IntroducerProtocolEngine
} }
private IntroducerSession onRemoteAbort(Transaction txn, private IntroducerSession onRemoteAbort(Transaction txn,
IntroducerSession s, AbortMessage m) IntroducerSession s, AbortMessage m) throws DbException {
throws DbException, FormatException {
// Mark any REQUEST messages in the session unavailable to answer
markRequestsUnavailableToAnswer(txn, s);
// Forward ABORT message // Forward ABORT message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long timestamp = getLocalTimestamp(s, i);
@@ -468,10 +451,7 @@ class IntroducerProtocolEngine
} }
private IntroducerSession abort(Transaction txn, private IntroducerSession abort(Transaction txn,
IntroducerSession s) throws DbException, FormatException { IntroducerSession s) throws DbException {
// Mark any REQUEST messages in the session unavailable to answer
markRequestsUnavailableToAnswer(txn, s);
// Broadcast abort event for testing // Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId())); txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
@@ -487,15 +467,6 @@ class IntroducerProtocolEngine
s.getRequestTimestamp(), introducee1, introducee2); s.getRequestTimestamp(), introducee1, introducee2);
} }
private void markRequestsUnavailableToAnswer(Transaction txn, Session s)
throws DbException, FormatException {
BdfDictionary query = messageParser
.getInvitesAvailableToAnswerQuery(s.getSessionId());
Map<MessageId, BdfDictionary> results = getSessions(txn, query);
for (MessageId m : results.keySet())
markRequestUnavailableToAnswer(txn, m);
}
private Introducee getIntroducee(IntroducerSession s, GroupId g) { private Introducee getIntroducee(IntroducerSession s, GroupId g) {
if (s.getIntroducee1().groupId.equals(g)) return s.getIntroducee1(); if (s.getIntroducee1().groupId.equals(g)) return s.getIntroducee1();
else if (s.getIntroducee2().groupId.equals(g)) else if (s.getIntroducee2().groupId.equals(g))

View File

@@ -12,7 +12,6 @@ interface IntroductionConstants {
String MSG_KEY_LOCAL = "local"; String MSG_KEY_LOCAL = "local";
String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_VISIBLE_IN_UI = "visibleInUi";
String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer";
String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
// Session Keys // Session Keys
String SESSION_KEY_SESSION_ID = "sessionId"; String SESSION_KEY_SESSION_ID = "sessionId";

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.introduction; package org.briarproject.briar.introduction;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
@@ -15,15 +14,13 @@ interface IntroductionCrypto {
/** /**
* Returns the {@link SessionId} based on the introducer * Returns the {@link SessionId} based on the introducer
* and the two introducees. * and the two introducees.
*
* Note: The roles of Alice and Bob can be switched.
*/ */
SessionId getSessionId(Author introducer, Author alice, Author bob); SessionId getSessionId(Author introducer, Author local, Author remote);
/** /**
* Returns true if the first author is indeed alice * Returns true if the local author is alice
*/ */
boolean isAlice(AuthorId alice, AuthorId bob); boolean isAlice(AuthorId local, AuthorId remote);
/** /**
* Generates an agreement key pair. * Generates an agreement key pair.
@@ -49,11 +46,11 @@ interface IntroductionCrypto {
SecretKey deriveMacKey(SecretKey masterKey, boolean alice); SecretKey deriveMacKey(SecretKey masterKey, boolean alice);
/** /**
* Generates a MAC that covers both introducee's ephemeral public keys and * Generates a MAC that covers both introducee's ephemeral public keys,
* transport properties. * transport properties, Author IDs and timestamps of the accept message.
*/ */
byte[] mac(SecretKey macKey, IntroduceeSession s, AuthorId localAuthorId, byte[] mac(SecretKey macKey, IntroduceeSession s, AuthorId localAuthorId,
boolean alice) throws FormatException; boolean alice);
/** /**
* Verifies a received MAC * Verifies a received MAC
@@ -63,7 +60,7 @@ interface IntroductionCrypto {
* @throws GeneralSecurityException if the verification fails * @throws GeneralSecurityException if the verification fails
*/ */
void verifyMac(byte[] mac, IntroduceeSession s, AuthorId localAuthorId) void verifyMac(byte[] mac, IntroduceeSession s, AuthorId localAuthorId)
throws GeneralSecurityException, FormatException; throws GeneralSecurityException;
/** /**
* Signs a nonce derived from the macKey * Signs a nonce derived from the macKey

View File

@@ -18,7 +18,6 @@ import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -49,14 +48,14 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
} }
@Override @Override
public SessionId getSessionId(Author introducer, Author alice, public SessionId getSessionId(Author introducer, Author local,
Author bob) { Author remote) {
boolean isAlice = isAlice(alice.getId(), bob.getId()); boolean isAlice = isAlice(local.getId(), remote.getId());
byte[] hash = crypto.hash( byte[] hash = crypto.hash(
LABEL_SESSION_ID, LABEL_SESSION_ID,
introducer.getId().getBytes(), introducer.getId().getBytes(),
isAlice ? alice.getId().getBytes() : bob.getId().getBytes(), isAlice ? local.getId().getBytes() : remote.getId().getBytes(),
isAlice ? bob.getId().getBytes() : alice.getId().getBytes() isAlice ? remote.getId().getBytes() : local.getId().getBytes()
); );
return new SessionId(hash); return new SessionId(hash);
} }
@@ -67,9 +66,9 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
} }
@Override @Override
public boolean isAlice(AuthorId alice, AuthorId bob) { public boolean isAlice(AuthorId local, AuthorId remote) {
byte[] a = alice.getBytes(); byte[] a = local.getBytes();
byte[] b = bob.getBytes(); byte[] b = remote.getBytes();
return Bytes.COMPARATOR.compare(new Bytes(a), new Bytes(b)) < 0; return Bytes.COMPARATOR.compare(new Bytes(a), new Bytes(b)) < 0;
} }
@@ -110,7 +109,7 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
@Override @Override
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
public byte[] mac(SecretKey macKey, IntroduceeSession s, public byte[] mac(SecretKey macKey, IntroduceeSession s,
AuthorId localAuthorId, boolean alice) throws FormatException { AuthorId localAuthorId, boolean alice) {
return mac(macKey, s.getIntroducer().getId(), localAuthorId, return mac(macKey, s.getIntroducer().getId(), localAuthorId,
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(), s.getRemoteAuthor().getId(), s.getAcceptTimestamp(),
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(), s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(),
@@ -124,7 +123,59 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey, byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey,
Map<TransportId, TransportProperties> transportProperties, Map<TransportId, TransportProperties> transportProperties,
Map<TransportId, TransportProperties> remoteTransportProperties, Map<TransportId, TransportProperties> remoteTransportProperties,
boolean alice) throws FormatException { boolean alice) {
byte[] inputs =
getMacInputs(introducerId, localAuthorId, remoteAuthorId,
acceptTimestamp, remoteAcceptTimestamp,
ephemeralPublicKey, remoteEphemeralPublicKey,
transportProperties, remoteTransportProperties, alice);
return crypto.mac(
LABEL_AUTH_MAC,
macKey,
inputs
);
}
@Override
@SuppressWarnings("ConstantConditions")
public void verifyMac(byte[] mac, IntroduceeSession s,
AuthorId localAuthorId)
throws GeneralSecurityException {
boolean alice = isAlice(localAuthorId, s.getRemoteAuthor().getId());
verifyMac(mac, new SecretKey(s.getMasterKey()),
s.getIntroducer().getId(), localAuthorId,
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(),
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(),
s.getRemotePublicKey(), s.getTransportProperties(),
s.getRemoteTransportProperties(), !alice);
}
void verifyMac(byte[] mac, SecretKey masterKey,
AuthorId introducerId, AuthorId localAuthorId,
AuthorId remoteAuthorId, long acceptTimestamp,
long remoteAcceptTimestamp, byte[] ephemeralPublicKey,
byte[] remoteEphemeralPublicKey,
Map<TransportId, TransportProperties> transportProperties,
Map<TransportId, TransportProperties> remoteTransportProperties,
boolean alice) throws GeneralSecurityException {
SecretKey macKey = deriveMacKey(masterKey, alice);
byte[] inputs =
getMacInputs(introducerId, localAuthorId, remoteAuthorId,
acceptTimestamp, remoteAcceptTimestamp,
ephemeralPublicKey, remoteEphemeralPublicKey,
transportProperties, remoteTransportProperties, !alice);
if (!crypto.verifyMac(mac, LABEL_AUTH_MAC, macKey, inputs)) {
throw new GeneralSecurityException();
}
}
private byte[] getMacInputs(AuthorId introducerId,
AuthorId localAuthorId, AuthorId remoteAuthorId,
long acceptTimestamp, long remoteAcceptTimestamp,
byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey,
Map<TransportId, TransportProperties> transportProperties,
Map<TransportId, TransportProperties> remoteTransportProperties,
boolean alice) {
BdfList localInfo = BdfList.of( BdfList localInfo = BdfList.of(
localAuthorId, localAuthorId,
acceptTimestamp, acceptTimestamp,
@@ -142,43 +193,10 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
alice ? localInfo : remoteInfo, alice ? localInfo : remoteInfo,
alice ? remoteInfo : localInfo alice ? remoteInfo : localInfo
); );
return crypto.mac( try {
LABEL_AUTH_MAC, return clientHelper.toByteArray(macList);
macKey, } catch (FormatException e) {
clientHelper.toByteArray(macList) throw new AssertionError();
);
}
@Override
@SuppressWarnings("ConstantConditions")
public void verifyMac(byte[] mac, IntroduceeSession s,
AuthorId localAuthorId)
throws GeneralSecurityException, FormatException {
boolean alice = isAlice(localAuthorId, s.getRemoteAuthor().getId());
verifyMac(mac, new SecretKey(s.getMasterKey()),
s.getIntroducer().getId(), localAuthorId,
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(),
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(),
s.getRemotePublicKey(), s.getTransportProperties(),
s.getRemoteTransportProperties(), !alice);
}
void verifyMac(byte[] mac, SecretKey masterKey,
AuthorId introducerId, AuthorId localAuthorId,
AuthorId remoteAuthorId, long acceptTimestamp,
long remoteAcceptTimestamp, byte[] ephemeralPublicKey,
byte[] remoteEphemeralPublicKey,
Map<TransportId, TransportProperties> transportProperties,
Map<TransportId, TransportProperties> remoteTransportProperties,
boolean alice) throws GeneralSecurityException, FormatException {
SecretKey macKey = deriveMacKey(masterKey, alice);
byte[] calculatedMac =
mac(macKey, introducerId, localAuthorId, remoteAuthorId,
acceptTimestamp, remoteAcceptTimestamp,
ephemeralPublicKey, remoteEphemeralPublicKey,
transportProperties, remoteTransportProperties, !alice);
if (!Arrays.equals(mac, calculatedMac)) {
throw new GeneralSecurityException();
} }
} }
@@ -204,7 +222,8 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
void verifySignature(SecretKey macKey, byte[] publicKey, void verifySignature(SecretKey macKey, byte[] publicKey,
byte[] signature) throws GeneralSecurityException { byte[] signature) throws GeneralSecurityException {
byte[] nonce = getNonce(macKey); byte[] nonce = getNonce(macKey);
if (!crypto.verify(LABEL_AUTH_SIGN, nonce, publicKey, signature)) { if (!crypto.verifySignature(signature, LABEL_AUTH_SIGN, nonce,
publicKey)) {
throw new GeneralSecurityException(); throw new GeneralSecurityException();
} }
} }

View File

@@ -5,6 +5,7 @@ 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.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.ContactManager.ContactHook; import org.briarproject.bramble.api.contact.ContactManager.ContactHook;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
@@ -37,6 +38,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -59,6 +61,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
implements IntroductionManager, Client, ContactHook { implements IntroductionManager, Client, ContactHook {
private final ContactGroupFactory contactGroupFactory; private final ContactGroupFactory contactGroupFactory;
private final ContactManager contactManager;
private final MessageParser messageParser; private final MessageParser messageParser;
private final SessionEncoder sessionEncoder; private final SessionEncoder sessionEncoder;
private final SessionParser sessionParser; private final SessionParser sessionParser;
@@ -74,6 +77,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
MetadataParser metadataParser, MetadataParser metadataParser,
MessageTracker messageTracker, MessageTracker messageTracker,
ContactGroupFactory contactGroupFactory, ContactGroupFactory contactGroupFactory,
ContactManager contactManager,
MessageParser messageParser, MessageParser messageParser,
SessionEncoder sessionEncoder, SessionEncoder sessionEncoder,
SessionParser sessionParser, SessionParser sessionParser,
@@ -83,6 +87,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
IdentityManager identityManager) { IdentityManager identityManager) {
super(db, clientHelper, metadataParser, messageTracker); super(db, clientHelper, metadataParser, messageTracker);
this.contactGroupFactory = contactGroupFactory; this.contactGroupFactory = contactGroupFactory;
this.contactManager = contactManager;
this.messageParser = messageParser; this.messageParser = messageParser;
this.sessionEncoder = sessionEncoder; this.sessionEncoder = sessionEncoder;
this.sessionParser = sessionParser; this.sessionParser = sessionParser;
@@ -107,8 +112,6 @@ class IntroductionManagerImpl extends ConversationClientImpl
public void addingContact(Transaction txn, Contact c) throws DbException { public void addingContact(Transaction txn, Contact c) throws DbException {
// Create a group to share with the contact // Create a group to share with the contact
Group g = getContactGroup(c); Group g = getContactGroup(c);
// Return if we've already set things up for this contact
if (db.containsGroup(txn, g.getId())) return;
// Store the group and share it with the contact // Store the group and share it with the contact
db.addGroup(txn, g); db.addGroup(txn, g);
db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED);
@@ -124,12 +127,9 @@ class IntroductionManagerImpl extends ConversationClientImpl
@Override @Override
public void removingContact(Transaction txn, Contact c) throws DbException { public void removingContact(Transaction txn, Contact c) throws DbException {
try { removeSessionWithIntroducer(txn, c);
removeSessionWithIntroducer(txn, c); abortOrRemoveSessionWithIntroducee(txn, c);
abortOrRemoveSessionWithIntroducee(txn, c);
} catch (FormatException e) {
throw new AssertionError();
}
// Remove the contact group (all messages will be removed with it) // Remove the contact group (all messages will be removed with it)
db.removeGroup(txn, getContactGroup(c)); db.removeGroup(txn, getContactGroup(c));
} }
@@ -185,12 +185,12 @@ class IntroductionManagerImpl extends ConversationClientImpl
Message m, BdfList body) throws DbException, FormatException { Message m, BdfList body) throws DbException, FormatException {
ContactId introducerId = getContactId(txn, m.getGroupId()); ContactId introducerId = getContactId(txn, m.getGroupId());
Author introducer = db.getContact(txn, introducerId).getAuthor(); Author introducer = db.getContact(txn, introducerId).getAuthor();
Author alice = identityManager.getLocalAuthor(txn); Author local = identityManager.getLocalAuthor(txn);
Author bob = messageParser.parseRequestMessage(m, body).getAuthor(); Author remote = messageParser.parseRequestMessage(m, body).getAuthor();
if (alice.equals(bob)) throw new FormatException(); if (local.equals(remote)) throw new FormatException();
SessionId sessionId = crypto.getSessionId(introducer, alice, bob); SessionId sessionId = crypto.getSessionId(introducer, local, remote);
return IntroduceeSession return IntroduceeSession
.getInitial(m.getGroupId(), sessionId, introducer, bob); .getInitial(m.getGroupId(), sessionId, introducer, remote);
} }
private <S extends Session> S handleMessage(Transaction txn, Message m, private <S extends Session> S handleMessage(Transaction txn, Message m,
@@ -249,7 +249,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
} }
private void storeSession(Transaction txn, MessageId storageId, private void storeSession(Transaction txn, MessageId storageId,
Session session) throws DbException, FormatException { Session session) throws DbException {
BdfDictionary d; BdfDictionary d;
if (session.getRole() == INTRODUCER) { if (session.getRole() == INTRODUCER) {
d = sessionEncoder d = sessionEncoder
@@ -260,7 +260,11 @@ class IntroductionManagerImpl extends ConversationClientImpl
} else { } else {
throw new AssertionError(); throw new AssertionError();
} }
clientHelper.mergeMessageMetadata(txn, storageId, d); try {
clientHelper.mergeMessageMetadata(txn, storageId, d);
} catch (FormatException e) {
throw new AssertionError();
}
} }
@Override @Override
@@ -356,7 +360,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
Map<MessageId, BdfDictionary> results = clientHelper Map<MessageId, BdfDictionary> results = clientHelper
.getMessageMetadataAsDictionary(txn, contactGroupId, query); .getMessageMetadataAsDictionary(txn, contactGroupId, query);
messages = new ArrayList<>(results.size()); messages = new ArrayList<>(results.size());
for (Map.Entry<MessageId, BdfDictionary> e : results.entrySet()) { for (Entry<MessageId, BdfDictionary> e : results.entrySet()) {
MessageId m = e.getKey(); MessageId m = e.getKey();
MessageMetadata meta = MessageMetadata meta =
messageParser.parseMetadata(e.getValue()); messageParser.parseMetadata(e.getValue());
@@ -394,11 +398,11 @@ class IntroductionManagerImpl extends ConversationClientImpl
Role role = sessionParser.getRole(bdfSession); Role role = sessionParser.getRole(bdfSession);
SessionId sessionId; SessionId sessionId;
Author author; Author author;
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
if (role == INTRODUCER) { if (role == INTRODUCER) {
IntroducerSession session = IntroducerSession session =
sessionParser.parseIntroducerSession(bdfSession); sessionParser.parseIntroducerSession(bdfSession);
sessionId = session.getSessionId(); sessionId = session.getSessionId();
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
if (localAuthor.equals(session.getIntroducee1().author)) { if (localAuthor.equals(session.getIntroducee1().author)) {
author = session.getIntroducee2().author; author = session.getIntroducee2().author;
} else { } else {
@@ -410,8 +414,14 @@ class IntroductionManagerImpl extends ConversationClientImpl
sessionId = session.getSessionId(); sessionId = session.getSessionId();
author = session.getRemoteAuthor(); author = session.getRemoteAuthor();
} else throw new AssertionError(); } else throw new AssertionError();
String message = ""; // TODO Message msg = clientHelper.getMessage(txn, m);
boolean contactExists = false; // TODO BdfList body = clientHelper.getMessageAsList(txn, m);
if (msg == null || body == null) throw new AssertionError();
RequestMessage rm = messageParser.parseRequestMessage(msg, body);
String message = rm.getMessage();
boolean contactExists = contactManager
.contactExists(txn, rm.getAuthor().getId(),
localAuthor.getId());
return new IntroductionRequest(sessionId, m, contactGroupId, return new IntroductionRequest(sessionId, m, contactGroupId,
role, meta.getTimestamp(), meta.isLocal(), role, meta.getTimestamp(), meta.isLocal(),
@@ -449,12 +459,16 @@ class IntroductionManagerImpl extends ConversationClientImpl
} }
private void removeSessionWithIntroducer(Transaction txn, private void removeSessionWithIntroducer(Transaction txn,
Contact introducer) throws DbException, FormatException { Contact introducer) throws DbException {
BdfDictionary query = sessionEncoder BdfDictionary query = sessionEncoder
.getIntroduceeSessionsByIntroducerQuery(introducer.getAuthor()); .getIntroduceeSessionsByIntroducerQuery(introducer.getAuthor());
Map<MessageId, BdfDictionary> sessions = clientHelper Map<MessageId, BdfDictionary> sessions;
.getMessageMetadataAsDictionary(txn, getLocalGroup().getId(), try {
query); sessions = clientHelper.getMessageMetadataAsDictionary(txn,
getLocalGroup().getId(), query);
} catch (FormatException e) {
throw new AssertionError(e);
}
for (MessageId id : sessions.keySet()) { for (MessageId id : sessions.keySet()) {
db.deleteMessageMetadata(txn, id); // TODO needed? db.deleteMessageMetadata(txn, id); // TODO needed?
db.removeMessage(txn, id); db.removeMessage(txn, id);
@@ -462,16 +476,23 @@ class IntroductionManagerImpl extends ConversationClientImpl
} }
private void abortOrRemoveSessionWithIntroducee(Transaction txn, private void abortOrRemoveSessionWithIntroducee(Transaction txn,
Contact c) throws DbException, FormatException { Contact c) throws DbException {
BdfDictionary query = sessionEncoder.getIntroducerSessionsQuery(); BdfDictionary query = sessionEncoder.getIntroducerSessionsQuery();
Map<MessageId, BdfDictionary> sessions = clientHelper Map<MessageId, BdfDictionary> sessions;
.getMessageMetadataAsDictionary(txn, getLocalGroup().getId(), try {
query); sessions = clientHelper.getMessageMetadataAsDictionary(txn,
getLocalGroup().getId(), query);
} catch (FormatException e) {
throw new AssertionError();
}
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
for (Map.Entry<MessageId, BdfDictionary> session : sessions for (Entry<MessageId, BdfDictionary> session : sessions.entrySet()) {
.entrySet()) { IntroducerSession s;
IntroducerSession s = try {
sessionParser.parseIntroducerSession(session.getValue()); s = sessionParser.parseIntroducerSession(session.getValue());
} catch (FormatException e) {
throw new AssertionError();
}
if (s.getIntroducee1().author.equals(c.getAuthor())) { if (s.getIntroducee1().author.equals(c.getAuthor())) {
abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(), abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(),
s.getIntroducee2(), localAuthor); s.getIntroducee2(), localAuthor);
@@ -484,7 +505,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
private void abortOrRemoveSessionWithIntroducee(Transaction txn, private void abortOrRemoveSessionWithIntroducee(Transaction txn,
IntroducerSession s, MessageId storageId, Introducee i, IntroducerSession s, MessageId storageId, Introducee i,
LocalAuthor localAuthor) throws DbException, FormatException { LocalAuthor localAuthor) throws DbException {
if (db.containsContact(txn, i.author.getId(), localAuthor.getId())) { if (db.containsContact(txn, i.author.getId(), localAuthor.getId())) {
IntroducerSession session = introducerEngine.onAbortAction(txn, s); IntroducerSession session = introducerEngine.onAbortAction(txn, s);
storeSession(txn, storageId, session); storeSession(txn, storageId, session);

View File

@@ -78,8 +78,7 @@ class IntroductionValidator extends BdfMessageValidator {
checkLength(msg, 1, MAX_REQUEST_MESSAGE_LENGTH); checkLength(msg, 1, MAX_REQUEST_MESSAGE_LENGTH);
BdfDictionary meta = messageEncoder BdfDictionary meta = messageEncoder
.encodeRequestMetadata(m.getTimestamp(), false, false, .encodeRequestMetadata(m.getTimestamp(), false, false, false);
false, false);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {

View File

@@ -18,7 +18,7 @@ import javax.annotation.Nullable;
interface MessageEncoder { interface MessageEncoder {
BdfDictionary encodeRequestMetadata(long timestamp, boolean local, BdfDictionary encodeRequestMetadata(long timestamp, boolean local,
boolean read, boolean available, boolean accepted); boolean read, boolean available);
BdfDictionary encodeMetadata(MessageType type, BdfDictionary encodeMetadata(MessageType type,
@Nullable SessionId sessionId, long timestamp, boolean local, @Nullable SessionId sessionId, long timestamp, boolean local,
@@ -30,8 +30,6 @@ interface MessageEncoder {
void setAvailableToAnswer(BdfDictionary meta, boolean available); void setAvailableToAnswer(BdfDictionary meta, boolean available);
void setInvitationAccepted(BdfDictionary meta, boolean accepted);
Message encodeRequestMessage(GroupId contactGroupId, long timestamp, Message encodeRequestMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, Author author, @Nullable MessageId previousMessageId, Author author,
@Nullable String message); @Nullable String message);

View File

@@ -21,7 +21,6 @@ import javax.inject.Inject;
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL;
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.MSG_KEY_SESSION_ID; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_SESSION_ID;
@@ -49,12 +48,10 @@ class MessageEncoderImpl implements MessageEncoder {
@Override @Override
public BdfDictionary encodeRequestMetadata(long timestamp, public BdfDictionary encodeRequestMetadata(long timestamp,
boolean local, boolean read, boolean available, boolean local, boolean read, boolean available) {
boolean accepted) {
BdfDictionary meta = BdfDictionary meta =
encodeMetadata(REQUEST, null, timestamp, local, read, false); encodeMetadata(REQUEST, null, timestamp, local, read, false);
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
return meta; return meta;
} }
@@ -90,11 +87,6 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
} }
@Override
public void setInvitationAccepted(BdfDictionary meta, boolean accepted) {
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
}
@Override @Override
public Message encodeRequestMessage(GroupId contactGroupId, long timestamp, public Message encodeRequestMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, Author author, @Nullable MessageId previousMessageId, Author author,

View File

@@ -14,11 +14,11 @@ class MessageMetadata {
@Nullable @Nullable
private final SessionId sessionId; private final SessionId sessionId;
private final long timestamp; private final long timestamp;
private final boolean local, read, visible, available, accepted; private final boolean local, read, visible, available;
MessageMetadata(MessageType type, @Nullable SessionId sessionId, MessageMetadata(MessageType type, @Nullable SessionId sessionId,
long timestamp, boolean local, boolean read, boolean visible, long timestamp, boolean local, boolean read, boolean visible,
boolean available, boolean accepted) { boolean available) {
this.type = type; this.type = type;
this.sessionId = sessionId; this.sessionId = sessionId;
this.timestamp = timestamp; this.timestamp = timestamp;
@@ -26,7 +26,6 @@ class MessageMetadata {
this.read = read; this.read = read;
this.visible = visible; this.visible = visible;
this.available = available; this.available = available;
this.accepted = accepted;
} }
MessageType getMessageType() { MessageType getMessageType() {
@@ -58,8 +57,4 @@ class MessageMetadata {
return available; return available;
} }
public boolean wasAccepted() {
return accepted;
}
} }

View File

@@ -12,7 +12,7 @@ interface MessageParser {
BdfDictionary getMessagesVisibleInUiQuery(); BdfDictionary getMessagesVisibleInUiQuery();
BdfDictionary getInvitesAvailableToAnswerQuery(SessionId sessionId); BdfDictionary getRequestsAvailableToAnswerQuery(SessionId sessionId);
MessageMetadata parseMetadata(BdfDictionary meta) throws FormatException; MessageMetadata parseMetadata(BdfDictionary meta) throws FormatException;

View File

@@ -19,7 +19,6 @@ import javax.inject.Inject;
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL;
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.MSG_KEY_SESSION_ID; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_SESSION_ID;
@@ -43,7 +42,7 @@ class MessageParserImpl implements MessageParser {
} }
@Override @Override
public BdfDictionary getInvitesAvailableToAnswerQuery(SessionId sessionId) { public BdfDictionary getRequestsAvailableToAnswerQuery(SessionId sessionId) {
return BdfDictionary.of( return BdfDictionary.of(
new BdfEntry(MSG_KEY_AVAILABLE_TO_ANSWER, true), new BdfEntry(MSG_KEY_AVAILABLE_TO_ANSWER, true),
new BdfEntry(MSG_KEY_MESSAGE_TYPE, REQUEST.getValue()), new BdfEntry(MSG_KEY_MESSAGE_TYPE, REQUEST.getValue()),
@@ -64,9 +63,8 @@ class MessageParserImpl implements MessageParser {
boolean read = d.getBoolean(MSG_KEY_READ); boolean read = d.getBoolean(MSG_KEY_READ);
boolean visible = d.getBoolean(MSG_KEY_VISIBLE_IN_UI); boolean visible = d.getBoolean(MSG_KEY_VISIBLE_IN_UI);
boolean available = d.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); boolean available = d.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false);
boolean accepted = d.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false);
return new MessageMetadata(type, sessionId, timestamp, local, read, return new MessageMetadata(type, sessionId, timestamp, local, read,
visible, available, accepted); visible, available);
} }
@Override @Override

View File

@@ -397,7 +397,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder) oneOf(messageEncoder)
.encodeRequestMetadata(message.getTimestamp(), false, false, .encodeRequestMetadata(message.getTimestamp(), false, false,
false, false); false);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
} }

View File

@@ -74,8 +74,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
@Test @Test
public void testRequestMessageMetadata() throws FormatException { public void testRequestMessageMetadata() throws FormatException {
BdfDictionary d = messageEncoder BdfDictionary d = messageEncoder
.encodeRequestMetadata(timestamp, true, false, false, .encodeRequestMetadata(timestamp, true, false, false);
true);
MessageMetadata meta = messageParser.parseMetadata(d); MessageMetadata meta = messageParser.parseMetadata(d);
assertEquals(REQUEST, meta.getMessageType()); assertEquals(REQUEST, meta.getMessageType());
@@ -85,7 +84,6 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertFalse(meta.isRead()); assertFalse(meta.isRead());
assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isVisibleInConversation());
assertFalse(meta.isAvailableToAnswer()); assertFalse(meta.isAvailableToAnswer());
assertTrue(meta.wasAccepted());
} }
@Test @Test
@@ -102,7 +100,6 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertTrue(meta.isRead()); assertTrue(meta.isRead());
assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isVisibleInConversation());
assertFalse(meta.isAvailableToAnswer()); assertFalse(meta.isAvailableToAnswer());
assertFalse(meta.wasAccepted());
} }
@Test @Test