Moved API classes into a separate project to enforce dependency rules.

This commit is contained in:
akwizgran
2012-12-05 22:19:12 +00:00
parent 5204e0b907
commit f5626bee05
124 changed files with 106 additions and 27 deletions

21
briar-api/src/build.xml Normal file
View File

@@ -0,0 +1,21 @@
<project name='briar-api' default='compile'>
<fileset id='api-jars' dir='../libs'>
<include name='*.jar'/>
</fileset>
<path id='api-classes'>
<pathelement location='../build'/>
</path>
<target name='clean'>
<delete dir='../build'/>
</target>
<target name='compile'>
<mkdir dir='../build'/>
<javac srcdir='.' destdir='../build' source='1.5'
includeantruntime='false' debug='off'>
<classpath>
<fileset refid='api-jars'/>
<path refid='api-classes'/>
</classpath>
</javac>
</target>
</project>

View File

@@ -0,0 +1,34 @@
package net.sf.briar.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,29 @@
package net.sf.briar.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 boolean equals(Object o) {
if(o instanceof ContactId) return id == ((ContactId) o).id;
return false;
}
@Override
public int hashCode() {
return id;
}
}

View File

@@ -0,0 +1,9 @@
package net.sf.briar.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,6 @@
package net.sf.briar.api;
/** The ratings that may be applied to an author in peer moderation. */
public enum Rating {
BAD, UNRATED, GOOD
}

View File

@@ -0,0 +1,17 @@
package net.sf.briar.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() {
super();
}
}

View File

@@ -0,0 +1,17 @@
package net.sf.briar.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() {
super();
}
}

View File

@@ -0,0 +1,16 @@
package net.sf.briar.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. */
<V> V run(Callable<V> c) throws InterruptedException, ExecutionException;
void shutdown();
}

View File

@@ -0,0 +1,11 @@
package net.sf.briar.api.clock;
/**
* An interface for time-related system functions that allows them to be
* replaced for testing.
*/
public interface Clock {
/** @see {@link java.lang.System#currentTimeMillis()} */
long currentTimeMillis();
}

View File

@@ -0,0 +1,9 @@
package net.sf.briar.api.clock;
/** Default clock implementation. */
public class SystemClock implements Clock {
public long currentTimeMillis() {
return System.currentTimeMillis();
}
}

View File

@@ -0,0 +1,29 @@
package net.sf.briar.api.clock;
import java.util.TimerTask;
/** Default timer implementation. */
public class SystemTimer implements Timer {
private final java.util.Timer timer = new java.util.Timer();
public void cancel() {
timer.cancel();
}
public int purge() {
return timer.purge();
}
public void schedule(TimerTask task, long delay) {
timer.schedule(task, delay);
}
public void schedule(TimerTask task, long delay, long period) {
timer.schedule(task, delay, period);
}
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
timer.scheduleAtFixedRate(task, delay, period);
}
}

View File

@@ -0,0 +1,27 @@
package net.sf.briar.api.clock;
import java.util.TimerTask;
/**
* A wrapper around a {@link java.util.Timer} that allows it to be replaced for
* testing.
*/
public interface Timer {
/** @see {@link java.util.Timer#cancel()} */
void cancel();
/** @see {@link java.util.Timer#purge()} */
int purge();
/** @see {@link java.util.Timer#schedule(TimerTask, long)} */
void schedule(TimerTask task, long delay);
/** @see {@link java.util.Timer#schedule(TimerTask, long, long)} */
void schedule(TimerTask task, long delay, long period);
/**
* @see {@link java.util.Timer#scheduleAtFixedRate(TimerTask, long, long)}
*/
void scheduleAtFixedRate(TimerTask task, long delay, long period);
}

View File

@@ -0,0 +1,29 @@
package net.sf.briar.api.crypto;
import java.security.InvalidKeyException;
import java.security.Key;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
/**
* A wrapper for a provider-dependent cipher class, since javax.crypto.Cipher
* doesn't support additional authenticated data until Java 7.
*/
public interface AuthenticatedCipher {
/**
* Initializes this cipher with a key, an initialisation vector (IV) and
* additional authenticated data (AAD).
*/
void init(int opmode, Key key, byte[] iv, byte[] aad)
throws InvalidKeyException;
/** Encrypts or decrypts data in a single-part operation. */
int doFinal(byte[] input, int inputOff, int len, byte[] output,
int outputOff) throws IllegalBlockSizeException,
BadPaddingException;
/** Returns the length of the message authenticated code (MAC) in bytes. */
int getMacLength();
}

View File

@@ -0,0 +1,81 @@
package net.sf.briar.api.crypto;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.SecureRandom;
import java.security.Signature;
import javax.crypto.Cipher;
public interface CryptoComponent {
/**
* Derives a tag key from the given temporary secret.
* @param alice indicates whether the key is for connections initiated by
* Alice or Bob.
*/
ErasableKey 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.
*/
ErasableKey deriveFrameKey(byte[] secret, long connection, boolean alice,
boolean initiator);
/**
* Derives an initial shared 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[] deriveInitialSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
/**
* Generates a random invitation code.
*/
int generateInvitationCode();
/**
* Derives two confirmation codes from the given initial shared 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 a temporary secret for the given period from the previous
* period's temporary secret.
*/
byte[] deriveNextSecret(byte[] secret, long period);
/** Encodes the pseudo-random tag that is used to recognise a connection. */
void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
long connection);
KeyPair generateAgreementKeyPair();
KeyParser getAgreementKeyParser();
KeyPair generateSignatureKeyPair();
KeyParser getSignatureKeyParser();
ErasableKey generateTestKey();
MessageDigest getMessageDigest();
PseudoRandom getPseudoRandom(int seed1, int seed2);
SecureRandom getSecureRandom();
Cipher getTagCipher();
AuthenticatedCipher getFrameCipher();
Signature getSignature();
}

View File

