mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 11:19:04 +01:00
Updated java.library.path.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.briar.api.client.BaseGroup;
|
||||
import org.briarproject.briar.api.sharing.Shareable;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class Blog extends BaseGroup implements Shareable {
|
||||
|
||||
private final Author author;
|
||||
|
||||
public Blog(Group group, Author author) {
|
||||
super(group);
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Blog && super.equals(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the blog's author's name, not the name as shown in the UI.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return author.getName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.briar.api.blog.MessageType.COMMENT;
|
||||
import static org.briarproject.briar.api.blog.MessageType.WRAPPED_COMMENT;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class BlogCommentHeader extends BlogPostHeader {
|
||||
|
||||
@Nullable
|
||||
private final String comment;
|
||||
private final BlogPostHeader parent;
|
||||
|
||||
public BlogCommentHeader(MessageType type, GroupId groupId,
|
||||
@Nullable String comment, BlogPostHeader parent, MessageId id,
|
||||
long timestamp, long timeReceived, Author author,
|
||||
Status authorStatus, boolean read) {
|
||||
|
||||
super(type, groupId, id, parent.getId(), timestamp,
|
||||
timeReceived, author, authorStatus, read);
|
||||
|
||||
if (type != COMMENT && type != WRAPPED_COMMENT)
|
||||
throw new IllegalArgumentException("Incompatible Message Type");
|
||||
|
||||
this.comment = comment;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public BlogPostHeader getParent() {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface BlogConstants {
|
||||
|
||||
/**
|
||||
* The maximum length of a blogs's name in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_BLOG_TITLE_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* The length of a blogs's description in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_BLOG_DESC_LENGTH = 240;
|
||||
|
||||
/**
|
||||
* The maximum length of a blog post's body in bytes.
|
||||
*/
|
||||
int MAX_BLOG_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
|
||||
/**
|
||||
* The maximum length of a blog comment in bytes.
|
||||
*/
|
||||
int MAX_BLOG_COMMENT_LENGTH = MAX_BLOG_POST_BODY_LENGTH;
|
||||
|
||||
/* Blog Sharing Constants */
|
||||
String BLOG_AUTHOR_NAME = "blogAuthorName";
|
||||
String BLOG_PUBLIC_KEY = "blogPublicKey";
|
||||
|
||||
// Metadata keys
|
||||
String KEY_TYPE = "type";
|
||||
String KEY_DESCRIPTION = "description";
|
||||
String KEY_TIMESTAMP = "timestamp";
|
||||
String KEY_TIME_RECEIVED = "timeReceived";
|
||||
String KEY_AUTHOR_ID = "id";
|
||||
String KEY_AUTHOR_NAME = "name";
|
||||
String KEY_PUBLIC_KEY = "publicKey";
|
||||
String KEY_AUTHOR = "author";
|
||||
String KEY_READ = "read";
|
||||
String KEY_COMMENT = "comment";
|
||||
String KEY_ORIGINAL_MSG_ID = "originalMessageId";
|
||||
String KEY_ORIGINAL_PARENT_MSG_ID = "originalParentMessageId";
|
||||
/**
|
||||
* This is the ID of either a message wrapped from a different group
|
||||
* or of a message from the same group that therefore needed no wrapping.
|
||||
*/
|
||||
String KEY_PARENT_MSG_ID = "parentMessageId";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface BlogFactory {
|
||||
|
||||
/**
|
||||
* Creates a personal blog for a given author.
|
||||
*/
|
||||
Blog createBlog(Author author);
|
||||
|
||||
/**
|
||||
* Parses a blog with the given Group
|
||||
*/
|
||||
Blog parseBlog(Group g) throws FormatException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public class BlogInvitationRequest extends InvitationRequest {
|
||||
|
||||
private final String blogAuthorName;
|
||||
|
||||
public BlogInvitationRequest(MessageId id, SessionId sessionId,
|
||||
GroupId groupId, ContactId contactId, String blogAuthorName,
|
||||
@Nullable String message, boolean available, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
|
||||
super(id, sessionId, groupId, contactId, message, available, time,
|
||||
local, sent, seen, read);
|
||||
this.blogAuthorName = blogAuthorName;
|
||||
}
|
||||
|
||||
public String getBlogAuthorName() {
|
||||
return blogAuthorName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
||||
|
||||
@NotNullByDefault
|
||||
public class BlogInvitationResponse extends InvitationResponse {
|
||||
|
||||
public BlogInvitationResponse(MessageId id, SessionId sessionId,
|
||||
GroupId groupId, ContactId contactId, boolean accept, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
|
||||
super(id, sessionId, groupId, contactId, accept, time, local, sent,
|
||||
seen, read);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface BlogManager {
|
||||
|
||||
/**
|
||||
* Unique ID of the blog client.
|
||||
*/
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog");
|
||||
|
||||
/**
|
||||
* Returns true if a blog can be removed.
|
||||
*/
|
||||
boolean canBeRemoved(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes and deletes a blog.
|
||||
*/
|
||||
void removeBlog(Blog b) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a local blog post.
|
||||
*/
|
||||
void addLocalPost(BlogPost p) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a local blog post.
|
||||
*/
|
||||
void addLocalPost(Transaction txn, BlogPost p) throws DbException;
|
||||
|
||||
/**
|
||||
* Adds a comment to an existing blog post or reblogs it.
|
||||
*/
|
||||
void addLocalComment(LocalAuthor author, GroupId groupId,
|
||||
@Nullable String comment, BlogPostHeader wHeader)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the blog with the given ID.
|
||||
*/
|
||||
Blog getBlog(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the blog with the given ID.
|
||||
*/
|
||||
Blog getBlog(Transaction txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all blogs owned by the given localAuthor.
|
||||
*/
|
||||
Collection<Blog> getBlogs(LocalAuthor localAuthor) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns only the personal blog of the given author.
|
||||
*/
|
||||
Blog getPersonalBlog(Author author);
|
||||
|
||||
/**
|
||||
* Returns all blogs to which the user subscribes.
|
||||
*/
|
||||
Collection<Blog> getBlogs() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the header of the blog post with the given ID.
|
||||
*/
|
||||
BlogPostHeader getPostHeader(GroupId g, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the body of the blog post with the given ID.
|
||||
*/
|
||||
String getPostBody(MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the headers of all posts in the given blog.
|
||||
*/
|
||||
Collection<BlogPostHeader> getPostHeaders(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks a blog post as read or unread.
|
||||
*/
|
||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
||||
|
||||
/**
|
||||
* Registers a hook to be called whenever a blog is removed.
|
||||
*/
|
||||
void registerRemoveBlogHook(RemoveBlogHook hook);
|
||||
|
||||
interface RemoveBlogHook {
|
||||
void removingBlog(Transaction txn, Blog b) throws DbException;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.forum.ForumPost;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class BlogPost extends ForumPost {
|
||||
|
||||
public BlogPost(Message message, @Nullable MessageId parent,
|
||||
Author author) {
|
||||
super(message, parent, author);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface BlogPostFactory {
|
||||
|
||||
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
|
||||
String SIGNING_LABEL_COMMENT = CLIENT_ID + "/COMMENT";
|
||||
|
||||
BlogPost createBlogPost(GroupId groupId, long timestamp,
|
||||
@Nullable MessageId parent, LocalAuthor author, String body)
|
||||
throws FormatException, GeneralSecurityException;
|
||||
|
||||
Message createBlogComment(GroupId groupId, LocalAuthor author,
|
||||
@Nullable String comment, MessageId originalId, MessageId wrappedId)
|
||||
throws FormatException, GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Wraps a blog post
|
||||
*/
|
||||
Message wrapPost(GroupId groupId, byte[] descriptor, long timestamp,
|
||||
BdfList body) throws FormatException;
|
||||
|
||||
/**
|
||||
* Re-wraps a previously wrapped post
|
||||
*/
|
||||
Message rewrapWrappedPost(GroupId groupId, BdfList body)
|
||||
throws FormatException;
|
||||
|
||||
/**
|
||||
* Wraps a blog comment
|
||||
*/
|
||||
Message wrapComment(GroupId groupId, byte[] descriptor, long timestamp,
|
||||
BdfList body, MessageId currentId) throws FormatException;
|
||||
|
||||
/**
|
||||
* Re-wraps a previously wrapped comment
|
||||
*/
|
||||
Message rewrapWrappedComment(GroupId groupId, BdfList body,
|
||||
MessageId currentId) throws FormatException;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.PostHeader;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class BlogPostHeader extends PostHeader {
|
||||
|
||||
private final MessageType type;
|
||||
private final GroupId groupId;
|
||||
private final long timeReceived;
|
||||
|
||||
public BlogPostHeader(MessageType type, GroupId groupId, MessageId id,
|
||||
@Nullable MessageId parentId, long timestamp, long timeReceived,
|
||||
Author author, Status authorStatus, boolean read) {
|
||||
super(id, parentId, timestamp, author, authorStatus, read);
|
||||
this.type = type;
|
||||
this.groupId = groupId;
|
||||
this.timeReceived = timeReceived;
|
||||
}
|
||||
|
||||
public BlogPostHeader(MessageType type, GroupId groupId, MessageId id,
|
||||
long timestamp, long timeReceived, Author author,
|
||||
Status authorStatus, boolean read) {
|
||||
this(type, groupId, id, null, timestamp, timeReceived, author,
|
||||
authorStatus, read);
|
||||
}
|
||||
|
||||
public MessageType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public long getTimeReceived() {
|
||||
return timeReceived;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.briar.api.sharing.SharingManager;
|
||||
|
||||
public interface BlogSharingManager extends SharingManager<Blog> {
|
||||
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog.sharing");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.SharingMessage.Invitation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME;
|
||||
import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_MSG;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.TIME;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface BlogSharingMessage {
|
||||
|
||||
class BlogInvitation extends Invitation {
|
||||
|
||||
private final String blogAuthorName;
|
||||
private final byte[] blogPublicKey;
|
||||
|
||||
public BlogInvitation(GroupId groupId, SessionId sessionId,
|
||||
String blogAuthorName, byte[] blogPublicKey, long time,
|
||||
@Nullable String message) {
|
||||
super(groupId, sessionId, time, message);
|
||||
|
||||
this.blogAuthorName = blogAuthorName;
|
||||
this.blogPublicKey = blogPublicKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BdfList toBdfList() {
|
||||
BdfList list = super.toBdfList();
|
||||
list.add(BdfList.of(blogAuthorName, blogPublicKey));
|
||||
if (message != null) list.add(message);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BdfDictionary toBdfDictionary() {
|
||||
BdfDictionary d = toBdfDictionaryHelper();
|
||||
d.put(BLOG_AUTHOR_NAME, blogAuthorName);
|
||||
d.put(BLOG_PUBLIC_KEY, blogPublicKey);
|
||||
if (message != null) d.put(INVITATION_MSG, message);
|
||||
return d;
|
||||
}
|
||||
|
||||
public static BlogInvitation from(GroupId groupId, BdfDictionary d)
|
||||
throws FormatException {
|
||||
|
||||
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
|
||||
String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
|
||||
byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
|
||||
String message = d.getOptionalString(INVITATION_MSG);
|
||||
long time = d.getLong(TIME);
|
||||
|
||||
return new BlogInvitation(groupId, sessionId, blogAuthorName,
|
||||
blogPublicKey, time, message);
|
||||
}
|
||||
|
||||
public String getBlogAuthorName() {
|
||||
return blogAuthorName;
|
||||
}
|
||||
|
||||
public byte[] getBlogPublicKey() {
|
||||
return blogPublicKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.briarproject.briar.api.blog;
|
||||
|
||||
public enum MessageType {
|
||||
|
||||
POST(0),
|
||||
COMMENT(1),
|
||||
WRAPPED_POST(2),
|
||||
WRAPPED_COMMENT(3);
|
||||
|
||||
int value;
|
||||
|
||||
MessageType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static MessageType valueOf(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return POST;
|
||||
case 1:
|
||||
return COMMENT;
|
||||
case 2:
|
||||
return WRAPPED_POST;
|
||||
case 3:
|
||||
return WRAPPED_COMMENT;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.blog.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.blog.Blog;
|
||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
||||
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class BlogInvitationRequestReceivedEvent extends
|
||||
InvitationRequestReceivedEvent<Blog> {
|
||||
|
||||
public BlogInvitationRequestReceivedEvent(Blog blog, ContactId contactId,
|
||||
InvitationRequest request) {
|
||||
super(blog, contactId, request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.briarproject.briar.api.blog.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.blog.BlogInvitationResponse;
|
||||
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class BlogInvitationResponseReceivedEvent
|
||||
extends InvitationResponseReceivedEvent {
|
||||
|
||||
public BlogInvitationResponseReceivedEvent(ContactId contactId,
|
||||
BlogInvitationResponse response) {
|
||||
super(contactId, response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.briarproject.briar.api.blog.event;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.blog.BlogPostHeader;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a blog post is added to the database.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class BlogPostAddedEvent extends Event {
|
||||
|
||||
private final GroupId groupId;
|
||||
private final BlogPostHeader header;
|
||||
private final boolean local;
|
||||
|
||||
public BlogPostAddedEvent(GroupId groupId, BlogPostHeader header,
|
||||
boolean local) {
|
||||
|
||||
this.groupId = groupId;
|
||||
this.header = header;
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public BlogPostHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class BaseGroup {
|
||||
|
||||
private final Group group;
|
||||
|
||||
public BaseGroup(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 BaseGroup &&
|
||||
getGroup().equals(((BaseGroup) o).getGroup());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class BaseMessageHeader {
|
||||
|
||||
private final MessageId id;
|
||||
private final GroupId groupId;
|
||||
private final long timestamp;
|
||||
private final boolean local, read, sent, seen;
|
||||
|
||||
public BaseMessageHeader(MessageId id, GroupId groupId, long timestamp,
|
||||
boolean local, boolean read, boolean sent, boolean seen) {
|
||||
|
||||
this.id = id;
|
||||
this.groupId = groupId;
|
||||
this.timestamp = timestamp;
|
||||
this.local = local;
|
||||
this.read = read;
|
||||
this.sent = sent;
|
||||
this.seen = seen;
|
||||
}
|
||||
|
||||
public MessageId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public boolean isRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
public boolean isSent() {
|
||||
return sent;
|
||||
}
|
||||
|
||||
public boolean isSeen() {
|
||||
return seen;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Metadata;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||
import org.briarproject.bramble.api.sync.MessageContext;
|
||||
|
||||
@Deprecated
|
||||
@NotNullByDefault
|
||||
public interface MessageQueueManager {
|
||||
|
||||
/**
|
||||
* The key used for storing the queue's state in the group metadata.
|
||||
*/
|
||||
String QUEUE_STATE_KEY = "queueState";
|
||||
|
||||
/**
|
||||
* Sends a message using the given queue.
|
||||
*/
|
||||
QueueMessage sendMessage(Transaction txn, Group queue, long timestamp,
|
||||
byte[] body, Metadata meta) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the message validator for the given client.
|
||||
*/
|
||||
void registerMessageValidator(ClientId c, QueueMessageValidator v);
|
||||
|
||||
/**
|
||||
* Sets the incoming message hook for the given client. The hook will be
|
||||
* called once for each incoming message that passes validation. Messages
|
||||
* are passed to the hook in order.
|
||||
*/
|
||||
void registerIncomingMessageHook(ClientId c, IncomingQueueMessageHook hook);
|
||||
|
||||
@Deprecated
|
||||
interface QueueMessageValidator {
|
||||
|
||||
/**
|
||||
* Validates the given message and returns its metadata and
|
||||
* dependencies.
|
||||
*/
|
||||
MessageContext validateMessage(QueueMessage q, Group g)
|
||||
throws InvalidMessageException;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
interface IncomingQueueMessageHook {
|
||||
|
||||
/**
|
||||
* Called once for each incoming message that passes validation.
|
||||
* Messages are passed to the hook in order.
|
||||
*
|
||||
* @throws DbException Should only be used for real database errors.
|
||||
* If this is thrown, delivery will be attempted again at next startup,
|
||||
* whereas if an InvalidMessageException is thrown,
|
||||
* the message will be permanently invalidated.
|
||||
* @throws InvalidMessageException for any non-database error
|
||||
* that occurs while handling remotely created data.
|
||||
* This includes errors that occur while handling locally created data
|
||||
* in a context controlled by remotely created data
|
||||
* (for example, parsing the metadata of a dependency
|
||||
* of an incoming message).
|
||||
* Never rethrow DbException as InvalidMessageException!
|
||||
*/
|
||||
void incomingMessage(Transaction txn, QueueMessage q, Metadata meta)
|
||||
throws DbException, InvalidMessageException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface MessageTracker {
|
||||
|
||||
/**
|
||||
* Gets the number of visible and unread messages in the group
|
||||
* as well as the timestamp of the latest message
|
||||
**/
|
||||
GroupCount getGroupCount(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Gets the number of visible and unread messages in the group
|
||||
* as well as the timestamp of the latest message
|
||||
**/
|
||||
GroupCount getGroupCount(Transaction txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Updates the group count for the given incoming message.
|
||||
*/
|
||||
void trackIncomingMessage(Transaction txn, Message m) throws DbException;
|
||||
|
||||
/**
|
||||
* Updates the group count for the given outgoing message.
|
||||
*/
|
||||
void trackOutgoingMessage(Transaction txn, Message m) throws DbException;
|
||||
|
||||
/**
|
||||
* Updates the group count for the given message.
|
||||
*/
|
||||
void trackMessage(Transaction txn, GroupId g, long timestamp, boolean read)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Marks a message as read or unread and updates the group count.
|
||||
*/
|
||||
void setReadFlag(GroupId g, MessageId m, boolean read) throws DbException;
|
||||
|
||||
class GroupCount {
|
||||
|
||||
private final int msgCount, unreadCount;
|
||||
private final long latestMsgTime;
|
||||
|
||||
public GroupCount(int msgCount, int unreadCount, long latestMsgTime) {
|
||||
this.msgCount = msgCount;
|
||||
this.unreadCount = unreadCount;
|
||||
this.latestMsgTime = latestMsgTime;
|
||||
}
|
||||
|
||||
public int getMsgCount() {
|
||||
return msgCount;
|
||||
}
|
||||
|
||||
public int getUnreadCount() {
|
||||
return unreadCount;
|
||||
}
|
||||
|
||||
public long getLatestMsgTime() {
|
||||
return latestMsgTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface MessageTree<T extends MessageTree.MessageNode> {
|
||||
|
||||
void add(Collection<T> nodes);
|
||||
|
||||
void add(T node);
|
||||
|
||||
void setComparator(Comparator<T> comparator);
|
||||
|
||||
void clear();
|
||||
|
||||
Collection<T> depthFirstOrder();
|
||||
|
||||
@NotNullByDefault
|
||||
interface MessageNode {
|
||||
|
||||
MessageId getId();
|
||||
|
||||
@Nullable
|
||||
MessageId getParentId();
|
||||
|
||||
void setLevel(int level);
|
||||
|
||||
void setDescendantCount(int descendantCount);
|
||||
|
||||
long getTimestamp();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class NamedGroup extends BaseGroup {
|
||||
|
||||
private final String name;
|
||||
private final byte[] salt;
|
||||
|
||||
public NamedGroup(Group group, String name, byte[] salt) {
|
||||
super(group);
|
||||
this.name = name;
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof NamedGroup && super.equals(o);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class PostHeader {
|
||||
|
||||
private final MessageId id;
|
||||
@Nullable
|
||||
private final MessageId parentId;
|
||||
private final long timestamp;
|
||||
private final Author author;
|
||||
private final Status authorStatus;
|
||||
private final boolean read;
|
||||
|
||||
public PostHeader(MessageId id, @Nullable MessageId parentId,
|
||||
long timestamp, Author author, Status authorStatus, boolean read) {
|
||||
this.id = id;
|
||||
this.parentId = parentId;
|
||||
this.timestamp = timestamp;
|
||||
this.author = author;
|
||||
this.authorStatus = authorStatus;
|
||||
this.read = read;
|
||||
}
|
||||
|
||||
public MessageId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public Status getAuthorStatus() {
|
||||
return authorStatus;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public boolean isRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MessageId getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
@NotNullByDefault
|
||||
public interface ProtocolEngine<A, S, M> {
|
||||
|
||||
StateUpdate<S, M> onLocalAction(S localState, A action);
|
||||
|
||||
StateUpdate<S, M> onMessageReceived(S localState, M received);
|
||||
|
||||
StateUpdate<S, M> onMessageDelivered(S localState, M delivered);
|
||||
|
||||
class StateUpdate<S, M> {
|
||||
public final boolean deleteMessage;
|
||||
public final boolean deleteState;
|
||||
public final S localState;
|
||||
public final List<M> toSend;
|
||||
public final List<Event> toBroadcast;
|
||||
|
||||
/**
|
||||
* This class represents an update of the local protocol state.
|
||||
* It only shows how the state should be updated,
|
||||
* but does not carry out the updates on its own.
|
||||
*
|
||||
* @param deleteMessage whether to delete the message that triggered
|
||||
* the state update. This will be ignored for
|
||||
* {@link ProtocolEngine#onLocalAction}.
|
||||
* @param deleteState whether to delete the localState {@link S}
|
||||
* @param localState the new local state
|
||||
* @param toSend a list of messages to be sent as part of the
|
||||
* state update
|
||||
* @param toBroadcast a list of events to broadcast as result of the
|
||||
* state update
|
||||
*/
|
||||
public StateUpdate(boolean deleteMessage, boolean deleteState,
|
||||
S localState, List<M> toSend, List<Event> toBroadcast) {
|
||||
|
||||
this.deleteMessage = deleteMessage;
|
||||
this.deleteState = deleteState;
|
||||
this.localState = localState;
|
||||
this.toSend = toSend;
|
||||
this.toBroadcast = toBroadcast;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
|
||||
/**
|
||||
* Thrown when a database operation is attempted as part of a protocol session
|
||||
* and the operation is not applicable to the current protocol state. This
|
||||
* exception may occur due to concurrent updates and does not indicate a
|
||||
* database error.
|
||||
*/
|
||||
public class ProtocolStateException extends DbException {
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||
|
||||
@Deprecated
|
||||
@NotNullByDefault
|
||||
public class QueueMessage extends Message {
|
||||
|
||||
public static final int QUEUE_MESSAGE_HEADER_LENGTH =
|
||||
MESSAGE_HEADER_LENGTH + 8;
|
||||
public static final int MAX_QUEUE_MESSAGE_BODY_LENGTH =
|
||||
MAX_MESSAGE_BODY_LENGTH - 8;
|
||||
|
||||
private final long queuePosition;
|
||||
|
||||
public QueueMessage(MessageId id, GroupId groupId, long timestamp,
|
||||
long queuePosition, byte[] raw) {
|
||||
super(id, groupId, timestamp, raw);
|
||||
this.queuePosition = queuePosition;
|
||||
}
|
||||
|
||||
public long getQueuePosition() {
|
||||
return queuePosition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
@Deprecated
|
||||
@NotNullByDefault
|
||||
public interface QueueMessageFactory {
|
||||
|
||||
QueueMessage createMessage(GroupId groupId, long timestamp,
|
||||
long queuePosition, byte[] body);
|
||||
|
||||
QueueMessage createMessage(MessageId id, byte[] raw);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.UniqueId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for a byte array that uniquely identifies a protocol
|
||||
* session.
|
||||
*/
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
public class SessionId extends UniqueId {
|
||||
|
||||
public SessionId(byte[] id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof SessionId && super.equals(o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.briarproject.briar.api.client;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class ThreadedMessage extends PrivateMessage {
|
||||
|
||||
@Nullable
|
||||
private final MessageId parent;
|
||||
private final Author author;
|
||||
|
||||
public ThreadedMessage(Message message, @Nullable MessageId parent,
|
||||
Author author) {
|
||||
super(message);
|
||||
this.parent = parent;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MessageId getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package org.briarproject.briar.api.feed;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfEntry;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_BLOG_GROUP_ID;
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_ADDED;
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_AUTHOR;
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_DESC;
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_LAST_ENTRY;
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_TITLE;
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_UPDATED;
|
||||
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_URL;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class Feed {
|
||||
|
||||
private final String url;
|
||||
private final GroupId blogId;
|
||||
@Nullable
|
||||
private final String title, description, author;
|
||||
private final long added, updated, lastEntryTime;
|
||||
|
||||
public Feed(String url, GroupId blogId, @Nullable String title,
|
||||
@Nullable String description, @Nullable String author,
|
||||
long added, long updated, long lastEntryTime) {
|
||||
|
||||
this.url = url;
|
||||
this.blogId = blogId;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.author = author;
|
||||
this.added = added;
|
||||
this.updated = updated;
|
||||
this.lastEntryTime = lastEntryTime;
|
||||
}
|
||||
|
||||
public Feed(String url, GroupId blogId, @Nullable String title,
|
||||
@Nullable String description, @Nullable String author, long added) {
|
||||
this(url, blogId, title, description, author, added, 0L, 0L);
|
||||
}
|
||||
|
||||
public Feed(String url, GroupId blogId, long added) {
|
||||
this(url, blogId, null, null, null, added, 0L, 0L);
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public GroupId getBlogId() {
|
||||
return blogId;
|
||||
}
|
||||
|
||||
public BdfDictionary toBdfDictionary() {
|
||||
BdfDictionary d = BdfDictionary.of(
|
||||
new BdfEntry(KEY_FEED_URL, url),
|
||||
new BdfEntry(KEY_BLOG_GROUP_ID, blogId.getBytes()),
|
||||
new BdfEntry(KEY_FEED_ADDED, added),
|
||||
new BdfEntry(KEY_FEED_UPDATED, updated),
|
||||
new BdfEntry(KEY_FEED_LAST_ENTRY, lastEntryTime)
|
||||
);
|
||||
if (title != null) d.put(KEY_FEED_TITLE, title);
|
||||
if (description != null) d.put(KEY_FEED_DESC, description);
|
||||
if (author != null) d.put(KEY_FEED_AUTHOR, author);
|
||||
return d;
|
||||
}
|
||||
|
||||
public static Feed from(BdfDictionary d) throws FormatException {
|
||||
String url = d.getString(KEY_FEED_URL);
|
||||
GroupId blogId = new GroupId(d.getRaw(KEY_BLOG_GROUP_ID));
|
||||
String title = d.getOptionalString(KEY_FEED_TITLE);
|
||||
String desc = d.getOptionalString(KEY_FEED_DESC);
|
||||
String author = d.getOptionalString(KEY_FEED_AUTHOR);
|
||||
long added = d.getLong(KEY_FEED_ADDED, 0L);
|
||||
long updated = d.getLong(KEY_FEED_UPDATED, 0L);
|
||||
long lastEntryTime = d.getLong(KEY_FEED_LAST_ENTRY, 0L);
|
||||
return new Feed(url, blogId, title, desc, author, added, updated,
|
||||
lastEntryTime);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public long getAdded() {
|
||||
return added;
|
||||
}
|
||||
|
||||
public long getUpdated() {
|
||||
return updated;
|
||||
}
|
||||
|
||||
public long getLastEntryTime() {
|
||||
return lastEntryTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o instanceof Feed) {
|
||||
Feed f = (Feed) o;
|
||||
return url.equals(f.url) && blogId.equals(f.getBlogId()) &&
|
||||
equalsWithNull(title, f.getTitle()) &&
|
||||
equalsWithNull(description, f.getDescription()) &&
|
||||
equalsWithNull(author, f.getAuthor()) &&
|
||||
added == f.getAdded() &&
|
||||
updated == f.getUpdated() &&
|
||||
lastEntryTime == f.getLastEntryTime();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equalsWithNull(@Nullable Object a, @Nullable Object b) {
|
||||
if (a == b) return true;
|
||||
if (a == null || b == null) return false;
|
||||
return a.equals(b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.briarproject.briar.api.feed;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
|
||||
public interface FeedConstants {
|
||||
|
||||
/* delay after start before fetching feed */
|
||||
int FETCH_DELAY_INITIAL = 1;
|
||||
|
||||
/* the interval the feed should be fetched */
|
||||
int FETCH_INTERVAL = 30;
|
||||
|
||||
/* the unit that applies to the fetch times */
|
||||
TimeUnit FETCH_UNIT = MINUTES;
|
||||
|
||||
// group metadata keys
|
||||
String KEY_FEEDS = "feeds";
|
||||
String KEY_FEED_URL = "feedURL";
|
||||
String KEY_BLOG_GROUP_ID = "blogGroupId";
|
||||
String KEY_FEED_TITLE = "feedTitle";
|
||||
String KEY_FEED_DESC = "feedDesc";
|
||||
String KEY_FEED_AUTHOR = "feedAuthor";
|
||||
String KEY_FEED_ADDED = "feedAdded";
|
||||
String KEY_FEED_UPDATED = "feedUpdated";
|
||||
String KEY_FEED_LAST_ENTRY = "feedLastEntryTime";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.briarproject.briar.api.feed;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface FeedManager {
|
||||
|
||||
/**
|
||||
* The unique ID of the RSS feed client.
|
||||
*/
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.feed");
|
||||
|
||||
/**
|
||||
* Adds an RSS feed.
|
||||
*/
|
||||
void addFeed(String url, GroupId g) throws DbException, IOException;
|
||||
|
||||
/**
|
||||
* Removes an RSS feed.
|
||||
*/
|
||||
void removeFeed(String url) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns a list of all added RSS feeds
|
||||
*/
|
||||
List<Feed> getFeeds() throws DbException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.briar.api.client.NamedGroup;
|
||||
import org.briarproject.briar.api.sharing.Shareable;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class Forum extends NamedGroup implements Shareable {
|
||||
|
||||
public Forum(Group group, String name, byte[] salt) {
|
||||
super(group, name, salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Forum && super.equals(o);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface ForumConstants {
|
||||
|
||||
/**
|
||||
* The maximum length of a forum's name in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_FORUM_NAME_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* 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 UTF-8 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;
|
||||
|
||||
/* Forum Sharing Constants */
|
||||
String FORUM_NAME = "forumName";
|
||||
String FORUM_SALT = "forumSalt";
|
||||
|
||||
// Database keys
|
||||
String KEY_TIMESTAMP = "timestamp";
|
||||
String KEY_PARENT = "parent";
|
||||
String KEY_ID = "id";
|
||||
String KEY_NAME = "name";
|
||||
String KEY_PUBLIC_NAME = "publicKey";
|
||||
String KEY_AUTHOR = "author";
|
||||
String KEY_LOCAL = "local";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ForumFactory {
|
||||
|
||||
/**
|
||||
* Creates a forum with the given name.
|
||||
*/
|
||||
Forum createForum(String name);
|
||||
|
||||
/**
|
||||
* Creates a forum with the given name and salt.
|
||||
*/
|
||||
Forum createForum(String name, byte[] salt);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ForumInvitationRequest extends InvitationRequest {
|
||||
|
||||
private final String forumName;
|
||||
|
||||
public ForumInvitationRequest(MessageId id, SessionId sessionId,
|
||||
GroupId groupId, ContactId contactId, String forumName,
|
||||
@Nullable String message, boolean available, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
|
||||
super(id, sessionId, groupId, contactId, message, available, time,
|
||||
local, sent, seen, read);
|
||||
this.forumName = forumName;
|
||||
}
|
||||
|
||||
public String getForumName() {
|
||||
return forumName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ForumInvitationResponse extends InvitationResponse {
|
||||
|
||||
public ForumInvitationResponse(MessageId id, SessionId sessionId,
|
||||
GroupId groupId, ContactId contactId, boolean accept, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
|
||||
super(id, sessionId, groupId, contactId, accept, time, local, sent,
|
||||
seen, read);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ForumManager {
|
||||
|
||||
/**
|
||||
* The unique ID of the forum client.
|
||||
*/
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum");
|
||||
|
||||
/**
|
||||
* Subscribes to a forum.
|
||||
*/
|
||||
Forum addForum(String name) throws DbException;
|
||||
|
||||
/**
|
||||
* Unsubscribes from a forum.
|
||||
*/
|
||||
void removeForum(Forum f) throws DbException;
|
||||
|
||||
/**
|
||||
* Creates a local forum post.
|
||||
*/
|
||||
@CryptoExecutor
|
||||
ForumPost createLocalPost(GroupId groupId, String body, long timestamp,
|
||||
@Nullable MessageId parentId, LocalAuthor author);
|
||||
|
||||
/**
|
||||
* Stores a local forum post.
|
||||
*/
|
||||
ForumPostHeader addLocalPost(ForumPost p) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the forum with the given ID.
|
||||
*/
|
||||
Forum getForum(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the forum with the given ID.
|
||||
*/
|
||||
Forum getForum(Transaction txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all forums to which the user subscribes.
|
||||
*/
|
||||
Collection<Forum> getForums() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the body of the forum post with the given ID.
|
||||
*/
|
||||
String getPostBody(MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the headers of all posts in the given forum.
|
||||
*/
|
||||
Collection<ForumPostHeader> getPostHeaders(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Registers a hook to be called whenever a forum is removed.
|
||||
*/
|
||||
void registerRemoveForumHook(RemoveForumHook hook);
|
||||
|
||||
/**
|
||||
* Returns the group count for the given forum.
|
||||
*/
|
||||
GroupCount getGroupCount(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks a message as read or unread and updates the group count.
|
||||
*/
|
||||
void setReadFlag(GroupId g, MessageId m, boolean read) throws DbException;
|
||||
|
||||
interface RemoveForumHook {
|
||||
void removingForum(Transaction txn, Forum f) throws DbException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.ThreadedMessage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ForumPost extends ThreadedMessage {
|
||||
|
||||
public ForumPost(Message message, @Nullable MessageId parent,
|
||||
Author author) {
|
||||
super(message, parent, author);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ForumPostFactory {
|
||||
|
||||
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
|
||||
|
||||
@CryptoExecutor
|
||||
ForumPost createPost(GroupId groupId, long timestamp,
|
||||
@Nullable MessageId parent, LocalAuthor author, String body)
|
||||
throws FormatException, GeneralSecurityException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.PostHeader;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ForumPostHeader extends PostHeader {
|
||||
|
||||
public ForumPostHeader(MessageId id, @Nullable MessageId parentId,
|
||||
long timestamp, Author author, Author.Status authorStatus,
|
||||
boolean read) {
|
||||
super(id, parentId, timestamp, author, authorStatus, read);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.briar.api.sharing.SharingManager;
|
||||
|
||||
public interface ForumSharingManager extends SharingManager<Forum> {
|
||||
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.forum.sharing");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.briarproject.briar.api.forum;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.SharingMessage.Invitation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.briar.api.forum.ForumConstants.FORUM_NAME;
|
||||
import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_MSG;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.TIME;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ForumSharingMessage {
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class ForumInvitation extends Invitation {
|
||||
|
||||
private final String forumName;
|
||||
private final byte[] forumSalt;
|
||||
|
||||
public ForumInvitation(GroupId groupId, SessionId sessionId,
|
||||
String forumName, byte[] forumSalt, long time,
|
||||
@Nullable String message) {
|
||||
|
||||
super(groupId, sessionId, time, message);
|
||||
|
||||
this.forumName = forumName;
|
||||
this.forumSalt = forumSalt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BdfList toBdfList() {
|
||||
BdfList list = super.toBdfList();
|
||||
list.add(forumName);
|
||||
list.add(forumSalt);
|
||||
if (message != null) list.add(message);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BdfDictionary toBdfDictionary() {
|
||||
BdfDictionary d = toBdfDictionaryHelper();
|
||||
d.put(FORUM_NAME, forumName);
|
||||
d.put(FORUM_SALT, forumSalt);
|
||||
if (message != null) d.put(INVITATION_MSG, message);
|
||||
return d;
|
||||
}
|
||||
|
||||
public static ForumInvitation from(GroupId groupId, BdfDictionary d)
|
||||
throws FormatException {
|
||||
|
||||
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
|
||||
String forumName = d.getString(FORUM_NAME);
|
||||
byte[] forumSalt = d.getRaw(FORUM_SALT);
|
||||
String message = d.getOptionalString(INVITATION_MSG);
|
||||
long time = d.getLong(TIME);
|
||||
|
||||
return new ForumInvitation(groupId, sessionId, forumName, forumSalt,
|
||||
time, message);
|
||||
}
|
||||
|
||||
public String getForumName() {
|
||||
return forumName;
|
||||
}
|
||||
|
||||
public byte[] getForumSalt() {
|
||||
return forumSalt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.forum.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.forum.Forum;
|
||||
import org.briarproject.briar.api.forum.ForumInvitationRequest;
|
||||
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ForumInvitationRequestReceivedEvent extends
|
||||
InvitationRequestReceivedEvent<Forum> {
|
||||
|
||||
public ForumInvitationRequestReceivedEvent(Forum forum, ContactId contactId,
|
||||
ForumInvitationRequest request) {
|
||||
super(forum, contactId, request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.forum.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.briar.api.forum.ForumInvitationResponse;
|
||||
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
|
||||
|
||||
public class ForumInvitationResponseReceivedEvent extends
|
||||
InvitationResponseReceivedEvent {
|
||||
|
||||
private final String forumName;
|
||||
|
||||
public ForumInvitationResponseReceivedEvent(String forumName,
|
||||
ContactId contactId, ForumInvitationResponse response) {
|
||||
super(contactId, response);
|
||||
this.forumName = forumName;
|
||||
}
|
||||
|
||||
public String getForumName() {
|
||||
return forumName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.briarproject.briar.api.forum.event;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.forum.ForumPostHeader;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a new forum post is received.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ForumPostReceivedEvent extends Event {
|
||||
|
||||
private final ForumPostHeader forumPostHeader;
|
||||
private final GroupId groupId;
|
||||
|
||||
public ForumPostReceivedEvent(ForumPostHeader forumPostHeader,
|
||||
GroupId groupId) {
|
||||
|
||||
this.forumPostHeader = forumPostHeader;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public ForumPostHeader getForumPostHeader() {
|
||||
return forumPostHeader;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
|
||||
@NotNullByDefault
|
||||
public enum IntroduceeAction {
|
||||
|
||||
LOCAL_ACCEPT,
|
||||
LOCAL_DECLINE,
|
||||
LOCAL_ABORT,
|
||||
REMOTE_REQUEST,
|
||||
REMOTE_ACCEPT,
|
||||
REMOTE_DECLINE,
|
||||
REMOTE_ABORT,
|
||||
ACK;
|
||||
|
||||
@Nullable
|
||||
public static IntroduceeAction getRemote(int type, boolean accept) {
|
||||
if (type == TYPE_REQUEST) return REMOTE_REQUEST;
|
||||
if (type == TYPE_RESPONSE && accept) return REMOTE_ACCEPT;
|
||||
if (type == TYPE_RESPONSE) return REMOTE_DECLINE;
|
||||
if (type == TYPE_ACK) return ACK;
|
||||
if (type == TYPE_ABORT) return REMOTE_ABORT;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IntroduceeAction getRemote(int type) {
|
||||
return getRemote(type, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IntroduceeAction getLocal(int type, boolean accept) {
|
||||
if (type == TYPE_RESPONSE && accept) return LOCAL_ACCEPT;
|
||||
if (type == TYPE_RESPONSE) return LOCAL_DECLINE;
|
||||
if (type == TYPE_ACK) return ACK;
|
||||
if (type == TYPE_ABORT) return LOCAL_ABORT;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IntroduceeAction getLocal(int type) {
|
||||
return getLocal(type, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.briar.api.introduction.IntroduceeAction.ACK;
|
||||
import static org.briarproject.briar.api.introduction.IntroduceeAction.LOCAL_ACCEPT;
|
||||
import static org.briarproject.briar.api.introduction.IntroduceeAction.LOCAL_DECLINE;
|
||||
import static org.briarproject.briar.api.introduction.IntroduceeAction.REMOTE_ACCEPT;
|
||||
import static org.briarproject.briar.api.introduction.IntroduceeAction.REMOTE_DECLINE;
|
||||
import static org.briarproject.briar.api.introduction.IntroduceeAction.REMOTE_REQUEST;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public enum IntroduceeProtocolState {
|
||||
|
||||
ERROR(0),
|
||||
AWAIT_REQUEST(1) {
|
||||
@Override
|
||||
public IntroduceeProtocolState next(IntroduceeAction a) {
|
||||
if (a == REMOTE_REQUEST) return AWAIT_RESPONSES;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_RESPONSES(2) {
|
||||
@Override
|
||||
public IntroduceeProtocolState next(IntroduceeAction a) {
|
||||
if (a == REMOTE_ACCEPT) return AWAIT_LOCAL_RESPONSE;
|
||||
if (a == REMOTE_DECLINE) return FINISHED;
|
||||
if (a == LOCAL_ACCEPT) return AWAIT_REMOTE_RESPONSE;
|
||||
if (a == LOCAL_DECLINE) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_REMOTE_RESPONSE(3) {
|
||||
@Override
|
||||
public IntroduceeProtocolState next(IntroduceeAction a) {
|
||||
if (a == REMOTE_ACCEPT) return AWAIT_ACK;
|
||||
if (a == REMOTE_DECLINE) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_LOCAL_RESPONSE(4) {
|
||||
@Override
|
||||
public IntroduceeProtocolState next(IntroduceeAction a) {
|
||||
if (a == LOCAL_ACCEPT) return AWAIT_ACK;
|
||||
if (a == LOCAL_DECLINE) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_ACK(5) {
|
||||
@Override
|
||||
public IntroduceeProtocolState next(IntroduceeAction a) {
|
||||
if (a == ACK) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
FINISHED(6);
|
||||
|
||||
private final int value;
|
||||
|
||||
IntroduceeProtocolState(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static IntroduceeProtocolState fromValue(int value) {
|
||||
for (IntroduceeProtocolState s : values()) {
|
||||
if (s.value == value) return s;
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public IntroduceeProtocolState next(IntroduceeAction a) {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
|
||||
@NotNullByDefault
|
||||
public enum IntroducerAction {
|
||||
|
||||
LOCAL_REQUEST,
|
||||
LOCAL_ABORT,
|
||||
REMOTE_ACCEPT_1,
|
||||
REMOTE_ACCEPT_2,
|
||||
REMOTE_DECLINE_1,
|
||||
REMOTE_DECLINE_2,
|
||||
REMOTE_ABORT,
|
||||
ACK_1,
|
||||
ACK_2;
|
||||
|
||||
@Nullable
|
||||
public static IntroducerAction getLocal(int type) {
|
||||
if (type == TYPE_REQUEST) return LOCAL_REQUEST;
|
||||
if (type == TYPE_ABORT) return LOCAL_ABORT;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IntroducerAction getRemote(int type, boolean one,
|
||||
boolean accept) {
|
||||
|
||||
if (one) {
|
||||
if (type == TYPE_RESPONSE && accept) return REMOTE_ACCEPT_1;
|
||||
if (type == TYPE_RESPONSE) return REMOTE_DECLINE_1;
|
||||
if (type == TYPE_ACK) return ACK_1;
|
||||
} else {
|
||||
if (type == TYPE_RESPONSE && accept) return REMOTE_ACCEPT_2;
|
||||
if (type == TYPE_RESPONSE) return REMOTE_DECLINE_2;
|
||||
if (type == TYPE_ACK) return ACK_2;
|
||||
}
|
||||
if (type == TYPE_ABORT) return REMOTE_ABORT;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IntroducerAction getRemote(int type, boolean one) {
|
||||
return getRemote(type, one, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.ACK_1;
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.ACK_2;
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.LOCAL_REQUEST;
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ABORT;
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ACCEPT_1;
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ACCEPT_2;
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_DECLINE_1;
|
||||
import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_DECLINE_2;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public enum IntroducerProtocolState {
|
||||
|
||||
ERROR(0),
|
||||
PREPARE_REQUESTS(1) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == LOCAL_REQUEST) return AWAIT_RESPONSES;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_RESPONSES(2) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == REMOTE_ACCEPT_1) return AWAIT_RESPONSE_2;
|
||||
if (a == REMOTE_ACCEPT_2) return AWAIT_RESPONSE_1;
|
||||
if (a == REMOTE_DECLINE_1) return FINISHED;
|
||||
if (a == REMOTE_DECLINE_2) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_RESPONSE_1(3) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == REMOTE_ACCEPT_1) return AWAIT_ACKS;
|
||||
if (a == REMOTE_DECLINE_1) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_RESPONSE_2(4) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == REMOTE_ACCEPT_2) return AWAIT_ACKS;
|
||||
if (a == REMOTE_DECLINE_2) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_ACKS(5) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == ACK_1) return AWAIT_ACK_2;
|
||||
if (a == ACK_2) return AWAIT_ACK_1;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_ACK_1(6) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == ACK_1) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
AWAIT_ACK_2(7) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == ACK_2) return FINISHED;
|
||||
return ERROR;
|
||||
}
|
||||
},
|
||||
FINISHED(8) {
|
||||
@Override
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
if (a == REMOTE_ABORT) return ERROR;
|
||||
return FINISHED;
|
||||
}
|
||||
};
|
||||
|
||||
private final int value;
|
||||
|
||||
IntroducerProtocolState(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static IntroducerProtocolState fromValue(int value) {
|
||||
for (IntroducerProtocolState s : values()) {
|
||||
if (s.value == value) return s;
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public static boolean isOngoing(IntroducerProtocolState state) {
|
||||
return state != FINISHED && state != ERROR;
|
||||
}
|
||||
|
||||
public IntroducerProtocolState next(IntroducerAction a) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface IntroductionConstants {
|
||||
|
||||
/* Protocol roles */
|
||||
int ROLE_INTRODUCER = 0;
|
||||
int ROLE_INTRODUCEE = 1;
|
||||
|
||||
/* Message types */
|
||||
int TYPE_REQUEST = 1;
|
||||
int TYPE_RESPONSE = 2;
|
||||
int TYPE_ACK = 3;
|
||||
int TYPE_ABORT = 4;
|
||||
|
||||
/* Message Constants */
|
||||
String TYPE = "type";
|
||||
String GROUP_ID = "groupId";
|
||||
String SESSION_ID = "sessionId";
|
||||
String CONTACT = "contactId";
|
||||
String NAME = "name";
|
||||
String PUBLIC_KEY = "publicKey";
|
||||
String E_PUBLIC_KEY = "ephemeralPublicKey";
|
||||
String MSG = "msg";
|
||||
String ACCEPT = "accept";
|
||||
String TIME = "time";
|
||||
String TRANSPORT = "transport";
|
||||
String MESSAGE_ID = "messageId";
|
||||
String MESSAGE_TIME = "timestamp";
|
||||
String MAC = "mac";
|
||||
String SIGNATURE = "signature";
|
||||
|
||||
/* Validation Constants */
|
||||
|
||||
/**
|
||||
* The length of the message authentication code in bytes.
|
||||
*/
|
||||
int MAC_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* The maximum length of the introducer's optional message to the
|
||||
* introducees in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_INTRODUCTION_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
|
||||
/* Introducer Local State Metadata */
|
||||
String STATE = "state";
|
||||
String ROLE = "role";
|
||||
String GROUP_ID_1 = "groupId1";
|
||||
String GROUP_ID_2 = "groupId2";
|
||||
String CONTACT_1 = "contact1";
|
||||
String CONTACT_2 = "contact2";
|
||||
String AUTHOR_ID_1 = "authorId1";
|
||||
String AUTHOR_ID_2 = "authorId2";
|
||||
String CONTACT_ID_1 = "contactId1";
|
||||
String CONTACT_ID_2 = "contactId2";
|
||||
String RESPONSE_1 = "response1";
|
||||
String RESPONSE_2 = "response2";
|
||||
|
||||
/* Introduction Request Action */
|
||||
String PUBLIC_KEY1 = "publicKey1";
|
||||
String PUBLIC_KEY2 = "publicKey2";
|
||||
|
||||
/* Introducee Local State Metadata (without those already defined) */
|
||||
String STORAGE_ID = "storageId";
|
||||
String INTRODUCER = "introducer";
|
||||
String LOCAL_AUTHOR_ID = "localAuthorId";
|
||||
String REMOTE_AUTHOR_ID = "remoteAuthorId";
|
||||
String OUR_PUBLIC_KEY = "ourEphemeralPublicKey";
|
||||
String OUR_PRIVATE_KEY = "ourEphemeralPrivateKey";
|
||||
String OUR_TIME = "ourTime";
|
||||
String ADDED_CONTACT_ID = "addedContactId";
|
||||
String NOT_OUR_RESPONSE = "notOurResponse";
|
||||
String EXISTS = "contactExists";
|
||||
String REMOTE_AUTHOR_IS_US = "remoteAuthorIsUs";
|
||||
String ANSWERED = "answered";
|
||||
String NONCE = "nonce";
|
||||
String MAC_KEY = "macKey";
|
||||
String OUR_TRANSPORT = "ourTransport";
|
||||
String OUR_MAC = "ourMac";
|
||||
String OUR_SIGNATURE = "ourSignature";
|
||||
|
||||
String TASK = "task";
|
||||
int TASK_ADD_CONTACT = 0;
|
||||
int TASK_ACTIVATE_CONTACT = 1;
|
||||
int TASK_ABORT = 2;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface IntroductionManager extends ConversationClient {
|
||||
|
||||
/**
|
||||
* The unique ID of the introduction client.
|
||||
*/
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.introduction");
|
||||
|
||||
/**
|
||||
* Sends two initial introduction messages.
|
||||
*/
|
||||
void makeIntroduction(Contact c1, Contact c2, @Nullable String msg,
|
||||
final long timestamp) throws DbException, FormatException;
|
||||
|
||||
/**
|
||||
* Accepts an introduction.
|
||||
*/
|
||||
void acceptIntroduction(final ContactId contactId,
|
||||
final SessionId sessionId, final long timestamp)
|
||||
throws DbException, FormatException;
|
||||
|
||||
/**
|
||||
* Declines an introduction.
|
||||
*/
|
||||
void declineIntroduction(final ContactId contactId,
|
||||
final SessionId sessionId, final long timestamp)
|
||||
throws DbException, FormatException;
|
||||
|
||||
/**
|
||||
* Returns all introduction messages for the given contact.
|
||||
*/
|
||||
Collection<IntroductionMessage> getIntroductionMessages(ContactId contactId)
|
||||
throws DbException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.BaseMessageHeader;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCER;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionMessage extends BaseMessageHeader {
|
||||
|
||||
private final SessionId sessionId;
|
||||
private final MessageId messageId;
|
||||
private final int role;
|
||||
|
||||
IntroductionMessage(SessionId sessionId, MessageId messageId,
|
||||
GroupId groupId, int role, long time, boolean local, boolean sent,
|
||||
boolean seen, boolean read) {
|
||||
|
||||
super(messageId, groupId, time, local, read, sent, seen);
|
||||
this.sessionId = sessionId;
|
||||
this.messageId = messageId;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public SessionId getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public MessageId getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
public boolean isIntroducer() {
|
||||
return role == ROLE_INTRODUCER;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionRequest extends IntroductionResponse {
|
||||
|
||||
@Nullable
|
||||
private final String message;
|
||||
private final boolean answered, exists, introducesOtherIdentity;
|
||||
|
||||
public IntroductionRequest(SessionId sessionId, MessageId messageId,
|
||||
GroupId groupId, int role, long time, boolean local, boolean sent,
|
||||
boolean seen, boolean read, AuthorId authorId, String name,
|
||||
boolean accepted, @Nullable String message, boolean answered,
|
||||
boolean exists, boolean introducesOtherIdentity) {
|
||||
|
||||
super(sessionId, messageId, groupId, role, time, local, sent, seen,
|
||||
read, authorId, name, accepted);
|
||||
|
||||
this.message = message;
|
||||
this.answered = answered;
|
||||
this.exists = exists;
|
||||
this.introducesOtherIdentity = introducesOtherIdentity;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean wasAnswered() {
|
||||
return answered;
|
||||
}
|
||||
|
||||
public boolean contactExists() {
|
||||
return exists;
|
||||
}
|
||||
|
||||
public boolean doesIntroduceOtherIdentity() {
|
||||
return introducesOtherIdentity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.briarproject.briar.api.introduction;
|
||||
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionResponse extends IntroductionMessage {
|
||||
|
||||
private final AuthorId remoteAuthorId;
|
||||
private final String name;
|
||||
private final boolean accepted;
|
||||
|
||||
public IntroductionResponse(SessionId sessionId, MessageId messageId,
|
||||
GroupId groupId, int role, long time, boolean local, boolean sent,
|
||||
boolean seen, boolean read, AuthorId remoteAuthorId, String name,
|
||||
boolean accepted) {
|
||||
|
||||
super(sessionId, messageId, groupId, role, time, local, sent, seen,
|
||||
read);
|
||||
|
||||
this.remoteAuthorId = remoteAuthorId;
|
||||
this.name = name;
|
||||
this.accepted = accepted;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean wasAccepted() {
|
||||
return accepted;
|
||||
}
|
||||
|
||||
public AuthorId getRemoteAuthorId() {
|
||||
return remoteAuthorId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.briarproject.briar.api.introduction.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionAbortedEvent extends Event {
|
||||
|
||||
private final ContactId contactId;
|
||||
private final SessionId sessionId;
|
||||
|
||||
public IntroductionAbortedEvent(ContactId contactId, SessionId sessionId) {
|
||||
this.contactId = contactId;
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public SessionId getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.briarproject.briar.api.introduction.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionRequestReceivedEvent extends Event {
|
||||
|
||||
private final ContactId contactId;
|
||||
private final IntroductionRequest introductionRequest;
|
||||
|
||||
public IntroductionRequestReceivedEvent(ContactId contactId,
|
||||
IntroductionRequest introductionRequest) {
|
||||
|
||||
this.contactId = contactId;
|
||||
this.introductionRequest = introductionRequest;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public IntroductionRequest getIntroductionRequest() {
|
||||
return introductionRequest;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.briarproject.briar.api.introduction.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionResponseReceivedEvent extends Event {
|
||||
|
||||
private final ContactId contactId;
|
||||
private final IntroductionResponse introductionResponse;
|
||||
|
||||
public IntroductionResponseReceivedEvent(ContactId contactId,
|
||||
IntroductionResponse introductionResponse) {
|
||||
|
||||
this.contactId = contactId;
|
||||
this.introductionResponse = introductionResponse;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public IntroductionResponse getIntroductionResponse() {
|
||||
return introductionResponse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.briarproject.briar.api.introduction.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IntroductionSucceededEvent extends Event {
|
||||
|
||||
private final Contact contact;
|
||||
|
||||
public IntroductionSucceededEvent(Contact contact) {
|
||||
this.contact = contact;
|
||||
}
|
||||
|
||||
public Contact getContact() {
|
||||
return contact;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.briarproject.briar.api.messaging;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ConversationManager {
|
||||
|
||||
/**
|
||||
* Clients that present messages in a private conversation need to
|
||||
* register themselves here.
|
||||
*/
|
||||
void registerConversationClient(ConversationClient client);
|
||||
|
||||
/**
|
||||
* Returns the unified group count for all private conversation messages.
|
||||
*/
|
||||
GroupCount getGroupCount(ContactId c) throws DbException;
|
||||
|
||||
@NotNullByDefault
|
||||
interface ConversationClient {
|
||||
|
||||
Group getContactGroup(Contact c);
|
||||
|
||||
GroupCount getGroupCount(Transaction txn, ContactId c)
|
||||
throws DbException;
|
||||
|
||||
void setReadFlag(GroupId g, MessageId m, boolean read)
|
||||
throws DbException;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.briarproject.briar.api.messaging;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface MessagingConstants {
|
||||
|
||||
/**
|
||||
* The maximum length of a private message's body in bytes.
|
||||
*/
|
||||
int MAX_PRIVATE_MESSAGE_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.briarproject.briar.api.messaging;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface MessagingManager extends ConversationClient {
|
||||
|
||||
/**
|
||||
* The unique ID of the messaging client.
|
||||
*/
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.messaging");
|
||||
|
||||
/**
|
||||
* Stores a local private message.
|
||||
*/
|
||||
void addLocalMessage(PrivateMessage m) 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.
|
||||
*/
|
||||
GroupId getConversationId(ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the headers of all messages in the given private conversation.
|
||||
*/
|
||||
Collection<PrivateMessageHeader> getMessageHeaders(ContactId c)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the body of the private message with the given ID.
|
||||
*/
|
||||
String getMessageBody(MessageId m) throws DbException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.briarproject.briar.api.messaging;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class PrivateMessage {
|
||||
|
||||
private final Message message;
|
||||
|
||||
public PrivateMessage(Message message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.briarproject.briar.api.messaging;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface PrivateMessageFactory {
|
||||
|
||||
PrivateMessage createPrivateMessage(GroupId groupId, long timestamp,
|
||||
String body) throws FormatException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.briarproject.briar.api.messaging;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.BaseMessageHeader;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class PrivateMessageHeader extends BaseMessageHeader {
|
||||
|
||||
public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp,
|
||||
boolean local, boolean read, boolean sent, boolean seen) {
|
||||
|
||||
super(id, groupId, timestamp, local, read, sent, seen);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.briarproject.briar.api.messaging.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a new private message is received.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class PrivateMessageReceivedEvent extends Event {
|
||||
|
||||
private final PrivateMessageHeader messageHeader;
|
||||
private final ContactId contactId;
|
||||
private final GroupId groupId;
|
||||
|
||||
public PrivateMessageReceivedEvent(PrivateMessageHeader messageHeader,
|
||||
ContactId contactId, GroupId groupId) {
|
||||
this.messageHeader = messageHeader;
|
||||
this.contactId = contactId;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public PrivateMessageHeader getMessageHeader() {
|
||||
return messageHeader;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupMember {
|
||||
|
||||
private final Author author;
|
||||
private final Status status;
|
||||
private final Visibility visibility;
|
||||
|
||||
public GroupMember(Author author, Status status, Visibility visibility) {
|
||||
this.author = author;
|
||||
this.status = status;
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public Visibility getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.ThreadedMessage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupMessage extends ThreadedMessage {
|
||||
|
||||
public GroupMessage(Message message, @Nullable MessageId parent,
|
||||
Author member) {
|
||||
super(message, parent, member);
|
||||
}
|
||||
|
||||
public Author getMember() {
|
||||
return super.getAuthor();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface GroupMessageFactory {
|
||||
|
||||
String SIGNING_LABEL_JOIN = CLIENT_ID + "/JOIN";
|
||||
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
|
||||
|
||||
/**
|
||||
* Creates a join announcement message for the creator of a group.
|
||||
*
|
||||
* @param groupId The ID of the private group that is being joined
|
||||
* @param timestamp The timestamp to be used in the join announcement
|
||||
* @param creator The creator's identity
|
||||
*/
|
||||
@CryptoExecutor
|
||||
GroupMessage createJoinMessage(GroupId groupId, long timestamp,
|
||||
LocalAuthor creator);
|
||||
|
||||
/**
|
||||
* Creates a join announcement message for a joining member.
|
||||
*
|
||||
* @param groupId The ID of the private group that is being joined
|
||||
* @param timestamp The timestamp to be used in the join announcement,
|
||||
* which must be greater than the timestamp of the invitation message
|
||||
* @param member The member's identity
|
||||
* @param inviteTimestamp The timestamp of the invitation message
|
||||
* @param creatorSignature The creator's signature from the invitation
|
||||
* message
|
||||
*/
|
||||
@CryptoExecutor
|
||||
GroupMessage createJoinMessage(GroupId groupId, long timestamp,
|
||||
LocalAuthor member, long inviteTimestamp, byte[] creatorSignature);
|
||||
|
||||
/**
|
||||
* Creates a private group post.
|
||||
*
|
||||
* @param groupId The ID of the private group
|
||||
* @param timestamp Must be greater than the timestamps of the parent
|
||||
* post, if any, and the member's previous message
|
||||
* @param parentId The ID of the parent post, or null if the post has no
|
||||
* parent
|
||||
* @param author The author of the post
|
||||
* @param body The content of the post
|
||||
* @param previousMsgId The ID of the author's previous message
|
||||
* in this group
|
||||
*/
|
||||
@CryptoExecutor
|
||||
GroupMessage createGroupMessage(GroupId groupId, long timestamp,
|
||||
@Nullable MessageId parentId, LocalAuthor author, String body,
|
||||
MessageId previousMsgId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.PostHeader;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupMessageHeader extends PostHeader {
|
||||
|
||||
private final GroupId groupId;
|
||||
|
||||
public GroupMessageHeader(GroupId groupId, MessageId id,
|
||||
@Nullable MessageId parentId, long timestamp,
|
||||
Author author, Status authorStatus, boolean read) {
|
||||
super(id, parentId, timestamp, author, authorStatus, read);
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class JoinMessageHeader extends GroupMessageHeader {
|
||||
|
||||
private final Visibility visibility;
|
||||
private final boolean isInitial;
|
||||
|
||||
public JoinMessageHeader(GroupMessageHeader h, Visibility visibility,
|
||||
boolean isInitial) {
|
||||
super(h.getGroupId(), h.getId(), h.getParentId(), h.getTimestamp(),
|
||||
h.getAuthor(), h.getAuthorStatus(), h.isRead());
|
||||
this.visibility = visibility;
|
||||
this.isInitial = isInitial;
|
||||
}
|
||||
|
||||
public Visibility getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
public boolean isInitial() {
|
||||
return isInitial;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public enum MessageType {
|
||||
|
||||
JOIN(0),
|
||||
POST(1);
|
||||
|
||||
private final int value;
|
||||
|
||||
MessageType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static MessageType valueOf(int value) {
|
||||
for (MessageType m : values()) if (m.value == value) return m;
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.briar.api.client.NamedGroup;
|
||||
import org.briarproject.briar.api.sharing.Shareable;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class PrivateGroup extends NamedGroup implements Shareable {
|
||||
|
||||
private final Author creator;
|
||||
|
||||
public PrivateGroup(Group group, String name, Author creator, byte[] salt) {
|
||||
super(group, name, salt);
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public Author getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof PrivateGroup && super.equals(o);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface PrivateGroupConstants {
|
||||
|
||||
/**
|
||||
* The maximum length of a group's name in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_GROUP_NAME_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* The length of a group's random salt in bytes.
|
||||
*/
|
||||
int GROUP_SALT_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* The maximum length of a group post's body in bytes.
|
||||
*/
|
||||
int MAX_GROUP_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
|
||||
/**
|
||||
* The maximum length of a group invitation message in bytes.
|
||||
*/
|
||||
int MAX_GROUP_INVITATION_MSG_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface PrivateGroupFactory {
|
||||
|
||||
/**
|
||||
* Creates a private group with the given name and author.
|
||||
*/
|
||||
PrivateGroup createPrivateGroup(String name, Author author);
|
||||
|
||||
/**
|
||||
* Creates a private group with the given name, author and salt.
|
||||
*/
|
||||
PrivateGroup createPrivateGroup(String name, Author author, byte[] salt);
|
||||
|
||||
/**
|
||||
* Parses a group and returns the corresponding PrivateGroup.
|
||||
*/
|
||||
PrivateGroup parsePrivateGroup(Group group) throws FormatException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface PrivateGroupManager {
|
||||
|
||||
/**
|
||||
* The unique ID of the private group client.
|
||||
*/
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.privategroup");
|
||||
|
||||
/**
|
||||
* Adds a new private group and joins it.
|
||||
*
|
||||
* @param group The private group to add
|
||||
* @param joinMsg The new member's join message
|
||||
* @param creator True if the group is added by its creator
|
||||
*/
|
||||
void addPrivateGroup(PrivateGroup group, GroupMessage joinMsg,
|
||||
boolean creator) throws DbException;
|
||||
|
||||
/**
|
||||
* Adds a new private group and joins it.
|
||||
*
|
||||
* @param group The private group to add
|
||||
* @param joinMsg The new member's join message
|
||||
* @param creator True if the group is added by its creator
|
||||
*/
|
||||
void addPrivateGroup(Transaction txn, PrivateGroup group,
|
||||
GroupMessage joinMsg, boolean creator) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a dissolved private group.
|
||||
*/
|
||||
void removePrivateGroup(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the ID of the user's previous message sent to the group
|
||||
*/
|
||||
MessageId getPreviousMsgId(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given private group as dissolved.
|
||||
*/
|
||||
void markGroupDissolved(Transaction txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the given private group has been dissolved.
|
||||
*/
|
||||
boolean isDissolved(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores and sends a local private group message.
|
||||
*/
|
||||
GroupMessageHeader addLocalMessage(GroupMessage p) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the private group with the given ID.
|
||||
*/
|
||||
PrivateGroup getPrivateGroup(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the private group with the given ID.
|
||||
*/
|
||||
PrivateGroup getPrivateGroup(Transaction txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all private groups the user is a member of.
|
||||
*/
|
||||
Collection<PrivateGroup> getPrivateGroups() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the body of the private group message with the given ID.
|
||||
*/
|
||||
String getMessageBody(MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the headers of all messages in the given private group.
|
||||
*/
|
||||
Collection<GroupMessageHeader> getHeaders(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all members of the given private group.
|
||||
*/
|
||||
Collection<GroupMember> getMembers(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the given author is a member of the given private group.
|
||||
*/
|
||||
boolean isMember(Transaction txn, GroupId g, Author a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the group count for the given private group.
|
||||
*/
|
||||
GroupCount getGroupCount(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks a message as read or unread and updates the group count.
|
||||
*/
|
||||
void setReadFlag(GroupId g, MessageId m, boolean read) throws DbException;
|
||||
|
||||
/**
|
||||
* Called when a contact relationship has been revealed between the user
|
||||
* and the given author in the given private group.
|
||||
*
|
||||
* @param byContact True if the contact revealed the relationship first,
|
||||
* otherwise false.
|
||||
*/
|
||||
void relationshipRevealed(Transaction txn, GroupId g, AuthorId a,
|
||||
boolean byContact) throws FormatException, DbException;
|
||||
|
||||
/**
|
||||
* Registers a hook to be called when members are added or private groups
|
||||
* are removed.
|
||||
*/
|
||||
void registerPrivateGroupHook(PrivateGroupHook hook);
|
||||
|
||||
@NotNullByDefault
|
||||
interface PrivateGroupHook {
|
||||
|
||||
void addingMember(Transaction txn, GroupId g, Author a)
|
||||
throws DbException;
|
||||
|
||||
void removingGroup(Transaction txn, GroupId g) throws DbException;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.briarproject.briar.api.privategroup;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public enum Visibility {
|
||||
|
||||
INVISIBLE(0),
|
||||
VISIBLE(1),
|
||||
REVEALED_BY_US(2),
|
||||
REVEALED_BY_CONTACT(3);
|
||||
|
||||
private final int value;
|
||||
|
||||
Visibility(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static Visibility valueOf(int value) throws FormatException {
|
||||
for (Visibility v : values()) if (v.value == value) return v;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.briarproject.briar.api.privategroup.event;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.privategroup.Visibility;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ContactRelationshipRevealedEvent extends Event {
|
||||
|
||||
private final GroupId groupId;
|
||||
private final AuthorId memberId;
|
||||
private final Visibility visibility;
|
||||
|
||||
public ContactRelationshipRevealedEvent(GroupId groupId, AuthorId memberId,
|
||||
Visibility visibility) {
|
||||
this.groupId = groupId;
|
||||
this.memberId = memberId;
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public AuthorId getMemberId() {
|
||||
return memberId;
|
||||
}
|
||||
|
||||
public Visibility getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.briarproject.briar.api.privategroup.event;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a private group is dissolved by a remote
|
||||
* creator.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupDissolvedEvent extends Event {
|
||||
|
||||
private final GroupId groupId;
|
||||
|
||||
public GroupDissolvedEvent(GroupId groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.api.privategroup.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
||||
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupInvitationRequestReceivedEvent extends
|
||||
InvitationRequestReceivedEvent<PrivateGroup> {
|
||||
|
||||
public GroupInvitationRequestReceivedEvent(PrivateGroup group,
|
||||
ContactId contactId, GroupInvitationRequest request) {
|
||||
super(group, contactId, request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.briarproject.briar.api.privategroup.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
||||
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupInvitationResponseReceivedEvent
|
||||
extends InvitationResponseReceivedEvent {
|
||||
|
||||
public GroupInvitationResponseReceivedEvent(ContactId contactId,
|
||||
InvitationResponse response) {
|
||||
super(contactId, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.briarproject.briar.api.privategroup.event;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a private group message was added
|
||||
* to the database.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupMessageAddedEvent extends Event {
|
||||
|
||||
private final GroupId groupId;
|
||||
private final GroupMessageHeader header;
|
||||
private final boolean local;
|
||||
|
||||
public GroupMessageAddedEvent(GroupId groupId, GroupMessageHeader header,
|
||||
boolean local) {
|
||||
|
||||
this.groupId = groupId;
|
||||
this.header = header;
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public GroupMessageHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.briarproject.briar.api.privategroup.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface GroupInvitationFactory {
|
||||
|
||||
String SIGNING_LABEL_INVITE = CLIENT_ID + "/INVITE";
|
||||
|
||||
/**
|
||||
* Returns a signature to include when inviting a member to join a private
|
||||
* group. If the member accepts the invitation, the signature will be
|
||||
* included in the member's join message.
|
||||
*/
|
||||
@CryptoExecutor
|
||||
byte[] signInvitation(Contact c, GroupId privateGroupId, long timestamp,
|
||||
byte[] privateKey);
|
||||
|
||||
/**
|
||||
* Returns a token to be signed by the creator when inviting a member to
|
||||
* join a private group. If the member accepts the invitation, the
|
||||
* signature will be included in the member's join message.
|
||||
*/
|
||||
BdfList createInviteToken(AuthorId creatorId, AuthorId memberId,
|
||||
GroupId privateGroupId, long timestamp);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.briarproject.briar.api.privategroup.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.briar.api.sharing.InvitationItem;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupInvitationItem extends InvitationItem<PrivateGroup> {
|
||||
|
||||
private final Contact creator;
|
||||
|
||||
public GroupInvitationItem(PrivateGroup privateGroup, Contact creator) {
|
||||
super(privateGroup, false);
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public Contact getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.briarproject.briar.api.privategroup.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.client.ProtocolStateException;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient;
|
||||
import org.briarproject.briar.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.briar.api.sharing.InvitationMessage;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface GroupInvitationManager extends ConversationClient {
|
||||
|
||||
/**
|
||||
* The unique ID of the private group invitation client.
|
||||
*/
|
||||
ClientId CLIENT_ID =
|
||||
new ClientId("org.briarproject.briar.privategroup.invitation");
|
||||
|
||||
/**
|
||||
* Sends an invitation to share the given private group with the given
|
||||
* contact, including an optional message.
|
||||
*
|
||||
* @throws ProtocolStateException if the group is no longer eligible to be
|
||||
* shared with the contact, for example because an invitation is already
|
||||
* pending.
|
||||
*/
|
||||
void sendInvitation(GroupId g, ContactId c, @Nullable String message,
|
||||
long timestamp, byte[] signature) throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending private group invitation from the given contact.
|
||||
*
|
||||
* @throws ProtocolStateException if the invitation is no longer pending,
|
||||
* for example because the group has been dissolved.
|
||||
*/
|
||||
void respondToInvitation(ContactId c, PrivateGroup g, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending private group invitation from the given contact.
|
||||
*
|
||||
* @throws ProtocolStateException if the invitation is no longer pending,
|
||||
* for example because the group has been dissolved.
|
||||
*/
|
||||
void respondToInvitation(ContactId c, SessionId s, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Makes the user's relationship with the given contact visible to the
|
||||
* given private group.
|
||||
*
|
||||
* @throws ProtocolStateException if the relationship is no longer eligible
|
||||
* to be revealed, for example because the contact has revealed it.
|
||||
*/
|
||||
void revealRelationship(ContactId c, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all private group invitation messages related to the given
|
||||
* contact.
|
||||
*/
|
||||
Collection<InvitationMessage> getInvitationMessages(ContactId c)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all private groups to which the user has been invited.
|
||||
*/
|
||||
Collection<GroupInvitationItem> getInvitations() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the given contact can be invited to the given private
|
||||
* group.
|
||||
*/
|
||||
boolean isInvitationAllowed(Contact c, GroupId g) throws DbException;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.briarproject.briar.api.privategroup.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupInvitationRequest extends InvitationRequest {
|
||||
|
||||
private final String groupName;
|
||||
private final Author creator;
|
||||
|
||||
public GroupInvitationRequest(MessageId id, SessionId sessionId,
|
||||
GroupId groupId, ContactId contactId, @Nullable String message,
|
||||
String groupName, Author creator, boolean available, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
super(id, sessionId, groupId, contactId, message, available, time,
|
||||
local, sent, seen, read);
|
||||
this.groupName = groupName;
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public Author getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.briarproject.briar.api.privategroup.invitation;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class GroupInvitationResponse extends InvitationResponse {
|
||||
|
||||
public GroupInvitationResponse(MessageId id, SessionId sessionId,
|
||||
GroupId groupId, ContactId contactId, boolean accept, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
super(id, sessionId, groupId, contactId, accept, time, local, sent,
|
||||
seen, read);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
public interface InvitationFactory<I extends SharingMessage.Invitation> {
|
||||
|
||||
I build(GroupId groupId, BdfDictionary d) throws FormatException;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class InvitationItem<S extends Shareable> {
|
||||
|
||||
private final S shareable;
|
||||
private final boolean subscribed;
|
||||
|
||||
public InvitationItem(S shareable, boolean subscribed) {
|
||||
this.shareable = shareable;
|
||||
this.subscribed = subscribed;
|
||||
}
|
||||
|
||||
public S getShareable() {
|
||||
return shareable;
|
||||
}
|
||||
|
||||
public GroupId getId() {
|
||||
return shareable.getId();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return shareable.getName();
|
||||
}
|
||||
|
||||
public boolean isSubscribed() {
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.BaseMessageHeader;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class InvitationMessage extends BaseMessageHeader {
|
||||
|
||||
private final SessionId sessionId;
|
||||
private final ContactId contactId;
|
||||
|
||||
public InvitationMessage(MessageId id, SessionId sessionId, GroupId groupId,
|
||||
ContactId contactId, long time, boolean local, boolean sent,
|
||||
boolean seen, boolean read) {
|
||||
|
||||
super(id, groupId, time, local, read, sent, seen);
|
||||
this.sessionId = sessionId;
|
||||
this.contactId = contactId;
|
||||
}
|
||||
|
||||
public SessionId getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class InvitationRequest extends InvitationMessage {
|
||||
|
||||
@Nullable
|
||||
private final String message;
|
||||
private final boolean available;
|
||||
|
||||
public InvitationRequest(MessageId id, SessionId sessionId, GroupId groupId,
|
||||
ContactId contactId, @Nullable String message, boolean available,
|
||||
long time, boolean local, boolean sent, boolean seen,
|
||||
boolean read) {
|
||||
|
||||
super(id, sessionId, groupId, contactId, time, local, sent, seen, read);
|
||||
this.message = message;
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
return available;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class InvitationResponse extends InvitationMessage {
|
||||
|
||||
private final boolean accept;
|
||||
|
||||
public InvitationResponse(MessageId id, SessionId sessionId,
|
||||
GroupId groupId, ContactId contactId, boolean accept, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
|
||||
super(id, sessionId, groupId, contactId, time, local, sent, seen, read);
|
||||
this.accept = accept;
|
||||
}
|
||||
|
||||
public boolean wasAccepted() {
|
||||
return accept;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface Shareable {
|
||||
|
||||
GroupId getId();
|
||||
|
||||
Group getGroup();
|
||||
|
||||
String getName();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface SharingConstants {
|
||||
|
||||
/**
|
||||
* The length of a sharing session's random salt in bytes.
|
||||
*/
|
||||
int SHARING_SALT_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* The maximum length of the optional message from the inviter to the
|
||||
* invitee in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_INVITATION_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
|
||||
String CONTACT_ID = "contactId";
|
||||
String GROUP_ID = "groupId";
|
||||
String TO_BE_SHARED_BY_US = "toBeSharedByUs";
|
||||
String SHARED_BY_US = "sharedByUs";
|
||||
String SHARED_WITH_US = "sharedWithUs";
|
||||
String TYPE = "type";
|
||||
String SESSION_ID = "sessionId";
|
||||
String STORAGE_ID = "storageId";
|
||||
String STATE = "state";
|
||||
String LOCAL = "local";
|
||||
String TIME = "time";
|
||||
String IS_SHARER = "isSharer";
|
||||
String SHAREABLE_ID = "shareableId";
|
||||
String INVITATION_MSG = "invitationMsg";
|
||||
String INVITATION_ID = "invitationId";
|
||||
String RESPONSE_ID = "responseId";
|
||||
int SHARE_MSG_TYPE_INVITATION = 1;
|
||||
int SHARE_MSG_TYPE_ACCEPT = 2;
|
||||
int SHARE_MSG_TYPE_DECLINE = 3;
|
||||
int SHARE_MSG_TYPE_LEAVE = 4;
|
||||
int SHARE_MSG_TYPE_ABORT = 5;
|
||||
int TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US = 0;
|
||||
int TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US = 1;
|
||||
int TASK_ADD_SHARED_SHAREABLE = 2;
|
||||
int TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US = 3;
|
||||
int TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US = 4;
|
||||
int TASK_SHARE_SHAREABLE = 5;
|
||||
int TASK_UNSHARE_SHAREABLE_SHARED_BY_US = 6;
|
||||
int TASK_UNSHARE_SHAREABLE_SHARED_WITH_US = 7;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class SharingInvitationItem extends InvitationItem<Shareable> {
|
||||
|
||||
private final Collection<Contact> newSharers;
|
||||
|
||||
public SharingInvitationItem(Shareable shareable, boolean subscribed,
|
||||
Collection<Contact> newSharers) {
|
||||
super(shareable, subscribed);
|
||||
|
||||
this.newSharers = newSharers;
|
||||
}
|
||||
|
||||
public Collection<Contact> getNewSharers() {
|
||||
return newSharers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface SharingManager<S extends Shareable>
|
||||
extends ConversationClient {
|
||||
|
||||
/**
|
||||
* Sends an invitation to share the given group with the given contact
|
||||
* and sends an optional message along with it.
|
||||
*/
|
||||
void sendInvitation(GroupId groupId, ContactId contactId,
|
||||
@Nullable String message) throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending group invitation
|
||||
*/
|
||||
void respondToInvitation(S s, Contact c, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending group invitation
|
||||
*/
|
||||
void respondToInvitation(SessionId id, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all group sharing messages sent by the Contact
|
||||
* identified by contactId.
|
||||
*/
|
||||
Collection<InvitationMessage> getInvitationMessages(
|
||||
ContactId contactId) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all invitations to groups.
|
||||
*/
|
||||
Collection<SharingInvitationItem> getInvitations() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts who are sharing the given group with us.
|
||||
*/
|
||||
Collection<Contact> getSharedBy(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts with whom the given group is shared.
|
||||
*/
|
||||
Collection<Contact> getSharedWith(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the group not already shared and no invitation is open
|
||||
*/
|
||||
boolean canBeShared(GroupId g, Contact c) throws DbException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package org.briarproject.briar.api.sharing;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfEntry;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.GROUP_ID;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.TIME;
|
||||
import static org.briarproject.briar.api.sharing.SharingConstants.TYPE;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface SharingMessage {
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
abstract class BaseMessage {
|
||||
|
||||
private final GroupId groupId;
|
||||
private final SessionId sessionId;
|
||||
private final long time;
|
||||
|
||||
BaseMessage(GroupId groupId, SessionId sessionId, long time) {
|
||||
this.groupId = groupId;
|
||||
this.sessionId = sessionId;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public BdfList toBdfList() {
|
||||
return BdfList.of(getType(), getSessionId());
|
||||
}
|
||||
|
||||
public abstract BdfDictionary toBdfDictionary();
|
||||
|
||||
protected BdfDictionary toBdfDictionaryHelper() {
|
||||
return BdfDictionary.of(
|
||||
new BdfEntry(TYPE, getType()),
|
||||
new BdfEntry(GROUP_ID, groupId),
|
||||
new BdfEntry(SESSION_ID, sessionId)
|
||||
);
|
||||
}
|
||||
|
||||
public static BaseMessage from(InvitationFactory invitationFactory,
|
||||
GroupId groupId, BdfDictionary d)
|
||||
throws FormatException {
|
||||
|
||||
long type = d.getLong(TYPE);
|
||||
|
||||
if (type == SHARE_MSG_TYPE_INVITATION)
|
||||
return invitationFactory.build(groupId, d);
|
||||
else
|
||||
return SimpleMessage.from(type, groupId, d);
|
||||
}
|
||||
|
||||
public abstract long getType();
|
||||
|
||||
public GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public SessionId getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
abstract class Invitation extends BaseMessage {
|
||||
|
||||
@Nullable
|
||||
protected final String message;
|
||||
|
||||
public Invitation(GroupId groupId, SessionId sessionId, long time,
|
||||
@Nullable String message) {
|
||||
|
||||
super(groupId, sessionId, time);
|
||||
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getType() {
|
||||
return SHARE_MSG_TYPE_INVITATION;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class SimpleMessage extends BaseMessage {
|
||||
|
||||
private final long type;
|
||||
|
||||
public SimpleMessage(long type, GroupId groupId, SessionId sessionId,
|
||||
long time) {
|
||||
super(groupId, sessionId, time);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BdfDictionary toBdfDictionary() {
|
||||
return toBdfDictionaryHelper();
|
||||
}
|
||||
|
||||
public static SimpleMessage from(long type, GroupId groupId,
|
||||
BdfDictionary d) throws FormatException {
|
||||
|
||||
if (type != SHARE_MSG_TYPE_ACCEPT &&
|
||||
type != SHARE_MSG_TYPE_DECLINE &&
|
||||
type != SHARE_MSG_TYPE_LEAVE &&
|
||||
type != SHARE_MSG_TYPE_ABORT) throw new FormatException();
|
||||
|
||||
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
|
||||
long time = d.getLong(TIME);
|
||||
return new SimpleMessage(type, groupId, sessionId, time);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.briarproject.briar.api.sharing.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
||||
import org.briarproject.briar.api.sharing.Shareable;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class InvitationRequestReceivedEvent<S extends Shareable>
|
||||
extends Event {
|
||||
|
||||
private final S shareable;
|
||||
private final ContactId contactId;
|
||||
private final InvitationRequest request;
|
||||
|
||||
protected InvitationRequestReceivedEvent(S shareable, ContactId contactId,
|
||||
InvitationRequest request) {
|
||||
this.shareable = shareable;
|
||||
this.contactId = contactId;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public InvitationRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public S getShareable() {
|
||||
return shareable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.briarproject.briar.api.sharing.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class InvitationResponseReceivedEvent extends Event {
|
||||
|
||||
private final ContactId contactId;
|
||||
private final InvitationResponse response;
|
||||
|
||||
public InvitationResponseReceivedEvent(ContactId contactId,
|
||||
InvitationResponse response) {
|
||||
this.contactId = contactId;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public InvitationResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user