From fb1d8e860f1345970e532ca18d74403195291ed8 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 30 Nov 2018 12:25:16 -0200 Subject: [PATCH] [api] Add interface for adding contacts remotely --- .../bramble/api/contact/ContactManager.java | 31 +++++++++++ .../bramble/api/contact/PendingContact.java | 54 +++++++++++++++++++ .../bramble/api/contact/PendingContactId.java | 11 ++++ .../PendingContactStateChangedEvent.java | 34 ++++++++++++ .../bramble/contact/ContactManagerImpl.java | 54 +++++++++++++++++++ 5 files changed, 184 insertions(+) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactId.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java index 0a04c7138..7996cbf54 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java @@ -13,6 +13,8 @@ import java.util.Collection; import javax.annotation.Nullable; +import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.FAILED; + @NotNullByDefault public interface ContactManager { @@ -52,6 +54,35 @@ public interface ContactManager { long timestamp, boolean alice, boolean verified, boolean active) throws DbException; + /** + * Returns the static link that needs to be sent to the contact to be added. + */ + String getRemoteContactLink(); + + /** + * Returns true if the given link is syntactically valid. + */ + boolean isValidRemoteContactLink(String link); + + /** + * Requests a new contact to be added via the given {@code link}. + * + * @param link The link received from the contact we want to add. + * @param alias The alias the user has given this contact. + * @return A PendingContact representing the contact to be added. + */ + PendingContact addRemoteContactRequest(String link, String alias); + + /** + * Returns a list of {@link PendingContact}s. + */ + Collection getPendingContacts(); + + /** + * Removes a {@link PendingContact} that is in state {@link FAILED}. + */ + void removePendingContact(PendingContact pendingContact); + /** * Returns the contact with the given ID. */ diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java new file mode 100644 index 000000000..025803026 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContact.java @@ -0,0 +1,54 @@ +package org.briarproject.bramble.api.contact; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class PendingContact { + + public enum PendingContactState { + WAITING_FOR_CONNECTION, + CONNECTED, + ADDING_CONTACT, + FAILED + } + + private final PendingContactId id; + private final String alias; + private final PendingContactState state; + private final long timestamp; + + public PendingContact(PendingContactId id, String alias, + PendingContactState state, long timestamp) { + this.id = id; + this.alias = alias; + this.state = state; + this.timestamp = timestamp; + } + + public String getAlias() { + return alias; + } + + public PendingContactState getState() { + return state; + } + + public long getTimestamp() { + return timestamp; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object o) { + return o instanceof PendingContact && + id.equals(((PendingContact) o).id); + } + +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactId.java new file mode 100644 index 000000000..6353cb792 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PendingContactId.java @@ -0,0 +1,11 @@ +package org.briarproject.bramble.api.contact; + +import org.briarproject.bramble.api.UniqueId; + +public class PendingContactId extends UniqueId { + + public PendingContactId(byte[] id) { + super(id); + } + +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java new file mode 100644 index 000000000..b5a8dc11a --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/event/PendingContactStateChangedEvent.java @@ -0,0 +1,34 @@ +package org.briarproject.bramble.api.contact.event; + +import org.briarproject.bramble.api.contact.PendingContact.PendingContactState; +import org.briarproject.bramble.api.contact.PendingContactId; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +/** + * An event that is broadcast when a pending contact's state is changed. + */ +@Immutable +@NotNullByDefault +public class PendingContactStateChangedEvent extends Event { + + private final PendingContactId id; + private final PendingContactState state; + + public PendingContactStateChangedEvent(PendingContactId id, + PendingContactState state) { + this.id = id; + this.state = state; + } + + public PendingContactId getId() { + return id; + } + + public PendingContactState getPendingContactState() { + return state; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java index fd6a8974e..bee28f7d2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java @@ -3,6 +3,8 @@ package org.briarproject.bramble.contact; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.contact.PendingContact; +import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; @@ -19,12 +21,16 @@ import org.briarproject.bramble.api.transport.KeyManager; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.regex.Pattern; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; +import static java.util.Collections.emptyList; +import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.WAITING_FOR_CONNECTION; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN; @@ -36,6 +42,12 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8; @NotNullByDefault class ContactManagerImpl implements ContactManager { + private static final int LINK_LENGTH = 64; + private static final String REMOTE_CONTACT_LINK = + "briar://" + getRandomBase32String(LINK_LENGTH); + private static final Pattern LINK_REGEX = + Pattern.compile("(briar://)?([a-z2-7]{" + LINK_LENGTH + "})"); + private final DatabaseComponent db; private final KeyManager keyManager; private final IdentityManager identityManager; @@ -84,6 +96,48 @@ class ContactManagerImpl implements ContactManager { verified, active)); } + @Override + public String getRemoteContactLink() { + // TODO replace with real implementation + return REMOTE_CONTACT_LINK; + } + + @SuppressWarnings("SameParameterValue") + private static String getRandomBase32String(int length) { + Random random = new Random(); + char[] c = new char[length]; + for (int i = 0; i < length; i++) { + int character = random.nextInt(32); + if (character < 26) c[i] = (char) ('a' + character); + else c[i] = (char) ('2' + (character - 26)); + } + return new String(c); + } + + @Override + public boolean isValidRemoteContactLink(String link) { + return LINK_REGEX.matcher(link).matches(); + } + + @Override + public PendingContact addRemoteContactRequest(String link, String alias) { + // TODO replace with real implementation + PendingContactId id = new PendingContactId(link.getBytes()); + return new PendingContact(id, alias, WAITING_FOR_CONNECTION, + System.currentTimeMillis()); + } + + @Override + public Collection getPendingContacts() { + // TODO replace with real implementation + return emptyList(); + } + + @Override + public void removePendingContact(PendingContact pendingContact) { + // TODO replace with real implementation + } + @Override public Contact getContact(ContactId c) throws DbException { return db.transactionWithResult(true, txn -> db.getContact(txn, c));