@@ -0,0 +1,12 @@
package net.sf.briar.api.crypto;
import javax.crypto.SecretKey;
public interface ErasableKey extends SecretKey {
/** Returns a copy of the key. */
ErasableKey copy();
/** Erases the key from memory. */
void erase();
}

View File

@@ -0,0 +1,31 @@
package net.sf.briar.api.crypto;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.transport.ConnectionContext;
import net.sf.briar.api.transport.ContactTransport;
public interface KeyManager {
/**
* Starts the key manager and returns true if it started successfully. This
* method must be called after the database has been opened.
*/
boolean start();
/** Stops the key manager. */
void stop();
/**
* 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 a contact transport has been added. The initial secret
* is erased before returning.
*/
void contactTransportAdded(ContactTransport ct, byte[] initialSecret);
}

View File

@@ -0,0 +1,9 @@
package net.sf.briar.api.crypto;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
public interface KeyParser {
PublicKey parsePublicKey(byte[] encodedKey) throws InvalidKeySpecException;
}

View File

@@ -0,0 +1,32 @@
package net.sf.briar.api.crypto;
/**
* A wrapper around a {@link java.security.MessageDigest} that allows it to be
* replaced for testing.
*/
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,14 @@
package net.sf.briar.api.crypto;
/**
* Encapsulates a password. Implementations may keep the password encrypted in
* memory to reduce the chances of writing it to the swapfile in plaintext.
*/
public interface Password {
/**
* Returns the password as a character array, which should be filled with
* zeroes as soon as it has been used.
*/
char[] getPassword();
}

View File

@@ -0,0 +1,6 @@
package net.sf.briar.api.crypto;
public interface PseudoRandom {
byte[] nextBytes(int bytes);
}

View File

@@ -0,0 +1,225 @@
package net.sf.briar.api.db;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.Rating;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.db.event.DatabaseListener;
import net.sf.briar.api.protocol.Ack;
import net.sf.briar.api.protocol.AuthorId;
import net.sf.briar.api.protocol.Batch;
import net.sf.briar.api.protocol.Group;
import net.sf.briar.api.protocol.GroupId;
import net.sf.briar.api.protocol.Message;
import net.sf.briar.api.protocol.MessageId;
import net.sf.briar.api.protocol.Offer;
import net.sf.briar.api.protocol.RawBatch;
import net.sf.briar.api.protocol.Request;
import net.sf.briar.api.protocol.SubscriptionUpdate;
import net.sf.briar.api.protocol.Transport;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.api.transport.ContactTransport;
import net.sf.briar.api.transport.TemporarySecret;
/**
* Encapsulates the database implementation and exposes high-level operations
* to other components.
*/
public interface DatabaseComponent {
/**
* Opens the database.
* @param resume true to reopen an existing database or false to create a
* new one.
*/
void open(boolean resume) 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(DatabaseListener d);
/** Removes a listener. */
void removeListener(DatabaseListener d);
/**
* Adds a new contact to the database and returns an ID for the contact.
*/
ContactId addContact() throws DbException;
/** Adds a contact transport to the database. */
void addContactTransport(ContactTransport ct) throws DbException;
/** Adds a locally generated group message to the database. */
void addLocalGroupMessage(Message m) throws DbException;
/** Adds a locally generated private message to the database. */
void addLocalPrivateMessage(Message m, ContactId c) throws DbException;
/**
* Stores the given temporary secrets and deletes any secrets that have
* been made obsolete.
*/
void addSecrets(Collection<TemporarySecret> secrets) throws DbException;
/**
* Generates an acknowledgement for the given contact. Returns null if
* there are no batches to acknowledge.
*/
Ack generateAck(ContactId c, int maxBatches) throws DbException;
/**
* Generates a batch of messages for the given contact. Returns null if
* there are no sendable messages that fit in the given capacity.
*/
RawBatch generateBatch(ContactId c, int capacity) throws DbException;
/**
* Generates a batch of messages for the given contact from the given
* collection of requested messages. Any messages that were either added to
* the batch, or were considered but are no longer sendable to the contact,
* are removed from the collection of requested messages before returning.
* Returns null if there are no sendable messages that fit in the given
* capacity.
*/
RawBatch generateBatch(ContactId c, int capacity,
Collection<MessageId> requested) throws DbException;
/**
* Generates an offer for the given contact. Returns null if there are no
* messages to offer.
*/
Offer generateOffer(ContactId c, int maxMessages) throws DbException;
/**
* Generates a subscription update for the given contact. Returns null if
* an update is not due.
*/
SubscriptionUpdate generateSubscriptionUpdate(ContactId c)
throws DbException;
/**
* Generates a transport update for the given contact. Returns null if an
* update is not due.
*/
TransportUpdate generateTransportUpdate(ContactId c) throws DbException;
/** Returns the configuration for the given transport. */
TransportConfig getConfig(TransportId t) throws DbException;
/** Returns the IDs of all contacts. */
Collection<ContactId> getContacts() throws DbException;
/** Returns the local transport properties for the given transport. */
TransportProperties getLocalProperties(TransportId t) throws DbException;
/** Returns all local transports. */
Collection<Transport> getLocalTransports() throws DbException;
/** Returns the headers of all messages in the given group. */
Collection<MessageHeader> getMessageHeaders(GroupId g) throws DbException;
/** Returns the user's rating for the given author. */
Rating getRating(AuthorId a) 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 set of groups to which the user subscribes. */
Collection<Group> getSubscriptions() throws DbException;
/** Returns the number of unread messages in each subscribed group. */
Map<GroupId, Integer> getUnreadMessageCounts() throws DbException;
/** Returns the contacts to which the given group is visible. */
Collection<ContactId> getVisibility(GroupId g) throws DbException;
/** Returns true if any messages are sendable to the given contact. */
boolean hasSendableMessages(ContactId c) throws DbException;
/**
* Increments the outgoing connection counter for the given contact
* transport in the given rotation period and returns the old value.
*/
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 acknowledgement from the given contact. */
void receiveAck(ContactId c, Ack a) throws DbException;
/** Processes a batch of messages from the given contact. */
void receiveBatch(ContactId c, Batch b) throws DbException;
/**
* Processes an offer from the given contact and generates a request for
* any messages in the offer that the contact should send. To prevent
* contacts from using offers to test for subscriptions that are not
* visible to them, any messages belonging to groups that are not visible
* to the contact are requested just as though they were not present in the
* database.
*/
Request receiveOffer(ContactId c, Offer o) throws DbException;
/** Processes a subscription update from the given contact. */
void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate s)
throws DbException;
/** Processes a transport update from the given contact. */
void receiveTransportUpdate(ContactId c, TransportUpdate t)
throws DbException;
/** Removes a contact (and all associated state) from the database. */
void removeContact(ContactId c) throws DbException;
/**
* Sets the connection reordering window for the given contact transport
* in the given rotation period.
*/
void setConnectionWindow(ContactId c, TransportId t, long period,
long centre, byte[] bitmap) throws DbException;
/** Records the user's rating for the given author. */
void setRating(AuthorId a, Rating r) throws DbException;
/** Records the given messages as having been seen by the given contact. */
void setSeen(ContactId c, Collection<MessageId> seen) throws DbException;
/**
* Makes the given group visible to the given set of contacts and invisible
* to any other contacts.
*/
void setVisibility(GroupId g, Collection<ContactId> visible)
throws DbException;
/** Subscribes to the given group. */
void subscribe(Group g) throws DbException;
/**
* Unsubscribes from the given group. Any messages belonging to the group
* are deleted from the database.
*/
void unsubscribe(GroupId g) throws DbException;
}

