Migrate blog sharing to new sharing client infrastructure

This commit is contained in:
Torsten Grote
2017-01-04 15:48:34 -02:00
parent d5443e9651
commit c13eafef14
36 changed files with 695 additions and 3129 deletions

View File

@@ -1,5 +1,6 @@
package org.briarproject.briar.api.blog;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
public interface BlogConstants {
@@ -7,12 +8,7 @@ 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;
int MAX_BLOG_NAME_LENGTH = MAX_AUTHOR_NAME_LENGTH;
/**
* The maximum length of a blog post's body in bytes.
@@ -24,13 +20,8 @@ public interface BlogConstants {
*/
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";

View File

@@ -1,10 +1,7 @@
package org.briarproject.briar.api.blog;
import org.briarproject.bramble.api.contact.ContactId;
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.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId;
@@ -15,24 +12,16 @@ import javax.annotation.Nullable;
@NotNullByDefault
public class BlogInvitationRequest extends InvitationRequest<Blog> {
private final String blogAuthorName;
public BlogInvitationRequest(MessageId id, SessionId sessionId,
GroupId groupId, ContactId contactId, String blogAuthorName,
@Nullable String message, GroupId blogId,
boolean available, boolean canBeOpened, long time,
boolean local, boolean sent, boolean seen, boolean read) {
// TODO pass a proper blog here when redoing the BlogSharingManager
super(id, groupId, time, local, sent, seen, read, sessionId,
new Blog(new Group(blogId, BlogManager.CLIENT_ID, new byte[0]),
new Author(new AuthorId(new byte[AuthorId.LENGTH]),
blogAuthorName, new byte[0])), contactId,
message, available, canBeOpened);
this.blogAuthorName = blogAuthorName;
public BlogInvitationRequest(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, Blog blog, ContactId contactId,
@Nullable String message, boolean available, boolean canBeOpened) {
super(id, groupId, time, local, sent, seen, read, sessionId, blog,
contactId, message, available, canBeOpened);
}
public String getBlogAuthorName() {
return blogAuthorName;
return getShareable().getName();
}
}

View File

@@ -10,10 +10,10 @@ import org.briarproject.briar.api.sharing.InvitationResponse;
@NotNullByDefault
public class BlogInvitationResponse extends InvitationResponse {
public BlogInvitationResponse(MessageId id, SessionId sessionId,
GroupId groupId, ContactId contactId, GroupId blogId,
boolean accept, long time, boolean local, boolean sent,
boolean seen, boolean read) {
public BlogInvitationResponse(MessageId id, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, GroupId blogId, ContactId contactId,
boolean accept) {
super(id, groupId, time, local, sent, seen, read, sessionId, blogId,
contactId, accept);
}

View File

@@ -21,6 +21,16 @@ public interface BlogManager {
*/
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog");
/**
* Adds a blog from the given author.
*/
Blog addBlog(Author author) throws DbException;
/**
* Adds the given {@link Blog} within the given {@link Transaction}.
*/
void addBlog(Transaction txn, Blog b) throws DbException;
/**
* Returns true if a blog can be removed.
*/

View File

@@ -1,74 +0,0 @@
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;
}
}
}

View File

@@ -1,79 +0,0 @@
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;
}
}
}

View File

@@ -1,11 +0,0 @@
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;
@Deprecated
public interface InvitationFactory<I extends SharingMessage.Invitation> {
I build(GroupId groupId, BdfDictionary d) throws FormatException;
}

View File

@@ -4,74 +4,10 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_L
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;
@Deprecated
String CONTACT_ID = "contactId";
@Deprecated
String GROUP_ID = "groupId";
@Deprecated
String TO_BE_SHARED_BY_US = "toBeSharedByUs";
@Deprecated
String SHARED_BY_US = "sharedByUs";
@Deprecated
String SHARED_WITH_US = "sharedWithUs";
@Deprecated
String TYPE = "type";
@Deprecated
String SESSION_ID = "sessionId";
@Deprecated
String STORAGE_ID = "storageId";
@Deprecated
String STATE = "state";
@Deprecated
String LOCAL = "local";
@Deprecated
String TIME = "time";
@Deprecated
String IS_SHARER = "isSharer";
@Deprecated
String SHAREABLE_ID = "shareableId";
@Deprecated
String INVITATION_MSG = "invitationMsg";
@Deprecated
String INVITATION_ID = "invitationId";
@Deprecated
String RESPONSE_ID = "responseId";
@Deprecated
int SHARE_MSG_TYPE_INVITATION = 1;
@Deprecated
int SHARE_MSG_TYPE_ACCEPT = 2;
@Deprecated
int SHARE_MSG_TYPE_DECLINE = 3;
@Deprecated
int SHARE_MSG_TYPE_LEAVE = 4;
@Deprecated
int SHARE_MSG_TYPE_ABORT = 5;
@Deprecated
int TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US = 0;
@Deprecated
int TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US = 1;
@Deprecated
int TASK_ADD_SHARED_SHAREABLE = 2;
@Deprecated
int TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US = 3;
@Deprecated
int TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US = 4;
@Deprecated
int TASK_SHARE_SHAREABLE = 5;
@Deprecated
int TASK_UNSHARE_SHAREABLE_SHARED_BY_US = 6;
@Deprecated
int TASK_UNSHARE_SHAREABLE_SHARED_WITH_US = 7;
}

View File

@@ -1,145 +0,0 @@
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;
@Deprecated
@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);
}
}
}

View File

@@ -108,7 +108,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
public void addingContact(Transaction txn, Contact c) throws DbException {
// Add the personal blog of the contact and share it with the contact
Blog b = blogFactory.createBlog(c.getAuthor());
db.addGroup(txn, b.getGroup());
addBlog(txn, b);
db.setGroupVisibility(txn, c.getId(), b.getId(), SHARED);
// Share our personal blog with the contact
LocalAuthor a = identityManager.getLocalAuthor(txn);
@@ -170,6 +170,25 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
return false;
}
@Override
public Blog addBlog(Author author) throws DbException {
Blog b = blogFactory.createBlog(author);
Transaction txn = db.startTransaction(false);
try {
db.addGroup(txn, b.getGroup());
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return b;
}
@Override
public void addBlog(Transaction txn, Blog b) throws DbException {
db.addGroup(txn, b.getGroup());
}
@Override
public boolean canBeRemoved(GroupId g) throws DbException {
Transaction txn = db.startTransaction(true);

View File

@@ -0,0 +1,39 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.client.SessionId;
import javax.inject.Inject;
public class BlogInvitationFactoryImpl implements InvitationFactory<Blog> {
@Inject
BlogInvitationFactoryImpl() {
}
@Override
public BlogInvitationRequest createInvitationRequest(boolean local,
boolean sent, boolean seen, boolean read, InviteMessage<Blog> m,
ContactId c, boolean available, boolean canBeOpened) {
SessionId sessionId = new SessionId(m.getShareableId().getBytes());
return new BlogInvitationRequest(m.getId(), m.getContactGroupId(),
m.getTimestamp(), local, sent, seen, read, sessionId,
m.getShareable(), c, m.getMessage(), available, canBeOpened);
}
@Override
public BlogInvitationResponse createInvitationResponse(MessageId id,
GroupId contactGroupId, long time, boolean local, boolean sent,
boolean seen, boolean read, GroupId shareableId,
ContactId contactId, boolean accept) {
SessionId sessionId = new SessionId(shareableId.getBytes());
return new BlogInvitationResponse(id, contactGroupId, time, local,
sent, seen, read, sessionId, shareableId, contactId, accept);
}
}

View File

@@ -1,47 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary;
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.NotThreadSafe;
import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME;
import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY;
@NotThreadSafe
@NotNullByDefault
class BlogInviteeSessionState extends InviteeSessionState {
private final String blogAuthorName;
private final byte[] blogPublicKey;
BlogInviteeSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId, GroupId blogId,
String blogAuthorName, byte[] blogPublicKey,
MessageId invitationId) {
super(sessionId, storageId, groupId, state, contactId, blogId,
invitationId);
this.blogAuthorName = blogAuthorName;
this.blogPublicKey = blogPublicKey;
}
@Override
public BdfDictionary toBdfDictionary() {
BdfDictionary d = super.toBdfDictionary();
d.put(BLOG_AUTHOR_NAME, getBlogAuthorName());
d.put(BLOG_PUBLIC_KEY, getBlogPublicKey());
return d;
}
String getBlogAuthorName() {
return blogAuthorName;
}
byte[] getBlogPublicKey() {
return blogPublicKey;
}
}

View File

@@ -0,0 +1,39 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogFactory;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
@Immutable
@NotNullByDefault
class BlogMessageParserImpl extends MessageParserImpl<Blog> {
private final BlogFactory blogFactory;
private final AuthorFactory authorFactory;
@Inject
BlogMessageParserImpl(ClientHelper clientHelper, BlogFactory blogFactory,
AuthorFactory authorFactory) {
super(clientHelper);
this.blogFactory = blogFactory;
this.authorFactory = authorFactory;
}
@Override
protected Blog createShareable(BdfList descriptor)
throws FormatException {
String name = descriptor.getString(0);
byte[] publicKey = descriptor.getRaw(1);
Author author = authorFactory.createAuthor(name, publicKey);
return blogFactory.createBlog(author);
}
}

View File

@@ -0,0 +1,93 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.client.MessageTracker;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
@Immutable
@NotNullByDefault
class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
private final BlogManager blogManager;
private final InvitationFactory<Blog> invitationFactory;
@Inject
BlogProtocolEngineImpl(DatabaseComponent db,
ClientHelper clientHelper, MessageEncoder messageEncoder,
MessageParser<Blog> messageParser, MessageTracker messageTracker,
Clock clock, BlogManager blogManager,
InvitationFactory<Blog> invitationFactory) {
super(db, clientHelper, messageEncoder, messageParser, messageTracker,
clock);
this.blogManager = blogManager;
this.invitationFactory = invitationFactory;
}
@Override
Event getInvitationRequestReceivedEvent(InviteMessage<Blog> m,
ContactId contactId, boolean available, boolean canBeOpened) {
BlogInvitationRequest request =
(BlogInvitationRequest) invitationFactory
.createInvitationRequest(false, false, true, false, m,
contactId, available, canBeOpened);
return new BlogInvitationRequestReceivedEvent(m.getShareable(),
contactId, request);
}
@Override
Event getInvitationResponseReceivedEvent(AcceptMessage m,
ContactId contactId) {
BlogInvitationResponse response =
(BlogInvitationResponse) invitationFactory
.createInvitationResponse(m.getId(),
m.getContactGroupId(), m.getTimestamp(), false,
false, true, false, m.getShareableId(),
contactId, true);
return new BlogInvitationResponseReceivedEvent(contactId, response);
}
@Override
Event getInvitationResponseReceivedEvent(DeclineMessage m,
ContactId contactId) {
BlogInvitationResponse response =
(BlogInvitationResponse) invitationFactory
.createInvitationResponse(m.getId(),
m.getContactGroupId(), m.getTimestamp(), false,
false, true, false, m.getShareableId(),
contactId, true);
return new BlogInvitationResponseReceivedEvent(contactId, response);
}
@Override
protected ClientId getClientId() {
return BlogSharingManager.CLIENT_ID;
}
@Override
protected void addShareable(Transaction txn, MessageId inviteId)
throws DbException, FormatException {
InviteMessage<Blog> invite =
messageParser.getInviteMessage(txn, inviteId);
blogManager.addBlog(txn, invite.getShareable());
}
}

