Changed the root package from net.sf.briar to org.briarproject.

This commit is contained in:
akwizgran
2014-01-08 16:18:30 +00:00
parent dce70f487c
commit 832476412c
427 changed files with 2507 additions and 2507 deletions

View File

@@ -0,0 +1,40 @@
package org.briarproject.api;
/** A pseudonym for a user. */
public class Author {
private final AuthorId id;
private final String name;
private final byte[] publicKey;
public Author(AuthorId id, String name, byte[] publicKey) {
this.id = id;
this.name = name;
this.publicKey = publicKey;
}
/** Returns the author's unique identifier. */
public AuthorId getId() {
return id;
}
/** Returns the author's name. */
public String getName() {
return name;
}
/** Returns the public key used to verify the pseudonym's signatures. */
public byte[] getPublicKey() {
return publicKey;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof Author && id.equals(((Author) o).id);
}
}

View File

@@ -0,0 +1,31 @@
package org.briarproject.api;
public interface AuthorConstants {
/** The maximum length of an author's name in UTF-8 bytes. */
int MAX_AUTHOR_NAME_LENGTH = 50;
/**
* The maximum length of a public key in bytes.
* <p>
* Public keys use SEC1 format: 0x04 x y, where x and y are unsigned
* big-endian integers.
* <p>
* For a 384-bit elliptic curve, the maximum length is 2 * (384/8) + 1.
*/
int MAX_PUBLIC_KEY_LENGTH = 97;
/**
* The maximum length of a signature in bytes.
* <p>
* A signature is an ASN.1 DER sequence containing two integers, r and s.
* The format is 0x30 len1 0x02 len2 r 0x02 len3 s, where len1 is
* len(0x02 len2 r 0x02 len3 s) as a DER length, len2 is len(r) as a DER
* length, len3 is len(s) as a DER length, and r and s are signed
* big-endian integers of minimal length.
* <p>
* For a 384-bit elliptic curve, the lengths are one byte each, so the
* maximum length is 2 * (384/8) + 8.
*/
int MAX_SIGNATURE_LENGTH = 104;
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.api;
public interface AuthorFactory {
Author createAuthor(String name, byte[] publicKey);
LocalAuthor createLocalAuthor(String name, byte[] publicKey,
byte[] privateKey);
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.api;
import java.util.Arrays;
/**
* Type-safe wrapper for a byte array that uniquely identifies an
* {@link Author}.
*/
public class AuthorId extends UniqueId {
public AuthorId(byte[] id) {
super(id);
}
@Override
public boolean equals(Object o) {
if(o instanceof AuthorId)
return Arrays.equals(id, ((AuthorId) o).id);
return false;
}
}

View File

@@ -0,0 +1,34 @@
package org.briarproject.api;
import java.util.Arrays;
/** A wrapper around a byte array, to allow it to be stored in maps etc. */
public class Bytes {
private final byte[] bytes;
private int hashCode = -1;
public Bytes(byte[] bytes) {
this.bytes = bytes;
}
public byte[] getBytes() {
return bytes;
}
@Override
public int hashCode() {
// Thread-safe because if two or more threads check and update the
// value, they'll calculate the same value
if(hashCode == -1) hashCode = Arrays.hashCode(bytes);
return hashCode;
}
@Override
public boolean equals(Object o) {
if(o instanceof Bytes)
return Arrays.equals(bytes, ((Bytes) o).bytes);
return false;
}
}

View File

@@ -0,0 +1,37 @@
package org.briarproject.api;
public class Contact {
private final ContactId id;
private final Author author;
private final AuthorId localAuthorId;
public Contact(ContactId id, Author author, AuthorId localAuthorId) {
this.id = id;
this.author = author;
this.localAuthorId = localAuthorId;
}
public ContactId getId() {
return id;
}
public Author getAuthor() {
return author;
}
public AuthorId getLocalAuthorId() {
return localAuthorId;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
if(o instanceof Contact) return id.equals(((Contact) o).id);
return false;
}
}

View File

@@ -0,0 +1,29 @@
package org.briarproject.api;
/**
* Type-safe wrapper for an integer that uniquely identifies a contact within
* the scope of a single node.
*/
public class ContactId {
private final int id;
public ContactId(int id) {
this.id = id;
}
public int getInt() {
return id;
}
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object o) {
if(o instanceof ContactId) return id == ((ContactId) o).id;
return false;
}
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.api;
import java.io.IOException;
/** An exception that indicates an unrecoverable formatting error. */
public class FormatException extends IOException {
private static final long serialVersionUID = 2274966775687766337L;
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.api;
/** A pseudonym for the local user. */
public class LocalAuthor extends Author {
private final byte[] privateKey;
public LocalAuthor(AuthorId id, String name, byte[] publicKey,
byte[] privateKey) {
super(id, name, publicKey);
this.privateKey = privateKey;
}
/** Returns the private key used to generate the pseudonym's signatures. */
public byte[] getPrivateKey() {
return privateKey;
}
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.api;
import java.util.Hashtable;
import java.util.Map;
public class TransportConfig extends Hashtable<String, String> {
private static final long serialVersionUID = 2330384620787778596L;
public TransportConfig(Map<String, String> c) {
super(c);
}
public TransportConfig() {}
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.api;
import java.util.Arrays;
/**
* Type-safe wrapper for a byte array that uniquely identifies a transport
* plugin.
*/
public class TransportId extends UniqueId {
public TransportId(byte[] id) {
super(id);
}
@Override
public boolean equals(Object o) {
if(o instanceof TransportId)
return Arrays.equals(id, ((TransportId) o).id);
return false;
}
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.api;
import java.util.Hashtable;
import java.util.Map;
public class TransportProperties extends Hashtable<String, String> {
private static final long serialVersionUID = 7533739534204953625L;
public TransportProperties(Map<String, String> p) {
super(p);
}
public TransportProperties() {}
}

View File

@@ -0,0 +1,10 @@
package org.briarproject.api;
public interface TransportPropertyConstants {
/** The maximum number of properties per transport. */
int MAX_PROPERTIES_PER_TRANSPORT = 100;
/** The maximum length of a property's key or value in UTF-8 bytes. */
int MAX_PROPERTY_LENGTH = 100;
}

View File

@@ -0,0 +1,30 @@
package org.briarproject.api;
import java.util.Arrays;
public abstract class UniqueId {
/** The length of a unique identifier in bytes. */
public static final int LENGTH = 48;
protected final byte[] id;
private int hashCode = -1;
protected UniqueId(byte[] id) {
if(id.length != LENGTH) throw new IllegalArgumentException();
this.id = id;
}
public byte[] getBytes() {
return id;
}
@Override
public int hashCode() {
// Thread-safe because if two or more threads check and update the
// value, they'll calculate the same value
if(hashCode == -1) hashCode = Arrays.hashCode(id);
return hashCode;
}
}

View File

@@ -0,0 +1,19 @@
package org.briarproject.api.android;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
/**
* Enables background threads to make Android API calls that must be made from
* a thread with a message queue.
*/
public interface AndroidExecutor {
/**
* Runs the given task on a thread with a message queue and returns the
* result of the task.
*/
<V> V call(Callable<V> c) throws InterruptedException, ExecutionException;
void shutdown();
}

View File

@@ -0,0 +1,19 @@
package org.briarproject.api.android;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.google.inject.BindingAnnotation;
/**
* Annotation for injecting the executor for accessing the database from the UI.
*/
@BindingAnnotation
@Target({ FIELD, METHOD, PARAMETER })
@Retention(RUNTIME)
public @interface DatabaseUiExecutor {}

View File

@@ -0,0 +1,27 @@
package org.briarproject.api.android;
/**
* Manages mappings between object references and serialisable handles. This
* enables references to be passed between Android UI objects that belong to
* the same process but can only communicate via serialisation.
*/
public interface ReferenceManager {
/**
* Returns the object with the given handle, or null if no mapping exists
* for the handle.
*/
<T> T getReference(long handle, Class<T> c);
/**
* Creates a mapping between the given reference and a handle, and returns
* the handle.
*/
<T> long putReference(T reference, Class<T> c);
/**
* Removes and returns the object with the given handle, or returns null
* if no mapping exists for the handle.
*/
<T> T removeReference(long handle, Class<T> c);
}

View File

@@ -0,0 +1,24 @@
package org.briarproject.api.crypto;
import java.security.GeneralSecurityException;
/** An authenticated cipher that support additional authenticated data. */
public interface AuthenticatedCipher {
/**
* Initializes this cipher with a key, an initialisation vector (IV) and
* additional authenticated data (AAD).
*/
void init(int opmode, SecretKey key, byte[] iv, byte[] aad)
throws GeneralSecurityException;
/** Encrypts or decrypts data in a single-part operation. */
int doFinal(byte[] input, int inputOff, int len, byte[] output,
int outputOff) throws GeneralSecurityException;
/** Returns the length of the message authenticated code (MAC) in bytes. */
int getMacLength();
/** Returns the block size of the cipher in bytes. */
int getBlockSize();
}

View File

@@ -0,0 +1,105 @@
package org.briarproject.api.crypto;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
public interface CryptoComponent {
SecretKey generateSecretKey();
MessageDigest getMessageDigest();
PseudoRandom getPseudoRandom(int seed1, int seed2);
SecureRandom getSecureRandom();
Signature getSignature();
KeyPair generateAgreementKeyPair();
KeyParser getAgreementKeyParser();
KeyPair generateSignatureKeyPair();
KeyParser getSignatureKeyParser();
/** Generates a random invitation code. */
int generateInvitationCode();
/**
* Derives two confirmation codes from the given master secret. The first
* code is for Alice to give to Bob; the second is for Bob to give to
* Alice.
*/
int[] deriveConfirmationCodes(byte[] secret);
/**
* Derives two nonces from the given master secret. The first nonce is for
* Alice to sign; the second is for Bob to sign.
*/
byte[][] deriveInvitationNonces(byte[] secret);
/**
* Derives a shared master secret from two public keys and one of the
* corresponding private keys.
* @param alice indicates whether the private key belongs to Alice or Bob.
*/
byte[] deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
/** Derives a group salt from the given master secret. */
byte[] deriveGroupSalt(byte[] secret);
/**
* Derives an initial secret for the given transport from the given master
* secret.
*/
byte[] deriveInitialSecret(byte[] secret, int transportIndex);
/**
* Derives a temporary secret for the given period from the given secret,
* which is either the initial shared secret or the previous period's
* temporary secret.
*/
byte[] deriveNextSecret(byte[] secret, long period);
/**
* Derives a tag key from the given temporary secret.
* @param alice indicates whether the key is for connections initiated by
* Alice or Bob.
*/
SecretKey deriveTagKey(byte[] secret, boolean alice);
/**
* Derives a frame key from the given temporary secret and connection
* number.
* @param alice indicates whether the key is for a connection initiated by
* Alice or Bob.
* @param initiator indicates whether the key is for the initiator's or the
* responder's side of the connection.
*/
SecretKey deriveFrameKey(byte[] secret, long connection, boolean alice,
boolean initiator);
/** Returns a cipher for encrypting and authenticating connections. */
AuthenticatedCipher getFrameCipher();
/** Encodes the pseudo-random tag that is used to recognise a connection. */
void encodeTag(byte[] tag, SecretKey tagKey, long connection);
/**
* Encrypts and authenticates the given plaintext so it can be written to
* storage. The encryption and authentication keys are derived from the
* given password. The ciphertext will be decryptable using the same
* password after the app restarts.
*/
byte[] encryptWithPassword(byte[] plaintext, char[] password);
/**
* Decrypts and authenticates the given ciphertext that has been read from
* storage. The encryption and authentication keys are derived from the
* given password. Returns null if the ciphertext cannot be decrypted and
* authenticated (for example, if the password is wrong).
*/
byte[] decryptWithPassword(byte[] ciphertext, char[] password);
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.crypto;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.google.inject.BindingAnnotation;
/** Annotation for injecting the executor for long-running crypto tasks. */
@BindingAnnotation
@Target({ FIELD, METHOD, PARAMETER })
@Retention(RUNTIME)
public @interface CryptoExecutor {}

View File

@@ -0,0 +1,23 @@
package org.briarproject.api.crypto;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.transport.ConnectionContext;
import org.briarproject.api.transport.Endpoint;
public interface KeyManager extends Service {
/**
* Returns a connection context for connecting to the given contact over
* the given transport, or null if an error occurs or the contact does not
* support the transport.
*/
ConnectionContext getConnectionContext(ContactId c, TransportId t);
/**
* Called whenever an endpoint has been added. The initial secret
* is erased before returning.
*/
void endpointAdded(Endpoint ep, long maxLatency, byte[] initialSecret);
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.api.crypto;
/** A key pair consisting of a {@link PublicKey} and a {@link PrivateKey). */
public class KeyPair {
private final PublicKey publicKey;
private final PrivateKey privateKey;
public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public PublicKey getPublic() {
return publicKey;
}
public PrivateKey getPrivate() {
return privateKey;
}
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.api.crypto;
import java.security.GeneralSecurityException;
public interface KeyParser {
PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException;
PrivateKey parsePrivateKey(byte[] encodedKey)
throws GeneralSecurityException;
}

View File

@@ -0,0 +1,28 @@
package org.briarproject.api.crypto;
public interface MessageDigest {
/** @see {@link java.security.MessageDigest#digest()} */
byte[] digest();
/** @see {@link java.security.MessageDigest#digest(byte[])} */
byte[] digest(byte[] input);
/** @see {@link java.security.MessageDigest#digest(byte[], int, int)} */
int digest(byte[] buf, int offset, int len);
/** @see {@link java.security.MessageDigest#getDigestLength()} */
int getDigestLength();
/** @see {@link java.security.MessageDigest#reset()} */
void reset();
/** @see {@link java.security.MessageDigest#update(byte)} */
void update(byte input);
/** @see {@link java.security.MessageDigest#update(byte[])} */
void update(byte[] input);
/** @see {@link java.security.MessageDigest#update(byte[], int, int)} */
void update(byte[] input, int offset, int len);
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.api.crypto;
/** The private half of a public/private {@link KeyPair}. */
public interface PrivateKey {
/** Returns the encoded representation of this key. */
byte[] getEncoded();
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.api.crypto;
/** A deterministic PRNG. */
public interface PseudoRandom {
byte[] nextBytes(int bytes);
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.api.crypto;
/** The public half of a public/private {@link KeyPair}. */
public interface PublicKey {
/** Returns the encoded representation of this key. */
byte[] getEncoded();
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.api.crypto;
/** A secret key used for encryption and/or authentication. */
public interface SecretKey {
/** Returns the encoded representation of this key. */
byte[] getEncoded();
/**
* Returns a copy of this key - erasing this key will erase the copy and
* vice versa.
*/
SecretKey copy();
/**
* Erases this key from memory. Any copies derived from this key via the
* {@link #copy()} method, and any keys from which this key was derived via
* the {@link #copy()} method, are also erased.
*/
void erase();
}

View File

@@ -0,0 +1,31 @@
package org.briarproject.api.crypto;
import java.security.GeneralSecurityException;
public interface Signature {
/**
* @see {@link java.security.Signature#initSign(java.security.PrivateKey)}
*/
void initSign(PrivateKey k) throws GeneralSecurityException;
/**
* @see {@link java.security.Signature#initVafiry(java.security.PublicKey)}
*/
void initVerify(PublicKey k) throws GeneralSecurityException;
/** @see {@link java.security.Signature#update(byte)} */
void update(byte b);
/** @see {@link java.security.Signature#update(byte[])} */
void update(byte[] b);
/** @see {@link java.security.Signature#update(byte[], int, int)} */
void update(byte[] b, int off, int len);
/** @see {@link java.security.Signature#sign()} */
byte[] sign();
/** @see {@link java.security.Signature#verify(byte[])} */
boolean verify(byte[] signature);
}

View File

@@ -0,0 +1,10 @@
package org.briarproject.api.db;
/**
* Thrown when a duplicate contact is added to the database. This exception may
* occur due to concurrent updates and does not indicate a database error.
*/
public class ContactExistsException extends DbException {
private static final long serialVersionUID = -6658762011691502411L;
}

View File

@@ -0,0 +1,357 @@
package org.briarproject.api.db;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorId;
import org.briarproject.api.Contact;
import org.briarproject.api.ContactId;
import org.briarproject.api.LocalAuthor;
import org.briarproject.api.TransportConfig;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.messaging.Ack;
import org.briarproject.api.messaging.Group;
import org.briarproject.api.messaging.GroupId;
import org.briarproject.api.messaging.GroupStatus;
import org.briarproject.api.messaging.Message;
import org.briarproject.api.messaging.MessageId;
import org.briarproject.api.messaging.Offer;
import org.briarproject.api.messaging.Request;
import org.briarproject.api.messaging.RetentionAck;
import org.briarproject.api.messaging.RetentionUpdate;
import org.briarproject.api.messaging.SubscriptionAck;
import org.briarproject.api.messaging.SubscriptionUpdate;
import org.briarproject.api.messaging.TransportAck;
import org.briarproject.api.messaging.TransportUpdate;
import org.briarproject.api.transport.Endpoint;
import org.briarproject.api.transport.TemporarySecret;
/**
* Encapsulates the database implementation and exposes high-level operations
* to other components.
*/
public interface DatabaseComponent {
/** Opens the database and returns true if the database already existed. */
boolean open() throws DbException, IOException;
/** Waits for any open transactions to finish and closes the database. */
void close() throws DbException, IOException;
/** Adds a listener to be notified when database events occur. */
void addListener(EventListener d);
/** Removes a listener. */
void removeListener(EventListener d);
/**
* Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact.
*/
ContactId addContact(Author remote, AuthorId local) throws DbException;
/** Stores an endpoint. */
void addEndpoint(Endpoint ep) throws DbException;
/**
* Subscribes to a group, or returns false if the user already has the
* maximum number of public subscriptions.
*/
boolean addGroup(Group g) throws DbException;
/** Stores a local pseudonym. */
void addLocalAuthor(LocalAuthor a) throws DbException;
/** Stores a local message. */
void addLocalMessage(Message m) throws DbException;
/**
* Stores the given temporary secrets and deletes any secrets that have
* been made obsolete.
*/
void addSecrets(Collection<TemporarySecret> secrets) throws DbException;
/**
* Stores a transport and returns true if the transport was not previously
* in the database.
*/
boolean addTransport(TransportId t, long maxLatency) throws DbException;
/**
* Returns an acknowledgement for the given contact, or null if there are
* no messages to acknowledge.
*/
Ack generateAck(ContactId c, int maxMessages) throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
* length less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Returns null if there are no
* sendable messages that fit in the given length.
*/
Collection<byte[]> generateBatch(ContactId c, int maxLength,
long maxLatency) throws DbException;
/**
* Returns an offer for the given contact for transmission over a
* transport with the given maximum latency, or null if there are no
* messages to offer.
*/
Offer generateOffer(ContactId c, int maxMessages, long maxLatency)
throws DbException;
/**
* Returns a request for the given contact, or null if there are no
* messages to request.
*/
Request generateRequest(ContactId c, int maxMessages) throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
* length less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Only messages that have been
* requested by the contact are returned. Returns null if there are no
* sendable messages that fit in the given length.
*/
Collection<byte[]> generateRequestedBatch(ContactId c, int maxLength,
long maxLatency) throws DbException;
/**
* Returns a retention ack for the given contact, or null if no retention
* ack is due.
*/
RetentionAck generateRetentionAck(ContactId c) throws DbException;
/**
* Returns a retention update for the given contact, for transmission
* over a transport with the given latency. Returns null if no update is
* due.
*/
RetentionUpdate generateRetentionUpdate(ContactId c, long maxLatency)
throws DbException;
/**
* Returns a subscription ack for the given contact, or null if no
* subscription ack is due.
*/
SubscriptionAck generateSubscriptionAck(ContactId c) throws DbException;
/**
* Returns a subscription update for the given contact, for transmission
* over a transport with the given latency. Returns null if no update is
* due.
*/
SubscriptionUpdate generateSubscriptionUpdate(ContactId c, long maxLatency)
throws DbException;
/**
* Returns a batch of transport acks for the given contact, or null if no
* transport acks are due.
*/
Collection<TransportAck> generateTransportAcks(ContactId c)
throws DbException;
/**
* Returns a batch of transport updates for the given contact, for
* transmission over a transport with the given latency. Returns null if no
* updates are due.
*/
Collection<TransportUpdate> generateTransportUpdates(ContactId c,
long maxLatency) throws DbException;
/**
* Returns the status of all groups to which the user subscribes or can
* subscribe, excluding inbox groups.
*/
Collection<GroupStatus> getAvailableGroups() throws DbException;
/** Returns the configuration for the given transport. */
TransportConfig getConfig(TransportId t) throws DbException;
/** Returns the contact with the given ID. */
Contact getContact(ContactId c) throws DbException;
/** Returns all contacts. */
Collection<Contact> getContacts() throws DbException;
/** Returns the group with the given ID, if the user subscribes to it. */
Group getGroup(GroupId g) throws DbException;
/** Returns all groups to which the user subscribes. */
Collection<Group> getGroups() throws DbException;
/**
* Returns the ID of the inbox group for the given contact, or null if no
* inbox group has been set.
*/
GroupId getInboxGroupId(ContactId c) throws DbException;
/**
* Returns the headers of all messages in the inbox group for the given
* contact, or null if no inbox group has been set.
*/
Collection<MessageHeader> getInboxMessageHeaders(ContactId c)
throws DbException;
/**
* Returns the time at which a connection to each contact was last opened
* or closed.
*/
Map<ContactId, Long> getLastConnected() throws DbException;
/** Returns the local pseudonym with the given ID. */
LocalAuthor getLocalAuthor(AuthorId a) throws DbException;
/** Returns all local pseudonyms. */
Collection<LocalAuthor> getLocalAuthors() throws DbException;
/** Returns the local transport properties for all transports. */
Map<TransportId, TransportProperties> getLocalProperties()
throws DbException;
/** Returns the local transport properties for the given transport. */
TransportProperties getLocalProperties(TransportId t) throws DbException;
/** Returns the body of the message with the given ID. */
byte[] getMessageBody(MessageId m) throws DbException;
/** Returns the headers of all messages in the given group. */
Collection<MessageHeader> getMessageHeaders(GroupId g)
throws DbException;
/** Returns true if the given message is marked as read. */
boolean getReadFlag(MessageId m) throws DbException;
/** Returns all remote transport properties for the given transport. */
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
throws DbException;
/** Returns all temporary secrets. */
Collection<TemporarySecret> getSecrets() throws DbException;
/** Returns the maximum latencies of all local transports. */
Map<TransportId, Long> getTransportLatencies() throws DbException;
/** Returns the number of unread messages in each subscribed group. */
Map<GroupId, Integer> getUnreadMessageCounts() throws DbException;
/** Returns the IDs of all contacts to which the given group is visible. */
Collection<ContactId> getVisibility(GroupId g) throws DbException;
/**
* Increments the outgoing connection counter for the given endpoint
* in the given rotation period and returns the old value, or -1 if the
* counter does not exist.
*/
long incrementConnectionCounter(ContactId c, TransportId t, long period)
throws DbException;
/**
* Merges the given configuration with existing configuration for the
* given transport.
*/
void mergeConfig(TransportId t, TransportConfig c) throws DbException;
/**
* Merges the given properties with the existing local properties for the
* given transport.
*/
void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException;
/** Processes an ack from the given contact. */
void receiveAck(ContactId c, Ack a) throws DbException;
/** Processes a message from the given contact. */
void receiveMessage(ContactId c, Message m) throws DbException;
/** Processes an offer from the given contact. */
void receiveOffer(ContactId c, Offer o) throws DbException;
/** Processes a request from the given contact. */
void receiveRequest(ContactId c, Request r) throws DbException;
/** Processes a retention ack from the given contact. */
void receiveRetentionAck(ContactId c, RetentionAck a) throws DbException;
/** Processes a retention update from the given contact. */
void receiveRetentionUpdate(ContactId c, RetentionUpdate u)
throws DbException;
/** Processes a subscription ack from the given contact. */
void receiveSubscriptionAck(ContactId c, SubscriptionAck a)
throws DbException;
/** Processes a subscription update from the given contact. */
void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate u)
throws DbException;
/** Processes a transport ack from the given contact. */
void receiveTransportAck(ContactId c, TransportAck a) throws DbException;
/** Processes a transport update from the given contact. */
void receiveTransportUpdate(ContactId c, TransportUpdate u)
throws DbException;
/** Removes a contact (and all associated state) from the database. */
void removeContact(ContactId c) throws DbException;
/**
* Unsubscribes from a group. Any messages belonging to the group
* are deleted from the database.
*/
void removeGroup(Group g) throws DbException;
/**
* Removes a local pseudonym (and all associated state) from the database.
*/
void removeLocalAuthor(AuthorId a) throws DbException;
/**
* Removes a transport (and any associated configuration and local
* properties) from the database.
*/
void removeTransport(TransportId t) throws DbException;
/**
* Sets the connection reordering window for the given endpoint in the
* given rotation period.
*/
void setConnectionWindow(ContactId c, TransportId t, long period,
long centre, byte[] bitmap) throws DbException;
/**
* Makes a group visible to the given contact, adds it to the contact's
* subscriptions, and sets it as the inbox group for the contact.
*/
public void setInboxGroup(ContactId c, Group g) throws DbException;
/**
* Marks a message as read or unread.
*/
void setReadFlag(MessageId m, boolean read) throws DbException;
/**
* Sets the remote transport properties for the given contact, replacing
* any existing properties.
*/
void setRemoteProperties(ContactId c,
Map<TransportId, TransportProperties> p) throws DbException;
/**
* Makes a group visible to the given set of contacts and invisible to any
* other current or future contacts.
*/
void setVisibility(GroupId g, Collection<ContactId> visible)
throws DbException;
/**
* Makes a group visible to all current and future contacts, or invisible
* to future contacts.
*/
void setVisibleToAll(GroupId g, boolean all) throws DbException;
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.api.db;
import java.io.File;
public interface DatabaseConfig {
boolean databaseExists();
File getDatabaseDirectory();
void setEncryptionKey(byte[] key);
byte[] getEncryptionKey();
long getMaxSize();
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.db;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.google.inject.BindingAnnotation;
/** Annotation for injecting the executor for database tasks. */
@BindingAnnotation
@Target({ FIELD, METHOD, PARAMETER })
@Retention(RUNTIME)
public @interface DatabaseExecutor {}

View File

@@ -0,0 +1,7 @@
package org.briarproject.api.db;
/** Thrown when a database operation is attempted and the database is closed. */
public class DbClosedException extends DbException {
private static final long serialVersionUID = -3679248177625310653L;
}

View File

@@ -0,0 +1,12 @@
package org.briarproject.api.db;
public class DbException extends Exception {
private static final long serialVersionUID = 3706581789209939441L;
public DbException() {}
public DbException(Throwable t) {
super(t);
}
}

View File

@@ -0,0 +1,10 @@
package org.briarproject.api.db;
/**
* Thrown when a duplicate pseudonym is added to the database. This exception
* may occur due to concurrent updates and does not indicate a database error.
*/
public class LocalAuthorExistsException extends DbException {
private static final long serialVersionUID = -1483877298070151673L;
}

View File

@@ -0,0 +1,68 @@
package org.briarproject.api.db;
import org.briarproject.api.Author;
import org.briarproject.api.messaging.GroupId;
import org.briarproject.api.messaging.MessageId;
public class MessageHeader {
private final MessageId id, parent;
private final GroupId groupId;
private final Author author;
private final String contentType;
private final long timestamp;
private final boolean read;
public MessageHeader(MessageId id, MessageId parent, GroupId groupId,
Author author, String contentType, long timestamp, boolean read) {
this.id = id;
this.parent = parent;
this.groupId = groupId;
this.author = author;
this.contentType = contentType;
this.timestamp = timestamp;
this.read = read;
}
/** Returns the message's unique identifier. */
public MessageId getId() {
return id;
}
/**
* Returns the message's parent, or null if this is the first message in a
* thread.
*/
public MessageId getParent() {
return parent;
}
/**
* Returns the unique identifier of the group to which the message belongs.
*/
public GroupId getGroupId() {
return groupId;
}
/**
* Returns the message's author, or null if this is an anonymous message.
*/
public Author getAuthor() {
return author;
}
/** Returns the message's content type. */
public String getContentType() {
return contentType;
}
/** Returns the timestamp created by the message's author. */
public long getTimestamp() {
return timestamp;
}
/** Returns true if the message has been read. */
public boolean isRead() {
return read;
}
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.api.db;
/**
* Thrown when a database operation is attempted for a contact that is not in
* the database. This exception may occur due to concurrent updates and does
* not indicate a database error.
*/
public class NoSuchContactException extends DbException {
private static final long serialVersionUID = -7048538231308207386L;
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.api.db;
/**
* Thrown when a database operation is attempted for a pseudonym that is not in
* the database. This exception may occur due to concurrent updates and does
* not indicate a database error.
*/
public class NoSuchLocalAuthorException extends DbException {
private static final long serialVersionUID = 494398665376703860L;
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.api.db;
/**
* Thrown when a database operation is attempted for a message that is not in
* the database. This exception may occur due to concurrent updates and does
* not indicate a database error.
*/
public class NoSuchMessageException extends DbException {
private static final long serialVersionUID = 9191508339698803848L;
}

View File

@@ -0,0 +1,12 @@
package org.briarproject.api.db;
/**
* Thrown when a database operation is attempted for a group to which the user
* does not subscribe. This exception may occur due to concurrent updates and
* does not indicate a database error.
*/
public class NoSuchSubscriptionException extends DbException {
private static final long serialVersionUID = -5494178507342571697L;
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.api.db;
/**
* Thrown when a database operation is attempted for a transport that is not in
* the database. This exception may occur due to concurrent updates and does
* not indicate a database error.
*/
public class NoSuchTransportException extends DbException {
private static final long serialVersionUID = -6274982612759573100L;
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
/** An event that is broadcast when a contact is added. */
public class ContactAddedEvent extends Event {
private final ContactId contactId;
public ContactAddedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
/** An event that is broadcast when a contact is removed. */
public class ContactRemovedEvent extends Event {
private final ContactId contactId;
public ContactRemovedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,6 @@
package org.briarproject.api.event;
/** An abstract superclass for events. */
public abstract class Event {
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.api.event;
/** An interface for receiving notifications when events occur. */
public interface EventListener {
void eventOccurred(Event e);
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.AuthorId;
/** An event that is broadcast when a local pseudonym is added. */
public class LocalAuthorAddedEvent extends Event {
private final AuthorId authorId;
public LocalAuthorAddedEvent(AuthorId authorId) {
this.authorId = authorId;
}
public AuthorId getAuthorId() {
return authorId;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.AuthorId;
/** An event that is broadcast when a local pseudonym is removed. */
public class LocalAuthorRemovedEvent extends Event {
private final AuthorId authorId;
public LocalAuthorRemovedEvent(AuthorId authorId) {
this.authorId = authorId;
}
public AuthorId getAuthorId() {
return authorId;
}
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.api.event;
import java.util.Collection;
import org.briarproject.api.ContactId;
/**
* An event that is broadcast when the set of subscriptions visible to one or
* more contacts is updated.
*/
public class LocalSubscriptionsUpdatedEvent extends Event {
private final Collection<ContactId> affected;
public LocalSubscriptionsUpdatedEvent(Collection<ContactId> affected) {
this.affected = affected;
}
/** Returns the contacts affected by the update. */
public Collection<ContactId> getAffectedContacts() {
return affected;
}
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.api.event;
/**
* An event that is broadcast when the local transport properties are
* updated.
*/
public class LocalTransportsUpdatedEvent extends Event {
}

View File

@@ -0,0 +1,29 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
import org.briarproject.api.messaging.Group;
/** An event that is broadcast when a message is added to the database. */
public class MessageAddedEvent extends Event {
private final Group group;
private final ContactId contactId;
public MessageAddedEvent(Group group, ContactId contactId) {
this.group = group;
this.contactId = contactId;
}
/** Returns the group to which the message belongs. */
public Group getGroup() {
return group;
}
/**
* Returns the ID of the contact from which the message was received, or
* null if the message was locally generated.
*/
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.api.event;
/**
* An event that is broadcast when one or messages expire from the database,
* potentially changing the database's retention time.
*/
public class MessageExpiredEvent extends Event {
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
/** An event that is broadcast when a message is requested by a contact. */
public class MessageRequestedEvent extends Event {
private final ContactId contactId;
public MessageRequestedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
/**
* An event that is broadcast when a message is received from or offered by a
* contact and needs to be acknowledged.
*/
public class MessageToAckEvent extends Event {
private final ContactId contactId;
public MessageToAckEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
/**
* An event that is broadcast when a message is offered by a contact and needs
* to be requested.
*/
public class MessageToRequestEvent extends Event {
private final ContactId contactId;
public MessageToRequestEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
/**
* An event that is broadcast when the retention time of a contact's database
* changes.
*/
public class RemoteRetentionTimeUpdatedEvent extends Event {
private final ContactId contactId;
public RemoteRetentionTimeUpdatedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
/** An event that is broadcast when a contact's subscriptions are updated. */
public class RemoteSubscriptionsUpdatedEvent extends Event {
private final ContactId contactId;
public RemoteSubscriptionsUpdatedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,28 @@
package org.briarproject.api.event;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
/**
* An event that is broadcast when a contact's remote transport properties
* are updated.
*/
public class RemoteTransportsUpdatedEvent extends Event {
private final ContactId contactId;
private final TransportId transportId;
public RemoteTransportsUpdatedEvent(ContactId contactId,
TransportId transportId) {
this.contactId = contactId;
this.transportId = transportId;
}
public ContactId getContactId() {
return contactId;
}
public TransportId getTransportId() {
return transportId;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.messaging.Group;
/** An event that is broadcast when the user subscribes to a group. */
public class SubscriptionAddedEvent extends Event {
private final Group group;
public SubscriptionAddedEvent(Group group) {
this.group = group;
}
public Group getGroup() {
return group;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.messaging.Group;
/** An event that is broadcast when the user unsubscribes from a group. */
public class SubscriptionRemovedEvent extends Event {
private final Group group;
public SubscriptionRemovedEvent(Group group) {
this.group = group;
}
public Group getGroup() {
return group;
}
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.api.event;
import org.briarproject.api.TransportId;
/** An event that is broadcast when a transport is added. */
public class TransportAddedEvent extends Event {
private final TransportId transportId;
private final long maxLatency;
public TransportAddedEvent(TransportId transportId, long maxLatency) {
this.transportId = transportId;
this.maxLatency = maxLatency;
}
public TransportId getTransportId() {
return transportId;
}
public long getMaxLatency() {
return maxLatency;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.event;
import org.briarproject.api.TransportId;
/** An event that is broadcast when a transport is removed. */
public class TransportRemovedEvent extends Event {
private final TransportId transportId;
public TransportRemovedEvent(TransportId transportId) {
this.transportId = transportId;
}
public TransportId getTransportId() {
return transportId;
}
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.api.invitation;
public interface InvitationConstants {
long CONNECTION_TIMEOUT = 30 * 1000; // Milliseconds
long CONFIRMATION_TIMEOUT = 60 * 1000; // Milliseconds
int CODE_BITS = 19; // Codes must fit into six decimal digits
int HASH_LENGTH = 48; // Bytes
int MAX_PUBLIC_KEY_LENGTH = 97; // Bytes
}

View File

@@ -0,0 +1,47 @@
package org.briarproject.api.invitation;
/**
* An interface for receiving updates about the state of an
* {@link InvitationTask}.
*/
public interface InvitationListener {
/** Called if a connection to the remote peer is established. */
void connectionSucceeded();
/**
* Called if a connection to the remote peer cannot be established. This
* indicates that the protocol has ended unsuccessfully.
*/
void connectionFailed();
/** Called if key agreement with the remote peer succeeds. */
void keyAgreementSucceeded(int localCode, int remoteCode);
/**
* Called if key agreement with the remote peer fails or the connection is
* lost. This indicates that the protocol has ended unsuccessfully.
*/
void keyAgreementFailed();
/** Called if the remote peer's confirmation check succeeds. */
void remoteConfirmationSucceeded();
/**
* Called if remote peer's confirmation check fails or the connection is
* lost. This indicates that the protocol has ended unsuccessfully.
*/
void remoteConfirmationFailed();
/**
* Called if the exchange of pseudonyms succeeds. This indicates that the
* protocol has ended successfully.
*/
void pseudonymExchangeSucceeded(String remoteName);
/**
* Called if the exchange of pseudonyms fails or the connection is lost.
* This indicates that the protocol has ended unsuccessfully.
*/
void pseudonymExchangeFailed();
}

View File

@@ -0,0 +1,73 @@
package org.briarproject.api.invitation;
public class InvitationState {
private final int localInvitationCode, remoteInvitationCode;
private final int localConfirmationCode, remoteConfirmationCode;
private final boolean connected, connectionFailed;
private final boolean localCompared, remoteCompared;
private final boolean localMatched, remoteMatched;
private final String contactName;
public InvitationState(int localInvitationCode, int remoteInvitationCode,
int localConfirmationCode, int remoteConfirmationCode,
boolean connected, boolean connectionFailed, boolean localCompared,
boolean remoteCompared, boolean localMatched,
boolean remoteMatched, String contactName) {
this.localInvitationCode = localInvitationCode;
this.remoteInvitationCode = remoteInvitationCode;
this.localConfirmationCode = localConfirmationCode;
this.remoteConfirmationCode = remoteConfirmationCode;
this.connected = connected;
this.connectionFailed = connectionFailed;
this.localCompared = localCompared;
this.remoteCompared = remoteCompared;
this.localMatched = localMatched;
this.remoteMatched = remoteMatched;
this.contactName = contactName;
}
public int getLocalInvitationCode() {
return localInvitationCode;
}
public int getRemoteInvitationCode() {
return remoteInvitationCode;
}
public int getLocalConfirmationCode() {
return localConfirmationCode;
}
public int getRemoteConfirmationCode() {
return remoteConfirmationCode;
}
public boolean getConnected() {
return connected;
}
public boolean getConnectionFailed() {
return connectionFailed;
}
public boolean getLocalCompared() {
return localCompared;
}
public boolean getRemoteCompared() {
return remoteCompared;
}
public boolean getLocalMatched() {
return localMatched;
}
public boolean getRemoteMatched() {
return remoteMatched;
}
public String getContactName() {
return contactName;
}
}

View File

@@ -0,0 +1,29 @@
package org.briarproject.api.invitation;
/** A task for exchanging invitations with a remote peer. */
public interface InvitationTask {
/**
* Adds a listener to be informed of state changes and returns the
* task's current state.
*/
InvitationState addListener(InvitationListener l);
/** Removes the given listener. */
void removeListener(InvitationListener l);
/** Asynchronously starts the connection process. */
void connect();
/**
* Asynchronously informs the remote peer that the local peer's
* confirmation codes matched.
*/
void localConfirmationSucceeded();
/**
* Asynchronously informs the remote peer that the local peer's
* confirmation codes did not match.
*/
void localConfirmationFailed();
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.api.invitation;
import org.briarproject.api.AuthorId;
/** Creates tasks for exchanging invitations with remote peers. */
public interface InvitationTaskFactory {
/** Creates a task using the given pseudonym and invitation codes. */
InvitationTask createTask(AuthorId localAuthorId, int localCode,
int remoteCode);
}

View File

@@ -0,0 +1,37 @@
package org.briarproject.api.lifecycle;
import java.util.concurrent.ExecutorService;
public interface LifecycleManager {
/** Registers a {@link Service} to be started and stopped. */
public void register(Service s);
/**
* Registers an {@link java.util.concurrent.ExecutorService ExecutorService}
* to be shut down.
*/
public void registerForShutdown(ExecutorService e);
/** Starts any registered {@link Service}s. */
public void startServices();
/**
* Stops any registered {@link Service}s and shuts down any registered
* {@link java.util.concurrent.ExecutorService ExecutorService}s.
*/
public void stopServices();
/** Waits for the database to be opened before returning. */
public void waitForDatabase() throws InterruptedException;
/** Waits for all registered {@link Service}s to start before returning. */
public void waitForStartup() throws InterruptedException;
/**
* Waits for all registered {@link Service}s to stop and all registered
* {@link java.util.concurrent.ExecutorService ExecutorService}s to shut
* down before returning.
*/
public void waitForShutdown() throws InterruptedException;
}

View File

@@ -0,0 +1,10 @@
package org.briarproject.api.lifecycle;
public interface Service {
/** Starts the service and returns true if it started successfully. */
public boolean start();
/** Stops the service and returns true if it stopped successfully. */
public boolean stop();
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.api.lifecycle;
public interface ShutdownManager {
/**
* Registers a hook to be run when the JVM shuts down and returns a handle
* that can be used to remove the hook.
*/
int addShutdownHook(Runnable hook);
/**
* Removes the shutdown hook identified by the given handle and returns
* true if the hook was removed.
*/
boolean removeShutdownHook(int handle);
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.api.messaging;
import java.util.Collection;
/** A packet acknowledging receipt of one or more {@link Message}s. */
public class Ack {
private final Collection<MessageId> acked;
public Ack(Collection<MessageId> acked) {
this.acked = acked;
}
/** Returns the identifiers of the acknowledged messages. */
public Collection<MessageId> getMessageIds() {
return acked;
}
}

View File

@@ -0,0 +1,43 @@
package org.briarproject.api.messaging;
/** A group to which users may subscribe. */
public class Group {
private final GroupId id;
private final String name;
private final byte[] salt;
public Group(GroupId id, String name, byte[] salt) {
this.id = id;
this.name = name;
this.salt = salt;
}
/** Returns the group's unique identifier. */
public GroupId getId() {
return id;
}
/** Returns the group's name. */
public String getName() {
return name;
}
/**
* Returns the salt used to distinguish the group from other groups with
* the same name.
*/
public byte[] getSalt() {
return salt;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof Group && id.equals(((Group) o).id);
}
}

View File

@@ -0,0 +1,10 @@
package org.briarproject.api.messaging;
public interface GroupFactory {
/** Creates a group with the given name and a random salt. */
Group createGroup(String name);
/** Creates a group with the given name and salt. */
Group createGroup(String name, byte[] salt);
}

View File

@@ -0,0 +1,22 @@
package org.briarproject.api.messaging;
import java.util.Arrays;
import org.briarproject.api.UniqueId;
/**
* Type-safe wrapper for a byte array that uniquely identifies a {@link Group}.
*/
public class GroupId extends UniqueId {
public GroupId(byte[] id) {
super(id);
}
@Override
public boolean equals(Object o) {
if(o instanceof GroupId)
return Arrays.equals(id, ((GroupId) o).id);
return false;
}
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.api.messaging;
public class GroupStatus {
private final Group group;
private final boolean subscribed, visibleToAll;
public GroupStatus(Group group, boolean subscribed, boolean visibleToAll) {
this.group = group;
this.subscribed = subscribed;
this.visibleToAll = visibleToAll;
}
public Group getGroup() {
return group;
}
public boolean isSubscribed() {
return subscribed;
}
public boolean isVisibleToAll() {
return visibleToAll;
}
}

View File

@@ -0,0 +1,42 @@
package org.briarproject.api.messaging;
import org.briarproject.api.Author;
public interface Message {
/** Returns the message's unique identifier. */
MessageId getId();
/**
* Returns the identifier of the message's parent, or null if this is the
* first message in a thread.
*/
MessageId getParent();
/**
* Returns the {@link Group} to which the message belongs, or null if this
* is a private message.
*/
Group getGroup();
/**
* Returns the message's {@link org.briarproject.api.Author Author}, or null
* if this is an anonymous message.
*/
Author getAuthor();
/** Returns the message's content type. */
String getContentType();
/** Returns the message's timestamp. */
long getTimestamp();
/** Returns the serialised message. */
byte[] getSerialised();
/** Returns the offset of the message body within the serialised message. */
int getBodyStart();
/** Returns the length of the message body in bytes. */
int getBodyLength();
}

View File

@@ -0,0 +1,19 @@
package org.briarproject.api.messaging;
import java.io.IOException;
import java.security.GeneralSecurityException;
import org.briarproject.api.Author;
import org.briarproject.api.crypto.PrivateKey;
public interface MessageFactory {
Message createAnonymousMessage(MessageId parent, Group group,
String contentType, long timestamp, byte[] body) throws IOException,
GeneralSecurityException;
Message createPseudonymousMessage(MessageId parent, Group group,
Author author, PrivateKey privateKey, String contentType,
long timestamp, byte[] body) throws IOException,
GeneralSecurityException;
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.api.messaging;
import java.util.Arrays;
import org.briarproject.api.UniqueId;
/**
* Type-safe wrapper for a byte array that uniquely identifies a
* {@link Message}.
*/
public class MessageId extends UniqueId {
public MessageId(byte[] id) {
super(id);
}
@Override
public boolean equals(Object o) {
if(o instanceof MessageId)
return Arrays.equals(id, ((MessageId) o).id);
return false;
}
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.api.messaging;
import java.security.GeneralSecurityException;
/** Verifies the signatures on an {@link UnverifiedMessage}. */
public interface MessageVerifier {
Message verifyMessage(UnverifiedMessage m) throws GeneralSecurityException;
}

View File

@@ -0,0 +1,45 @@
package org.briarproject.api.messaging;
import static org.briarproject.api.transport.TransportConstants.MIN_CONNECTION_LENGTH;
public interface MessagingConstants {
/**
* The maximum length of a serialised packet in bytes. To allow for future
* changes in the protocol, this is smaller than the minimum connection
* length minus the maximum encryption and authentication overhead.
*/
int MAX_PACKET_LENGTH = MIN_CONNECTION_LENGTH / 2;
/** The maximum number of public groups a user may subscribe to. */
int MAX_SUBSCRIPTIONS = 3000;
/** The maximum length of a group's name in UTF-8 bytes. */
int MAX_GROUP_NAME_LENGTH = 50;
/** The length of a group's random salt in bytes. */
int GROUP_SALT_LENGTH = 32;
/**
* The maximum length of a message body in bytes. To allow for future
* changes in the protocol, this is smaller than the maximum packet length
* even when all the message's other fields have their maximum lengths.
*/
int MAX_BODY_LENGTH = MAX_PACKET_LENGTH - 1024;
/** The maximum length of a message's content type in UTF-8 bytes. */
int MAX_CONTENT_TYPE_LENGTH = 50;
/** The maximum length of a message's subject line in UTF-8 bytes. */
int MAX_SUBJECT_LENGTH = 100;
/** The length of a message's random salt in bytes. */
int MESSAGE_SALT_LENGTH = 32;
/**
* When calculating the retention time of the database, the timestamp of
* the oldest message in the database is rounded down to a multiple of
* this value to avoid revealing the presence of any particular message.
*/
int RETENTION_GRANULARITY = 60 * 1000; // 1 minute
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.api.messaging;
import java.util.Collection;
/** A packet offering the recipient one or more {@link Messages}. */
public class Offer {
private final Collection<MessageId> offered;
public Offer(Collection<MessageId> offered) {
this.offered = offered;
}
/** Returns the identifiers of the offered messages. */
public Collection<MessageId> getMessageIds() {
return offered;
}
}

View File

@@ -0,0 +1,38 @@
package org.briarproject.api.messaging;
import java.io.IOException;
public interface PacketReader {
boolean eof() throws IOException;
boolean hasAck() throws IOException;
Ack readAck() throws IOException;
boolean hasMessage() throws IOException;
UnverifiedMessage readMessage() throws IOException;
boolean hasOffer() throws IOException;
Offer readOffer() throws IOException;
boolean hasRequest() throws IOException;
Request readRequest() throws IOException;
boolean hasRetentionAck() throws IOException;
RetentionAck readRetentionAck() throws IOException;
boolean hasRetentionUpdate() throws IOException;
RetentionUpdate readRetentionUpdate() throws IOException;
boolean hasSubscriptionAck() throws IOException;
SubscriptionAck readSubscriptionAck() throws IOException;
boolean hasSubscriptionUpdate() throws IOException;
SubscriptionUpdate readSubscriptionUpdate() throws IOException;
boolean hasTransportAck() throws IOException;
TransportAck readTransportAck() throws IOException;
boolean hasTransportUpdate() throws IOException;
TransportUpdate readTransportUpdate() throws IOException;
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.api.messaging;
import java.io.InputStream;
public interface PacketReaderFactory {
PacketReader createPacketReader(InputStream in);
}

View File

@@ -0,0 +1,34 @@
package org.briarproject.api.messaging;
import java.io.IOException;
public interface PacketWriter {
int getMaxMessagesForRequest(long capacity);
int getMaxMessagesForOffer(long capacity);
void writeAck(Ack a) throws IOException;
void writeMessage(byte[] raw) throws IOException;
void writeOffer(Offer o) throws IOException;
void writeRequest(Request r) throws IOException;
void writeRetentionAck(RetentionAck a) throws IOException;
void writeRetentionUpdate(RetentionUpdate u) throws IOException;
void writeSubscriptionAck(SubscriptionAck a) throws IOException;
void writeSubscriptionUpdate(SubscriptionUpdate u) throws IOException;
void writeTransportAck(TransportAck a) throws IOException;
void writeTransportUpdate(TransportUpdate u) throws IOException;
void flush() throws IOException;
void close() throws IOException;
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.api.messaging;
import java.io.OutputStream;
public interface PacketWriterFactory {
PacketWriter createPacketWriter(OutputStream out, boolean flush);
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.api.messaging;
import java.util.Collection;
/** A packet requesting one or more {@link Message}s from the recipient. */
public class Request {
private final Collection<MessageId> requested;
public Request(Collection<MessageId> requested) {
this.requested = requested;
}
/** Returns the identifiers of the requested messages. */
public Collection<MessageId> getMessageIds() {
return requested;
}
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.api.messaging;
/** A packet acknowledging a (@link RetentionUpdate} */
public class RetentionAck {
private final long version;
public RetentionAck(long version) {
this.version = version;
}
/** Returns the version number of the acknowledged update. */
public long getVersion() {
return version;
}
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.api.messaging;
/**
* A packet updating the recipient's view of the retention time of the sender's
* database.
*/
public class RetentionUpdate {
private final long retention, version;
public RetentionUpdate(long retention, long version) {
this.retention = retention;
this.version = version;
}
public long getRetentionTime() {
return retention;
}
public long getVersion() {
return version;
}
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.api.messaging;
/** A packet acknowledging a {@link SubscriptionUpdate}. */
public class SubscriptionAck {
private final long version;
public SubscriptionAck(long version) {
this.version = version;
}
/** Returns the version number of the acknowledged update. */
public long getVersion() {
return version;
}
}

View File

@@ -0,0 +1,28 @@
package org.briarproject.api.messaging;
import java.util.Collection;
/** A packet updating the recipient's view of the sender's subscriptions. */
public class SubscriptionUpdate {
private final Collection<Group> groups;
private final long version;
public SubscriptionUpdate(Collection<Group> groups, long version) {
this.groups = groups;
this.version = version;
}
/**
* Returns the groups to which the sender subscribes, and which the sender
* has made visible to the recipient.
*/
public Collection<Group> getGroups() {
return groups;
}
/** Returns the update's version number. */
public long getVersion() {
return version;
}
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.api.messaging;
import org.briarproject.api.TransportId;
/** A packet acknowledging a {@link TransportUpdate}. */
public class TransportAck {
private final TransportId id;
private final long version;
public TransportAck(TransportId id, long version) {
this.id = id;
this.version = version;
}
/** Returns the identifier of the updated transport. */
public TransportId getId() {
return id;
}
/** Returns the version number of the acknowledged update. */
public long getVersion() {
return version;
}
}

View File

@@ -0,0 +1,36 @@
package org.briarproject.api.messaging;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
/**
* A packet updating the recipient's view of the sender's transport properties.
*/
public class TransportUpdate {
private final TransportId id;
private final TransportProperties properties;
private final long version;
public TransportUpdate(TransportId id, TransportProperties properties,
long version) {
this.id = id;
this.properties = properties;
this.version = version;
}
/** Returns the identifier of the updated transport. */
public TransportId getId() {
return id;
}
/** Returns the transport's updated properties. */
public TransportProperties getProperties() {
return properties;
}
/** Returns the update's version number. */
public long getVersion() {
return version;
}
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.api.messaging;
/** Struct identifiers for encoding and decoding protocol objects. */
public interface Types {
int AUTHOR = 0;
int GROUP = 1;
int ACK = 2;
int MESSAGE = 3;
int OFFER = 4;
int REQUEST = 5;
int RETENTION_ACK = 6;
int RETENTION_UPDATE = 7;
int SUBSCRIPTION_ACK = 8;
int SUBSCRIPTION_UPDATE = 9;
int TRANSPORT_ACK = 10;
int TRANSPORT_UPDATE = 11;
}

View File

@@ -0,0 +1,94 @@
package org.briarproject.api.messaging;
import org.briarproject.api.Author;
/** A {@link Message} that has not yet had its signatures (if any) verified. */
public class UnverifiedMessage {
private final MessageId parent;
private final Group group;
private final Author author;
private final String contentType;
private final long timestamp;
private final byte[] raw, signature;
private final int bodyStart, bodyLength, signedLength;
public UnverifiedMessage(MessageId parent, Group group, Author author,
String contentType, long timestamp, byte[] raw, byte[] signature,
int bodyStart, int bodyLength, int signedLength) {
this.parent = parent;
this.group = group;
this.author = author;
this.contentType = contentType;
this.timestamp = timestamp;
this.raw = raw;
this.signature = signature;
this.bodyStart = bodyStart;
this.bodyLength = bodyLength;
this.signedLength = signedLength;
}
/**
* Returns the identifier of the message's parent, or null if this is the
* first message in a thread.
*/
public MessageId getParent() {
return parent;
}
/**
* Returns the {@link Group} to which the message belongs, or null if this
* is a private message.
*/
public Group getGroup() {
return group;
}
/**
* Returns the message's {@link org.briarproject.api.Author Author}, or null
* if this is an anonymous message.
*/
public Author getAuthor() {
return author;
}
/** Returns the message's content type. */
public String getContentType() {
return contentType;
}
/** Returns the message's timestamp. */
public long getTimestamp() {
return timestamp;
}
/** Returns the serialised message. */
public byte[] getSerialised() {
return raw;
}
/**
* Returns the author's signature, or null if this is an anonymous message.
*/
public byte[] getSignature() {
return signature;
}
/** Returns the offset of the message body within the serialised message. */
public int getBodyStart() {
return bodyStart;
}
/** Returns the length of the message body in bytes. */
public int getBodyLength() {
return bodyLength;
}
/**
* Returns the length in bytes of the data covered by the author's
* signature.
*/
public int getSignedLength() {
return signedLength;
}
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.api.messaging.duplex;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.transport.ConnectionContext;
public interface DuplexConnectionFactory {
void createIncomingConnection(ConnectionContext ctx,
DuplexTransportConnection d);
void createOutgoingConnection(ContactId c, TransportId t,
DuplexTransportConnection d);
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.api.messaging.simplex;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.simplex.SimplexTransportReader;
import org.briarproject.api.plugins.simplex.SimplexTransportWriter;
import org.briarproject.api.transport.ConnectionContext;
public interface SimplexConnectionFactory {
void createIncomingConnection(ConnectionContext ctx,
SimplexTransportReader r);
void createOutgoingConnection(ContactId c, TransportId t,
SimplexTransportWriter w);
}

View File

@@ -0,0 +1,47 @@
package org.briarproject.api.plugins;
import java.io.IOException;
import java.util.Collection;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
public interface Plugin {
/** Returns the plugin's transport identifier. */
TransportId getId();
/** Returns a label for looking up the plugin's translated name. */
String getName();
/** Returns the transport's maximum frame length in bytes. */
int getMaxFrameLength();
/** Returns the transport's maximum latency in milliseconds. */
long getMaxLatency();
/** Starts the plugin and returns true if it started successfully. */
boolean start() throws IOException;
/** Stops the plugin. */
void stop() throws IOException;
/**
* Returns true if the plugin's {@link #poll(Collection)} method should be
* called periodically to attempt to establish connections.
*/
boolean shouldPoll();
/**
* Returns the desired interval in milliseconds between calls to the
* plugin's {@link #poll(Collection)} method.
*/
long getPollingInterval();
/**
* Attempts to establish connections to contacts, passing any created
* connections to the callback. To avoid creating redundant connections,
* the plugin may exclude the given contacts from polling.
*/
void poll(Collection<ContactId> connected);
}

View File

@@ -0,0 +1,52 @@
package org.briarproject.api.plugins;
import java.util.Map;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportConfig;
import org.briarproject.api.TransportProperties;
/**
* An interface through which a transport plugin interacts with the rest of
* the application.
*/
public interface PluginCallback {
/** Returns the plugin's configuration. */
TransportConfig getConfig();
/** Returns the plugin's local transport properties. */
TransportProperties getLocalProperties();
/** Returns the plugin's remote transport properties. */
Map<ContactId, TransportProperties> getRemoteProperties();
/** Merges the given configuration with the plugin's configuration. */
void mergeConfig(TransportConfig c);
/**
* Merges the given properties with the plugin's local transport properties.
*/
void mergeLocalProperties(TransportProperties p);
/**
* Presents the user with a choice among two or more named options and
* returns the user's response. The message may consist of a translatable
* format string and arguments.
* @return an index into the array of options indicating the user's choice,
* or -1 if the user cancelled the choice.
*/
int showChoice(String[] options, String... message);
/**
* Asks the user to confirm an action and returns the user's response. The
* message may consist of a translatable format string and arguments.
*/
boolean showConfirmationMessage(String... message);
/**
* Shows a message to the user. The message may consist of a translatable
* format string and arguments.
*/
void showMessage(String... message);
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.api.plugins;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.google.inject.BindingAnnotation;
/** Annotation for injecting the executor used by transport plugins. */
@BindingAnnotation
@Target({ FIELD, METHOD, PARAMETER })
@Retention(RUNTIME)
public @interface PluginExecutor {}

View File

@@ -0,0 +1,16 @@
package org.briarproject.api.plugins;
import java.util.Collection;
import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
/**
* Responsible for starting transport plugins at startup, stopping them at
* shutdown, and providing access to plugins for exchanging invitations.
*/
public interface PluginManager extends Service {
/** Returns any running duplex plugins that support invitations. */
Collection<DuplexPlugin> getInvitationPlugins();
}

Some files were not shown because too many files have changed in this diff Show More