View File

@@ -0,0 +1,14 @@
package net.sf.briar.api.db;
import java.io.File;
import net.sf.briar.api.crypto.Password;
public interface DatabaseConfig {
File getDataDirectory();
Password getPassword();
long getMaxSize();
}

View File

@@ -0,0 +1,15 @@
package net.sf.briar.api.db;
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({ PARAMETER })
@Retention(RUNTIME)
public @interface DatabaseExecutor {}

View File

@@ -0,0 +1,7 @@
package net.sf.briar.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,14 @@
package net.sf.briar.api.db;
public class DbException extends Exception {
private static final long serialVersionUID = 3706581789209939441L;
public DbException() {
super();
}
public DbException(Throwable t) {
super(t);
}
}

View File

@@ -0,0 +1,35 @@
package net.sf.briar.api.db;
import net.sf.briar.api.protocol.AuthorId;
import net.sf.briar.api.protocol.GroupId;
import net.sf.briar.api.protocol.MessageId;
public interface MessageHeader {
/** Returns the message's unique identifier. */
MessageId getId();
/**
* Returns the message's parent, or null if this is the first message in a
* thread.
*/
MessageId getParent();
/** Returns the group to which the message belongs. */
GroupId getGroup();
/** Returns the message's author. */
AuthorId getAuthor();
/** Returns the message's subject line. */
String getSubject();
/** Returns the timestamp created by the message's author. */
long getTimestamp();
/** Returns true if the message has been read. */
boolean getRead();
/** Returns true if the message has been starred. */
boolean getStarred();
}

View File

@@ -0,0 +1,10 @@
package net.sf.briar.api.db;
/**
* Thrown when a database operation is attempted for a contact that is not in
* the database.
*/
public class NoSuchContactException extends DbException {
private static final long serialVersionUID = -7048538231308207386L;
}

View File

@@ -0,0 +1,10 @@
package net.sf.briar.api.db;
/**
* Thrown when a database operation is attempted for a contact transport that
* is not in the database.
*/
public class NoSuchContactTransportException extends DbException {
private static final long serialVersionUID = -6274982612759573100L;
}

View File

@@ -0,0 +1,6 @@
package net.sf.briar.api.db.event;
/** An event that is broadcast when a batch of messages is received. */
public class BatchReceivedEvent extends DatabaseEvent {
}

View File

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

View File

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

View File

@@ -0,0 +1,6 @@
package net.sf.briar.api.db.event;
/** An abstract superclass for database events. */
public abstract class DatabaseEvent {
}

View File

@@ -0,0 +1,7 @@
package net.sf.briar.api.db.event;
/** An interface for receiving notifications when database events occur. */
public interface DatabaseListener {
void eventOccurred(DatabaseEvent e);
}

View File

@@ -0,0 +1,9 @@
package net.sf.briar.api.db.event;
/**
* An event that is broadcast when the local transport properties are
* updated.
*/
public class LocalTransportsUpdatedEvent extends DatabaseEvent {
}

View File

@@ -0,0 +1,9 @@
package net.sf.briar.api.db.event;
/**
* An event that is broadcast when one or more messages are added to the
* database.
*/
public class MessagesAddedEvent extends DatabaseEvent {
}

View File

@@ -0,0 +1,23 @@
package net.sf.briar.api.db.event;
import net.sf.briar.api.Rating;
import net.sf.briar.api.protocol.AuthorId;
public class RatingChangedEvent extends DatabaseEvent {
private final AuthorId author;
private final Rating rating;
public RatingChangedEvent(AuthorId author, Rating rating) {
this.author = author;
this.rating = rating;
}
public AuthorId getAuthor() {
return author;
}
public Rating getRating() {
return rating;
}
}

View File

@@ -0,0 +1,27 @@
package net.sf.briar.api.db.event;
import java.util.Collection;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.protocol.Transport;
/** An event that is broadcast when a contact's transports are updated. */
public class RemoteTransportsUpdatedEvent extends DatabaseEvent {
private final ContactId contactId;
private final Collection<Transport> transports;
public RemoteTransportsUpdatedEvent(ContactId contactId,
Collection<Transport> transports) {
this.contactId = contactId;
this.transports = transports;
}
public ContactId getContactId() {
return contactId;
}
public Collection<Transport> getTransports() {
return transports;
}
}

View File