View File

@@ -1,49 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary;
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.NotThreadSafe;
import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME;
import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY;
@NotThreadSafe
@NotNullByDefault
class BlogSharerSessionState extends SharerSessionState {
private final String blogAuthorName;
private final byte[] blogPublicKey;
BlogSharerSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId, GroupId blogId,
String blogAuthorName, byte[] blogPublicKey,
@Nullable MessageId responseId) {
super(sessionId, storageId, groupId, state, contactId, blogId,
responseId);
this.blogAuthorName = blogAuthorName;
this.blogPublicKey = blogPublicKey;
}
@Override
public BdfDictionary toBdfDictionary() {
BdfDictionary d = super.toBdfDictionary();
d.put(BLOG_AUTHOR_NAME, getBlogAuthorName());
d.put(BLOG_PUBLIC_KEY, getBlogPublicKey());
return d;
}
String getBlogAuthorName() {
return blogAuthorName;
}
byte[] getBlogPublicKey() {
return blogPublicKey;
}
}

View File

@@ -1,93 +1,48 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.client.ContactGroupFactory;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.data.MetadataParser;
import org.briarproject.bramble.api.db.DatabaseComponent;
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.AuthorFactory;
import org.briarproject.bramble.api.identity.IdentityManager;
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.bramble.api.system.Clock;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogFactory;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogManager.RemoveBlogHook;
import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.BlogSharingMessage.BlogInvitation;
import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.client.MessageQueueManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.sharing.InvitationMessage;
import java.security.SecureRandom;
import java.util.Collection;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
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_ID;
import static org.briarproject.briar.api.sharing.SharingConstants.RESPONSE_ID;
@Immutable
@NotNullByDefault
class BlogSharingManagerImpl extends
OldSharingManagerImpl<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationRequestReceivedEvent, BlogInvitationResponseReceivedEvent>
class BlogSharingManagerImpl extends SharingManagerImpl<Blog>
implements BlogSharingManager, RemoveBlogHook {
private final ContactManager contactManager;
private final IdentityManager identityManager;
private final BlogManager blogManager;
private final SFactory sFactory;
private final IFactory iFactory;
private final ISFactory isFactory;
private final SSFactory ssFactory;
private final IRFactory irFactory;
private final IRRFactory irrFactory;
@Inject
BlogSharingManagerImpl(AuthorFactory authorFactory, BlogFactory blogFactory,
BlogManager blogManager, ClientHelper clientHelper, Clock clock,
DatabaseComponent db, MessageQueueManager messageQueueManager,
MetadataEncoder metadataEncoder, MetadataParser metadataParser,
ContactGroupFactory contactGroupFactory, SecureRandom random,
ContactManager contactManager, IdentityManager identityManager,
MessageTracker messageTracker) {
super(db, messageQueueManager, clientHelper, metadataParser,
metadataEncoder, random, contactGroupFactory, messageTracker,
clock);
this.blogManager = blogManager;
this.contactManager = contactManager;
BlogSharingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
MetadataParser metadataParser, MessageParser<Blog> messageParser,
SessionEncoder sessionEncoder, SessionParser sessionParser,
MessageTracker messageTracker,
ContactGroupFactory contactGroupFactory,
ProtocolEngine<Blog> engine,
InvitationFactory<Blog> invitationFactory,
IdentityManager identityManager, BlogManager blogManager) {
super(db, clientHelper, metadataParser, messageParser, sessionEncoder,
sessionParser, messageTracker, contactGroupFactory, engine,
invitationFactory);
this.identityManager = identityManager;
sFactory = new SFactory(authorFactory, blogFactory, blogManager);
iFactory = new IFactory();
isFactory = new ISFactory();
ssFactory = new SSFactory();
irFactory = new IRFactory(sFactory);
irrFactory = new IRRFactory();
this.blogManager = blogManager;
}
@Override
@@ -96,91 +51,18 @@ class BlogSharingManagerImpl extends
}
@Override
protected boolean canBeShared(Transaction txn, GroupId g, Contact c)
throws DbException {
// check if g is our personal blog
protected boolean canBeShared(Transaction txn, GroupId shareableId,
Contact c) throws DbException {
// check if shareableId belongs to our personal blog
LocalAuthor author = identityManager.getLocalAuthor(txn);
Blog b = blogManager.getPersonalBlog(author);
if (b.getId().equals(g)) return false;
if (b.getId().equals(shareableId)) return false;
// check if g is c's personal blog
// check if shareableId belongs to c's personal blog
b = blogManager.getPersonalBlog(c.getAuthor());
if (b.getId().equals(g)) return false;
if (b.getId().equals(shareableId)) return false;
return super.canBeShared(txn, g, c);
}
@Override
public Collection<Contact> getSharedWith(GroupId g) throws DbException {
Blog blog = blogManager.getBlog(g);
LocalAuthor author = identityManager.getLocalAuthor();
if (blog.getAuthor().equals(author)) {
// This is our personal blog. It is shared with all our contacts
return contactManager.getActiveContacts();
} else {
// This is someone else's blog. Look up who it is shared with
Collection<Contact> shared = super.getSharedWith(g);
// If the blog author is our contact, also add her to the list
boolean isContact = contactManager
.contactExists(blog.getAuthor().getId(), author.getId());
if (isContact) {
shared.add(contactManager
.getContact(blog.getAuthor().getId(), author.getId()));
}
return shared;
}
}
@Override
protected InvitationMessage createInvitationRequest(MessageId id,
BlogInvitation msg, ContactId contactId, GroupId blogId,
boolean available, boolean canBeOpened, long time, boolean local,
boolean sent, boolean seen, boolean read) {
return new BlogInvitationRequest(id, msg.getSessionId(),
msg.getGroupId(), contactId, msg.getBlogAuthorName(),
msg.getMessage(), blogId, available, canBeOpened, time, local,
sent, seen, read);
}
@Override
protected InvitationMessage createInvitationResponse(MessageId id,
SessionId sessionId, GroupId groupId, ContactId contactId,
GroupId blogId, boolean accept, long time, boolean local,
boolean sent, boolean seen, boolean read) {
return new BlogInvitationResponse(id, sessionId, groupId, contactId,
blogId, accept, time, local, sent, seen, read);
}
@Override
protected ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> getSFactory() {
return sFactory;
}
@Override
protected OldInvitationFactory<BlogInvitation, BlogSharerSessionState> getIFactory() {
return iFactory;
}
@Override
protected InviteeSessionStateFactory<Blog, BlogInviteeSessionState> getISFactory() {
return isFactory;
}
@Override
protected SharerSessionStateFactory<Blog, BlogSharerSessionState> getSSFactory() {
return ssFactory;
}
@Override
protected InvitationReceivedEventFactory<BlogInviteeSessionState, BlogInvitationRequestReceivedEvent> getIRFactory() {
return irFactory;
}
@Override
protected InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> getIRRFactory() {
return irrFactory;
return super.canBeShared(txn, shareableId, c);
}
@Override
@@ -188,187 +70,4 @@ class BlogSharingManagerImpl extends
removingShareable(txn, b);
}
private static class SFactory implements
ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> {
private final AuthorFactory authorFactory;
private final BlogFactory blogFactory;
private final BlogManager blogManager;
private SFactory(AuthorFactory authorFactory, BlogFactory BlogFactory,
BlogManager BlogManager) {
this.authorFactory = authorFactory;
this.blogFactory = BlogFactory;
this.blogManager = BlogManager;
}
@Override
public BdfList encode(Blog f) {
return BdfList.of(
BdfList.of(
f.getAuthor().getName(),
f.getAuthor().getPublicKey()
)
);
}
@Override
public Blog get(Transaction txn, GroupId groupId)
throws DbException {
return blogManager.getBlog(txn, groupId);
}
@Override
public Blog parse(BdfList shareable) throws FormatException {
Author author = authorFactory
.createAuthor(shareable.getList(0).getString(0),
shareable.getList(0).getRaw(1));
return blogFactory.createBlog(author);
}
@Override
public Blog parse(BlogInvitation msg) {
Author author = authorFactory.createAuthor(msg.getBlogAuthorName(),
msg.getBlogPublicKey());
return blogFactory.createBlog(author);
}
@Override
public Blog parse(BlogInviteeSessionState state) {
Author author = authorFactory
.createAuthor(state.getBlogAuthorName(),
state.getBlogPublicKey());
return blogFactory.createBlog(author);
}
@Override
public Blog parse(BlogSharerSessionState state) {
Author author = authorFactory
.createAuthor(state.getBlogAuthorName(),
state.getBlogPublicKey());
return blogFactory.createBlog(author);
}
}
private static class IFactory implements
OldInvitationFactory<BlogInvitation, BlogSharerSessionState> {
@Override
public BlogInvitation build(GroupId groupId, BdfDictionary d)
throws FormatException {
return BlogInvitation.from(groupId, d);
}
@Override
public BlogInvitation build(BlogSharerSessionState localState,
long time) {
return new BlogInvitation(localState.getContactGroupId(),
localState.getSessionId(), localState.getBlogAuthorName(),
localState.getBlogPublicKey(), time,
localState.getMessage());
}
}
private static class ISFactory implements
InviteeSessionStateFactory<Blog, BlogInviteeSessionState> {
@Override
public BlogInviteeSessionState build(SessionId sessionId,
MessageId storageId, GroupId groupId,
InviteeSessionState.State state, ContactId contactId,
GroupId blogId, BdfDictionary d) throws FormatException {
String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID));
return new BlogInviteeSessionState(sessionId, storageId,
groupId, state, contactId, blogId, blogAuthorName,
blogPublicKey, invitationId);
}
@Override
public BlogInviteeSessionState build(SessionId sessionId,
MessageId storageId, GroupId groupId,
InviteeSessionState.State state, ContactId contactId,
Blog blog, MessageId invitationId) {
return new BlogInviteeSessionState(sessionId, storageId,
groupId, state, contactId, blog.getId(),
blog.getAuthor().getName(), blog.getAuthor().getPublicKey(),
invitationId);
}
}
private static class SSFactory implements
SharerSessionStateFactory<Blog, BlogSharerSessionState> {
@Override
public BlogSharerSessionState build(SessionId sessionId,
MessageId storageId, GroupId groupId,
SharerSessionState.State state, ContactId contactId,
GroupId blogId, BdfDictionary d) throws FormatException {
String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
MessageId responseId = null;
byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID);
if (responseIdBytes != null)
responseId = new MessageId(responseIdBytes);
return new BlogSharerSessionState(sessionId, storageId,
groupId, state, contactId, blogId, blogAuthorName,
blogPublicKey, responseId);
}
@Override
public BlogSharerSessionState build(SessionId sessionId,
MessageId storageId, GroupId groupId,
SharerSessionState.State state, ContactId contactId,
Blog blog) {
return new BlogSharerSessionState(sessionId, storageId,
groupId, state, contactId, blog.getId(),
blog.getAuthor().getName(), blog.getAuthor().getPublicKey(),
null);
}
}
private static class IRFactory implements
InvitationReceivedEventFactory<BlogInviteeSessionState, BlogInvitationRequestReceivedEvent> {
private final SFactory sFactory;
private IRFactory(SFactory sFactory) {
this.sFactory = sFactory;
}
@Override
public BlogInvitationRequestReceivedEvent build(
BlogInviteeSessionState localState, long time,
@Nullable String msg) {
Blog blog = sFactory.parse(localState);
ContactId contactId = localState.getContactId();
BlogInvitationRequest request =
new BlogInvitationRequest(localState.getInvitationId(),
localState.getSessionId(),
localState.getContactGroupId(), contactId,
blog.getAuthor().getName(), msg,
localState.getShareableId(), true, false, time,
false, false, false, false);
return new BlogInvitationRequestReceivedEvent(blog, contactId,
request);
}
}
private static class IRRFactory implements
InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> {
@Override
public BlogInvitationResponseReceivedEvent build(
BlogSharerSessionState localState, boolean accept, long time) {
ContactId c = localState.getContactId();
MessageId responseId = localState.getResponseId();
if (responseId == null)
throw new IllegalStateException("No responseId");
BlogInvitationResponse response =
new BlogInvitationResponse(responseId,
localState.getSessionId(),
localState.getContactGroupId(),
localState.getContactId(),
localState.getShareableId(), accept, time, false,
false, false, false);
return new BlogInvitationResponseReceivedEvent(c, response);
}
}
}

