mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 07:09:56 +01:00
Address first round of review comments for new IntroductionClient
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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));
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user