@@ -0,0 +1,28 @@
package net.sf.briar.api.db.event;
import java.util.Collection;
import java.util.Collections;
import net.sf.briar.api.ContactId;
/**
* An event that is broadcast when the set of subscriptions visible to one or
* more contacts is updated.
*/
public class SubscriptionsUpdatedEvent extends DatabaseEvent {
private final Collection<ContactId> affectedContacts;
public SubscriptionsUpdatedEvent() {
affectedContacts = Collections.emptyList();
}
public SubscriptionsUpdatedEvent(Collection<ContactId> affectedContacts) {
this.affectedContacts = affectedContacts;
}
/** Returns the contacts affected by the update. */
public Collection<ContactId> getAffectedContacts() {
return affectedContacts;
}
}

View File

@@ -0,0 +1,26 @@
package net.sf.briar.api.invitation;
/**
* An interface for receiving updates about the state of an
* {@link InvitationTask}.
*/
public interface InvitationListener {
/** Called if a connection is established and key agreement succeeds. */
void connectionSucceeded(int localCode, int remoteCode);
/** Called if a connection cannot be established. */
void connectionFailed();
/**
* Informs the local peer that the remote peer's confirmation check
* succeeded.
*/
void remoteConfirmationSucceeded();
/**
* Informs the local peer that the remote peer's confirmation check did
* not succeed, or the connection was lost during confirmation.
*/
void remoteConfirmationFailed();
}

View File

@@ -0,0 +1,22 @@
package net.sf.briar.api.invitation;
/** Creates and manages tasks for exchanging invitations with remote peers. */
public interface InvitationManager {
/** Creates a task using the given invitation codes. */
InvitationTask createTask(int localCode, int remoteCode);
/**
* Returns the previously created task with the given handle, unless the
* task has subsequently removed itself.
*/
InvitationTask getTask(int handle);
/** Called by tasks to add themselves to the manager when they start. */
void putTask(int handle, InvitationTask task);
/**
* Called by tasks to remove themselves from the managet when they finish.
*/
void removeTask(int handle);
}

View File

@@ -0,0 +1,62 @@
package net.sf.briar.api.invitation;
public class InvitationState {
private final int localInvitationCode, remoteInvitationCode;
private final int localConfirmationCode, remoteConfirmationCode;
private final boolean connectionFailed;
private final boolean localCompared, remoteCompared;
private final boolean localMatched, remoteMatched;
public InvitationState(int localInvitationCode, int remoteInvitationCode,
int localConfirmationCode, int remoteConfirmationCode,
boolean connectionFailed, boolean localCompared,
boolean remoteCompared, boolean localMatched,
boolean remoteMatched) {
this.localInvitationCode = localInvitationCode;
this.remoteInvitationCode = remoteInvitationCode;
this.localConfirmationCode = localConfirmationCode;
this.remoteConfirmationCode = remoteConfirmationCode;
this.connectionFailed = connectionFailed;
this.localCompared = localCompared;
this.remoteCompared = remoteCompared;
this.localMatched = localMatched;
this.remoteMatched = remoteMatched;
}
public int getLocalInvitationCode() {
return localInvitationCode;
}
public int getRemoteInvitationCode() {
return remoteInvitationCode;
}
public int getLocalConfirmationCode() {
return localConfirmationCode;
}
public int getRemoteConfirmationCode() {
return remoteConfirmationCode;
}
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;
}
}

View File

