mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Separate the sync layer from its clients. #112
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
public abstract class UniqueId {
|
||||
|
||||
@@ -27,4 +28,20 @@ public abstract class UniqueId {
|
||||
if (hashCode == -1) hashCode = Arrays.hashCode(id);
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public static class IdComparator implements Comparator<UniqueId> {
|
||||
|
||||
public static final IdComparator INSTANCE = new IdComparator();
|
||||
|
||||
@Override
|
||||
public int compare(UniqueId a, UniqueId b) {
|
||||
byte[] aBytes = a.getBytes(), bBytes = b.getBytes();
|
||||
for (int i = 0; i < UniqueId.LENGTH; i++) {
|
||||
int aUnsigned = aBytes[i] & 0xFF, bUnsigned = bBytes[i] & 0xFF;
|
||||
if (aUnsigned < bUnsigned) return -1;
|
||||
if (aUnsigned > bUnsigned) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.briarproject.api.android;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Enables background threads to make Android API calls that must be made from
|
||||
@@ -10,10 +10,11 @@ import java.util.concurrent.ExecutionException;
|
||||
public interface AndroidExecutor {
|
||||
|
||||
/**
|
||||
* Runs the given task on a thread with a message queue and returns the
|
||||
* result of the task.
|
||||
* Runs the given task on the main UI thread and returns a Future for
|
||||
* getting the result.
|
||||
*/
|
||||
<V> V call(Callable<V> c) throws InterruptedException, ExecutionException;
|
||||
<V> Future<V> submit(Callable<V> c);
|
||||
|
||||
void shutdown();
|
||||
/** Runs the given task on the main UI thread. */
|
||||
void execute(Runnable r);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
package org.briarproject.api.android;
|
||||
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
/**
|
||||
* Manages notifications for private messages and group posts. All methods must
|
||||
* be called from the Android UI thread.
|
||||
*/
|
||||
/** Manages notifications for private messages and forum posts. */
|
||||
public interface AndroidNotificationManager extends Service {
|
||||
|
||||
void showPrivateMessageNotification(ContactId c);
|
||||
void showPrivateMessageNotification(GroupId g);
|
||||
|
||||
void clearPrivateMessageNotification(ContactId c);
|
||||
|
||||
void blockPrivateMessageNotification(ContactId c);
|
||||
|
||||
void unblockPrivateMessageNotification(ContactId c);
|
||||
void clearPrivateMessageNotification(GroupId g);
|
||||
|
||||
void showForumPostNotification(GroupId g);
|
||||
|
||||
void clearForumPostNotification(GroupId g);
|
||||
|
||||
void clearNotifications();
|
||||
void blockNotification(GroupId g);
|
||||
|
||||
void unblockNotification(GroupId g);
|
||||
}
|
||||
|
||||
@@ -57,9 +57,6 @@ public interface CryptoComponent {
|
||||
*/
|
||||
byte[] deriveSignatureNonce(SecretKey master, boolean alice);
|
||||
|
||||
/** Derives a group salt from the given master secret. */
|
||||
byte[] deriveGroupSalt(SecretKey master);
|
||||
|
||||
/**
|
||||
* Derives initial transport keys for the given transport in the given
|
||||
* rotation period from the given master secret.
|
||||
@@ -77,6 +74,12 @@ public interface CryptoComponent {
|
||||
/** Encodes the pseudo-random tag that is used to recognise a stream. */
|
||||
void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber);
|
||||
|
||||
/**
|
||||
* Returns the hash of the given inputs. The inputs are unambiguously
|
||||
* combined by prefixing each input with its length.
|
||||
*/
|
||||
byte[] hash(byte[]... inputs);
|
||||
|
||||
/**
|
||||
* Encrypts and authenticates the given plaintext so it can be written to
|
||||
* storage. The encryption and authentication keys are derived from the
|
||||
|
||||
@@ -1,46 +1,90 @@
|
||||
package org.briarproject.api.data;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
// This class is not thread-safe
|
||||
public class BdfDictionary extends HashMap<String, Object> {
|
||||
|
||||
public Boolean getBoolean(String key) throws FormatException {
|
||||
Object o = get(key);
|
||||
if (o instanceof Boolean) return (Boolean) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public Boolean getBoolean(String key, Boolean defaultValue) {
|
||||
Object o = get(key);
|
||||
if (o instanceof Boolean) return (Boolean) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public Long getInteger(String key) throws FormatException {
|
||||
Object o = get(key);
|
||||
if (o instanceof Long) return (Long) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public Long getInteger(String key, Long defaultValue) {
|
||||
Object o = get(key);
|
||||
if (o instanceof Long) return (Long) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public Double getFloat(String key) throws FormatException {
|
||||
Object o = get(key);
|
||||
if (o instanceof Double) return (Double) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public Double getFloat(String key, Double defaultValue) {
|
||||
Object o = get(key);
|
||||
if (o instanceof Double) return (Double) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public String getString(String key) throws FormatException {
|
||||
Object o = get(key);
|
||||
if (o instanceof String) return (String) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public String getString(String key, String defaultValue) {
|
||||
Object o = get(key);
|
||||
if (o instanceof String) return (String) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public byte[] getRaw(String key) throws FormatException {
|
||||
Object o = get(key);
|
||||
if (o instanceof byte[]) return (byte[]) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public byte[] getRaw(String key, byte[] defaultValue) {
|
||||
Object o = get(key);
|
||||
if (o instanceof byte[]) return (byte[]) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public BdfList getList(String key) throws FormatException {
|
||||
Object o = get(key);
|
||||
if (o instanceof BdfList) return (BdfList) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public BdfList getList(String key, BdfList defaultValue) {
|
||||
Object o = get(key);
|
||||
if (o instanceof BdfList) return (BdfList) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public BdfDictionary getDictionary(String key) throws FormatException {
|
||||
Object o = get(key);
|
||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public BdfDictionary getDictionary(String key, BdfDictionary defaultValue) {
|
||||
Object o = get(key);
|
||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
||||
|
||||
@@ -1,46 +1,90 @@
|
||||
package org.briarproject.api.data;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// This class is not thread-safe
|
||||
public class BdfList extends ArrayList<Object> {
|
||||
|
||||
public Boolean getBoolean(int index) throws FormatException {
|
||||
Object o = get(index);
|
||||
if (o instanceof Boolean) return (Boolean) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public Boolean getBoolean(int index, Boolean defaultValue) {
|
||||
Object o = get(index);
|
||||
if (o instanceof Boolean) return (Boolean) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public Long getInteger(int index) throws FormatException {
|
||||
Object o = get(index);
|
||||
if (o instanceof Long) return (Long) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public Long getInteger(int index, Long defaultValue) {
|
||||
Object o = get(index);
|
||||
if (o instanceof Long) return (Long) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public Double getFloat(int index) throws FormatException {
|
||||
Object o = get(index);
|
||||
if (o instanceof Double) return (Double) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public Double getFloat(int index, Double defaultValue) {
|
||||
Object o = get(index);
|
||||
if (o instanceof Double) return (Double) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public String getString(int index) throws FormatException {
|
||||
Object o = get(index);
|
||||
if (o instanceof String) return (String) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public String getString(int index, String defaultValue) {
|
||||
Object o = get(index);
|
||||
if (o instanceof String) return (String) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public byte[] getRaw(int index) throws FormatException {
|
||||
Object o = get(index);
|
||||
if (o instanceof byte[]) return (byte[]) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public byte[] getRaw(int index, byte[] defaultValue) {
|
||||
Object o = get(index);
|
||||
if (o instanceof byte[]) return (byte[]) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public BdfList getList(int index) throws FormatException {
|
||||
Object o = get(index);
|
||||
if (o instanceof BdfList) return (BdfList) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public BdfList getList(int index, BdfList defaultValue) {
|
||||
Object o = get(index);
|
||||
if (o instanceof BdfList) return (BdfList) o;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public BdfDictionary getDictionary(int index) throws FormatException {
|
||||
Object o = get(index);
|
||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) {
|
||||
Object o = get(index);
|
||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
||||
|
||||
@@ -7,9 +7,6 @@ public interface BdfReader {
|
||||
boolean eof() throws IOException;
|
||||
void close() throws IOException;
|
||||
|
||||
void addConsumer(Consumer c);
|
||||
void removeConsumer(Consumer c);
|
||||
|
||||
boolean hasNull() throws IOException;
|
||||
void readNull() throws IOException;
|
||||
void skipNull() throws IOException;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.briarproject.api.data;
|
||||
|
||||
import org.briarproject.api.UniqueId;
|
||||
|
||||
public interface DataConstants {
|
||||
|
||||
int LIST_START_LENGTH = 1;
|
||||
|
||||
int LIST_END_LENGTH = 1;
|
||||
|
||||
int UNIQUE_ID_LENGTH = 2 + UniqueId.LENGTH;
|
||||
}
|
||||
@@ -9,11 +9,12 @@ import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.sync.Ack;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.Group;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.MessageHeader;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
import org.briarproject.api.sync.MessageStatus;
|
||||
import org.briarproject.api.sync.Offer;
|
||||
import org.briarproject.api.sync.Request;
|
||||
import org.briarproject.api.sync.SubscriptionAck;
|
||||
@@ -44,9 +45,12 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
ContactId addContact(Author remote, AuthorId local) throws DbException;
|
||||
|
||||
/** Adds a group to the given contact's subscriptions. */
|
||||
void addGroup(ContactId c, Group g) throws DbException;
|
||||
|
||||
/**
|
||||
* Subscribes to a group, or returns false if the user already has the
|
||||
* maximum number of public subscriptions.
|
||||
* maximum number of subscriptions.
|
||||
*/
|
||||
boolean addGroup(Group g) throws DbException;
|
||||
|
||||
@@ -54,7 +58,8 @@ public interface DatabaseComponent {
|
||||
void addLocalAuthor(LocalAuthor a) throws DbException;
|
||||
|
||||
/** Stores a local message. */
|
||||
void addLocalMessage(Message m) throws DbException;
|
||||
void addLocalMessage(Message m, ClientId c, Metadata meta)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a transport and returns true if the transport was not previously
|
||||
@@ -147,22 +152,9 @@ public interface DatabaseComponent {
|
||||
/** 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, excluding inboxes. */
|
||||
/** 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 local pseudonym with the given ID. */
|
||||
LocalAuthor getLocalAuthor(AuthorId a) throws DbException;
|
||||
|
||||
@@ -176,15 +168,35 @@ public interface DatabaseComponent {
|
||||
/** 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 IDs of any messages that need to be validated by the given
|
||||
* client.
|
||||
*/
|
||||
Collection<MessageId> getMessagesToValidate(ClientId c) throws DbException;
|
||||
|
||||
/** Returns the headers of all messages in the given group. */
|
||||
Collection<MessageHeader> getMessageHeaders(GroupId g)
|
||||
/** Returns the message with the given ID, in serialised form. */
|
||||
byte[] getRawMessage(MessageId m) throws DbException;
|
||||
|
||||
/** Returns the metadata for all messages in the given group. */
|
||||
Map<MessageId, Metadata> getMessageMetadata(GroupId g)
|
||||
throws DbException;
|
||||
|
||||
/** Returns true if the given message is marked as read. */
|
||||
boolean getReadFlag(MessageId m) throws DbException;
|
||||
/** Returns the metadata for the given message. */
|
||||
Metadata getMessageMetadata(MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the status of all messages in the given group with respect to
|
||||
* the given contact.
|
||||
*/
|
||||
Collection<MessageStatus> getMessageStatus(ContactId c, GroupId g)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the status of the given message with respect to the given
|
||||
* contact.
|
||||
*/
|
||||
MessageStatus getMessageStatus(ContactId c, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/** Returns all remote transport properties for the given transport. */
|
||||
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
|
||||
@@ -203,9 +215,6 @@ public interface DatabaseComponent {
|
||||
/** Returns the maximum latencies in milliseconds of all transports. */
|
||||
Map<TransportId, Integer> 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;
|
||||
|
||||
@@ -223,6 +232,12 @@ public interface DatabaseComponent {
|
||||
void mergeLocalProperties(TransportId t, TransportProperties p)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Merges the given metadata with the existing metadata for the given
|
||||
* message.
|
||||
*/
|
||||
void mergeMessageMetadata(MessageId m, Metadata meta) throws DbException;
|
||||
|
||||
/**
|
||||
* Merges the given settings with the existing settings in the given
|
||||
* namespace.
|
||||
@@ -276,16 +291,9 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
void removeTransport(TransportId t) 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.
|
||||
*/
|
||||
void setInboxGroup(ContactId c, Group g) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks a message as read or unread.
|
||||
*/
|
||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
||||
/** Marks the given message as valid or invalid. */
|
||||
void setMessageValidity(Message m, ClientId c, boolean valid)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the remote transport properties for the given contact, replacing
|
||||
|
||||
@@ -22,7 +22,7 @@ public class MessageAddedEvent extends Event {
|
||||
|
||||
/** Returns the ID of the group to which the message belongs. */
|
||||
public GroupId getGroupId() {
|
||||
return message.getGroup().getId();
|
||||
return message.getGroupId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.briarproject.api.event;
|
||||
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.Message;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a message has passed or failed validation.
|
||||
*/
|
||||
public class MessageValidatedEvent extends Event {
|
||||
|
||||
private final Message message;
|
||||
private final ClientId clientId;
|
||||
private final boolean local, valid;
|
||||
|
||||
public MessageValidatedEvent(Message message, ClientId clientId,
|
||||
boolean local, boolean valid) {
|
||||
this.message = message;
|
||||
this.clientId = clientId;
|
||||
this.local = local;
|
||||
this.valid = valid;
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public ClientId getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,37 @@
|
||||
package org.briarproject.api.forum;
|
||||
|
||||
import org.briarproject.api.sync.Group;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
public interface Forum {
|
||||
public class Forum {
|
||||
|
||||
GroupId getId();
|
||||
private final Group group;
|
||||
private final String name;
|
||||
|
||||
String getName();
|
||||
public Forum(Group group, String name) {
|
||||
this.group = group;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public GroupId getId() {
|
||||
return group.getId();
|
||||
}
|
||||
|
||||
public Group getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return group.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Forum && group.equals(((Forum) o).group);
|
||||
}
|
||||
}
|
||||
|
||||
19
briar-api/src/org/briarproject/api/forum/ForumConstants.java
Normal file
19
briar-api/src/org/briarproject/api/forum/ForumConstants.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.briarproject.api.forum;
|
||||
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface ForumConstants {
|
||||
|
||||
/** The maximum length of a forum's name in bytes. */
|
||||
int MAX_FORUM_NAME_LENGTH = MAX_GROUP_DESCRIPTOR_LENGTH - 10;
|
||||
|
||||
/** The length of a forum's random salt in bytes. */
|
||||
int FORUM_SALT_LENGTH = 32;
|
||||
|
||||
/** The maximum length of a forum post's content type in bytes. */
|
||||
int MAX_CONTENT_TYPE_LENGTH = 50;
|
||||
|
||||
/** The maximum length of a forum post's body in bytes. */
|
||||
int MAX_FORUM_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.briarproject.api.forum;
|
||||
|
||||
public interface ForumFactory {
|
||||
|
||||
/** Creates a forum with the given name and a random salt. */
|
||||
Forum createForum(String name);
|
||||
}
|
||||
@@ -3,14 +3,20 @@ package org.briarproject.api.forum;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ForumManager {
|
||||
|
||||
/** Returns the unique ID of the forum client. */
|
||||
ClientId getClientId();
|
||||
|
||||
/** Creates a forum with the given name. */
|
||||
Forum createForum(String name);
|
||||
|
||||
/**
|
||||
* Subscribes to a forum, or returns false if the user already has the
|
||||
* maximum number of forum subscriptions.
|
||||
@@ -18,7 +24,7 @@ public interface ForumManager {
|
||||
boolean addForum(Forum f) throws DbException;
|
||||
|
||||
/** Stores a local forum post. */
|
||||
void addLocalPost(Message m) throws DbException;
|
||||
void addLocalPost(ForumPost p) throws DbException;
|
||||
|
||||
/** Returns all forums to which the user could subscribe. */
|
||||
Collection<Forum> getAvailableForums() throws DbException;
|
||||
|
||||
37
briar-api/src/org/briarproject/api/forum/ForumPost.java
Normal file
37
briar-api/src/org/briarproject/api/forum/ForumPost.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package org.briarproject.api.forum;
|
||||
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
public class ForumPost {
|
||||
|
||||
private final Message message;
|
||||
private final MessageId parent;
|
||||
private final Author author;
|
||||
private final String contentType;
|
||||
|
||||
public ForumPost(Message message, MessageId parent, Author author,
|
||||
String contentType) {
|
||||
this.message = message;
|
||||
this.parent = parent;
|
||||
this.author = author;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public MessageId getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package org.briarproject.api.forum;
|
||||
|
||||
import org.briarproject.api.crypto.PrivateKey;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -10,12 +10,12 @@ import java.security.GeneralSecurityException;
|
||||
|
||||
public interface ForumPostFactory {
|
||||
|
||||
Message createAnonymousPost(MessageId parent, Forum forum,
|
||||
String contentType, long timestamp, byte[] body) throws IOException,
|
||||
GeneralSecurityException;
|
||||
ForumPost createAnonymousPost(GroupId groupId, long timestamp,
|
||||
MessageId parent, String contentType, byte[] body)
|
||||
throws IOException, GeneralSecurityException;
|
||||
|
||||
Message createPseudonymousPost(MessageId parent, Forum forum,
|
||||
Author author, PrivateKey privateKey, String contentType,
|
||||
long timestamp, byte[] body) throws IOException,
|
||||
ForumPost createPseudonymousPost(GroupId groupId, long timestamp,
|
||||
MessageId parent, Author author, String contentType, byte[] body,
|
||||
PrivateKey privateKey) throws IOException,
|
||||
GeneralSecurityException;
|
||||
}
|
||||
|
||||
@@ -3,17 +3,46 @@ package org.briarproject.api.forum;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
public interface ForumPostHeader {
|
||||
public class ForumPostHeader {
|
||||
|
||||
MessageId getId();
|
||||
private final MessageId id;
|
||||
private final long timestamp;
|
||||
private final Author author;
|
||||
private final Author.Status authorStatus;
|
||||
private final String contentType;
|
||||
private final boolean read;
|
||||
|
||||
Author getAuthor();
|
||||
public ForumPostHeader(MessageId id, long timestamp, Author author,
|
||||
Author.Status authorStatus, String contentType, boolean read) {
|
||||
this.id = id;
|
||||
this.timestamp = timestamp;
|
||||
this.author = author;
|
||||
this.authorStatus = authorStatus;
|
||||
this.contentType = contentType;
|
||||
this.read = read;
|
||||
}
|
||||
|
||||
Author.Status getAuthorStatus();
|
||||
public MessageId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
String getContentType();
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
long getTimestamp();
|
||||
public Author.Status getAuthorStatus() {
|
||||
return authorStatus;
|
||||
}
|
||||
|
||||
boolean isRead();
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public boolean isRead() {
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,25 @@ package org.briarproject.api.identity;
|
||||
|
||||
import org.briarproject.api.UniqueId;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for a byte array that uniquely identifies an
|
||||
* {@link Author}.
|
||||
* {@link org.briarproject.api.identity.Author Author}.
|
||||
*/
|
||||
public class AuthorId extends UniqueId {
|
||||
|
||||
/** Label for hashing authors to calculate their identities. */
|
||||
public static final byte[] LABEL =
|
||||
"AUTHOR_ID".getBytes(Charset.forName("US-ASCII"));
|
||||
|
||||
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;
|
||||
return o instanceof AuthorId && Arrays.equals(id, ((AuthorId) o).id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.briarproject.api.messaging;
|
||||
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface MessagingConstants {
|
||||
|
||||
/** The maximum length of a private message's content type in bytes. */
|
||||
int MAX_CONTENT_TYPE_LENGTH = 50;
|
||||
|
||||
/** The maximum length of a private message's body in bytes. */
|
||||
int MAX_PRIVATE_MESSAGE_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
}
|
||||
@@ -1,37 +1,35 @@
|
||||
package org.briarproject.api.messaging;
|
||||
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface MessagingManager {
|
||||
|
||||
/** Returns the unique ID of the messaging client. */
|
||||
ClientId getClientId();
|
||||
|
||||
/**
|
||||
* Informs the messaging manager that a new contact has been added.
|
||||
* Creates a private conversation with the contact.
|
||||
*/
|
||||
void addContact(ContactId c, SecretKey master) throws DbException;
|
||||
void addContact(ContactId c) throws DbException;
|
||||
|
||||
/** Stores a local private message. */
|
||||
void addLocalMessage(Message m) throws DbException;
|
||||
void addLocalMessage(PrivateMessage m) throws DbException;
|
||||
|
||||
/** Returns the private conversation with the given ID. */
|
||||
PrivateConversation getConversation(GroupId g) throws DbException;
|
||||
/** Returns the ID of the contact with the given private conversation. */
|
||||
ContactId getContactId(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the ID of the private conversation with the given contact, or
|
||||
* null if no private conversation ID has been set.
|
||||
*/
|
||||
/** Returns the ID of the private conversation with the given contact. */
|
||||
GroupId getConversationId(ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the headers of all messages in the private conversation with the
|
||||
* given contact, or null if no private conversation ID has been set.
|
||||
* Returns the headers of all messages in the given private conversation.
|
||||
*/
|
||||
Collection<PrivateMessageHeader> getMessageHeaders(ContactId c)
|
||||
throws DbException;
|
||||
@@ -39,13 +37,6 @@ public interface MessagingManager {
|
||||
/** Returns the body of the private message with the given ID. */
|
||||
byte[] getMessageBody(MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Makes a private conversation visible to the given contact, adds it to
|
||||
* the contact's subscriptions, and sets it as the private conversation for
|
||||
* the contact.
|
||||
*/
|
||||
void setConversation(ContactId c, PrivateConversation p) throws DbException;
|
||||
|
||||
/** Marks a private message as read or unread. */
|
||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
package org.briarproject.api.messaging;
|
||||
|
||||
import org.briarproject.api.sync.Group;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
public interface PrivateConversation {
|
||||
// TODO: Remove if no longer needed
|
||||
public class PrivateConversation {
|
||||
|
||||
GroupId getId();
|
||||
private final Group group;
|
||||
|
||||
public PrivateConversation(Group group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public GroupId getId() {
|
||||
return group.getId();
|
||||
}
|
||||
|
||||
public Group getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return group.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof PrivateConversation
|
||||
&& group.equals(((PrivateConversation) o).group);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.briarproject.api.messaging;
|
||||
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
public class PrivateMessage {
|
||||
|
||||
private final Message message;
|
||||
private final MessageId parent;
|
||||
private final String contentType;
|
||||
|
||||
public PrivateMessage(Message message, MessageId parent,
|
||||
String contentType) {
|
||||
this.message = message;
|
||||
this.parent = parent;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public MessageId getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.briarproject.api.messaging;
|
||||
|
||||
import org.briarproject.api.sync.Message;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -8,8 +8,7 @@ import java.security.GeneralSecurityException;
|
||||
|
||||
public interface PrivateMessageFactory {
|
||||
|
||||
Message createPrivateMessage(MessageId parent,
|
||||
PrivateConversation conversation, String contentType,
|
||||
long timestamp, byte[] body) throws IOException,
|
||||
GeneralSecurityException;
|
||||
PrivateMessage createPrivateMessage(GroupId groupId, long timestamp,
|
||||
MessageId parent, String contentType, byte[] body)
|
||||
throws IOException, GeneralSecurityException;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,51 @@
|
||||
package org.briarproject.api.messaging;
|
||||
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
public interface PrivateMessageHeader {
|
||||
public class PrivateMessageHeader {
|
||||
|
||||
enum Status { STORED, SENT, DELIVERED }
|
||||
private final MessageId id;
|
||||
private final long timestamp;
|
||||
private final String contentType;
|
||||
private final boolean local, read, sent, seen;
|
||||
|
||||
MessageId getId();
|
||||
public PrivateMessageHeader(MessageId id, long timestamp,
|
||||
String contentType, boolean local, boolean read, boolean sent,
|
||||
boolean seen) {
|
||||
this.id = id;
|
||||
this.timestamp = timestamp;
|
||||
this.contentType = contentType;
|
||||
this.local = local;
|
||||
this.read = read;
|
||||
this.sent = sent;
|
||||
this.seen = seen;
|
||||
}
|
||||
|
||||
Author getAuthor();
|
||||
public MessageId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
String getContentType();
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
long getTimestamp();
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
boolean isLocal();
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
boolean isRead();
|
||||
public boolean isRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
Status getStatus();
|
||||
public boolean isSent() {
|
||||
return sent;
|
||||
}
|
||||
|
||||
public boolean isSeen() {
|
||||
return seen;
|
||||
}
|
||||
}
|
||||
|
||||
20
briar-api/src/org/briarproject/api/sync/ClientId.java
Normal file
20
briar-api/src/org/briarproject/api/sync/ClientId.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.UniqueId;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for a byte array that uniquely identifies a sync client.
|
||||
*/
|
||||
public class ClientId extends UniqueId {
|
||||
|
||||
public ClientId(byte[] id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof ClientId && Arrays.equals(id, ((ClientId) o).id);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,20 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||
|
||||
/** A group to which users may subscribe. */
|
||||
public class Group {
|
||||
|
||||
private final GroupId id;
|
||||
private final String name;
|
||||
private final byte[] salt;
|
||||
private final ClientId clientId;
|
||||
private final byte[] descriptor;
|
||||
|
||||
public Group(GroupId id, String name, byte[] salt) {
|
||||
int length;
|
||||
try {
|
||||
length = name.getBytes("UTF-8").length;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (length == 0 || length > MessagingConstants.MAX_GROUP_NAME_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
if (salt.length != MessagingConstants.GROUP_SALT_LENGTH)
|
||||
public Group(GroupId id, ClientId clientId, byte[] descriptor) {
|
||||
if (descriptor.length > MAX_GROUP_DESCRIPTOR_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.salt = salt;
|
||||
this.clientId = clientId;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
/** Returns the group's unique identifier. */
|
||||
@@ -30,17 +22,14 @@ public class Group {
|
||||
return id;
|
||||
}
|
||||
|
||||
/** Returns the group's name. */
|
||||
public String getName() {
|
||||
return name;
|
||||
/** Returns the ID of the client to which the group belongs. */
|
||||
public ClientId getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the salt used to distinguish the group from other groups with
|
||||
* the same name.
|
||||
*/
|
||||
public byte[] getSalt() {
|
||||
return salt;
|
||||
/** Returns the group's descriptor. */
|
||||
public byte[] getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,9 +2,6 @@ package org.briarproject.api.sync;
|
||||
|
||||
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);
|
||||
/** Creates a group with the given client ID and descriptor. */
|
||||
Group createGroup(ClientId c, byte[] descriptor);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.UniqueId;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
@@ -9,14 +10,16 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class GroupId extends UniqueId {
|
||||
|
||||
/** Label for hashing groups to calculate their identifiers. */
|
||||
public static final byte[] LABEL =
|
||||
"GROUP_ID".getBytes(Charset.forName("US-ASCII"));
|
||||
|
||||
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;
|
||||
return o instanceof GroupId && Arrays.equals(id, ((GroupId) o).id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,58 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.identity.Author;
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
||||
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||
|
||||
public interface Message {
|
||||
public class Message {
|
||||
|
||||
private final MessageId id;
|
||||
private final GroupId groupId;
|
||||
private final long timestamp;
|
||||
private final byte[] raw;
|
||||
|
||||
public Message(MessageId id, GroupId groupId, long timestamp, byte[] raw) {
|
||||
if (raw.length <= MESSAGE_HEADER_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
if (raw.length > MAX_MESSAGE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
this.id = id;
|
||||
this.groupId = groupId;
|
||||
this.timestamp = timestamp;
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
/** Returns the message's unique identifier. */
|
||||
MessageId getId();
|
||||
public MessageId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Author Author}, or null
|
||||
* if this is an anonymous message.
|
||||
*/
|
||||
Author getAuthor();
|
||||
|
||||
/** Returns the message's content type. */
|
||||
String getContentType();
|
||||
/** Returns the ID of the {@link Group} to which the message belongs. */
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
/** Returns the message's timestamp in milliseconds since the Unix epoch. */
|
||||
long getTimestamp();
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/** Returns the serialised message. */
|
||||
byte[] getSerialised();
|
||||
/** Returns the length of the raw message in bytes. */
|
||||
public int getLength() {
|
||||
return raw.length;
|
||||
}
|
||||
|
||||
/** Returns the offset of the message body within the serialised message. */
|
||||
int getBodyStart();
|
||||
/** Returns the raw message. */
|
||||
public byte[] getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
/** Returns the length of the message body in bytes. */
|
||||
int getBodyLength();
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Message && id.equals(((Message) o).getId());
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,9 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.crypto.PrivateKey;
|
||||
import org.briarproject.api.identity.Author;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
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;
|
||||
Message createMessage(GroupId groupId, long timestamp, byte[] body)
|
||||
throws IOException;
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.identity.Author;
|
||||
|
||||
public class MessageHeader {
|
||||
|
||||
public enum State { STORED, SENT, DELIVERED }
|
||||
|
||||
private final MessageId id, parent;
|
||||
private final GroupId groupId;
|
||||
private final Author author;
|
||||
private final Author.Status authorStatus;
|
||||
private final String contentType;
|
||||
private final long timestamp;
|
||||
private final boolean local, read;
|
||||
private final State status;
|
||||
|
||||
public MessageHeader(MessageId id, MessageId parent, GroupId groupId,
|
||||
Author author, Author.Status authorStatus, String contentType,
|
||||
long timestamp, boolean local, boolean read, State status) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
this.groupId = groupId;
|
||||
this.author = author;
|
||||
this.authorStatus = authorStatus;
|
||||
this.contentType = contentType;
|
||||
this.timestamp = timestamp;
|
||||
this.local = local;
|
||||
this.read = read;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/** 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 status of the message's author. */
|
||||
public Author.Status getAuthorStatus() {
|
||||
return authorStatus;
|
||||
}
|
||||
|
||||
/** 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 was locally generated. */
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
/** Returns true if the message has been read. */
|
||||
public boolean isRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns message status. (This only applies to locally generated private
|
||||
* messages.)
|
||||
*/
|
||||
public State getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.UniqueId;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
@@ -10,14 +11,16 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class MessageId extends UniqueId {
|
||||
|
||||
/** Label for hashing messages to calculate their identifiers. */
|
||||
public static final byte[] LABEL =
|
||||
"MESSAGE_ID".getBytes(Charset.forName("US-ASCII"));
|
||||
|
||||
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;
|
||||
return o instanceof MessageId && Arrays.equals(id, ((MessageId) o).id);
|
||||
}
|
||||
}
|
||||
|
||||
38
briar-api/src/org/briarproject/api/sync/MessageStatus.java
Normal file
38
briar-api/src/org/briarproject/api/sync/MessageStatus.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
|
||||
public class MessageStatus {
|
||||
|
||||
private final MessageId messageId;
|
||||
private final ContactId contactId;
|
||||
private final boolean sent, seen;
|
||||
|
||||
public MessageStatus(MessageId messageId, ContactId contactId,
|
||||
boolean sent, boolean seen) {
|
||||
this.messageId = messageId;
|
||||
this.contactId = contactId;
|
||||
this.sent = sent;
|
||||
this.seen = seen;
|
||||
}
|
||||
|
||||
/** Returns the ID of the message. */
|
||||
public MessageId getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
/** Returns the ID of the contact. */
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
/** Returns true if the message has been sent to the contact. */
|
||||
public boolean isSent() {
|
||||
return sent;
|
||||
}
|
||||
|
||||
/** Returns true if the message has been seen by the contact. */
|
||||
public boolean isSeen() {
|
||||
return seen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.db.Metadata;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
|
||||
public interface MessageValidator extends Service {
|
||||
|
||||
/**
|
||||
* Validates the given message and returns its metadata if the message
|
||||
* is valid, or null if the message is invalid.
|
||||
*/
|
||||
Metadata validateMessage(Message m);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/** Verifies the signatures on an {@link UnverifiedMessage}. */
|
||||
public interface MessageVerifier {
|
||||
|
||||
Message verifyMessage(UnverifiedMessage m) throws GeneralSecurityException;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
|
||||
public interface MessagingConstants {
|
||||
|
||||
/** The current version of the messaging protocol. */
|
||||
byte PROTOCOL_VERSION = 0;
|
||||
|
||||
/** The length of the packet header in bytes. */
|
||||
int HEADER_LENGTH = 4;
|
||||
|
||||
/** The maximum length of the packet payload in bytes. */
|
||||
int MAX_PAYLOAD_LENGTH = 32 * 1024; // 32 KiB
|
||||
|
||||
/** The maximum number of public groups a user may subscribe to. */
|
||||
int MAX_SUBSCRIPTIONS = 300;
|
||||
|
||||
/** 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 payload length
|
||||
* even when all the message's other fields have their maximum lengths.
|
||||
*/
|
||||
int MAX_BODY_LENGTH = MAX_PAYLOAD_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
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public interface PacketReader {
|
||||
Ack readAck() throws IOException;
|
||||
|
||||
boolean hasMessage() throws IOException;
|
||||
UnverifiedMessage readMessage() throws IOException;
|
||||
Message readMessage() throws IOException;
|
||||
|
||||
boolean hasOffer() throws IOException;
|
||||
Offer readOffer() throws IOException;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
/** Packet types for the messaging protocol. */
|
||||
/** Packet types for the sync protocol. */
|
||||
public interface PacketTypes {
|
||||
|
||||
byte ACK = 0;
|
||||
|
||||
30
briar-api/src/org/briarproject/api/sync/SyncConstants.java
Normal file
30
briar-api/src/org/briarproject/api/sync/SyncConstants.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.UniqueId;
|
||||
|
||||
public interface SyncConstants {
|
||||
|
||||
/** The current version of the sync protocol. */
|
||||
byte PROTOCOL_VERSION = 0;
|
||||
|
||||
/** The length of the packet header in bytes. */
|
||||
int PACKET_HEADER_LENGTH = 4;
|
||||
|
||||
/** The maximum length of the packet payload in bytes. */
|
||||
int MAX_PACKET_PAYLOAD_LENGTH = 32 * 1024; // 32 KiB
|
||||
|
||||
/** The maximum number of groups a user may subscribe to. */
|
||||
int MAX_SUBSCRIPTIONS = 200;
|
||||
|
||||
/** The maximum length of a group descriptor in bytes. */
|
||||
int MAX_GROUP_DESCRIPTOR_LENGTH = 100;
|
||||
|
||||
/** The maximum length of a message in bytes. */
|
||||
int MAX_MESSAGE_LENGTH = MAX_PACKET_PAYLOAD_LENGTH - PACKET_HEADER_LENGTH;
|
||||
|
||||
/** The length of the message header in bytes. */
|
||||
int MESSAGE_HEADER_LENGTH = UniqueId.LENGTH + 8;
|
||||
|
||||
/** The maximum length of a message body in bytes. */
|
||||
int MAX_MESSAGE_BODY_LENGTH = MAX_MESSAGE_LENGTH - MESSAGE_HEADER_LENGTH;
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package org.briarproject.api.sync;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface MessagingSession {
|
||||
public interface SyncSession {
|
||||
|
||||
/**
|
||||
* Runs the session. This method returns when there are no more packets to
|
||||
@@ -6,14 +6,14 @@ import org.briarproject.api.contact.ContactId;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface MessagingSessionFactory {
|
||||
public interface SyncSessionFactory {
|
||||
|
||||
MessagingSession createIncomingSession(ContactId c, TransportId t,
|
||||
SyncSession createIncomingSession(ContactId c, TransportId t,
|
||||
InputStream in);
|
||||
|
||||
MessagingSession createSimplexOutgoingSession(ContactId c, TransportId t,
|
||||
SyncSession createSimplexOutgoingSession(ContactId c, TransportId t,
|
||||
int maxLatency, OutputStream out);
|
||||
|
||||
MessagingSession createDuplexOutgoingSession(ContactId c, TransportId t,
|
||||
SyncSession createDuplexOutgoingSession(ContactId c, TransportId t,
|
||||
int maxLatency, int maxIdleTime, OutputStream out);
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.identity.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 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.briarproject.api.sync;
|
||||
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
|
||||
/**
|
||||
* Responsible for managing message validators and passing them messages to
|
||||
* validate.
|
||||
*/
|
||||
public interface ValidationManager extends Service {
|
||||
|
||||
/** Sets the message validator for the given client. */
|
||||
void setMessageValidator(ClientId c, MessageValidator v);
|
||||
}
|
||||
Reference in New Issue
Block a user