View File

@@ -1,17 +1,16 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.BdfMessageContext;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.client.BdfQueueMessageValidator;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogFactory;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
@@ -20,73 +19,35 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
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.LOCAL;
import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH;
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;
@Immutable
@NotNullByDefault
class BlogSharingValidator extends BdfQueueMessageValidator {
class BlogSharingValidator extends SharingValidator {
private final BlogFactory blogFactory;
private final AuthorFactory authorFactory;
@Inject
BlogSharingValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) {
super(clientHelper, metadataEncoder, clock);
BlogSharingValidator(MessageEncoder messageEncoder,
ClientHelper clientHelper, MetadataEncoder metadataEncoder,
Clock clock, BlogFactory blogFactory, AuthorFactory authorFactory) {
super(messageEncoder, clientHelper, metadataEncoder, clock);
this.blogFactory = blogFactory;
this.authorFactory = authorFactory;
}
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException {
protected GroupId validateDescriptor(BdfList descriptor)
throws FormatException {
checkSize(descriptor, 2);
String name = descriptor.getString(0);
checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
byte[] publicKey = descriptor.getRaw(1);
checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH);
BdfDictionary d = new BdfDictionary();
long type = body.getLong(0);
byte[] id = body.getRaw(1);
checkLength(id, SessionId.LENGTH);
if (type == SHARE_MSG_TYPE_INVITATION) {
checkSize(body, 3, 4);
BdfList author = body.getList(2);
checkSize(author, 2);
String authorName = author.getString(0);
checkLength(authorName, 1, MAX_AUTHOR_NAME_LENGTH);
byte[] publicKey = author.getRaw(1);
checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH);
d.put(BLOG_AUTHOR_NAME, authorName);
d.put(BLOG_PUBLIC_KEY, publicKey);
if (body.size() > 3) {
String msg = body.getString(3);
checkLength(msg, 0, MAX_INVITATION_MESSAGE_LENGTH);
d.put(INVITATION_MSG, msg);
}
} else {
checkSize(body, 2);
if (type != SHARE_MSG_TYPE_ACCEPT &&
type != SHARE_MSG_TYPE_DECLINE &&
type != SHARE_MSG_TYPE_LEAVE &&
type != SHARE_MSG_TYPE_ABORT) {
throw new FormatException();
}
}
// Return the metadata
d.put(TYPE, type);
d.put(SESSION_ID, id);
d.put(LOCAL, false);
d.put(TIME, m.getTimestamp());
return new BdfMessageContext(d);
Author author = authorFactory.createAuthor(name, publicKey);
Blog blog = blogFactory.createBlog(author);
return blog.getId();
}
}

View File

@@ -1,13 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import javax.annotation.Nullable;
@Deprecated
@NotNullByDefault
interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent> {
IR build(IS localState, long time, @Nullable String msg);
}

View File

@@ -1,11 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
@Deprecated
@NotNullByDefault
interface InvitationResponseReceivedEventFactory<SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent> {
IRR build(SS localState, boolean accept, long time);
}

View File