@@ -0,0 +1,32 @@
package net.sf.briar.api.invitation;
/** A task for exchanging invitations with a remote peer. */
public interface InvitationTask {
/** Returns the task's unique handle. */
int getHandle();
/**
* 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,16 @@
package net.sf.briar.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,16 @@
package net.sf.briar.api.plugins;
public interface InvitationConstants {
long CONNECTION_TIMEOUT = 15 * 1000; // Milliseconds
long CONFIRMATION_TIMEOUT = 60 * 1000; // Milliseconds
int CODE_BITS = 19; // Codes must fit into six decimal digits
int MAX_CODE = (1 << CODE_BITS) - 1; // 524287
int HASH_LENGTH = 48; // Bytes
int MAX_PUBLIC_KEY_LENGTH = 120; // Bytes
}

View File

@@ -0,0 +1,41 @@
package net.sf.briar.api.plugins;
import java.io.IOException;
import java.util.Collection;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.protocol.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();
/** 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 Plugin#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 Plugin#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 net.sf.briar.api.plugins;
import java.util.Map;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.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,15 @@
package net.sf.briar.api.plugins;
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({ PARAMETER })
@Retention(RUNTIME)
public @interface PluginExecutor {}

View File

@@ -0,0 +1,28 @@
package net.sf.briar.api.plugins;
import java.util.Collection;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import android.content.Context;
/**
* Responsible for starting transport plugins at startup, stopping them at
* shutdown, and providing access to plugins for exchanging invitations.
*/
public interface PluginManager {
/**
* Starts the plugins and returns the number of plugins successfully
* started. This method must not be called until the database has been
* opened. The appContext argument is null on non-Android platforms.
*/
int start(Context appContext);
/**
* Stops the plugins and returns the number of plugins successfully stopped.
*/
int stop();
/** Returns any duplex plugins that support invitations. */
Collection<DuplexPlugin> getInvitationPlugins();
}

View File

@@ -0,0 +1,31 @@
package net.sf.briar.api.plugins.duplex;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.crypto.PseudoRandom;
import net.sf.briar.api.plugins.Plugin;
/** An interface for transport plugins that support duplex communication. */
public interface DuplexPlugin extends Plugin {
/**
* Attempts to create and return a connection to the given contact using
* the current transport and configuration properties. Returns null if a
* connection could not be created.
*/
DuplexTransportConnection createConnection(ContactId c);
/** Returns true if the plugin supports exchanging invitations. */
boolean supportsInvitations();
/**
* Starts the invitation process from the inviter's side. Returns null if
* no connection can be established within the given timeout.
*/
DuplexTransportConnection sendInvitation(PseudoRandom r, long timeout);
/**
* Starts the invitation process from the invitee's side. Returns null if
* no connection can be established within the given timeout.
*/
DuplexTransportConnection acceptInvitation(PseudoRandom r, long timeout);
}

View File

@@ -0,0 +1,14 @@
package net.sf.briar.api.plugins.duplex;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.PluginCallback;
/**
* An interface for handling connections created by a duplex transport plugin.
*/
public interface DuplexPluginCallback extends PluginCallback {
void incomingConnectionCreated(DuplexTransportConnection d);
void outgoingConnectionCreated(ContactId c, DuplexTransportConnection d);
}

View File

@@ -0,0 +1,17 @@
package net.sf.briar.api.plugins.duplex;
import java.util.concurrent.Executor;
import net.sf.briar.api.android.AndroidExecutor;
import net.sf.briar.api.lifecycle.ShutdownManager;
import net.sf.briar.api.protocol.TransportId;
import android.content.Context;
public interface DuplexPluginFactory {
TransportId getId();
DuplexPlugin createPlugin(Executor pluginExecutor,
AndroidExecutor androidExecutor, Context appContext,
ShutdownManager shutdownManager, DuplexPluginCallback callback);
}

View File

@@ -0,0 +1,32 @@
package net.sf.briar.api.plugins.duplex;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* An interface for reading and writing data over a duplex transport. The
* connection is not responsible for encrypting/decrypting or authenticating
* the data.
*/
public interface DuplexTransportConnection {
/** Returns an input stream for reading from the connection. */
InputStream getInputStream() throws IOException;
/** Returns an output stream for writing to the connection. */
OutputStream getOutputStream() throws IOException;
/**
* Returns true if the output stream should be flushed after each packet.
*/
boolean shouldFlush();
/**
* Closes the connection and disposes of any associated resources. The
* first argument indicates whether the connection is being closed because
* of an exception and the second argument indicates whether the connection
* was recognised, which may affect how resources are disposed of.
*/
void dispose(boolean exception, boolean recognised) throws IOException;
}

View File

@@ -0,0 +1,22 @@
package net.sf.briar.api.plugins.simplex;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.Plugin;
/** An interface for transport plugins that support simplex communication. */
public interface SimplexPlugin extends Plugin {
/**
* Attempts to create and return a reader for the given contact using the
* current transport and configuration properties. Returns null if a reader
* could not be created.
*/
SimplexTransportReader createReader(ContactId c);
/**
* Attempts to create and return a writer for the given contact using the
* current transport and configuration properties. Returns null if a writer
* could not be created.
*/
SimplexTransportWriter createWriter(ContactId c);
}

View File

@@ -0,0 +1,15 @@
package net.sf.briar.api.plugins.simplex;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.PluginCallback;
/**
* An interface for handling readers and writers created by a simplex transport
* plugin.
*/
public interface SimplexPluginCallback extends PluginCallback {
void readerCreated(SimplexTransportReader r);
void writerCreated(ContactId c, SimplexTransportWriter w);
}

View File

@@ -0,0 +1,17 @@
package net.sf.briar.api.plugins.simplex;
import java.util.concurrent.Executor;
import net.sf.briar.api.android.AndroidExecutor;
import net.sf.briar.api.lifecycle.ShutdownManager;
import net.sf.briar.api.protocol.TransportId;
import android.content.Context;
public interface SimplexPluginFactory {
TransportId getId();
SimplexPlugin createPlugin(Executor pluginExecutor,
AndroidExecutor androidExecutor, Context appContext,
ShutdownManager shutdownManager, SimplexPluginCallback callback);
}

View File

@@ -0,0 +1,22 @@
package net.sf.briar.api.plugins.simplex;
import java.io.IOException;
import java.io.InputStream;
/**
* An interface for reading data from a simplex transport. The reader is not
* responsible for decrypting or authenticating the data before returning it.
*/
public interface SimplexTransportReader {
/** Returns an input stream for reading from the transport. */
InputStream getInputStream() throws IOException;
/**
* Closes the reader and disposes of any associated resources. The first
* argument indicates whether the reader is being closed because of an
* exception and the second argument indicates whether the connection was
* recognised, which may affect how resources are disposed of.
*/
void dispose(boolean exception, boolean recognised) throws IOException;
}

View File

@@ -0,0 +1,29 @@
package net.sf.briar.api.plugins.simplex;
import java.io.IOException;
import java.io.OutputStream;
/**
* An interface for writing data to a simplex transport. The writer is not
* responsible for authenticating or encrypting the data before writing it.
*/
public interface SimplexTransportWriter {
/** Returns the capacity of the transport in bytes. */
long getCapacity();
/** Returns an output stream for writing to the transport. */
OutputStream getOutputStream() throws IOException;
/**
* Returns true if the output stream should be flushed after each packet.
*/
boolean shouldFlush();
/**
* Closes the writer and disposes of any associated resources. The
* argument indicates whether the writer is being closed because of an
* exception, which may affect how resources are disposed of.
*/
void dispose(boolean exception) throws IOException;
}

View File

@@ -0,0 +1,10 @@
package net.sf.briar.api.protocol;
import java.util.Collection;
/** A packet acknowledging receipt of one or more batches. */
public interface Ack {
/** Returns the IDs of the acknowledged batches. */
Collection<BatchId> getBatchIds();
}

View File

@@ -0,0 +1,17 @@
package net.sf.briar.api.protocol;
/** A pseudonymous author of messages. */
public interface Author {
/** Returns the author's unique identifier. */
AuthorId getId();
/** Returns the author's name. */
String getName();
/**
* Returns the public key that is used to verify messages signed by the
* author.
*/
byte[] getPublicKey();
}

View File

@@ -0,0 +1,10 @@
package net.sf.briar.api.protocol;
import java.io.IOException;
public interface AuthorFactory {
Author createAuthor(String name, byte[] publicKey) throws IOException;
Author createAuthor(AuthorId id, String name, byte[] publicKey);
}

View File

@@ -0,0 +1,18 @@
package net.sf.briar.api.protocol;
import java.util.Arrays;
/** Type-safe wrapper for a byte array that uniquely identifies an 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,13 @@
package net.sf.briar.api.protocol;
import java.util.Collection;
/** An incoming packet containing messages. */
public interface Batch {
/** Returns the batch's unique identifier. */
BatchId getId();
/** Returns the messages contained in the batch. */
Collection<Message> getMessages();
}

View File

@@ -0,0 +1,21 @@
package net.sf.briar.api.protocol;
import java.util.Arrays;
/**
* Type-safe wrapper for a byte array that uniquely identifies a batch of
* messages.
*/
public class BatchId extends UniqueId {
public BatchId(byte[] id) {
super(id);
}
@Override
public boolean equals(Object o) {
if(o instanceof BatchId)
return Arrays.equals(id, ((BatchId) o).id);
return false;
}
}

View File

@@ -0,0 +1,17 @@
package net.sf.briar.api.protocol;
/** A group to which users may subscribe. */
public interface Group {
/** Returns the group's unique identifier. */
GroupId getId();
/** Returns the group's name. */
String getName();
/**
* If the group is restricted, returns the public key that is used to
* authorise all messages sent to the group. Otherwise returns null.
*/
byte[] getPublicKey();
}

View File

@@ -0,0 +1,10 @@
package net.sf.briar.api.protocol;
import java.io.IOException;
public interface GroupFactory {
Group createGroup(String name, byte[] publicKey) throws IOException;
Group createGroup(GroupId id, String name, byte[] publicKey);
}

View File

@@ -0,0 +1,21 @@
package net.sf.briar.api.protocol;
import java.util.Arrays;
/**
* Type-safe wrapper for a byte array that uniquely identifies a group to which
* users may subscribe.
*/
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,34 @@
package net.sf.briar.api.protocol;
public interface Message {
/** Returns the message's unique identifier. */
MessageId getId();
/**
* Returns the message's parent, or null if this is the first message in a
* thread.
*/
MessageId getParent();
/** Returns the group to which the message belongs. */
GroupId getGroup();
/** Returns the message's author. */
AuthorId getAuthor();
/** Returns the message's subject line. */
String getSubject();
/** Returns the timestamp created by the message's author. */
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,31 @@
package net.sf.briar.api.protocol;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
public interface MessageFactory {
/** Creates a private message. */
Message createMessage(MessageId parent, String subject, byte[] body)
throws IOException, GeneralSecurityException;
/** Creates an anonymous message to an unrestricted group. */
Message createMessage(MessageId parent, Group group, String subject,
byte[] body) throws IOException, GeneralSecurityException;
/** Creates an anonymous message to a restricted group. */
Message createMessage(MessageId parent, Group group, PrivateKey groupKey,
String subject, byte[] body) throws IOException,
GeneralSecurityException;
/** Creates a pseudonymous message to an unrestricted group. */
Message createMessage(MessageId parent, Group group, Author author,
PrivateKey authorKey, String subject, byte[] body)
throws IOException, GeneralSecurityException;
/** Creates a pseudonymous message to a restricted group. */
Message createMessage(MessageId parent, Group group, PrivateKey groupKey,
Author author, PrivateKey authorKey, String subject, byte[] body)
throws IOException, GeneralSecurityException;
}

View File

@@ -0,0 +1,18 @@
package net.sf.briar.api.protocol;
import java.util.Arrays;
/** Type-safe wrapper for a byte array that uniquely identifies a 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,10 @@
package net.sf.briar.api.protocol;
import java.util.Collection;
/** A packet offering the recipient some messages. */
public interface Offer {
/** Returns the message IDs contained in the offer. */
Collection<MessageId> getMessageIds();
}

View File

@@ -0,0 +1,22 @@
package net.sf.briar.api.protocol;
import java.util.BitSet;
import java.util.Collection;
import java.util.Map;
public interface PacketFactory {
Ack createAck(Collection<BatchId> acked);
RawBatch createBatch(Collection<byte[]> messages);
Offer createOffer(Collection<MessageId> offered);
Request createRequest(BitSet requested, int length);
SubscriptionUpdate createSubscriptionUpdate(Map<GroupId, GroupId> holes,
Map<Group, Long> subs, long expiry, long timestamp);
TransportUpdate createTransportUpdate(Collection<Transport> transports,
long timestamp);
}

View File

@@ -0,0 +1,47 @@
package net.sf.briar.api.protocol;
import static net.sf.briar.api.transport.TransportConstants.MIN_CONNECTION_LENGTH;
public interface ProtocolConstants {
/**
* 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 transports a node may support. */
int MAX_TRANSPORTS = 25;
/** 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;
/** The maximum length of a group's name in UTF-8 bytes. */
int MAX_GROUP_NAME_LENGTH = 50;
/** The maximum length of a public key in bytes. */
int MAX_PUBLIC_KEY_LENGTH = 120;
/** The maximum length of an author's name in UTF-8 bytes. */
int MAX_AUTHOR_NAME_LENGTH = 50;
/**
* 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 subject line in UTF-8 bytes. */
int MAX_SUBJECT_LENGTH = 100;
/** The maximum length of a signature in bytes. */
int MAX_SIGNATURE_LENGTH = 120;
/** The length of a message's random salt in bytes. */
int SALT_LENGTH = 8;
}

View File

@@ -0,0 +1,26 @@
package net.sf.briar.api.protocol;
import java.io.IOException;
public interface ProtocolReader {
boolean eof() throws IOException;
boolean hasAck() throws IOException;
Ack readAck() throws IOException;
boolean hasBatch() throws IOException;
UnverifiedBatch readBatch() throws IOException;
boolean hasOffer() throws IOException;
Offer readOffer() throws IOException;
boolean hasRequest() throws IOException;
Request readRequest() throws IOException;
boolean hasSubscriptionUpdate() throws IOException;
SubscriptionUpdate readSubscriptionUpdate() throws IOException;
boolean hasTransportUpdate() throws IOException;
TransportUpdate readTransportUpdate() throws IOException;
}

View File

@@ -0,0 +1,8 @@
package net.sf.briar.api.protocol;
import java.io.InputStream;
public interface ProtocolReaderFactory {
ProtocolReader createProtocolReader(InputStream in);
}

View File

@@ -0,0 +1,28 @@
package net.sf.briar.api.protocol;
import java.io.IOException;
public interface ProtocolWriter {
int getMaxBatchesForAck(long capacity);
int getMaxMessagesForOffer(long capacity);
int getMessageCapacityForBatch(long capacity);
void writeAck(Ack a) throws IOException;
void writeBatch(RawBatch b) throws IOException;
void writeOffer(Offer o) throws IOException;
void writeRequest(Request r) throws IOException;
void writeSubscriptionUpdate(SubscriptionUpdate s) throws IOException;
void writeTransportUpdate(TransportUpdate t) throws IOException;
void flush() throws IOException;
void close() throws IOException;
}

View File

@@ -0,0 +1,8 @@
package net.sf.briar.api.protocol;
import java.io.OutputStream;
public interface ProtocolWriterFactory {
ProtocolWriter createProtocolWriter(OutputStream out, boolean flush);
}

View File

@@ -0,0 +1,13 @@
package net.sf.briar.api.protocol;
import java.util.Collection;
/** An outgoing packet containing messages. */
public interface RawBatch {
/** Returns the batch's unique identifier. */
BatchId getId();
/** Returns the serialised messages contained in the batch. */
Collection<byte[]> getMessages();
}

View File

@@ -0,0 +1,16 @@
package net.sf.briar.api.protocol;
import java.util.BitSet;
/** A packet requesting some or all of the messages from an offer. */
public interface Request {
/**
* Returns a sequence of bits corresponding to the sequence of messages in
* the offer, where the i^th bit is set if the i^th message should be sent.
*/
BitSet getBitmap();
/** Returns the length of the bitmap in bits. */
int getLength();
}

View File

@@ -0,0 +1,25 @@
package net.sf.briar.api.protocol;
import java.util.Map;
/** A packet updating the sender's subscriptions. */
public interface SubscriptionUpdate {
/** Returns the holes contained in the update. */
Map<GroupId, GroupId> getHoles();
/** Returns the subscriptions contained in the update. */
Map<Group, Long> getSubscriptions();
/**
* Returns the expiry time of the contact's database. Messages that are
* older than the expiry time must not be sent to the contact.
*/
long getExpiryTime();
/**
* Returns the update's timestamp. Updates that are older than the newest
* update received from the same contact must be ignored.
*/
long getTimestamp();
}

View File

@@ -0,0 +1,39 @@
package net.sf.briar.api.protocol;
import java.util.Map;
import java.util.TreeMap;
public class Transport extends TreeMap<String, String> {
private static final long serialVersionUID = 4900420175715429560L;
private final TransportId id;
public Transport(TransportId id, Map<String, String> p) {
super(p);
this.id = id;
}
public Transport(TransportId id) {
super();
this.id = id;
}
public TransportId getId() {
return id;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
if(o instanceof Transport) {
Transport t = (Transport) o;
return id.equals(t.id) && super.equals(o);
}
return false;
}
}

View File

@@ -0,0 +1,21 @@
package net.sf.briar.api.protocol;
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,16 @@
package net.sf.briar.api.protocol;
import java.util.Collection;
/** A packet updating the sender's transport properties. */
public interface TransportUpdate {
/** Returns the transports contained in the update. */
Collection<Transport> getTransports();
/**
* Returns the update's timestamp. Updates that are older than the newest
* update received from the same contact must be ignored.
*/
long getTimestamp();
}

View File

@@ -0,0 +1,16 @@
package net.sf.briar.api.protocol;
/** Struct identifiers for encoding and decoding protocol objects. */
public interface Types {
int ACK = 0;
int AUTHOR = 1;
int BATCH = 2;
int GROUP = 3;
int MESSAGE = 4;
int OFFER = 5;
int REQUEST = 6;
int SUBSCRIPTION_UPDATE = 7;
int TRANSPORT = 8;
int TRANSPORT_UPDATE = 9;
}

View File

@@ -0,0 +1,30 @@
package net.sf.briar.api.protocol;
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,8 @@
package net.sf.briar.api.protocol;
import java.security.GeneralSecurityException;
public interface UnverifiedBatch {
Batch verify() throws GeneralSecurityException;
}

View File

@@ -0,0 +1,15 @@
package net.sf.briar.api.protocol;
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 message verification tasks. */
@BindingAnnotation
@Target({ PARAMETER })
@Retention(RUNTIME)
public @interface VerificationExecutor {}

View File

@@ -0,0 +1,14 @@
package net.sf.briar.api.protocol.duplex;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.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,15 @@
package net.sf.briar.api.protocol.simplex;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.simplex.SimplexTransportReader;
import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.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,10 @@
package net.sf.briar.api.serial;
import java.io.IOException;
public interface Consumer {
void write(byte b) throws IOException;
void write(byte[] b, int off, int len) throws IOException;
}

View File

@@ -0,0 +1,22 @@
package net.sf.briar.api.serial;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/** A consumer that makes a copy of the bytes consumed. */
public class CopyingConsumer implements Consumer {
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
public byte[] getCopy() {
return out.toByteArray();
}
public void write(byte b) throws IOException {
out.write(b);
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}
}

View File

@@ -0,0 +1,33 @@
package net.sf.briar.api.serial;
import java.io.IOException;
import net.sf.briar.api.FormatException;
/**
* A consumer that counts the number of bytes consumed and throws a
* FormatException if the count exceeds a given limit.
*/
public class CountingConsumer implements Consumer {
private final long limit;
private long count = 0L;
public CountingConsumer(long limit) {
this.limit = limit;
}
public long getCount() {
return count;
}
public void write(byte b) throws IOException {
count++;
if(count > limit) throw new FormatException();
}
public void write(byte[] b, int off, int len) throws IOException {
count += len;
if(count > limit) throw new FormatException();
}
}

View File

@@ -0,0 +1,21 @@
package net.sf.briar.api.serial;
import net.sf.briar.api.crypto.MessageDigest;
/** A consumer that passes its input through a message digest. */
public class DigestingConsumer implements Consumer {
private final MessageDigest messageDigest;
public DigestingConsumer(MessageDigest messageDigest) {
this.messageDigest = messageDigest;
}
public void write(byte b) {
messageDigest.update(b);
}
public void write(byte[] b, int off, int len) {
messageDigest.update(b, off, len);
}
}

View File

@@ -0,0 +1,73 @@
package net.sf.briar.api.serial;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public interface Reader {
boolean eof() throws IOException;
void close() throws IOException;
void setMaxStringLength(int length);
void resetMaxStringLength();
void setMaxBytesLength(int length);
void resetMaxBytesLength();
void addConsumer(Consumer c);
void removeConsumer(Consumer c);
void addStructReader(int id, StructReader<?> o);
void removeStructReader(int id);
boolean hasBoolean() throws IOException;
boolean readBoolean() throws IOException;
boolean hasUint7() throws IOException;
byte readUint7() throws IOException;
boolean hasInt8() throws IOException;
byte readInt8() throws IOException;
boolean hasInt16() throws IOException;
short readInt16() throws IOException;
boolean hasInt32() throws IOException;
int readInt32() throws IOException;
boolean hasInt64() throws IOException;
long readInt64() throws IOException;
boolean hasIntAny() throws IOException;
long readIntAny() throws IOException;
boolean hasFloat32() throws IOException;
float readFloat32() throws IOException;
boolean hasFloat64() throws IOException;
double readFloat64() throws IOException;
boolean hasString() throws IOException;
String readString() throws IOException;
String readString(int maxLength) throws IOException;
boolean hasBytes() throws IOException;
byte[] readBytes() throws IOException;
byte[] readBytes(int maxLength) throws IOException;
boolean hasList() throws IOException;
<E> List<E> readList(Class<E> e) throws IOException;
boolean hasListStart() throws IOException;
void readListStart() throws IOException;
boolean hasListEnd() throws IOException;
void readListEnd() throws IOException;
boolean hasMap() throws IOException;
<K, V> Map<K, V> readMap(Class<K> k, Class<V> v) throws IOException;
boolean hasMapStart() throws IOException;
void readMapStart() throws IOException;
boolean hasMapEnd() throws IOException;
void readMapEnd() throws IOException;
boolean hasNull() throws IOException;
void readNull() throws IOException;
boolean hasStruct(int id) throws IOException;
<T> T readStruct(int id, Class<T> t) throws IOException;
void readStructId(int id) throws IOException;
}

View File

@@ -0,0 +1,8 @@
package net.sf.briar.api.serial;
import java.io.InputStream;
public interface ReaderFactory {
Reader createReader(InputStream in);
}

View File

@@ -0,0 +1,12 @@
package net.sf.briar.api.serial;
public interface SerialComponent {
int getSerialisedListEndLength();
int getSerialisedListStartLength();
int getSerialisedStructIdLength(int id);
int getSerialisedUniqueIdLength();
}

View File

@@ -0,0 +1,31 @@
package net.sf.briar.api.serial;
import java.io.IOException;
import java.security.Signature;
import java.security.SignatureException;
/** A consumer that passes its input through a signature. */
public class SigningConsumer implements Consumer {
private final Signature signature;
public SigningConsumer(Signature signature) {
this.signature = signature;
}
public void write(byte b) throws IOException {
try {
signature.update(b);
} catch(SignatureException e) {
throw new IOException(e.toString());
}
}
public void write(byte[] b, int off, int len) throws IOException {
try {
signature.update(b, off, len);
} catch(SignatureException e) {
throw new IOException(e.toString());
}
}
}

View File

@@ -0,0 +1,8 @@
package net.sf.briar.api.serial;
import java.io.IOException;
public interface StructReader<T> {
T readStruct(Reader r) throws IOException;
}

View File

@@ -0,0 +1,41 @@
package net.sf.briar.api.serial;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
public interface Writer {
void flush() throws IOException;
void close() throws IOException;
void addConsumer(Consumer c);
void removeConsumer(Consumer c);
void writeBoolean(boolean b) throws IOException;
void writeUint7(byte b) throws IOException;
void writeInt8(byte b) throws IOException;
void writeInt16(short s) throws IOException;
void writeInt32(int i) throws IOException;
void writeInt64(long l) throws IOException;
void writeIntAny(long l) throws IOException;
void writeFloat32(float f) throws IOException;
void writeFloat64(double d) throws IOException;
void writeString(String s) throws IOException;
void writeBytes(byte[] b) throws IOException;
void writeList(Collection<?> c) throws IOException;
void writeListStart() throws IOException;
void writeListEnd() throws IOException;
void writeMap(Map<?, ?> m) throws IOException;
void writeMapStart() throws IOException;
void writeMapEnd() throws IOException;
void writeNull() throws IOException;
void writeStructId(int id) throws IOException;
}

View File

@@ -0,0 +1,8 @@
package net.sf.briar.api.serial;
import java.io.OutputStream;
public interface WriterFactory {
Writer createWriter(OutputStream out);
}

View File

@@ -0,0 +1,42 @@
package net.sf.briar.api.transport;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.protocol.TransportId;
public class ConnectionContext {
private final ContactId contactId;
private final TransportId transportId;
private final byte[] secret;
private final long connection;
private final boolean alice;
public ConnectionContext(ContactId contactId, TransportId transportId,
byte[] secret, long connection, boolean alice) {
this.contactId = contactId;
this.transportId = transportId;
this.secret = secret;
this.connection = connection;
this.alice = alice;
}
public ContactId getContactId() {
return contactId;
}
public TransportId getTransportId() {
return transportId;
}
public byte[] getSecret() {
return secret;
}
public long getConnectionNumber() {
return connection;
}
public boolean getAlice() {
return alice;
}
}

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