mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 14:49:53 +01:00
Changed the root package from net.sf.briar to org.briarproject.
This commit is contained in:
186
briar-core/src/org/briarproject/invitation/AliceConnector.java
Normal file
186
briar-core/src/org/briarproject/invitation/AliceConnector.java
Normal file
@@ -0,0 +1,186 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.briarproject.api.Author;
|
||||
import org.briarproject.api.AuthorFactory;
|
||||
import org.briarproject.api.LocalAuthor;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyManager;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.messaging.GroupFactory;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.serial.Reader;
|
||||
import org.briarproject.api.serial.ReaderFactory;
|
||||
import org.briarproject.api.serial.Writer;
|
||||
import org.briarproject.api.serial.WriterFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.ConnectionDispatcher;
|
||||
import org.briarproject.api.transport.ConnectionReader;
|
||||
import org.briarproject.api.transport.ConnectionReaderFactory;
|
||||
import org.briarproject.api.transport.ConnectionWriter;
|
||||
import org.briarproject.api.transport.ConnectionWriterFactory;
|
||||
|
||||
/** A connection thread for the peer being Alice in the invitation protocol. */
|
||||
class AliceConnector extends Connector {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AliceConnector.class.getName());
|
||||
|
||||
AliceConnector(CryptoComponent crypto, DatabaseComponent db,
|
||||
ReaderFactory readerFactory, WriterFactory writerFactory,
|
||||
ConnectionReaderFactory connectionReaderFactory,
|
||||
ConnectionWriterFactory connectionWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionDispatcher connectionDispatcher,
|
||||
Clock clock, ConnectorGroup group, DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps,
|
||||
PseudoRandom random) {
|
||||
super(crypto, db, readerFactory, writerFactory, connectionReaderFactory,
|
||||
connectionWriterFactory, authorFactory, groupFactory,
|
||||
keyManager, connectionDispatcher, clock, group, plugin,
|
||||
localAuthor, localProps, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Create an incoming or outgoing connection
|
||||
DuplexTransportConnection conn = createInvitationConnection();
|
||||
if(conn == null) return;
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
||||
// Don't proceed with more than one connection
|
||||
if(group.getAndSetConnected()) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
// Carry out the key agreement protocol
|
||||
InputStream in;
|
||||
OutputStream out;
|
||||
Reader r;
|
||||
Writer w;
|
||||
byte[] secret;
|
||||
try {
|
||||
in = conn.getInputStream();
|
||||
out = conn.getOutputStream();
|
||||
r = readerFactory.createReader(in);
|
||||
w = writerFactory.createWriter(out);
|
||||
// Alice goes first
|
||||
sendPublicKeyHash(w);
|
||||
byte[] hash = receivePublicKeyHash(r);
|
||||
sendPublicKey(w);
|
||||
byte[] key = receivePublicKey(r);
|
||||
secret = deriveMasterSecret(hash, key, true);
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch(GeneralSecurityException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
}
|
||||
// The key agreement succeeded - derive the confirmation codes
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
||||
int[] codes = crypto.deriveConfirmationCodes(secret);
|
||||
int aliceCode = codes[0], bobCode = codes[1];
|
||||
group.keyAgreementSucceeded(aliceCode, bobCode);
|
||||
// Exchange confirmation results
|
||||
boolean localMatched, remoteMatched;
|
||||
try {
|
||||
localMatched = group.waitForLocalConfirmationResult();
|
||||
sendConfirmation(w, localMatched);
|
||||
remoteMatched = receiveConfirmation(r);
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.warning("Interrupted while waiting for confirmation");
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
if(remoteMatched) group.remoteConfirmationSucceeded();
|
||||
else group.remoteConfirmationFailed();
|
||||
if(!(localMatched && remoteMatched)) {
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
// The timestamp is taken after exhanging confirmation results
|
||||
long localTimestamp = clock.currentTimeMillis();
|
||||
// Confirmation succeeded - upgrade to a secure connection
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " confirmation succeeded");
|
||||
int maxFrameLength = conn.getMaxFrameLength();
|
||||
ConnectionReader connectionReader =
|
||||
connectionReaderFactory.createInvitationConnectionReader(in,
|
||||
maxFrameLength, secret, false);
|
||||
r = readerFactory.createReader(connectionReader.getInputStream());
|
||||
ConnectionWriter connectionWriter =
|
||||
connectionWriterFactory.createInvitationConnectionWriter(out,
|
||||
maxFrameLength, secret, true);
|
||||
w = writerFactory.createWriter(connectionWriter.getOutputStream());
|
||||
// Derive the invitation nonces
|
||||
byte[][] nonces = crypto.deriveInvitationNonces(secret);
|
||||
byte[] aliceNonce = nonces[0], bobNonce = nonces[1];
|
||||
// Exchange pseudonyms, signed nonces, timestamps and transports
|
||||
Author remoteAuthor;
|
||||
long remoteTimestamp;
|
||||
Map<TransportId, TransportProperties> remoteProps;
|
||||
try {
|
||||
sendPseudonym(w, aliceNonce);
|
||||
sendTimestamp(w, localTimestamp);
|
||||
sendTransportProperties(w);
|
||||
remoteAuthor = receivePseudonym(r, bobNonce);
|
||||
remoteTimestamp = receiveTimestamp(r);
|
||||
remoteProps = receiveTransportProperties(r);
|
||||
} catch(GeneralSecurityException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.pseudonymExchangeFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.pseudonymExchangeFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
}
|
||||
// The epoch is the minimum of the peers' timestamps
|
||||
long epoch = Math.min(localTimestamp, remoteTimestamp);
|
||||
// Add the contact and store the transports
|
||||
try {
|
||||
addContact(remoteAuthor, remoteProps, secret, epoch, true);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
tryToClose(conn, true);
|
||||
group.pseudonymExchangeFailed();
|
||||
return;
|
||||
}
|
||||
// Pseudonym exchange succeeded
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " pseudonym exchange succeeded");
|
||||
group.pseudonymExchangeSucceeded(remoteAuthor);
|
||||
// Reuse the connection as an outgoing BTP connection
|
||||
reuseConnection(conn, true);
|
||||
}
|
||||
}
|
||||
186
briar-core/src/org/briarproject/invitation/BobConnector.java
Normal file
186
briar-core/src/org/briarproject/invitation/BobConnector.java
Normal file
@@ -0,0 +1,186 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.briarproject.api.Author;
|
||||
import org.briarproject.api.AuthorFactory;
|
||||
import org.briarproject.api.LocalAuthor;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyManager;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.messaging.GroupFactory;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.serial.Reader;
|
||||
import org.briarproject.api.serial.ReaderFactory;
|
||||
import org.briarproject.api.serial.Writer;
|
||||
import org.briarproject.api.serial.WriterFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.ConnectionDispatcher;
|
||||
import org.briarproject.api.transport.ConnectionReader;
|
||||
import org.briarproject.api.transport.ConnectionReaderFactory;
|
||||
import org.briarproject.api.transport.ConnectionWriter;
|
||||
import org.briarproject.api.transport.ConnectionWriterFactory;
|
||||
|
||||
/** A connection thread for the peer being Bob in the invitation protocol. */
|
||||
class BobConnector extends Connector {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(BobConnector.class.getName());
|
||||
|
||||
BobConnector(CryptoComponent crypto, DatabaseComponent db,
|
||||
ReaderFactory readerFactory, WriterFactory writerFactory,
|
||||
ConnectionReaderFactory connectionReaderFactory,
|
||||
ConnectionWriterFactory connectionWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionDispatcher connectionDispatcher,
|
||||
Clock clock, ConnectorGroup group, DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps,
|
||||
PseudoRandom random) {
|
||||
super(crypto, db, readerFactory, writerFactory, connectionReaderFactory,
|
||||
connectionWriterFactory, authorFactory, groupFactory,
|
||||
keyManager, connectionDispatcher, clock, group, plugin,
|
||||
localAuthor, localProps, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Create an incoming or outgoing connection
|
||||
DuplexTransportConnection conn = createInvitationConnection();
|
||||
if(conn == null) return;
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
||||
// Carry out the key agreement protocol
|
||||
InputStream in;
|
||||
OutputStream out;
|
||||
Reader r;
|
||||
Writer w;
|
||||
byte[] secret;
|
||||
try {
|
||||
in = conn.getInputStream();
|
||||
out = conn.getOutputStream();
|
||||
r = readerFactory.createReader(in);
|
||||
w = writerFactory.createWriter(out);
|
||||
// Alice goes first
|
||||
byte[] hash = receivePublicKeyHash(r);
|
||||
// Don't proceed with more than one connection
|
||||
if(group.getAndSetConnected()) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
sendPublicKeyHash(w);
|
||||
byte[] key = receivePublicKey(r);
|
||||
sendPublicKey(w);
|
||||
secret = deriveMasterSecret(hash, key, false);
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch(GeneralSecurityException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.keyAgreementFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
}
|
||||
// The key agreement succeeded - derive the confirmation codes
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
||||
int[] codes = crypto.deriveConfirmationCodes(secret);
|
||||
int aliceCode = codes[0], bobCode = codes[1];
|
||||
group.keyAgreementSucceeded(bobCode, aliceCode);
|
||||
// Exchange confirmation results
|
||||
boolean localMatched, remoteMatched;
|
||||
try {
|
||||
remoteMatched = receiveConfirmation(r);
|
||||
localMatched = group.waitForLocalConfirmationResult();
|
||||
sendConfirmation(w, localMatched);
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.warning("Interrupted while waiting for confirmation");
|
||||
group.remoteConfirmationFailed();
|
||||
tryToClose(conn, true);
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
if(remoteMatched) group.remoteConfirmationSucceeded();
|
||||
else group.remoteConfirmationFailed();
|
||||
if(!(localMatched && remoteMatched)) {
|
||||
tryToClose(conn, false);
|
||||
return;
|
||||
}
|
||||
// The timestamp is taken after exhanging confirmation results
|
||||
long localTimestamp = clock.currentTimeMillis();
|
||||
// Confirmation succeeded - upgrade to a secure connection
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " confirmation succeeded");
|
||||
int maxFrameLength = conn.getMaxFrameLength();
|
||||
ConnectionReader connectionReader =
|
||||
connectionReaderFactory.createInvitationConnectionReader(in,
|
||||
maxFrameLength, secret, true);
|
||||
r = readerFactory.createReader(connectionReader.getInputStream());
|
||||
ConnectionWriter connectionWriter =
|
||||
connectionWriterFactory.createInvitationConnectionWriter(out,
|
||||
maxFrameLength, secret, false);
|
||||
w = writerFactory.createWriter(connectionWriter.getOutputStream());
|
||||
// Derive the nonces
|
||||
byte[][] nonces = crypto.deriveInvitationNonces(secret);
|
||||
byte[] aliceNonce = nonces[0], bobNonce = nonces[1];
|
||||
// Exchange pseudonyms, signed nonces, timestamps and transports
|
||||
Author remoteAuthor;
|
||||
long remoteTimestamp;
|
||||
Map<TransportId, TransportProperties> remoteProps;
|
||||
try {
|
||||
remoteAuthor = receivePseudonym(r, aliceNonce);
|
||||
remoteTimestamp = receiveTimestamp(r);
|
||||
remoteProps = receiveTransportProperties(r);
|
||||
sendPseudonym(w, bobNonce);
|
||||
sendTimestamp(w, localTimestamp);
|
||||
sendTransportProperties(w);
|
||||
} catch(GeneralSecurityException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.pseudonymExchangeFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
group.pseudonymExchangeFailed();
|
||||
tryToClose(conn, true);
|
||||
return;
|
||||
}
|
||||
// The epoch is the minimum of the peers' timestamps
|
||||
long epoch = Math.min(localTimestamp, remoteTimestamp);
|
||||
// Add the contact and store the transports
|
||||
try {
|
||||
addContact(remoteAuthor, remoteProps, secret, epoch, false);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
tryToClose(conn, true);
|
||||
group.pseudonymExchangeFailed();
|
||||
return;
|
||||
}
|
||||
// Pseudonym exchange succeeded
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " pseudonym exchange succeeded");
|
||||
group.pseudonymExchangeSucceeded(remoteAuthor);
|
||||
// Reuse the connection as an incoming BTP connection
|
||||
reuseConnection(conn, false);
|
||||
}
|
||||
}
|
||||
342
briar-core/src/org/briarproject/invitation/Connector.java
Normal file
342
briar-core/src/org/briarproject/invitation/Connector.java
Normal file
@@ -0,0 +1,342 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.api.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
||||
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
||||
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
||||
import static org.briarproject.api.invitation.InvitationConstants.CONNECTION_TIMEOUT;
|
||||
import static org.briarproject.api.invitation.InvitationConstants.HASH_LENGTH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.briarproject.api.Author;
|
||||
import org.briarproject.api.AuthorConstants;
|
||||
import org.briarproject.api.AuthorFactory;
|
||||
import org.briarproject.api.ContactId;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.LocalAuthor;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.UniqueId;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyManager;
|
||||
import org.briarproject.api.crypto.KeyPair;
|
||||
import org.briarproject.api.crypto.KeyParser;
|
||||
import org.briarproject.api.crypto.MessageDigest;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.crypto.Signature;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.NoSuchTransportException;
|
||||
import org.briarproject.api.invitation.InvitationConstants;
|
||||
import org.briarproject.api.messaging.Group;
|
||||
import org.briarproject.api.messaging.GroupFactory;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.serial.Reader;
|
||||
import org.briarproject.api.serial.ReaderFactory;
|
||||
import org.briarproject.api.serial.Writer;
|
||||
import org.briarproject.api.serial.WriterFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.ConnectionDispatcher;
|
||||
import org.briarproject.api.transport.ConnectionReaderFactory;
|
||||
import org.briarproject.api.transport.ConnectionWriterFactory;
|
||||
import org.briarproject.api.transport.Endpoint;
|
||||
|
||||
abstract class Connector extends Thread {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(Connector.class.getName());
|
||||
|
||||
protected final CryptoComponent crypto;
|
||||
protected final DatabaseComponent db;
|
||||
protected final ReaderFactory readerFactory;
|
||||
protected final WriterFactory writerFactory;
|
||||
protected final ConnectionReaderFactory connectionReaderFactory;
|
||||
protected final ConnectionWriterFactory connectionWriterFactory;
|
||||
protected final AuthorFactory authorFactory;
|
||||
protected final GroupFactory groupFactory;
|
||||
protected final KeyManager keyManager;
|
||||
protected final ConnectionDispatcher connectionDispatcher;
|
||||
protected final Clock clock;
|
||||
protected final ConnectorGroup group;
|
||||
protected final DuplexPlugin plugin;
|
||||
protected final LocalAuthor localAuthor;
|
||||
protected final Map<TransportId, TransportProperties> localProps;
|
||||
protected final PseudoRandom random;
|
||||
protected final String pluginName;
|
||||
|
||||
private final KeyPair keyPair;
|
||||
private final KeyParser keyParser;
|
||||
private final MessageDigest messageDigest;
|
||||
|
||||
private volatile ContactId contactId = null;
|
||||
|
||||
Connector(CryptoComponent crypto, DatabaseComponent db,
|
||||
ReaderFactory readerFactory, WriterFactory writerFactory,
|
||||
ConnectionReaderFactory connectionReaderFactory,
|
||||
ConnectionWriterFactory connectionWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionDispatcher connectionDispatcher,
|
||||
Clock clock, ConnectorGroup group, DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps,
|
||||
PseudoRandom random) {
|
||||
super("Connector");
|
||||
this.crypto = crypto;
|
||||
this.db = db;
|
||||
this.readerFactory = readerFactory;
|
||||
this.writerFactory = writerFactory;
|
||||
this.connectionReaderFactory = connectionReaderFactory;
|
||||
this.connectionWriterFactory = connectionWriterFactory;
|
||||
this.authorFactory = authorFactory;
|
||||
this.groupFactory = groupFactory;
|
||||
this.keyManager = keyManager;
|
||||
this.connectionDispatcher = connectionDispatcher;
|
||||
this.clock = clock;
|
||||
this.group = group;
|
||||
this.plugin = plugin;
|
||||
this.localAuthor = localAuthor;
|
||||
this.localProps = localProps;
|
||||
this.random = random;
|
||||
pluginName = plugin.getClass().getName();
|
||||
keyPair = crypto.generateAgreementKeyPair();
|
||||
keyParser = crypto.getAgreementKeyParser();
|
||||
messageDigest = crypto.getMessageDigest();
|
||||
}
|
||||
|
||||
protected DuplexTransportConnection createInvitationConnection() {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " creating invitation connection");
|
||||
return plugin.createInvitationConnection(random, CONNECTION_TIMEOUT);
|
||||
}
|
||||
|
||||
protected void sendPublicKeyHash(Writer w) throws IOException {
|
||||
w.writeBytes(messageDigest.digest(keyPair.getPublic().getEncoded()));
|
||||
w.flush();
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash");
|
||||
}
|
||||
|
||||
protected byte[] receivePublicKeyHash(Reader r) throws IOException {
|
||||
byte[] b = r.readBytes(HASH_LENGTH);
|
||||
if(b.length < HASH_LENGTH) throw new FormatException();
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received hash");
|
||||
return b;
|
||||
}
|
||||
|
||||
protected void sendPublicKey(Writer w) throws IOException {
|
||||
byte[] key = keyPair.getPublic().getEncoded();
|
||||
w.writeBytes(key);
|
||||
w.flush();
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent key");
|
||||
}
|
||||
|
||||
protected byte[] receivePublicKey(Reader r) throws GeneralSecurityException,
|
||||
IOException {
|
||||
byte[] b = r.readBytes(InvitationConstants.MAX_PUBLIC_KEY_LENGTH);
|
||||
keyParser.parsePublicKey(b);
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received key");
|
||||
return b;
|
||||
}
|
||||
|
||||
protected byte[] deriveMasterSecret(byte[] hash, byte[] key, boolean alice)
|
||||
throws GeneralSecurityException {
|
||||
// Check that the hash matches the key
|
||||
if(!Arrays.equals(hash, messageDigest.digest(key))) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " hash does not match key");
|
||||
throw new GeneralSecurityException();
|
||||
}
|
||||
// Derive the master secret
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " deriving master secret");
|
||||
return crypto.deriveMasterSecret(key, keyPair, alice);
|
||||
}
|
||||
|
||||
protected void sendConfirmation(Writer w, boolean matched)
|
||||
throws IOException {
|
||||
w.writeBoolean(matched);
|
||||
w.flush();
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " sent confirmation: " + matched);
|
||||
}
|
||||
|
||||
protected boolean receiveConfirmation(Reader r) throws IOException {
|
||||
boolean matched = r.readBoolean();
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " received confirmation: " + matched);
|
||||
return matched;
|
||||
}
|
||||
|
||||
protected void sendPseudonym(Writer w, byte[] nonce)
|
||||
throws GeneralSecurityException, IOException {
|
||||
// Sign the nonce
|
||||
Signature signature = crypto.getSignature();
|
||||
KeyParser keyParser = crypto.getSignatureKeyParser();
|
||||
byte[] privateKey = localAuthor.getPrivateKey();
|
||||
signature.initSign(keyParser.parsePrivateKey(privateKey));
|
||||
signature.update(nonce);
|
||||
byte[] sig = signature.sign();
|
||||
// Write the name, public key and signature
|
||||
w.writeString(localAuthor.getName());
|
||||
w.writeBytes(localAuthor.getPublicKey());
|
||||
w.writeBytes(sig);
|
||||
w.flush();
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent pseudonym");
|
||||
}
|
||||
|
||||
protected Author receivePseudonym(Reader r, byte[] nonce)
|
||||
throws GeneralSecurityException, IOException {
|
||||
// Read the name, public key and signature
|
||||
String name = r.readString(MAX_AUTHOR_NAME_LENGTH);
|
||||
byte[] publicKey = r.readBytes(AuthorConstants.MAX_PUBLIC_KEY_LENGTH);
|
||||
byte[] sig = r.readBytes(MAX_SIGNATURE_LENGTH);
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received pseudonym");
|
||||
// Verify the signature
|
||||
Signature signature = crypto.getSignature();
|
||||
KeyParser keyParser = crypto.getSignatureKeyParser();
|
||||
signature.initVerify(keyParser.parsePublicKey(publicKey));
|
||||
signature.update(nonce);
|
||||
if(!signature.verify(sig)) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " invalid signature");
|
||||
throw new GeneralSecurityException();
|
||||
}
|
||||
return authorFactory.createAuthor(name, publicKey);
|
||||
}
|
||||
|
||||
protected void sendTimestamp(Writer w, long timestamp) throws IOException {
|
||||
w.writeInt64(timestamp);
|
||||
w.flush();
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent timestamp");
|
||||
}
|
||||
|
||||
protected long receiveTimestamp(Reader r) throws IOException {
|
||||
long timestamp = r.readInt64();
|
||||
if(timestamp < 0) throw new FormatException();
|
||||
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received timestamp");
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
protected void sendTransportProperties(Writer w) throws IOException {
|
||||
w.writeListStart();
|
||||
for(Entry<TransportId, TransportProperties> e : localProps.entrySet()) {
|
||||
w.writeBytes(e.getKey().getBytes());
|
||||
w.writeMap(e.getValue());
|
||||
}
|
||||
w.writeListEnd();
|
||||
w.flush();
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " sent transport properties");
|
||||
}
|
||||
|
||||
protected Map<TransportId, TransportProperties> receiveTransportProperties(
|
||||
Reader r) throws IOException {
|
||||
Map<TransportId, TransportProperties> remoteProps =
|
||||
new HashMap<TransportId, TransportProperties>();
|
||||
r.readListStart();
|
||||
while(!r.hasListEnd()) {
|
||||
byte[] b = r.readBytes(UniqueId.LENGTH);
|
||||
if(b.length != UniqueId.LENGTH) throw new FormatException();
|
||||
TransportId id = new TransportId(b);
|
||||
Map<String, String> p = new HashMap<String, String>();
|
||||
r.readMapStart();
|
||||
for(int i = 0; !r.hasMapEnd(); i++) {
|
||||
if(i == MAX_PROPERTIES_PER_TRANSPORT)
|
||||
throw new FormatException();
|
||||
String key = r.readString(MAX_PROPERTY_LENGTH);
|
||||
String value = r.readString(MAX_PROPERTY_LENGTH);
|
||||
p.put(key, value);
|
||||
}
|
||||
r.readMapEnd();
|
||||
remoteProps.put(id, new TransportProperties(p));
|
||||
}
|
||||
r.readListEnd();
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " received transport properties");
|
||||
return remoteProps;
|
||||
}
|
||||
|
||||
protected void addContact(Author remoteAuthor,
|
||||
Map<TransportId, TransportProperties> remoteProps, byte[] secret,
|
||||
long epoch, boolean alice) throws DbException {
|
||||
// Add the contact to the database
|
||||
contactId = db.addContact(remoteAuthor, localAuthor.getId());
|
||||
// Create and store the inbox group
|
||||
byte[] salt = crypto.deriveGroupSalt(secret);
|
||||
Group inbox = groupFactory.createGroup("Inbox", salt);
|
||||
db.addGroup(inbox);
|
||||
db.setInboxGroup(contactId, inbox);
|
||||
// Store the remote transport properties
|
||||
db.setRemoteProperties(contactId, remoteProps);
|
||||
// Create an endpoint for each transport shared with the contact
|
||||
List<TransportId> ids = new ArrayList<TransportId>();
|
||||
Map<TransportId, Long> latencies = db.getTransportLatencies();
|
||||
for(TransportId id : localProps.keySet()) {
|
||||
if(latencies.containsKey(id) && remoteProps.containsKey(id))
|
||||
ids.add(id);
|
||||
}
|
||||
// Assign indices to the transports deterministically and derive keys
|
||||
Collections.sort(ids, TransportIdComparator.INSTANCE);
|
||||
int size = ids.size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
TransportId id = ids.get(i);
|
||||
Endpoint ep = new Endpoint(contactId, id, epoch, alice);
|
||||
long maxLatency = latencies.get(id);
|
||||
try {
|
||||
db.addEndpoint(ep);
|
||||
} catch(NoSuchTransportException e) {
|
||||
continue;
|
||||
}
|
||||
byte[] initialSecret = crypto.deriveInitialSecret(secret, i);
|
||||
keyManager.endpointAdded(ep, maxLatency, initialSecret);
|
||||
}
|
||||
}
|
||||
|
||||
protected void tryToClose(DuplexTransportConnection conn,
|
||||
boolean exception) {
|
||||
try {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Closing connection");
|
||||
conn.dispose(exception, true);
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void reuseConnection(DuplexTransportConnection conn,
|
||||
boolean alice) {
|
||||
if(contactId == null) throw new IllegalStateException();
|
||||
TransportId t = plugin.getId();
|
||||
if(alice)
|
||||
connectionDispatcher.dispatchOutgoingConnection(contactId, t, conn);
|
||||
else connectionDispatcher.dispatchIncomingConnection(t, conn);
|
||||
}
|
||||
|
||||
private static class TransportIdComparator
|
||||
implements Comparator<TransportId> {
|
||||
|
||||
private static final TransportIdComparator INSTANCE =
|
||||
new TransportIdComparator();
|
||||
|
||||
public int compare(TransportId t1, TransportId t2) {
|
||||
byte[] b1 = t1.getBytes(), b2 = t2.getBytes();
|
||||
for(int i = 0; i < UniqueId.LENGTH; i++) {
|
||||
if((b1[i] & 0xff) < (b2[i] & 0xff)) return -1;
|
||||
if((b1[i] & 0xff) > (b2[i] & 0xff)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
263
briar-core/src/org/briarproject/invitation/ConnectorGroup.java
Normal file
263
briar-core/src/org/briarproject/invitation/ConnectorGroup.java
Normal file
@@ -0,0 +1,263 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.invitation.InvitationConstants.CONFIRMATION_TIMEOUT;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.briarproject.api.Author;
|
||||
import org.briarproject.api.AuthorFactory;
|
||||
import org.briarproject.api.AuthorId;
|
||||
import org.briarproject.api.LocalAuthor;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyManager;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.invitation.InvitationListener;
|
||||
import org.briarproject.api.invitation.InvitationState;
|
||||
import org.briarproject.api.invitation.InvitationTask;
|
||||
import org.briarproject.api.messaging.GroupFactory;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.serial.ReaderFactory;
|
||||
import org.briarproject.api.serial.WriterFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.ConnectionDispatcher;
|
||||
import org.briarproject.api.transport.ConnectionReaderFactory;
|
||||
import org.briarproject.api.transport.ConnectionWriterFactory;
|
||||
|
||||
/** A task consisting of one or more parallel connection attempts. */
|
||||
class ConnectorGroup extends Thread implements InvitationTask {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ConnectorGroup.class.getName());
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final DatabaseComponent db;
|
||||
private final ReaderFactory readerFactory;
|
||||
private final WriterFactory writerFactory;
|
||||
private final ConnectionReaderFactory connectionReaderFactory;
|
||||
private final ConnectionWriterFactory connectionWriterFactory;
|
||||
private final AuthorFactory authorFactory;
|
||||
private final GroupFactory groupFactory;
|
||||
private final KeyManager keyManager;
|
||||
private final ConnectionDispatcher connectionDispatcher;
|
||||
private final Clock clock;
|
||||
private final PluginManager pluginManager;
|
||||
private final AuthorId localAuthorId;
|
||||
private final int localInvitationCode, remoteInvitationCode;
|
||||
private final Collection<InvitationListener> listeners;
|
||||
private final AtomicBoolean connected;
|
||||
private final CountDownLatch localConfirmationLatch;
|
||||
|
||||
/*
|
||||
* All of the following require locking: this. We don't want to call the
|
||||
* listeners with a lock held, but we need to avoid a race condition in
|
||||
* addListener(), so the state that's accessed there after calling
|
||||
* listeners.add() must be guarded by a lock.
|
||||
*/
|
||||
private int localConfirmationCode = -1, remoteConfirmationCode = -1;
|
||||
private boolean connectionFailed = false;
|
||||
private boolean localCompared = false, remoteCompared = false;
|
||||
private boolean localMatched = false, remoteMatched = false;
|
||||
private String remoteName = null;
|
||||
|
||||
ConnectorGroup(CryptoComponent crypto, DatabaseComponent db,
|
||||
ReaderFactory readerFactory, WriterFactory writerFactory,
|
||||
ConnectionReaderFactory connectionReaderFactory,
|
||||
ConnectionWriterFactory connectionWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionDispatcher connectionDispatcher,
|
||||
Clock clock, PluginManager pluginManager, AuthorId localAuthorId,
|
||||
int localInvitationCode, int remoteInvitationCode) {
|
||||
super("ConnectorGroup");
|
||||
this.crypto = crypto;
|
||||
this.db = db;
|
||||
this.readerFactory = readerFactory;
|
||||
this.writerFactory = writerFactory;
|
||||
this.connectionReaderFactory = connectionReaderFactory;
|
||||
this.connectionWriterFactory = connectionWriterFactory;
|
||||
this.authorFactory = authorFactory;
|
||||
this.groupFactory = groupFactory;
|
||||
this.keyManager = keyManager;
|
||||
this.connectionDispatcher = connectionDispatcher;
|
||||
this.clock = clock;
|
||||
this.pluginManager = pluginManager;
|
||||
this.localAuthorId = localAuthorId;
|
||||
this.localInvitationCode = localInvitationCode;
|
||||
this.remoteInvitationCode = remoteInvitationCode;
|
||||
listeners = new CopyOnWriteArrayList<InvitationListener>();
|
||||
connected = new AtomicBoolean(false);
|
||||
localConfirmationLatch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
public synchronized InvitationState addListener(InvitationListener l) {
|
||||
listeners.add(l);
|
||||
return new InvitationState(localInvitationCode, remoteInvitationCode,
|
||||
localConfirmationCode, remoteConfirmationCode, connected.get(),
|
||||
connectionFailed, localCompared, remoteCompared, localMatched,
|
||||
remoteMatched, remoteName);
|
||||
}
|
||||
|
||||
public void removeListener(InvitationListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LocalAuthor localAuthor;
|
||||
Map<TransportId, TransportProperties> localProps;
|
||||
// Load the local pseudonym and transport properties
|
||||
try {
|
||||
localAuthor = db.getLocalAuthor(localAuthorId);
|
||||
localProps = db.getLocalProperties();
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
synchronized(this) {
|
||||
connectionFailed = true;
|
||||
}
|
||||
for(InvitationListener l : listeners) l.connectionFailed();
|
||||
return;
|
||||
}
|
||||
// Start the connection threads
|
||||
Collection<Connector> connectors = new ArrayList<Connector>();
|
||||
// Alice is the party with the smaller invitation code
|
||||
if(localInvitationCode < remoteInvitationCode) {
|
||||
for(DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
||||
Connector c = createAliceConnector(plugin, localAuthor,
|
||||
localProps);
|
||||
connectors.add(c);
|
||||
c.start();
|
||||
}
|
||||
} else {
|
||||
for(DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
|
||||
Connector c = createBobConnector(plugin, localAuthor,
|
||||
localProps);
|
||||
connectors.add(c);
|
||||
c.start();
|
||||
}
|
||||
}
|
||||
// Wait for the connection threads to finish
|
||||
try {
|
||||
for(Connector c : connectors) c.join();
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.warning("Interrupted while waiting for connectors");
|
||||
}
|
||||
// If none of the threads connected, inform the listeners
|
||||
if(!connected.get()) {
|
||||
synchronized(this) {
|
||||
connectionFailed = true;
|
||||
}
|
||||
for(InvitationListener l : listeners) l.connectionFailed();
|
||||
}
|
||||
}
|
||||
|
||||
private Connector createAliceConnector(DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps) {
|
||||
PseudoRandom random = crypto.getPseudoRandom(localInvitationCode,
|
||||
remoteInvitationCode);
|
||||
return new AliceConnector(crypto, db, readerFactory, writerFactory,
|
||||
connectionReaderFactory, connectionWriterFactory, authorFactory,
|
||||
groupFactory, keyManager, connectionDispatcher, clock, this,
|
||||
plugin, localAuthor, localProps, random);
|
||||
}
|
||||
|
||||
private Connector createBobConnector(DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps) {
|
||||
PseudoRandom random = crypto.getPseudoRandom(remoteInvitationCode,
|
||||
localInvitationCode);
|
||||
return new BobConnector(crypto, db, readerFactory, writerFactory,
|
||||
connectionReaderFactory, connectionWriterFactory, authorFactory,
|
||||
groupFactory, keyManager, connectionDispatcher, clock, this,
|
||||
plugin, localAuthor, localProps, random);
|
||||
}
|
||||
|
||||
public void localConfirmationSucceeded() {
|
||||
synchronized(this) {
|
||||
localCompared = true;
|
||||
localMatched = true;
|
||||
}
|
||||
localConfirmationLatch.countDown();
|
||||
}
|
||||
|
||||
public void localConfirmationFailed() {
|
||||
synchronized(this) {
|
||||
localCompared = true;
|
||||
localMatched = false;
|
||||
}
|
||||
localConfirmationLatch.countDown();
|
||||
}
|
||||
|
||||
boolean getAndSetConnected() {
|
||||
boolean redundant = connected.getAndSet(true);
|
||||
if(!redundant)
|
||||
for(InvitationListener l : listeners) l.connectionSucceeded();
|
||||
return redundant;
|
||||
}
|
||||
|
||||
void keyAgreementSucceeded(int localCode, int remoteCode) {
|
||||
synchronized(this) {
|
||||
localConfirmationCode = localCode;
|
||||
remoteConfirmationCode = remoteCode;
|
||||
}
|
||||
for(InvitationListener l : listeners)
|
||||
l.keyAgreementSucceeded(localCode, remoteCode);
|
||||
}
|
||||
|
||||
void keyAgreementFailed() {
|
||||
for(InvitationListener l : listeners) l.keyAgreementFailed();
|
||||
}
|
||||
|
||||
boolean waitForLocalConfirmationResult() throws InterruptedException {
|
||||
localConfirmationLatch.await(CONFIRMATION_TIMEOUT, MILLISECONDS);
|
||||
synchronized(this) {
|
||||
return localMatched;
|
||||
}
|
||||
}
|
||||
|
||||
void remoteConfirmationSucceeded() {
|
||||
synchronized(this) {
|
||||
remoteCompared = true;
|
||||
remoteMatched = true;
|
||||
}
|
||||
for(InvitationListener l : listeners) l.remoteConfirmationSucceeded();
|
||||
}
|
||||
|
||||
void remoteConfirmationFailed() {
|
||||
synchronized(this) {
|
||||
remoteCompared = true;
|
||||
remoteMatched = false;
|
||||
}
|
||||
for(InvitationListener l : listeners) l.remoteConfirmationFailed();
|
||||
}
|
||||
|
||||
void pseudonymExchangeSucceeded(Author remoteAuthor) {
|
||||
String name = remoteAuthor.getName();
|
||||
synchronized(this) {
|
||||
remoteName = name;
|
||||
}
|
||||
for(InvitationListener l : listeners)
|
||||
l.pseudonymExchangeSucceeded(name);
|
||||
}
|
||||
|
||||
void pseudonymExchangeFailed() {
|
||||
for(InvitationListener l : listeners) l.pseudonymExchangeFailed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.briarproject.api.invitation.InvitationTaskFactory;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
public class InvitationModule extends AbstractModule {
|
||||
|
||||
protected void configure() {
|
||||
bind(InvitationTaskFactory.class).to(
|
||||
InvitationTaskFactoryImpl.class).in(Singleton.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.briarproject.api.AuthorFactory;
|
||||
import org.briarproject.api.AuthorId;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyManager;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.invitation.InvitationTask;
|
||||
import org.briarproject.api.invitation.InvitationTaskFactory;
|
||||
import org.briarproject.api.messaging.GroupFactory;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
import org.briarproject.api.serial.ReaderFactory;
|
||||
import org.briarproject.api.serial.WriterFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.ConnectionDispatcher;
|
||||
import org.briarproject.api.transport.ConnectionReaderFactory;
|
||||
import org.briarproject.api.transport.ConnectionWriterFactory;
|
||||
|
||||
class InvitationTaskFactoryImpl implements InvitationTaskFactory {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final DatabaseComponent db;
|
||||
private final ReaderFactory readerFactory;
|
||||
private final WriterFactory writerFactory;
|
||||
private final ConnectionReaderFactory connectionReaderFactory;
|
||||
private final ConnectionWriterFactory connectionWriterFactory;
|
||||
private final AuthorFactory authorFactory;
|
||||
private final GroupFactory groupFactory;
|
||||
private final KeyManager keyManager;
|
||||
private final ConnectionDispatcher connectionDispatcher;
|
||||
private final Clock clock;
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
@Inject
|
||||
InvitationTaskFactoryImpl(CryptoComponent crypto, DatabaseComponent db,
|
||||
ReaderFactory readerFactory, WriterFactory writerFactory,
|
||||
ConnectionReaderFactory connectionReaderFactory,
|
||||
ConnectionWriterFactory connectionWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionDispatcher connectionDispatcher,
|
||||
Clock clock, PluginManager pluginManager) {
|
||||
this.crypto = crypto;
|
||||
this.db = db;
|
||||
this.readerFactory = readerFactory;
|
||||
this.writerFactory = writerFactory;
|
||||
this.connectionReaderFactory = connectionReaderFactory;
|
||||
this.connectionWriterFactory = connectionWriterFactory;
|
||||
this.authorFactory = authorFactory;
|
||||
this.groupFactory = groupFactory;
|
||||
this.keyManager = keyManager;
|
||||
this.connectionDispatcher = connectionDispatcher;
|
||||
this.clock = clock;
|
||||
this.pluginManager = pluginManager;
|
||||
}
|
||||
|
||||
public InvitationTask createTask(AuthorId localAuthorId, int localCode,
|
||||
int remoteCode) {
|
||||
return new ConnectorGroup(crypto, db, readerFactory, writerFactory,
|
||||
connectionReaderFactory, connectionWriterFactory,
|
||||
authorFactory, groupFactory, keyManager, connectionDispatcher,
|
||||
clock, pluginManager, localAuthorId, localCode, remoteCode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user