@@ -1,242 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.ProtocolEngine;
import org.briarproject.briar.api.sharing.SharingMessage.Invitation;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
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.TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US;
import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHARED_SHAREABLE;
import static org.briarproject.briar.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US;
import static org.briarproject.briar.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_WITH_US;
import static org.briarproject.briar.api.sharing.SharingMessage.BaseMessage;
import static org.briarproject.briar.api.sharing.SharingMessage.SimpleMessage;
@Deprecated
@Immutable
@NotNullByDefault
class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent>
implements ProtocolEngine<InviteeSessionState.Action, IS, BaseMessage> {
private static final Logger LOG =
Logger.getLogger(InviteeEngine.class.getName());
private final InvitationReceivedEventFactory<IS, IR>
invitationReceivedEventFactory;
private final Clock clock;
InviteeEngine(
InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory,
Clock clock) {
this.invitationReceivedEventFactory = invitationReceivedEventFactory;
this.clock = clock;
}
@Override
public StateUpdate<IS, BaseMessage> onLocalAction(
IS localState, InviteeSessionState.Action action) {
try {
InviteeSessionState.State currentState = localState.getState();
InviteeSessionState.State nextState = currentState.next(action);
localState.setState(nextState);
if (action == InviteeSessionState.Action.LOCAL_ABORT &&
currentState != InviteeSessionState.State.ERROR) {
return abortSession(currentState, localState);
}
if (nextState == InviteeSessionState.State.ERROR) {
if (LOG.isLoggable(WARNING)) {
LOG.warning("Error: Invalid action in state " +
currentState.name());
}
return noUpdate(localState, true);
}
List<BaseMessage> messages;
List<Event> events = Collections.emptyList();
if (action == InviteeSessionState.Action.LOCAL_ACCEPT ||
action == InviteeSessionState.Action.LOCAL_DECLINE) {
BaseMessage msg;
if (action == InviteeSessionState.Action.LOCAL_ACCEPT) {
localState.setTask(TASK_ADD_SHARED_SHAREABLE);
msg = new SimpleMessage(SHARE_MSG_TYPE_ACCEPT,
localState.getContactGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
} else {
localState.setTask(
TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US);
msg = new SimpleMessage(SHARE_MSG_TYPE_DECLINE,
localState.getContactGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
}
messages = Collections.singletonList(msg);
logLocalAction(currentState, localState, msg);
} else if (action == InviteeSessionState.Action.LOCAL_LEAVE) {
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
localState.getContactGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
messages = Collections.singletonList(msg);
logLocalAction(currentState, localState, msg);
} else {
throw new IllegalArgumentException("Unknown Local Action");
}
return new StateUpdate<IS, BaseMessage>(false,
false, localState, messages, events);
} catch (FormatException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public StateUpdate<IS, BaseMessage> onMessageReceived(
IS localState, BaseMessage msg) {
try {
InviteeSessionState.State currentState = localState.getState();
InviteeSessionState.Action action =
InviteeSessionState.Action.getRemote(msg.getType());
InviteeSessionState.State nextState = currentState.next(action);
localState.setState(nextState);
logMessageReceived(currentState, nextState, msg.getType(), msg);
if (nextState == InviteeSessionState.State.ERROR) {
if (currentState != InviteeSessionState.State.ERROR) {
return abortSession(currentState, localState);
} else {
return noUpdate(localState, true);
}
}
List<BaseMessage> messages = Collections.emptyList();
List<Event> events = Collections.emptyList();
boolean deleteMsg = false;
if (currentState == InviteeSessionState.State.LEFT) {
// ignore and delete messages coming in while in that state
deleteMsg = true;
}
// the sharer left the forum she had shared with us
else if (action == InviteeSessionState.Action.REMOTE_LEAVE &&
currentState == InviteeSessionState.State.FINISHED) {
localState.setTask(TASK_UNSHARE_SHAREABLE_SHARED_WITH_US);
} else if (currentState == InviteeSessionState.State.FINISHED) {
// ignore and delete messages coming in while in that state
// note that LEAVE is possible, but was handled above
deleteMsg = true;
}
// the sharer left the forum before we couldn't even respond
else if (action == InviteeSessionState.Action.REMOTE_LEAVE) {
localState.setTask(
TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US);
}
// we have just received our invitation
else if (action == InviteeSessionState.Action.REMOTE_INVITATION) {
localState.setTask(TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US);
Invitation invitation = (Invitation) msg;
Event event = invitationReceivedEventFactory.build(localState,
msg.getTime(), invitation.getMessage());
events = Collections.singletonList(event);
} else {
throw new IllegalArgumentException("Bad state");
}
return new StateUpdate<IS, BaseMessage>(deleteMsg,
false, localState, messages, events);
} catch (FormatException e) {
throw new IllegalArgumentException(e);
}
}
private void logLocalAction(InviteeSessionState.State state,
InviteeSessionState localState, BaseMessage msg) {
if (!LOG.isLoggable(INFO)) return;
String a = "response";
if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave";
LOG.info("Sending " + a + " in state " + state.name() +
" with session ID " +
msg.getSessionId().hashCode() + " in group " +
msg.getGroupId().hashCode() + ". " +
"Moving on to state " + localState.getState().name()
);
}
private void logMessageReceived(InviteeSessionState.State currentState,
InviteeSessionState.State nextState,
long type, BaseMessage msg) {
if (!LOG.isLoggable(INFO)) return;
String t = "unknown";
if (type == SHARE_MSG_TYPE_INVITATION) t = "INVITE";
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
LOG.info("Received " + t + " in state " + currentState.name() +
" with session ID " +
msg.getSessionId().hashCode() + " in group " +
msg.getGroupId().hashCode() + ". " +
"Moving on to state " + nextState.name()
);
}
@Override
public StateUpdate<IS, BaseMessage> onMessageDelivered(
IS localState, BaseMessage delivered) {
try {
return noUpdate(localState, false);
} catch (FormatException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
}
}
private StateUpdate<IS, BaseMessage> abortSession(
InviteeSessionState.State currentState, IS localState)
throws FormatException {
if (LOG.isLoggable(WARNING)) {
LOG.warning("Aborting protocol session " +
localState.getSessionId().hashCode() +
" in state " + currentState.name());
}
localState.setState(InviteeSessionState.State.ERROR);
BaseMessage msg =
new SimpleMessage(SHARE_MSG_TYPE_ABORT, localState.getContactGroupId(),
localState.getSessionId(), clock.currentTimeMillis());
List<BaseMessage> messages = Collections.singletonList(msg);
List<Event> events = Collections.emptyList();
return new StateUpdate<IS, BaseMessage>(false, false,
localState, messages, events);
}
private StateUpdate<IS, BaseMessage> noUpdate(
IS localState, boolean delete) throws FormatException {
return new StateUpdate<IS, BaseMessage>(delete, false,
localState, Collections.<BaseMessage>emptyList(),
Collections.<Event>emptyList());
}
}

View File

@@ -1,141 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary;
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;
import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_ID;
import static org.briarproject.briar.api.sharing.SharingConstants.IS_SHARER;
import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
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.STATE;
import static org.briarproject.briar.sharing.InviteeSessionState.Action.LOCAL_ACCEPT;
import static org.briarproject.briar.sharing.InviteeSessionState.Action.LOCAL_DECLINE;
import static org.briarproject.briar.sharing.InviteeSessionState.Action.LOCAL_LEAVE;
import static org.briarproject.briar.sharing.InviteeSessionState.Action.REMOTE_INVITATION;
import static org.briarproject.briar.sharing.InviteeSessionState.Action.REMOTE_LEAVE;
@Deprecated
@NotThreadSafe
@NotNullByDefault
public abstract class InviteeSessionState extends SharingSessionState {
private State state;
private final MessageId invitationId;
public InviteeSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId,
GroupId shareableId, MessageId invitationId) {
super(sessionId, storageId, groupId, contactId, shareableId);
this.state = state;
this.invitationId = invitationId;
}
@Override
public BdfDictionary toBdfDictionary() {
BdfDictionary d = super.toBdfDictionary();
d.put(STATE, getState().getValue());
d.put(IS_SHARER, false);
d.put(INVITATION_ID, invitationId);
return d;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
public MessageId getInvitationId() {
return invitationId;
}
@Immutable
@NotNullByDefault
public enum State {
ERROR(0),
AWAIT_INVITATION(1) {
@Override
public State next(Action a) {
if (a == REMOTE_INVITATION) return AWAIT_LOCAL_RESPONSE;
return ERROR;
}
},
AWAIT_LOCAL_RESPONSE(2) {
@Override
public State next(Action a) {
if (a == LOCAL_ACCEPT || a == LOCAL_DECLINE) return FINISHED;
if (a == REMOTE_LEAVE) return LEFT;
return ERROR;
}
},
FINISHED(3) {
@Override
public State next(Action a) {
if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT;
return FINISHED;
}
},
LEFT(4) {
@Override
public State next(Action a) {
if (a == LOCAL_LEAVE) return ERROR;
return LEFT;
}
};
private final int value;
State(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static State fromValue(int value) {
for (State s : values()) {
if (s.value == value) return s;
}
throw new IllegalArgumentException();
}
public State next(Action a) {
return this;
}
}
@NotNullByDefault
public enum Action {
LOCAL_ACCEPT,
LOCAL_DECLINE,
LOCAL_LEAVE,
LOCAL_ABORT,
REMOTE_INVITATION,
REMOTE_LEAVE,
REMOTE_ABORT;
@Nullable
public static Action getRemote(long type) {
if (type == SHARE_MSG_TYPE_INVITATION) return REMOTE_INVITATION;
if (type == SHARE_MSG_TYPE_LEAVE) return REMOTE_LEAVE;
if (type == SHARE_MSG_TYPE_ABORT) return REMOTE_ABORT;
return null;
}
}
}

View File

@@ -1,21 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary;
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.Shareable;
@Deprecated
interface InviteeSessionStateFactory<S extends Shareable, IS extends InviteeSessionState> {
IS build(SessionId sessionId, MessageId storageId, GroupId groupId,
InviteeSessionState.State state, ContactId contactId,
GroupId shareableId, BdfDictionary d) throws FormatException;
IS build(SessionId sessionId, MessageId storageId, GroupId groupId,
InviteeSessionState.State state, ContactId contactId, S shareable,
MessageId invitationId);
}

View File

@@ -1,12 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.sharing.SharingMessage;
@Deprecated
@NotNullByDefault
interface OldInvitationFactory<I extends SharingMessage.Invitation, SS extends SharerSessionState>
extends org.briarproject.briar.api.sharing.InvitationFactory<I> {
I build(SS localState, long time);
}

View File

@@ -20,6 +20,7 @@ import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.sharing.Shareable;
import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent;
import java.util.Map;
@@ -486,6 +487,14 @@ abstract class ProtocolEngineImpl<S extends Shareable>
// The dependency, if any, must be the last remote message
if (!isValidDependency(s, m.getPreviousMessageId()))
return abort(txn, s);
if (s.getState() == SHARING) {
// Broadcast event informing that contact left
ContactId contactId = getContactId(txn, s.getContactGroupId());
ContactLeftShareableEvent e =
new ContactLeftShareableEvent(s.getShareableId(),
contactId);
txn.attach(e);
}
// Move to the next state
return new Session(nextState, s.getContactGroupId(), s.getShareableId(),
s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(),

View File

@@ -1,27 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.data.BdfList;
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.briar.api.sharing.Shareable;
import org.briarproject.briar.api.sharing.SharingMessage;
@Deprecated
@NotNullByDefault
interface ShareableFactory<S extends Shareable, I extends SharingMessage.Invitation, IS extends InviteeSessionState, SS extends SharerSessionState> {
BdfList encode(S sh);
S get(Transaction txn, GroupId groupId) throws DbException;
S parse(BdfList shareable) throws FormatException;
S parse(I msg);
S parse(IS state);
S parse(SS state);
}

View File

@@ -1,240 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.ProtocolEngine;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
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_LEAVE;
import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US;
import static org.briarproject.briar.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US;
import static org.briarproject.briar.api.sharing.SharingConstants.TASK_SHARE_SHAREABLE;
import static org.briarproject.briar.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_BY_US;
import static org.briarproject.briar.api.sharing.SharingMessage.BaseMessage;
import static org.briarproject.briar.api.sharing.SharingMessage.Invitation;
import static org.briarproject.briar.api.sharing.SharingMessage.SimpleMessage;
import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_ACCEPT;
import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_DECLINE;
@Deprecated
@Immutable
@NotNullByDefault
class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent>
implements ProtocolEngine<SharerSessionState.Action, SS, BaseMessage> {
private static final Logger LOG =
Logger.getLogger(SharerEngine.class.getName());
private final OldInvitationFactory<I, SS> invitationFactory;
private final InvitationResponseReceivedEventFactory<SS, IRR>
invitationResponseReceivedEventFactory;
private final Clock clock;
SharerEngine(OldInvitationFactory<I, SS> invitationFactory,
InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory,
Clock clock) {
this.invitationFactory = invitationFactory;
this.invitationResponseReceivedEventFactory =
invitationResponseReceivedEventFactory;
this.clock = clock;
}
@Override
public StateUpdate<SS, BaseMessage> onLocalAction(
SS localState, SharerSessionState.Action action) {
try {
SharerSessionState.State currentState = localState.getState();
SharerSessionState.State nextState = currentState.next(action);
localState.setState(nextState);
if (action == SharerSessionState.Action.LOCAL_ABORT &&
currentState != SharerSessionState.State.ERROR) {
return abortSession(currentState, localState);
}
if (nextState == SharerSessionState.State.ERROR) {
if (LOG.isLoggable(WARNING)) {
LOG.warning("Error: Invalid action in state " +
currentState.name());
}
return noUpdate(localState, true);
}
List<BaseMessage> messages;
List<Event> events = Collections.emptyList();
if (action == SharerSessionState.Action.LOCAL_INVITATION) {
BaseMessage msg = invitationFactory.build(localState,
clock.currentTimeMillis());
messages = Collections.singletonList(msg);
logLocalAction(currentState, nextState, msg);
// remember that we offered to share this forum
localState
.setTask(TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US);
} else if (action == SharerSessionState.Action.LOCAL_LEAVE) {
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
localState.getContactGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
messages = Collections.singletonList(msg);
logLocalAction(currentState, nextState, msg);
} else {
throw new IllegalArgumentException("Unknown Local Action");
}
return new StateUpdate<SS, BaseMessage>(false,
false, localState, messages, events);
} catch (FormatException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public StateUpdate<SS, BaseMessage> onMessageReceived(
SS localState, BaseMessage msg) {
try {
SharerSessionState.State currentState = localState.getState();
SharerSessionState.Action action =
SharerSessionState.Action.getRemote(msg.getType());
SharerSessionState.State nextState = currentState.next(action);
localState.setState(nextState);
logMessageReceived(currentState, nextState, msg.getType(), msg);
if (nextState == SharerSessionState.State.ERROR) {
if (currentState != SharerSessionState.State.ERROR) {
return abortSession(currentState, localState);
} else {
return noUpdate(localState, true);
}
}
List<BaseMessage> messages = Collections.emptyList();
List<Event> events = Collections.emptyList();
boolean deleteMsg = false;
if (currentState == SharerSessionState.State.LEFT) {
// ignore and delete messages coming in while in that state
deleteMsg = true;
} else if (action == SharerSessionState.Action.REMOTE_LEAVE) {
localState.setTask(TASK_UNSHARE_SHAREABLE_SHARED_BY_US);
} else if (currentState == SharerSessionState.State.FINISHED) {
// ignore and delete messages coming in while in that state
// note that LEAVE is possible, but was handled above
deleteMsg = true;
}
// we have sent our invitation and just got a response
else if (action == REMOTE_ACCEPT || action == REMOTE_DECLINE) {
if (action == REMOTE_ACCEPT) {
localState.setTask(TASK_SHARE_SHAREABLE);
} else {
// this ensures that the forum can be shared again
localState.setTask(
TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US);
}
Event event = invitationResponseReceivedEventFactory
.build(localState, action == REMOTE_ACCEPT,
msg.getTime());
events = Collections.singletonList(event);
} else {
throw new IllegalArgumentException("Bad state");
}
return new StateUpdate<SS, BaseMessage>(deleteMsg,
false, localState, messages, events);
} catch (FormatException e) {
throw new IllegalArgumentException(e);
}
}
private void logLocalAction(SharerSessionState.State currentState,
SharerSessionState.State nextState,
BaseMessage msg) {
if (!LOG.isLoggable(INFO)) return;
String a = "invitation";
if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave";
LOG.info("Sending " + a + " in state " + currentState.name() +
" with session ID " +
msg.getSessionId().hashCode() + " in group " +
msg.getGroupId().hashCode() + ". " +
"Moving on to state " + nextState.name()
);
}
private void logMessageReceived(SharerSessionState.State currentState,
SharerSessionState.State nextState,
long type, BaseMessage msg) {
if (!LOG.isLoggable(INFO)) return;
String t = "unknown";
if (type == SHARE_MSG_TYPE_ACCEPT) t = "ACCEPT";
else if (type == SHARE_MSG_TYPE_DECLINE) t = "DECLINE";
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
LOG.info("Received " + t + " in state " + currentState.name() +
" with session ID " +
msg.getSessionId().hashCode() + " in group " +
msg.getGroupId().hashCode() + ". " +
"Moving on to state " + nextState.name()
);
}
@Override
public StateUpdate<SS, BaseMessage> onMessageDelivered(
SS localState, BaseMessage delivered) {
try {
return noUpdate(localState, false);
} catch (FormatException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
}
}
private StateUpdate<SS, BaseMessage> abortSession(
SharerSessionState.State currentState, SS localState)
throws FormatException {
if (LOG.isLoggable(WARNING)) {
LOG.warning("Aborting protocol session " +
localState.getSessionId().hashCode() +
" in state " + currentState.name());
}
localState.setState(SharerSessionState.State.ERROR);
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT,
localState.getContactGroupId(), localState.getSessionId(),
clock.currentTimeMillis());
List<BaseMessage> messages = Collections.singletonList(msg);
List<Event> events = Collections.emptyList();
return new StateUpdate<SS, BaseMessage>(false, false,
localState, messages, events);
}
private StateUpdate<SS, BaseMessage> noUpdate(
SS localState, boolean delete)
throws FormatException {
return new StateUpdate<SS, BaseMessage>(delete, false,
localState, Collections.<BaseMessage>emptyList(),
Collections.<Event>emptyList());
}
}

View File

@@ -1,153 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary;
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.NotThreadSafe;
import static org.briarproject.briar.api.sharing.SharingConstants.IS_SHARER;
import static org.briarproject.briar.api.sharing.SharingConstants.RESPONSE_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_LEAVE;
import static org.briarproject.briar.api.sharing.SharingConstants.STATE;
import static org.briarproject.briar.sharing.SharerSessionState.Action.LOCAL_INVITATION;
import static org.briarproject.briar.sharing.SharerSessionState.Action.LOCAL_LEAVE;
import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_ACCEPT;
import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_DECLINE;
import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_LEAVE;
@Deprecated
@NotThreadSafe
@NotNullByDefault
public abstract class SharerSessionState extends SharingSessionState {
private State state;
@Nullable
private String msg = null;
@Nullable
private MessageId responseId;
public SharerSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, State state, ContactId contactId,
GroupId shareableId, @Nullable MessageId responseId) {
super(sessionId, storageId, groupId, contactId, shareableId);
this.state = state;
this.responseId = responseId;
}
@Override
public BdfDictionary toBdfDictionary() {
BdfDictionary d = super.toBdfDictionary();
d.put(STATE, getState().getValue());
d.put(IS_SHARER, true);
if (responseId != null) d.put(RESPONSE_ID, responseId);
return d;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setMessage(String msg) {
this.msg = msg;
}
@Nullable
public String getMessage() {
return msg;
}
public void setResponseId(@Nullable MessageId responseId) {
this.responseId = responseId;
}
@Nullable
public MessageId getResponseId() {
return responseId;
}
public enum State {
ERROR(0),
PREPARE_INVITATION(1) {
@Override
public State next(Action a) {
if (a == LOCAL_INVITATION) return AWAIT_RESPONSE;
return ERROR;
}
},
AWAIT_RESPONSE(2) {
@Override
public State next(Action a) {
if (a == REMOTE_ACCEPT || a == REMOTE_DECLINE) return FINISHED;
if (a == LOCAL_LEAVE) return LEFT;
return ERROR;
}
},
FINISHED(3) {
@Override
public State next(Action a) {
if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT;
return FINISHED;
}
},
LEFT(4) {
@Override
public State next(Action a) {
if (a == LOCAL_LEAVE) return ERROR;
return LEFT;
}
};
private final int value;
State(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static State fromValue(int value) {
for (State s : values()) {
if (s.value == value) return s;
}
throw new IllegalArgumentException();
}
public State next(Action a) {
return this;
}
}
public enum Action {
LOCAL_INVITATION,
LOCAL_LEAVE,
LOCAL_ABORT,
REMOTE_ACCEPT,
REMOTE_DECLINE,
REMOTE_LEAVE,
REMOTE_ABORT;
public static Action getRemote(long type) {
if (type == SHARE_MSG_TYPE_ACCEPT) return REMOTE_ACCEPT;
if (type == SHARE_MSG_TYPE_DECLINE) return REMOTE_DECLINE;
if (type == SHARE_MSG_TYPE_LEAVE) return REMOTE_LEAVE;
if (type == SHARE_MSG_TYPE_ABORT) return REMOTE_ABORT;
return null;
}
}
}

View File

@@ -1,22 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary;
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.Shareable;
@Deprecated
@NotNullByDefault
interface SharerSessionStateFactory<S extends Shareable, SS extends SharerSessionState> {
SS build(SessionId sessionId, MessageId storageId, GroupId groupId,
SharerSessionState.State state, ContactId contactId,
GroupId shareableId, BdfDictionary d) throws FormatException;
SS build(SessionId sessionId, MessageId storageId, GroupId groupId,
SharerSessionState.State state, ContactId contactId, S shareable);
}

View File

@@ -23,6 +23,7 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.sharing.InvitationMessage;
import org.briarproject.briar.api.sharing.InvitationRequest;
@@ -211,8 +212,10 @@ abstract class SharingManagerImpl<S extends Shareable>
SessionId sessionId = getSessionId(shareableId);
Transaction txn = db.startTransaction(false);
try {
// Look up the session, if there is one
Contact contact = db.getContact(txn, contactId);
if (!canBeShared(txn, shareableId, contact))
throw new ProtocolStateException();
// Look up the session, if there is one
GroupId contactGroupId = getContactGroup(contact).getId();
StoredSession ss = getSession(txn, contactGroupId, sessionId);
// Create or parse the session
@@ -400,12 +403,22 @@ abstract class SharingManagerImpl<S extends Shareable>
@Override
public boolean canBeShared(GroupId g, Contact c) throws DbException {
GroupId contactGroupId = getContactGroup(c).getId();
SessionId sessionId = getSessionId(g);
Transaction txn = db.startTransaction(true);
try {
StoredSession ss = getSession(txn, contactGroupId, sessionId);
boolean canBeShared = canBeShared(txn, g, c);
db.commitTransaction(txn);
return canBeShared;
} finally {
db.endTransaction(txn);
}
}
protected boolean canBeShared(Transaction txn, GroupId g, Contact c)
throws DbException {
GroupId contactGroupId = getContactGroup(c).getId();
SessionId sessionId = getSessionId(g);
try {
StoredSession ss = getSession(txn, contactGroupId, sessionId);
// If there's no session, we can share the group with the contact
if (ss == null) return true;
// If the session's in the right state, the contact can be invited
@@ -414,8 +427,6 @@ abstract class SharingManagerImpl<S extends Shareable>
return session.getState().canInvite();
} catch (FormatException e) {
throw new DbException(e);
} finally {
db.endTransaction(txn);
}
}

View File

@@ -3,12 +3,14 @@ package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogFactory;
import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.client.MessageQueueManager;
import org.briarproject.briar.api.forum.Forum;
import org.briarproject.briar.api.forum.ForumFactory;
import org.briarproject.briar.api.forum.ForumManager;
@@ -35,17 +37,32 @@ public class SharingModule {
BlogSharingManager blogSharingManager;
}
@Provides
MessageEncoder provideMessageEncoder(MessageEncoderImpl messageEncoder) {
return messageEncoder;
}
@Provides
SessionEncoder provideSessionEncoder(SessionEncoderImpl sessionEncoder) {
return sessionEncoder;
}
@Provides
SessionParser provideSessionParser(SessionParserImpl sessionParser) {
return sessionParser;
}
@Provides
@Singleton
BlogSharingValidator provideBlogSharingValidator(
MessageQueueManager messageQueueManager, ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) {
ValidationManager validationManager, MessageEncoder messageEncoder,
ClientHelper clientHelper, MetadataEncoder metadataEncoder,
Clock clock, BlogFactory blogFactory, AuthorFactory authorFactory) {
BlogSharingValidator validator =
new BlogSharingValidator(clientHelper, metadataEncoder, clock);
messageQueueManager.registerMessageValidator(
BlogSharingManager.CLIENT_ID, validator);
new BlogSharingValidator(messageEncoder, clientHelper,
metadataEncoder, clock, blogFactory, authorFactory);
validationManager.registerMessageValidator(BlogSharingManager.CLIENT_ID,
validator);
return validator;
}
@@ -53,14 +70,13 @@ public class SharingModule {
@Singleton
BlogSharingManager provideBlogSharingManager(
LifecycleManager lifecycleManager, ContactManager contactManager,
MessageQueueManager messageQueueManager,
ValidationManager validationManager,
ConversationManager conversationManager, BlogManager blogManager,
BlogSharingManagerImpl blogSharingManager) {
lifecycleManager.registerClient(blogSharingManager);
contactManager.registerAddContactHook(blogSharingManager);
contactManager.registerRemoveContactHook(blogSharingManager);
messageQueueManager.registerIncomingMessageHook(
validationManager.registerIncomingMessageHook(
BlogSharingManager.CLIENT_ID, blogSharingManager);
conversationManager.registerConversationClient(blogSharingManager);
blogManager.registerRemoveBlogHook(blogSharingManager);
@@ -68,6 +84,24 @@ public class SharingModule {
return blogSharingManager;
}
@Provides
MessageParser<Blog> provideBlogMessageParser(
BlogMessageParserImpl blogMessageParser) {
return blogMessageParser;
}
@Provides
ProtocolEngine<Blog> provideBlogProtocolEngine(
BlogProtocolEngineImpl blogProtocolEngine) {
return blogProtocolEngine;
}
@Provides
InvitationFactory<Blog> provideBlogInvitationFactory(
BlogInvitationFactoryImpl blogInvitationFactory) {
return blogInvitationFactory;
}
@Provides
@Singleton
ForumSharingValidator provideForumSharingValidator(
@@ -102,27 +136,12 @@ public class SharingModule {
return forumSharingManager;
}
@Provides
MessageEncoder provideMessageEncoder(MessageEncoderImpl messageEncoder) {
return messageEncoder;
}
@Provides
MessageParser<Forum> provideForumMessageParser(
ForumMessageParserImpl forumMessageParser) {
return forumMessageParser;
}
@Provides
SessionEncoder provideSessionEncoder(SessionEncoderImpl sessionEncoder) {
return sessionEncoder;
}
@Provides
SessionParser provideSessionParser(SessionParserImpl sessionParser) {
return sessionParser;
}
@Provides
ProtocolEngine<Forum> provideForumProtocolEngine(
ForumProtocolEngineImpl forumProtocolEngine) {

View File

@@ -1,107 +0,0 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfDictionary;
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.NotThreadSafe;
import static org.briarproject.briar.api.sharing.SharingConstants.CONTACT_ID;
import static org.briarproject.briar.api.sharing.SharingConstants.GROUP_ID;
import static org.briarproject.briar.api.sharing.SharingConstants.IS_SHARER;
import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID;
import static org.briarproject.briar.api.sharing.SharingConstants.SHAREABLE_ID;
import static org.briarproject.briar.api.sharing.SharingConstants.STATE;
import static org.briarproject.briar.api.sharing.SharingConstants.STORAGE_ID;
@Deprecated
@NotThreadSafe
@NotNullByDefault
abstract class SharingSessionState {
private final SessionId sessionId;
private final MessageId storageId;
private final GroupId groupId;
private final ContactId contactId;
private final GroupId shareableId;
private int task = -1; // TODO get rid of task, see #376
SharingSessionState(SessionId sessionId, MessageId storageId,
GroupId groupId, ContactId contactId, GroupId shareableId) {
this.sessionId = sessionId;
this.storageId = storageId;
this.groupId = groupId;
this.contactId = contactId;
this.shareableId = shareableId;
}
static SharingSessionState fromBdfDictionary(
InviteeSessionStateFactory isFactory,
SharerSessionStateFactory ssFactory, BdfDictionary d)
throws FormatException {
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
MessageId messageId = new MessageId(d.getRaw(STORAGE_ID));
GroupId groupId = new GroupId(d.getRaw(GROUP_ID));
ContactId contactId = new ContactId(d.getLong(CONTACT_ID).intValue());
GroupId forumId = new GroupId(d.getRaw(SHAREABLE_ID));
int intState = d.getLong(STATE).intValue();
if (d.getBoolean(IS_SHARER)) {
SharerSessionState.State state =
SharerSessionState.State.fromValue(intState);
return ssFactory.build(sessionId, messageId, groupId, state,
contactId, forumId, d);
} else {
InviteeSessionState.State state =
InviteeSessionState.State.fromValue(intState);
return isFactory.build(sessionId, messageId, groupId, state,
contactId, forumId, d);
}
}
public BdfDictionary toBdfDictionary() {
BdfDictionary d = new BdfDictionary();
d.put(SESSION_ID, getSessionId());
d.put(STORAGE_ID, getStorageId());
d.put(GROUP_ID, getContactGroupId());
d.put(CONTACT_ID, getContactId().getInt());
d.put(SHAREABLE_ID, getShareableId());
return d;
}
public SessionId getSessionId() {
return sessionId;
}
public MessageId getStorageId() {
return storageId;
}
public GroupId getContactGroupId() {
return groupId;
}
public ContactId getContactId() {
return contactId;
}
public GroupId getShareableId() {
return shareableId;
}
public void setTask(int task) {
this.task = task;
}
public int getTask() {
return task;
}
}

View File

@@ -4,7 +4,6 @@ import net.jodah.concurrentunit.Waiter;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -17,6 +16,7 @@ import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.sharing.InvitationMessage;
import org.briarproject.briar.test.BriarIntegrationTest;
import org.briarproject.briar.test.BriarIntegrationTestComponent;
@@ -35,7 +35,6 @@ import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class BlogSharingIntegrationTest
extends BriarIntegrationTest<BriarIntegrationTestComponent> {
@@ -92,7 +91,7 @@ public class BlogSharingIntegrationTest
injectEagerSingletons(c2);
}
@Test
@Test(expected = ProtocolStateException.class)
public void testPersonalBlogCannotBeSharedWithOwner() throws Exception {
listenToEvents(true);
@@ -109,11 +108,6 @@ public class BlogSharingIntegrationTest
blogSharingManager0
.sendInvitation(blog1.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
// sync invitation
sync0To1(1, false);
// make sure the invitee ignored the request for their own blog
assertFalse(listener1.requestReceived);
}
@Test
@@ -293,17 +287,11 @@ public class BlogSharingIntegrationTest
assertFalse(blogSharingManager0.getSharedWith(blog2.getId())
.contains(contact1From0));
// invitee no longer has blog shared by sharer
try {
blogSharingManager1.getSharedWith(blog2.getId());
fail();
} catch (NoSuchGroupException e) {
// expected
}
// blog can be shared again
assertEquals(0,
blogSharingManager1.getSharedWith(blog2.getId()).size());
// blog can be shared again by sharer
assertTrue(
blogSharingManager0.canBeShared(blog2.getId(), contact1From0));
assertTrue(
blogSharingManager1.canBeShared(blog2.getId(), contact0From1));
}
@Test

View File

@@ -0,0 +1,185 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.BdfMessageContext;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.briar.api.blog.Blog;
import org.jmock.Expectations;
import org.junit.Test;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_NAME_LENGTH;
import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH;
import static org.briarproject.briar.sharing.MessageType.INVITE;
public class BlogSharingValidatorTest extends SharingValidatorTest {
private final AuthorId authorId = new AuthorId(getRandomId());
private final String authorName = TestUtils.getRandomString(42);
private final byte[] publicKey =
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
private final Author author = new Author(authorId, authorName, publicKey);
private final Blog blog = new Blog(group, author);
private final BdfList descriptor = BdfList.of(authorName, publicKey);
private final String content =
TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH);
@Override
SharingValidator getValidator() {
return new BlogSharingValidator(messageEncoder, clientHelper,
metadataEncoder, clock, blogFactory, authorFactory);
}
@Test
public void testAcceptsInvitationWithContent() throws Exception {
expectCreateBlog(authorName, publicKey);
expectEncodeMetadata(INVITE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor,
content));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsInvitationWithNullContent() throws Exception {
expectCreateBlog(authorName, publicKey);
expectEncodeMetadata(INVITE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsInvitationWithNullPreviousMsgId() throws Exception {
expectCreateBlog(authorName, publicKey);
expectEncodeMetadata(INVITE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), null, descriptor, null));
assertExpectedContext(messageContext, null);
}
@Test(expected = FormatException.class)
public void testRejectsNullBlogName() throws Exception {
BdfList invalidDescriptor = BdfList.of(null, publicKey);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
null));
}
@Test(expected = FormatException.class)
public void testRejectsNonStringBlogName() throws Exception {
BdfList invalidDescriptor = BdfList.of(123, publicKey);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
null));
}
@Test(expected = FormatException.class)
public void testRejectsTooShortBlogName() throws Exception {
BdfList invalidDescriptor = BdfList.of("", publicKey);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
null));
}
@Test
public void testAcceptsMinLengthBlogName() throws Exception {
String shortBlogName = TestUtils.getRandomString(1);
BdfList validDescriptor = BdfList.of(shortBlogName, publicKey);
expectCreateBlog(shortBlogName, publicKey);
expectEncodeMetadata(INVITE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, validDescriptor,
null));
assertExpectedContext(messageContext, previousMsgId);
}
@Test(expected = FormatException.class)
public void testRejectsTooLongBlogName() throws Exception {
String invalidBlogName =
TestUtils.getRandomString(MAX_BLOG_NAME_LENGTH + 1);
BdfList invalidDescriptor = BdfList.of(invalidBlogName, publicKey);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
null));
}
@Test(expected = FormatException.class)
public void testRejectsNullPublicKey() throws Exception {
BdfList invalidDescriptor = BdfList.of(authorName, null);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
null));
}
@Test(expected = FormatException.class)
public void testRejectsNonRawPublicKey() throws Exception {
BdfList invalidDescriptor = BdfList.of(authorName, 123);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
null));
}
@Test(expected = FormatException.class)
public void testRejectsTooLongPublicKey() throws Exception {
byte[] invalidKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1);
BdfList invalidDescriptor = BdfList.of(authorName, invalidKey);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
null));
}
@Test
public void testAcceptsMinLengthPublicKey() throws Exception {
byte[] key = TestUtils.getRandomBytes(1);
BdfList validDescriptor = BdfList.of(authorName, key);
expectCreateBlog(authorName, key);
expectEncodeMetadata(INVITE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, validDescriptor,
null));
assertExpectedContext(messageContext, previousMsgId);
}
@Test(expected = FormatException.class)
public void testRejectsNonStringContent() throws Exception {
expectCreateBlog(authorName, publicKey);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor,
123));
}
@Test
public void testAcceptsMinLengthContent() throws Exception {
expectCreateBlog(authorName, publicKey);
expectEncodeMetadata(INVITE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor, "1"));
assertExpectedContext(messageContext, previousMsgId);
}
@Test(expected = FormatException.class)
public void testRejectsTooLongContent() throws Exception {
String invalidContent =
TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH + 1);
expectCreateBlog(authorName, publicKey);
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor,
invalidContent));
}
private void expectCreateBlog(final String name, final byte[] key) {
context.checking(new Expectations() {{
oneOf(authorFactory).createAuthor(name, key);
will(returnValue(author));
oneOf(blogFactory).createBlog(author);
will(returnValue(blog));
}});
}
}

