From d6bbe59d3ac181f26af79081200adff49d39b50c Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 16 Feb 2022 15:50:12 -0300 Subject: [PATCH 1/6] Implement backend for pairing mailbox --- .../bramble/api/mailbox/MailboxManager.java | 30 ++++ .../api/mailbox/MailboxPairingState.java | 59 +++++++ .../api/mailbox/MailboxPairingTask.java | 21 +++ .../bramble/mailbox/MailboxApi.java | 4 + .../bramble/mailbox/MailboxApiImpl.java | 3 +- .../bramble/mailbox/MailboxManagerImpl.java | 72 ++++++++ .../bramble/mailbox/MailboxModule.java | 20 +++ .../mailbox/MailboxPairingTaskFactory.java | 12 ++ .../MailboxPairingTaskFactoryImpl.java | 44 +++++ .../mailbox/MailboxPairingTaskImpl.java | 166 ++++++++++++++++++ 10 files changed, 429 insertions(+), 2 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingTask.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactory.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java new file mode 100644 index 000000000..3fbdda57a --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java @@ -0,0 +1,30 @@ +package org.briarproject.bramble.api.mailbox; + +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; + +import javax.annotation.Nullable; + +public interface MailboxManager { + + /** + * @return true if a mailbox is already paired. + */ + boolean isPaired(Transaction txn) throws DbException; + + /** + * Returns the currently running pairing task, + * or null if no pairing task is running. + */ + @Nullable + MailboxPairingTask getCurrentPairingTask(); + + /** + * Starts and returns a pairing task. If a pairing task is already running, + * it will be returned and the argument will be ignored. + * + * @param qrCodePayload The ISO-8859-1 encoded bytes of the mailbox QR code. + */ + MailboxPairingTask startPairingTask(String qrCodePayload); + +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java new file mode 100644 index 000000000..f2f1cc948 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java @@ -0,0 +1,59 @@ +package org.briarproject.bramble.api.mailbox; + +import javax.annotation.Nullable; + +public abstract class MailboxPairingState { + + /** + * The QR code payload that was scanned by the user. + * This is null if the code should not be re-used anymore in this state. + */ + @Nullable + public final String qrCodePayload; + + MailboxPairingState(@Nullable String qrCodePayload) { + this.qrCodePayload = qrCodePayload; + } + + public static class QrCodeReceived extends MailboxPairingState { + public QrCodeReceived(String qrCodePayload) { + super(qrCodePayload); + } + } + + public static class Pairing extends MailboxPairingState { + public Pairing(String qrCodePayload) { + super(qrCodePayload); + } + } + + public static class Paired extends MailboxPairingState { + public Paired() { + super(null); + } + } + + public static class InvalidQrCode extends MailboxPairingState { + public InvalidQrCode() { + super(null); + } + } + + public static class MailboxAlreadyPaired extends MailboxPairingState { + public MailboxAlreadyPaired() { + super(null); + } + } + + public static class ConnectionError extends MailboxPairingState { + public ConnectionError(String qrCodePayload) { + super(qrCodePayload); + } + } + + public static class AssertionError extends MailboxPairingState { + public AssertionError(String qrCodePayload) { + super(qrCodePayload); + } + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingTask.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingTask.java new file mode 100644 index 000000000..0f8cd05d7 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingTask.java @@ -0,0 +1,21 @@ +package org.briarproject.bramble.api.mailbox; + +import org.briarproject.bramble.api.Consumer; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +public interface MailboxPairingTask extends Runnable { + + /** + * Adds an observer to the task. The observer will be notified on the + * event thread of the current state of the task and any subsequent state + * changes. + */ + void addObserver(Consumer observer); + + /** + * Removes an observer from the task. + */ + void removeObserver(Consumer observer); + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java index 82a628766..b079a6104 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java @@ -155,6 +155,10 @@ interface MailboxApi { class ApiException extends Exception { } + @Immutable + class MailboxAlreadyPairedException extends ApiException { + } + /** * A failure that does not need to be retried, * e.g. when adding a contact that already exists. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java index 9c80bdda7..0bf0bef47 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java @@ -65,8 +65,7 @@ class MailboxApiImpl implements MailboxApi { .build(); OkHttpClient client = httpClientProvider.get(); Response response = client.newCall(request).execute(); - // TODO consider throwing a special exception for the 401 case - if (response.code() == 401) throw new ApiException(); + if (response.code() == 401) throw new MailboxAlreadyPairedException(); if (!response.isSuccessful()) throw new ApiException(); ResponseBody body = response.body(); if (body == null) throw new ApiException(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java new file mode 100644 index 000000000..16a6dccde --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java @@ -0,0 +1,72 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.mailbox.MailboxManager; +import org.briarproject.bramble.api.mailbox.MailboxPairingTask; +import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.concurrent.Executor; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +@Immutable +@NotNullByDefault +class MailboxManagerImpl implements MailboxManager { + + private final Executor ioExecutor; + private final MailboxSettingsManager mailboxSettingsManager; + private final MailboxPairingTaskFactory pairingTaskFactory; + private final Object lock = new Object(); + + @Nullable + @GuardedBy("lock") + private MailboxPairingTask pairingTask = null; + + @Inject + MailboxManagerImpl( + @IoExecutor Executor ioExecutor, + MailboxSettingsManager mailboxSettingsManager, + MailboxPairingTaskFactory pairingTaskFactory) { + this.ioExecutor = ioExecutor; + this.mailboxSettingsManager = mailboxSettingsManager; + this.pairingTaskFactory = pairingTaskFactory; + } + + @Override + public boolean isPaired(Transaction txn) throws DbException { + return mailboxSettingsManager.getOwnMailboxProperties(txn) != null; + } + + @Nullable + @Override + public MailboxPairingTask getCurrentPairingTask() { + synchronized (lock) { + return pairingTask; + } + } + + @Override + public MailboxPairingTask startPairingTask(String payload) { + MailboxPairingTask created; + synchronized (lock) { + if (pairingTask != null) return pairingTask; + created = pairingTaskFactory.createPairingTask(payload); + pairingTask = created; + } + ioExecutor.execute(() -> { + created.run(); + synchronized (lock) { + // remove task after it finished + pairingTask = null; + } + }); + return created; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxModule.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxModule.java index a01b15098..85e925202 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxModule.java @@ -1,16 +1,36 @@ package org.briarproject.bramble.mailbox; +import org.briarproject.bramble.api.mailbox.MailboxManager; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import javax.inject.Singleton; + import dagger.Module; import dagger.Provides; @Module public class MailboxModule { + @Provides + @Singleton + MailboxManager providesMailboxManager(MailboxManagerImpl mailboxManager) { + return mailboxManager; + } + + @Provides + MailboxPairingTaskFactory provideMailboxPairingTaskFactory( + MailboxPairingTaskFactoryImpl mailboxPairingTaskFactory) { + return mailboxPairingTaskFactory; + } + @Provides MailboxSettingsManager provideMailboxSettingsManager( MailboxSettingsManagerImpl mailboxSettingsManager) { return mailboxSettingsManager; } + + @Provides + MailboxApi providesMailboxApi(MailboxApiImpl mailboxApi) { + return mailboxApi; + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactory.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactory.java new file mode 100644 index 000000000..749a7f31c --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactory.java @@ -0,0 +1,12 @@ +package org.briarproject.bramble.mailbox; + + +import org.briarproject.bramble.api.mailbox.MailboxPairingTask; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +interface MailboxPairingTaskFactory { + + MailboxPairingTask createPairingTask(String qrCodePayload); + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java new file mode 100644 index 000000000..9cbee44a6 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java @@ -0,0 +1,44 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.db.TransactionManager; +import org.briarproject.bramble.api.event.EventExecutor; +import org.briarproject.bramble.api.mailbox.MailboxPairingTask; +import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.concurrent.Executor; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +@Immutable +@NotNullByDefault +class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory { + + private final Executor eventExecutor; + private final TransactionManager db; + private final CryptoComponent crypto; + private final MailboxApi api; + private final MailboxSettingsManager mailboxSettingsManager; + + @Inject + MailboxPairingTaskFactoryImpl( + @EventExecutor Executor eventExecutor, + TransactionManager db, + CryptoComponent crypto, + MailboxApi api, + MailboxSettingsManager mailboxSettingsManager) { + this.eventExecutor = eventExecutor; + this.db = db; + this.crypto = crypto; + this.api = api; + this.mailboxSettingsManager = mailboxSettingsManager; + } + + @Override + public MailboxPairingTask createPairingTask(String qrCodePayload) { + return new MailboxPairingTaskImpl(qrCodePayload, eventExecutor, db, + crypto, api, mailboxSettingsManager); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java new file mode 100644 index 000000000..479b59f4d --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java @@ -0,0 +1,166 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.bramble.api.Consumer; +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.TransactionManager; +import org.briarproject.bramble.api.event.EventExecutor; +import org.briarproject.bramble.api.mailbox.MailboxAuthToken; +import org.briarproject.bramble.api.mailbox.MailboxPairingState; +import org.briarproject.bramble.api.mailbox.MailboxPairingTask; +import org.briarproject.bramble.api.mailbox.MailboxProperties; +import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.mailbox.MailboxApi.ApiException; +import org.briarproject.bramble.mailbox.MailboxApi.MailboxAlreadyPairedException; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.util.LogUtils.logException; + +@ThreadSafe +@NotNullByDefault +class MailboxPairingTaskImpl implements MailboxPairingTask { + + private final static Logger LOG = + getLogger(MailboxPairingTaskImpl.class.getName()); + @SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19 + private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + private static final int VERSION_REQUIRED = 32; + + private final String payload; + private final Executor eventExecutor; + private final TransactionManager db; + private final CryptoComponent crypto; + private final MailboxApi api; + private final MailboxSettingsManager mailboxSettingsManager; + + private final Object lock = new Object(); + @GuardedBy("lock") + private final List> observers = + new ArrayList<>(); + @GuardedBy("lock") + private MailboxPairingState state; + + MailboxPairingTaskImpl( + String payload, + @EventExecutor Executor eventExecutor, + TransactionManager db, + CryptoComponent crypto, + MailboxApi api, + MailboxSettingsManager mailboxSettingsManager) { + this.payload = payload; + this.eventExecutor = eventExecutor; + this.db = db; + this.crypto = crypto; + this.api = api; + this.mailboxSettingsManager = mailboxSettingsManager; + state = new MailboxPairingState.QrCodeReceived(payload); + } + + @Override + public void addObserver(Consumer o) { + MailboxPairingState state; + synchronized (lock) { + observers.add(o); + state = this.state; + eventExecutor.execute(() -> o.accept(state)); + } + } + + @Override + public void removeObserver(Consumer o) { + synchronized (lock) { + observers.remove(o); + } + } + + @Override + public void run() { + try { + pairMailbox(); + } catch (FormatException e) { + onMailboxError(e, new MailboxPairingState.InvalidQrCode()); + } catch (MailboxAlreadyPairedException e) { + onMailboxError(e, new MailboxPairingState.MailboxAlreadyPaired()); + } catch (IOException e) { + onMailboxError(e, new MailboxPairingState.ConnectionError(payload)); + } catch (ApiException | DbException e) { + onMailboxError(e, new MailboxPairingState.AssertionError(payload)); + } + } + + private void pairMailbox() throws IOException, ApiException, DbException { + MailboxProperties mailboxProperties = decodeQrCodePayload(payload); + synchronized (lock) { + this.state = new MailboxPairingState.Pairing(payload); + notifyObservers(); + } + MailboxAuthToken ownerToken = api.setup(mailboxProperties); + MailboxProperties ownerProperties = new MailboxProperties( + mailboxProperties.getOnionAddress(), ownerToken, true); + db.transaction(false, txn -> mailboxSettingsManager + .setOwnMailboxProperties(txn, ownerProperties)); + synchronized (lock) { + this.state = new MailboxPairingState.Paired(); + notifyObservers(); + } + // TODO already do mailboxSettingsManager.setOwnMailboxStatus() ? + } + + private void onMailboxError(Exception e, MailboxPairingState state) { + logException(LOG, WARNING, e); + synchronized (lock) { + this.state = state; + notifyObservers(); + } + } + + @GuardedBy("lock") + private void notifyObservers() { + List> observers = + new ArrayList<>(this.observers); + MailboxPairingState state = this.state; + eventExecutor.execute(() -> { + for (Consumer o : observers) o.accept(state); + }); + } + + private MailboxProperties decodeQrCodePayload(String payload) + throws FormatException { + byte[] bytes = payload.getBytes(ISO_8859_1); + if (bytes.length != 65) { + if (LOG.isLoggable(WARNING)) { + LOG.warning("QR code length is not 65: " + bytes.length); + } + throw new FormatException(); + } + int version = bytes[0] & 0xFF; + if (version != VERSION_REQUIRED) { + if (LOG.isLoggable(WARNING)) { + LOG.warning("QR code has not version " + VERSION_REQUIRED + + ": " + version); + } + throw new FormatException(); + } + LOG.info("QR code is valid"); + byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33); + String onionAddress = crypto.encodeOnionAddress(onionPubKey); + byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65); + MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes); + return new MailboxProperties(onionAddress, setupToken, true); + } + +} From 65e7bcb94ecddbc931f6f76f3b20d65cb817f8ed Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 11:55:55 -0300 Subject: [PATCH 2/6] Add unit tests for MailboxPairingTask --- .../mailbox/MailboxPairingTaskImplTest.java | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java new file mode 100644 index 000000000..619eafd4b --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java @@ -0,0 +1,187 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.db.TransactionManager; +import org.briarproject.bramble.api.mailbox.MailboxAuthToken; +import org.briarproject.bramble.api.mailbox.MailboxPairingState; +import org.briarproject.bramble.api.mailbox.MailboxPairingTask; +import org.briarproject.bramble.api.mailbox.MailboxProperties; +import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.bramble.test.DbExpectations; +import org.briarproject.bramble.test.ImmediateExecutor; +import org.briarproject.bramble.test.PredicateMatcher; +import org.jmock.Expectations; +import org.junit.Test; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.briarproject.bramble.test.TestUtils.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class MailboxPairingTaskImplTest extends BrambleMockTestCase { + + private final Executor executor = new ImmediateExecutor(); + private final TransactionManager db = + context.mock(TransactionManager.class); + private final CryptoComponent crypto = context.mock(CryptoComponent.class); + private final MailboxApi api = context.mock(MailboxApi.class); + private final MailboxSettingsManager mailboxSettingsManager = + context.mock(MailboxSettingsManager.class); + private final MailboxPairingTaskFactory factory = + new MailboxPairingTaskFactoryImpl(executor, db, crypto, api, + mailboxSettingsManager); + + private final String onion = getRandomString(64); + private final byte[] onionBytes = getRandomBytes(32); + private final MailboxAuthToken setupToken = + new MailboxAuthToken(getRandomId()); + private final MailboxAuthToken ownerToken = + new MailboxAuthToken(getRandomId()); + private final String validPayload = getValidPayload(); + private final MailboxProperties setupProperties = + new MailboxProperties(onion, setupToken, true); + private final MailboxProperties ownerProperties = + new MailboxProperties(onion, ownerToken, true); + + @Test + public void testInitialQrCodeReceivedState() { + MailboxPairingTask task = + factory.createPairingTask(getRandomString(42)); + task.addObserver(state -> + assertTrue(state instanceof MailboxPairingState.QrCodeReceived) + ); + } + + @Test + public void testInvalidQrCode() { + MailboxPairingTask task1 = + factory.createPairingTask(getRandomString(42)); + task1.run(); + task1.addObserver(state -> + assertTrue(state instanceof MailboxPairingState.InvalidQrCode) + ); + + MailboxPairingTask task2 = + factory.createPairingTask(getRandomString(65)); + task2.run(); + task2.addObserver(state -> + assertTrue(state instanceof MailboxPairingState.InvalidQrCode) + ); + } + + @Test + public void testSuccessfulPairing() throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).encodeOnionAddress(onionBytes); + will(returnValue(onion)); + oneOf(api).setup(with(matches(setupProperties))); + will(returnValue(ownerToken)); + }}); + Transaction txn = new Transaction(null, false); + context.checking(new DbExpectations() {{ + oneOf(db).transaction(with(false), withDbRunnable(txn)); + oneOf(mailboxSettingsManager).setOwnMailboxProperties( + with(txn), with(matches(ownerProperties))); + }}); + + AtomicInteger i = new AtomicInteger(0); + MailboxPairingTask task = factory.createPairingTask(validPayload); + task.addObserver(state -> { + if (i.get() == 0) { + assertEquals(MailboxPairingState.QrCodeReceived.class, + state.getClass()); + } else if (i.get() == 1) { + assertEquals(MailboxPairingState.Pairing.class, + state.getClass()); + } else if (i.get() == 2) { + assertEquals(MailboxPairingState.Paired.class, + state.getClass()); + } else fail("Unexpected change of state " + state.getClass()); + i.getAndIncrement(); + }); + task.run(); + } + + @Test + public void testAlreadyPaired() throws Exception { + testApiException(new MailboxApi.MailboxAlreadyPairedException(), + MailboxPairingState.MailboxAlreadyPaired.class); + } + + @Test + public void testMailboxApiException() throws Exception { + testApiException(new MailboxApi.ApiException(), + MailboxPairingState.AssertionError.class); + } + + @Test + public void testApiIOException() throws Exception { + testApiException(new IOException(), + MailboxPairingState.ConnectionError.class); + } + + private void testApiException(Exception e, + Class s) throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).encodeOnionAddress(onionBytes); + will(returnValue(onion)); + oneOf(api).setup(with(matches(setupProperties))); + will(throwException(e)); + }}); + + MailboxPairingTask task = factory.createPairingTask(validPayload); + task.run(); + task.addObserver(state -> assertEquals(state.getClass(), s)); + } + + @Test + public void testDbException() throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).encodeOnionAddress(onionBytes); + will(returnValue(onion)); + oneOf(api).setup(with(matches(setupProperties))); + will(returnValue(ownerToken)); + }}); + Transaction txn = new Transaction(null, false); + context.checking(new DbExpectations() {{ + oneOf(db).transaction(with(false), withDbRunnable(txn)); + oneOf(mailboxSettingsManager).setOwnMailboxProperties( + with(txn), with(matches(ownerProperties))); + will(throwException(new DbException())); + }}); + + MailboxPairingTask task = factory.createPairingTask(validPayload); + task.run(); + task.addObserver(state -> assertEquals(state.getClass(), + MailboxPairingState.AssertionError.class)); + } + + private String getValidPayload() { + byte[] payloadBytes = ByteBuffer.allocate(65) + .put((byte) 32) // 1 + .put(onionBytes) // 32 + .put(setupToken.getBytes()) // 32 + .array(); + //noinspection CharsetObjectCanBeUsed + return new String(payloadBytes, Charset.forName("ISO-8859-1")); + } + + private PredicateMatcher matches(MailboxProperties p2) { + return new PredicateMatcher<>(MailboxProperties.class, p1 -> + p1.getAuthToken().equals(p2.getAuthToken()) && + p1.getOnionAddress().equals(p2.getOnionAddress()) && + p1.isOwner() == p2.isOwner()); + } + +} From 653b744a02fe687c7b21d01fbdd9665bc011402a Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 13:22:50 -0300 Subject: [PATCH 3/6] Add getMailboxStatus method to MailboxManager --- .../briarproject/bramble/api/mailbox/MailboxManager.java | 5 +++++ .../briarproject/bramble/mailbox/MailboxManagerImpl.java | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java index 3fbdda57a..dabfb9ea4 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxManager.java @@ -12,6 +12,11 @@ public interface MailboxManager { */ boolean isPaired(Transaction txn) throws DbException; + /** + * @return the current status of the mailbox. + */ + MailboxStatus getMailboxStatus(Transaction txn) throws DbException; + /** * Returns the currently running pairing task, * or null if no pairing task is running. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java index 16a6dccde..7bbeb0e12 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxManagerImpl.java @@ -6,6 +6,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.mailbox.MailboxManager; import org.briarproject.bramble.api.mailbox.MailboxPairingTask; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.mailbox.MailboxStatus; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import java.util.concurrent.Executor; @@ -43,6 +44,11 @@ class MailboxManagerImpl implements MailboxManager { return mailboxSettingsManager.getOwnMailboxProperties(txn) != null; } + @Override + public MailboxStatus getMailboxStatus(Transaction txn) throws DbException { + return mailboxSettingsManager.getOwnMailboxStatus(txn); + } + @Nullable @Override public MailboxPairingTask getCurrentPairingTask() { From 88c54ed3b02a723b6d1db1661850ef52a032c48c Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 14:18:07 -0300 Subject: [PATCH 4/6] Rename getOnionAddress() to getBaseUrl() This can later include a version parameter as well. --- .../bramble/api/mailbox/MailboxProperties.java | 10 +++++----- .../briarproject/bramble/mailbox/MailboxApiImpl.java | 10 +++++----- .../bramble/mailbox/MailboxPairingTaskImpl.java | 5 +++-- .../bramble/mailbox/MailboxSettingsManagerImpl.java | 2 +- .../bramble/mailbox/MailboxIntegrationTest.java | 2 +- .../bramble/mailbox/MailboxPairingTaskImplTest.java | 7 ++++--- .../mailbox/MailboxSettingsManagerImplTest.java | 2 +- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxProperties.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxProperties.java index 26025fc8e..7d8d3c5c4 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxProperties.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxProperties.java @@ -8,19 +8,19 @@ import javax.annotation.concurrent.Immutable; @NotNullByDefault public class MailboxProperties { - private final String onionAddress; + private final String baseUrl; private final MailboxAuthToken authToken; private final boolean owner; - public MailboxProperties(String onionAddress, MailboxAuthToken authToken, + public MailboxProperties(String baseUrl, MailboxAuthToken authToken, boolean owner) { - this.onionAddress = onionAddress; + this.baseUrl = baseUrl; this.authToken = authToken; this.owner = owner; } - public String getOnionAddress() { - return onionAddress; + public String getBaseUrl() { + return baseUrl; } public MailboxAuthToken getAuthToken() { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java index 0bf0bef47..e1c67841a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java @@ -60,7 +60,7 @@ class MailboxApiImpl implements MailboxApi { throws IOException, ApiException { if (!properties.isOwner()) throw new IllegalArgumentException(); Request request = getRequestBuilder(properties.getAuthToken()) - .url(properties.getOnionAddress() + "/setup") + .url(properties.getBaseUrl() + "/setup") .put(EMPTY_REQUEST) .build(); OkHttpClient client = httpClientProvider.get(); @@ -108,7 +108,7 @@ class MailboxApiImpl implements MailboxApi { public void deleteContact(MailboxProperties properties, ContactId contactId) throws IOException, ApiException, TolerableFailureException { if (!properties.isOwner()) throw new IllegalArgumentException(); - String url = properties.getOnionAddress() + "/contacts/" + + String url = properties.getBaseUrl() + "/contacts/" + contactId.getInt(); Request request = getRequestBuilder(properties.getAuthToken()) .delete() @@ -212,7 +212,7 @@ class MailboxApiImpl implements MailboxApi { String path = "/files/" + folderId + "/" + fileId; Request request = getRequestBuilder(properties.getAuthToken()) .delete() - .url(properties.getOnionAddress() + path) + .url(properties.getBaseUrl() + path) .build(); OkHttpClient client = httpClientProvider.get(); Response response = client.newCall(request).execute(); @@ -254,7 +254,7 @@ class MailboxApiImpl implements MailboxApi { private Response sendGetRequest(MailboxProperties properties, String path) throws IOException { Request request = getRequestBuilder(properties.getAuthToken()) - .url(properties.getOnionAddress() + path) + .url(properties.getBaseUrl() + path) .build(); OkHttpClient client = httpClientProvider.get(); return client.newCall(request).execute(); @@ -263,7 +263,7 @@ class MailboxApiImpl implements MailboxApi { private Response sendPostRequest(MailboxProperties properties, String path, RequestBody body) throws IOException { Request request = getRequestBuilder(properties.getAuthToken()) - .url(properties.getOnionAddress() + path) + .url(properties.getBaseUrl() + path) .post(body) .build(); OkHttpClient client = httpClientProvider.get(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java index 479b59f4d..ac288b432 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java @@ -110,7 +110,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { } MailboxAuthToken ownerToken = api.setup(mailboxProperties); MailboxProperties ownerProperties = new MailboxProperties( - mailboxProperties.getOnionAddress(), ownerToken, true); + mailboxProperties.getBaseUrl(), ownerToken, true); db.transaction(false, txn -> mailboxSettingsManager .setOwnMailboxProperties(txn, ownerProperties)); synchronized (lock) { @@ -158,9 +158,10 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { LOG.info("QR code is valid"); byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33); String onionAddress = crypto.encodeOnionAddress(onionPubKey); + String baseUrl = "http://" + onionAddress + ".onion"; byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65); MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes); - return new MailboxProperties(onionAddress, setupToken, true); + return new MailboxProperties(baseUrl, setupToken, true); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java index bfb9f085e..4e0065037 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java @@ -57,7 +57,7 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager { public void setOwnMailboxProperties(Transaction txn, MailboxProperties p) throws DbException { Settings s = new Settings(); - s.put(SETTINGS_KEY_ONION, p.getOnionAddress()); + s.put(SETTINGS_KEY_ONION, p.getBaseUrl()); s.put(SETTINGS_KEY_TOKEN, p.getAuthToken().toString()); settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTest.java index eccb311ed..f0b130059 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTest.java @@ -131,7 +131,7 @@ public class MailboxIntegrationTest extends BrambleTestCase { ContactId contactId = new ContactId(1); MailboxContact contact = getMailboxContact(contactId); MailboxProperties contactProperties = new MailboxProperties( - ownerProperties.getOnionAddress(), contact.token, false); + ownerProperties.getBaseUrl(), contact.token, false); api.addContact(ownerProperties, contact); // upload a file for our contact diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java index 619eafd4b..47c937eea 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java @@ -44,15 +44,16 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { private final String onion = getRandomString(64); private final byte[] onionBytes = getRandomBytes(32); + private final String onionAddress = "http://" + onion + ".onion"; private final MailboxAuthToken setupToken = new MailboxAuthToken(getRandomId()); private final MailboxAuthToken ownerToken = new MailboxAuthToken(getRandomId()); private final String validPayload = getValidPayload(); private final MailboxProperties setupProperties = - new MailboxProperties(onion, setupToken, true); + new MailboxProperties(onionAddress, setupToken, true); private final MailboxProperties ownerProperties = - new MailboxProperties(onion, ownerToken, true); + new MailboxProperties(onionAddress, ownerToken, true); @Test public void testInitialQrCodeReceivedState() { @@ -180,7 +181,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { private PredicateMatcher matches(MailboxProperties p2) { return new PredicateMatcher<>(MailboxProperties.class, p1 -> p1.getAuthToken().equals(p2.getAuthToken()) && - p1.getOnionAddress().equals(p2.getOnionAddress()) && + p1.getBaseUrl().equals(p2.getBaseUrl()) && p1.isOwner() == p2.isOwner()); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java index 57aa8894a..21fe9266f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImplTest.java @@ -73,7 +73,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase { MailboxProperties properties = manager.getOwnMailboxProperties(txn); assertNotNull(properties); - assertEquals(onion, properties.getOnionAddress()); + assertEquals(onion, properties.getBaseUrl()); assertEquals(token, properties.getAuthToken()); assertTrue(properties.isOwner()); } From 4a46b13e9d2b5e25520937afd7086f2bd68507ec Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 18 Feb 2022 09:50:38 -0300 Subject: [PATCH 5/6] Address mailbox pairing backend review feedback --- .../bramble/api/mailbox/MailboxPairingState.java | 4 ++-- .../bramble/mailbox/MailboxPairingTaskImpl.java | 16 +++++++--------- .../plugin/file/RemovableDriveTaskRegistry.java | 1 + .../mailbox/MailboxPairingTaskImplTest.java | 10 +++++----- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java index f2f1cc948..8581da441 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java @@ -51,8 +51,8 @@ public abstract class MailboxPairingState { } } - public static class AssertionError extends MailboxPairingState { - public AssertionError(String qrCodePayload) { + public static class UnexpectedError extends MailboxPairingState { + public UnexpectedError(String qrCodePayload) { super(qrCodePayload); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java index ac288b432..ffc2212a0 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java @@ -98,30 +98,28 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { } catch (IOException e) { onMailboxError(e, new MailboxPairingState.ConnectionError(payload)); } catch (ApiException | DbException e) { - onMailboxError(e, new MailboxPairingState.AssertionError(payload)); + onMailboxError(e, new MailboxPairingState.UnexpectedError(payload)); } } private void pairMailbox() throws IOException, ApiException, DbException { MailboxProperties mailboxProperties = decodeQrCodePayload(payload); - synchronized (lock) { - this.state = new MailboxPairingState.Pairing(payload); - notifyObservers(); - } + setState(new MailboxPairingState.Pairing(payload)); MailboxAuthToken ownerToken = api.setup(mailboxProperties); MailboxProperties ownerProperties = new MailboxProperties( mailboxProperties.getBaseUrl(), ownerToken, true); db.transaction(false, txn -> mailboxSettingsManager .setOwnMailboxProperties(txn, ownerProperties)); - synchronized (lock) { - this.state = new MailboxPairingState.Paired(); - notifyObservers(); - } + setState(new MailboxPairingState.Paired()); // TODO already do mailboxSettingsManager.setOwnMailboxStatus() ? } private void onMailboxError(Exception e, MailboxPairingState state) { logException(LOG, WARNING, e); + setState(state); + } + + private void setState(MailboxPairingState state) { synchronized (lock) { this.state = state; notifyObservers(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/RemovableDriveTaskRegistry.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/RemovableDriveTaskRegistry.java index 1f073bbf2..ca29b473e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/RemovableDriveTaskRegistry.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/RemovableDriveTaskRegistry.java @@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.file; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.file.RemovableDriveTask; +@Deprecated // We can simply remove tasks when they finish @NotNullByDefault interface RemovableDriveTaskRegistry { diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java index 47c937eea..8ee069e78 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java @@ -42,7 +42,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { new MailboxPairingTaskFactoryImpl(executor, db, crypto, api, mailboxSettingsManager); - private final String onion = getRandomString(64); + private final String onion = getRandomString(56); private final byte[] onionBytes = getRandomBytes(32); private final String onionAddress = "http://" + onion + ".onion"; private final MailboxAuthToken setupToken = @@ -73,8 +73,8 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { assertTrue(state instanceof MailboxPairingState.InvalidQrCode) ); - MailboxPairingTask task2 = - factory.createPairingTask(getRandomString(65)); + String goodLength = "00" + getRandomString(63); + MailboxPairingTask task2 = factory.createPairingTask(goodLength); task2.run(); task2.addObserver(state -> assertTrue(state instanceof MailboxPairingState.InvalidQrCode) @@ -123,7 +123,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { @Test public void testMailboxApiException() throws Exception { testApiException(new MailboxApi.ApiException(), - MailboxPairingState.AssertionError.class); + MailboxPairingState.UnexpectedError.class); } @Test @@ -165,7 +165,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { MailboxPairingTask task = factory.createPairingTask(validPayload); task.run(); task.addObserver(state -> assertEquals(state.getClass(), - MailboxPairingState.AssertionError.class)); + MailboxPairingState.UnexpectedError.class)); } private String getValidPayload() { From ce7f44de01eb0f5c9b6b181612cbdf00d9a7d2af Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 18 Feb 2022 10:07:51 -0300 Subject: [PATCH 6/6] Set our own mailbox status right after pairing --- .../mailbox/MailboxPairingTaskFactoryImpl.java | 6 +++++- .../bramble/mailbox/MailboxPairingTaskImpl.java | 13 ++++++++++--- .../bramble/mailbox/MailboxPairingTaskImplTest.java | 10 +++++++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java index 9cbee44a6..6c5150eb3 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskFactoryImpl.java @@ -6,6 +6,7 @@ import org.briarproject.bramble.api.event.EventExecutor; import org.briarproject.bramble.api.mailbox.MailboxPairingTask; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.Clock; import java.util.concurrent.Executor; @@ -19,6 +20,7 @@ class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory { private final Executor eventExecutor; private final TransactionManager db; private final CryptoComponent crypto; + private final Clock clock; private final MailboxApi api; private final MailboxSettingsManager mailboxSettingsManager; @@ -27,11 +29,13 @@ class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory { @EventExecutor Executor eventExecutor, TransactionManager db, CryptoComponent crypto, + Clock clock, MailboxApi api, MailboxSettingsManager mailboxSettingsManager) { this.eventExecutor = eventExecutor; this.db = db; this.crypto = crypto; + this.clock = clock; this.api = api; this.mailboxSettingsManager = mailboxSettingsManager; } @@ -39,6 +43,6 @@ class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory { @Override public MailboxPairingTask createPairingTask(String qrCodePayload) { return new MailboxPairingTaskImpl(qrCodePayload, eventExecutor, db, - crypto, api, mailboxSettingsManager); + crypto, clock, api, mailboxSettingsManager); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java index ffc2212a0..03f36d2f7 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java @@ -12,6 +12,7 @@ import org.briarproject.bramble.api.mailbox.MailboxPairingTask; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.mailbox.MailboxApi.ApiException; import org.briarproject.bramble.mailbox.MailboxApi.MailboxAlreadyPairedException; @@ -44,6 +45,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { private final Executor eventExecutor; private final TransactionManager db; private final CryptoComponent crypto; + private final Clock clock; private final MailboxApi api; private final MailboxSettingsManager mailboxSettingsManager; @@ -59,12 +61,14 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { @EventExecutor Executor eventExecutor, TransactionManager db, CryptoComponent crypto, + Clock clock, MailboxApi api, MailboxSettingsManager mailboxSettingsManager) { this.payload = payload; this.eventExecutor = eventExecutor; this.db = db; this.crypto = crypto; + this.clock = clock; this.api = api; this.mailboxSettingsManager = mailboxSettingsManager; state = new MailboxPairingState.QrCodeReceived(payload); @@ -108,10 +112,13 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { MailboxAuthToken ownerToken = api.setup(mailboxProperties); MailboxProperties ownerProperties = new MailboxProperties( mailboxProperties.getBaseUrl(), ownerToken, true); - db.transaction(false, txn -> mailboxSettingsManager - .setOwnMailboxProperties(txn, ownerProperties)); + long time = clock.currentTimeMillis(); + db.transaction(false, txn -> { + mailboxSettingsManager + .setOwnMailboxProperties(txn, ownerProperties); + mailboxSettingsManager.recordSuccessfulConnection(txn, time); + }); setState(new MailboxPairingState.Paired()); - // TODO already do mailboxSettingsManager.setOwnMailboxStatus() ? } private void onMailboxError(Exception e, MailboxPairingState state) { diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java index 8ee069e78..7b8d70779 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.mailbox.MailboxPairingState; import org.briarproject.bramble.api.mailbox.MailboxPairingTask; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.DbExpectations; import org.briarproject.bramble.test.ImmediateExecutor; @@ -35,11 +36,12 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { private final TransactionManager db = context.mock(TransactionManager.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); + private final Clock clock = context.mock(Clock.class); private final MailboxApi api = context.mock(MailboxApi.class); private final MailboxSettingsManager mailboxSettingsManager = context.mock(MailboxSettingsManager.class); private final MailboxPairingTaskFactory factory = - new MailboxPairingTaskFactoryImpl(executor, db, crypto, api, + new MailboxPairingTaskFactoryImpl(executor, db, crypto, clock, api, mailboxSettingsManager); private final String onion = getRandomString(56); @@ -50,6 +52,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { private final MailboxAuthToken ownerToken = new MailboxAuthToken(getRandomId()); private final String validPayload = getValidPayload(); + private final long time = System.currentTimeMillis(); private final MailboxProperties setupProperties = new MailboxProperties(onionAddress, setupToken, true); private final MailboxProperties ownerProperties = @@ -88,12 +91,15 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { will(returnValue(onion)); oneOf(api).setup(with(matches(setupProperties))); will(returnValue(ownerToken)); + oneOf(clock).currentTimeMillis(); + will(returnValue(time)); }}); Transaction txn = new Transaction(null, false); context.checking(new DbExpectations() {{ oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(mailboxSettingsManager).setOwnMailboxProperties( with(txn), with(matches(ownerProperties))); + oneOf(mailboxSettingsManager).recordSuccessfulConnection(txn, time); }}); AtomicInteger i = new AtomicInteger(0); @@ -153,6 +159,8 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { will(returnValue(onion)); oneOf(api).setup(with(matches(setupProperties))); will(returnValue(ownerToken)); + oneOf(clock).currentTimeMillis(); + will(returnValue(time)); }}); Transaction txn = new Transaction(null, false); context.checking(new DbExpectations() {{