diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java index 430f2c274b0890863255be18ddc03fcfeaae7851..7ddb31a3661c175cd50cc277542aeb1959103854 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java @@ -2,28 +2,44 @@ package org.briarproject.bramble.mailbox; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.mailbox.MailboxConstants; import org.briarproject.bramble.api.mailbox.MailboxInfo; import org.briarproject.bramble.api.sync.SyncSessionFactory; import org.briarproject.bramble.api.transport.KeyManager; +import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.StreamReaderFactory; import org.briarproject.bramble.api.transport.StreamWriterFactory; import org.briarproject.bramble.mailbox.protocol.MailboxMessage; import org.briarproject.bramble.mailbox.protocol.MailboxProtocol; import org.briarproject.bramble.mailbox.protocol.MailboxRequest; +import org.briarproject.bramble.mailbox.protocol.MailboxRequestHandler; import org.briarproject.bramble.mailbox.protocol.MailboxRequestStore; +import org.briarproject.bramble.mailbox.protocol.MailboxRequestTake; +import java.io.ByteArrayInputStream; +import java.io.EOFException; import java.io.IOException; +import java.io.InputStream; import java.net.ProtocolException; import java.util.concurrent.Executor; import java.util.logging.Logger; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; +import static org.briarproject.bramble.mailbox.protocol.MailboxMessage.TYPE.TAKE; import static org.briarproject.bramble.util.LogUtils.logException; -class PrivateMailboxSession extends AbstractMailboxSession { +/** + * This session represents an Owner (of a private mailbox) connecting + * to their mailbox + */ +public class PrivateMailboxSession extends AbstractMailboxSession { private static final Logger LOG = Logger.getLogger(PrivateMailboxSession.class.getName()); + private final KeyManager keyManager; + private final SyncSessionFactory syncSessionFactory; + private final StreamReaderFactory streamReaderFactory; private MailboxProtocol mailboxProtocol; public PrivateMailboxSession(ContactId contactId, Executor ioExecutor, @@ -37,16 +53,22 @@ class PrivateMailboxSession extends AbstractMailboxSession { super(ioExecutor, keyManager, syncSessionFactory, streamWriterFactory, streamReaderFactory, mailboxProtocol, transportMaxLatency, transportMaxIdleTime, contactId); + this.keyManager = keyManager; + this.syncSessionFactory = syncSessionFactory; + this.streamReaderFactory = streamReaderFactory; this.mailboxProtocol = mailboxProtocol; - registerSupportedRequest(MailboxMessage.TYPE.SYNC); + mailboxProtocol.registerRequestHandler(new TAKEHandler()); + // Register SYNC handler and run outgoing SYNC session + enableSYNCHandling(); + mailboxProtocol.enableRequestHandling(); } /** * Stores messages on the private mailbox for a contact - * who does not have a mailbox + * who does not own a mailbox */ - public void handleOwnerContact(MailboxInfo mailboxInfo) { + public void handleContactWithoutPrivateMailbox(MailboxInfo mailboxInfo) { byte[] encryptedStream; try { encryptedStream = @@ -71,12 +93,65 @@ class PrivateMailboxSession extends AbstractMailboxSession { } @Override - public void run() { + public void run() { try { - waitForHandlersToFinish(); + awaitSYNCHandlerFinished(); } catch (InterruptedException e) { - if (LOG.isLoggable(INFO)) - LOG.info(e.toString()); + logException(LOG, WARNING, e); + } + } + + /** + * Handles an incoming TAKE request. The request contains an encrypted BSP + * stream. From this stream, the tag is read and a StreamReader is created. + * A BSP IncomingSession is created for the stream + */ + private class TAKEHandler implements MailboxRequestHandler { + @Override + public void handleRequest(MailboxRequest request) + throws ProtocolException { + MailboxRequestTake takeRequest = (MailboxRequestTake) request; + InputStream in = new ByteArrayInputStream( + takeRequest.getEncryptedSyncStream()); + byte[] tag = new byte[TAG_LENGTH]; + StreamContext ctx; + + try { + // read tag from input stream + int offset = 0; + while (offset < tag.length) { + int read = in.read(tag, offset, tag.length - offset); + if (read == -1) throw new EOFException(); + offset += read; + } + + ctx = + keyManager.getStreamContext(MailboxConstants.ID, tag); + + if (ctx == null) { + throw new ProtocolException( + "Received stream with unrecognisable tag"); + } + + InputStream reader = + streamReaderFactory.createStreamReader(in, ctx); + + syncSessionFactory + .createIncomingSession(ctx.getContactId(), reader) + .run(); + } catch (DbException | IOException e) { + logException(LOG, WARNING, e); + throw new ProtocolException("Received invalid stream"); + } + } + + @Override + public MailboxMessage.TYPE getType() { + return TAKE; + } + + @Override + public void protocolFinished() { } } }