View File

@@ -1,45 +1,20 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.client.BdfMessageContext;
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.sync.MessageId;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.bramble.test.ValidatorTestCase;
import org.briarproject.briar.api.forum.Forum;
import org.briarproject.briar.api.forum.ForumFactory;
import org.jmock.Expectations;
import org.junit.Test;
import java.util.Collection;
import javax.annotation.Nullable;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT_LENGTH;
import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH;
import static org.briarproject.briar.sharing.MessageType.ABORT;
import static org.briarproject.briar.sharing.MessageType.ACCEPT;
import static org.briarproject.briar.sharing.MessageType.DECLINE;
import static org.briarproject.briar.sharing.MessageType.INVITE;
import static org.briarproject.briar.sharing.MessageType.LEAVE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class ForumSharingValidatorTest extends ValidatorTestCase {
public class ForumSharingValidatorTest extends SharingValidatorTest {
private final MessageEncoder messageEncoder =
context.mock(MessageEncoder.class);
private final ForumFactory forumFactory = context.mock(ForumFactory.class);
private final ForumSharingValidator v =
new ForumSharingValidator(messageEncoder, clientHelper,
metadataEncoder, clock, forumFactory);
private final MessageId previousMsgId = new MessageId(getRandomId());
private final String forumName =
TestUtils.getRandomString(MAX_FORUM_NAME_LENGTH);
private final byte[] salt = TestUtils.getRandomBytes(FORUM_SALT_LENGTH);
@@ -47,8 +22,12 @@ public class ForumSharingValidatorTest extends ValidatorTestCase {
private final BdfList descriptor = BdfList.of(forumName, salt);
private final String content =
TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH);
private final BdfDictionary meta =
BdfDictionary.of(new BdfEntry("meta", "data"));
@Override
SharingValidator getValidator() {
return new ForumSharingValidator(messageEncoder, clientHelper,
metadataEncoder, clock, forumFactory);
}
@Test
public void testAcceptsInvitationWithContent() throws Exception {
@@ -78,107 +57,6 @@ public class ForumSharingValidatorTest extends ValidatorTestCase {
assertExpectedContext(messageContext, null);
}
@Test
public void testAcceptsAccept() throws Exception {
expectEncodeMetadata(ACCEPT);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(ACCEPT.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsDecline() throws Exception {
expectEncodeMetadata(DECLINE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(DECLINE.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsLeave() throws Exception {
expectEncodeMetadata(LEAVE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(LEAVE.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsAbort() throws Exception {
expectEncodeMetadata(ABORT);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test(expected = FormatException.class)
public void testRejectsNullMessageType() throws Exception {
v.validateMessage(message, group,
BdfList.of(null, groupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsNonLongMessageType() throws Exception {
v.validateMessage(message, group,
BdfList.of("", groupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsInvalidMessageType() throws Exception {
int invalidMessageType = ABORT.getValue() + 1;
v.validateMessage(message, group,
BdfList.of(invalidMessageType, groupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsNullSessionId() throws Exception {
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), null, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsNonRawSessionId() throws Exception {
v.validateMessage(message, group, BdfList.of(ABORT.getValue(), 123));
}
@Test(expected = FormatException.class)
public void testRejectsTooShortSessionId() throws Exception {
byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH - 1);
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsTooLongSessionId() throws Exception {
byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH + 1);
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsTooShortBodyForAbort() throws Exception {
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), groupId));
}
@Test(expected = FormatException.class)
public void testRejectsTooLongBodyForAbort() throws Exception {
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), groupId, previousMsgId, 123));
}
@Test(expected = FormatException.class)
public void testRejectsTooShortBodyForInvitation() throws Exception {
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor));
}
@Test(expected = FormatException.class)
public void testRejectsTooLongBodyForInvitation() throws Exception {
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null,
123));
}
@Test(expected = FormatException.class)
public void testRejectsNullForumName() throws Exception {
BdfList invalidDescriptor = BdfList.of(null, salt);
@@ -293,25 +171,4 @@ public class ForumSharingValidatorTest extends ValidatorTestCase {
}});
}
private void expectEncodeMetadata(final MessageType type) {
context.checking(new Expectations() {{
oneOf(messageEncoder)
.encodeMetadata(type, groupId, timestamp, false, false,
false, false);
will(returnValue(meta));
}});
}
private void assertExpectedContext(BdfMessageContext messageContext,
@Nullable MessageId previousMsgId) throws FormatException {
Collection<MessageId> dependencies = messageContext.getDependencies();
if (previousMsgId == null) {
assertTrue(dependencies.isEmpty());
} else {
assertEquals(1, dependencies.size());
assertTrue(dependencies.contains(previousMsgId));
}
assertEquals(meta, messageContext.getDictionary());
}
}

View File

@@ -0,0 +1,167 @@
package org.briarproject.briar.sharing;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.client.BdfMessageContext;
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.sync.MessageId;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.bramble.test.ValidatorTestCase;
import org.briarproject.briar.api.blog.BlogFactory;
import org.briarproject.briar.api.forum.ForumFactory;
import org.jmock.Expectations;
import org.junit.Test;
import java.util.Collection;
import javax.annotation.Nullable;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.briar.sharing.MessageType.ABORT;
import static org.briarproject.briar.sharing.MessageType.ACCEPT;
import static org.briarproject.briar.sharing.MessageType.DECLINE;
import static org.briarproject.briar.sharing.MessageType.INVITE;
import static org.briarproject.briar.sharing.MessageType.LEAVE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public abstract class SharingValidatorTest extends ValidatorTestCase {
protected final MessageEncoder messageEncoder =
context.mock(MessageEncoder.class);
protected final ForumFactory forumFactory =
context.mock(ForumFactory.class);
protected final BlogFactory blogFactory = context.mock(BlogFactory.class);
protected final SharingValidator v = getValidator();
protected final MessageId previousMsgId = new MessageId(getRandomId());
private final BdfDictionary meta =
BdfDictionary.of(new BdfEntry("meta", "data"));
abstract SharingValidator getValidator();
@Test(expected = FormatException.class)
public void testRejectsTooShortBodyForInvitation() throws Exception {
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor));
}
@Test(expected = FormatException.class)
public void testRejectsTooLongBodyForInvitation() throws Exception {
v.validateMessage(message, group,
BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null,
123));
}
@Test
public void testAcceptsAccept() throws Exception {
expectEncodeMetadata(ACCEPT);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(ACCEPT.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsDecline() throws Exception {
expectEncodeMetadata(DECLINE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(DECLINE.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsLeave() throws Exception {
expectEncodeMetadata(LEAVE);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(LEAVE.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsAbort() throws Exception {
expectEncodeMetadata(ABORT);
BdfMessageContext messageContext = v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), groupId, previousMsgId));
assertExpectedContext(messageContext, previousMsgId);
}
@Test(expected = FormatException.class)
public void testRejectsNullMessageType() throws Exception {
v.validateMessage(message, group,
BdfList.of(null, groupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsNonLongMessageType() throws Exception {
v.validateMessage(message, group,
BdfList.of("", groupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsInvalidMessageType() throws Exception {
int invalidMessageType = ABORT.getValue() + 1;
v.validateMessage(message, group,
BdfList.of(invalidMessageType, groupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsNullSessionId() throws Exception {
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), null, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsNonRawSessionId() throws Exception {
v.validateMessage(message, group, BdfList.of(ABORT.getValue(), 123));
}
@Test(expected = FormatException.class)
public void testRejectsTooShortSessionId() throws Exception {
byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH - 1);
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsTooLongSessionId() throws Exception {
byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH + 1);
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId));
}
@Test(expected = FormatException.class)
public void testRejectsTooShortBodyForAbort() throws Exception {
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), groupId));
}
@Test(expected = FormatException.class)
public void testRejectsTooLongBodyForAbort() throws Exception {
v.validateMessage(message, group,
BdfList.of(ABORT.getValue(), groupId, previousMsgId, 123));
}
protected void expectEncodeMetadata(final MessageType type) {
context.checking(new Expectations() {{
oneOf(messageEncoder)
.encodeMetadata(type, groupId, timestamp, false, false,
false, false);
will(returnValue(meta));
}});
}
protected void assertExpectedContext(BdfMessageContext messageContext,
@Nullable MessageId previousMsgId) throws FormatException {
Collection<MessageId> dependencies = messageContext.getDependencies();
if (previousMsgId == null) {
assertTrue(dependencies.isEmpty());
} else {
assertEquals(1, dependencies.size());
assertTrue(dependencies.contains(previousMsgId));
}
assertEquals(meta, messageContext.getDictionary());
}
}