Preliminaries for private group invitation protocol.

This commit is contained in:
akwizgran
2016-11-08 15:44:23 +00:00
parent 32f0b53d15
commit edbf5ff5b4
21 changed files with 179 additions and 84 deletions

View File

@@ -12,6 +12,8 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:gravity="bottom" android:gravity="bottom"
android:maxLines="1"
android:inputType="text|textCapSentences"
android:hint="@string/groups_create_group_hint"/> android:hint="@string/groups_create_group_hint"/>
<Button <Button

View File

@@ -181,7 +181,7 @@
<!-- Private Group Invitations --> <!-- Private Group Invitations -->
<string name="groups_invitations_title">Group Invitations</string> <string name="groups_invitations_title">Group Invitations</string>
<string name="groups_invitations_invitation_sent">You have invited %1$s to your group "%2$s".</string> <string name="groups_invitations_invitation_sent">You have invited %1$s to join the group "%2$s".</string>
<string name="groups_invitations_invitation_received">%1$s has invited you to join the group "%2$s".</string> <string name="groups_invitations_invitation_received">%1$s has invited you to join the group "%2$s".</string>
<string name="groups_invitations_joined">Joined group</string> <string name="groups_invitations_joined">Joined group</string>
<string name="groups_invitations_declined">Group invitation declined</string> <string name="groups_invitations_declined">Group invitation declined</string>
@@ -191,8 +191,8 @@
</plurals> </plurals>
<string name="groups_invitations_response_accepted_sent">You accepted the group invitation from %s.</string> <string name="groups_invitations_response_accepted_sent">You accepted the group invitation from %s.</string>
<string name="groups_invitations_response_declined_sent">You declined the group invitation from %s.</string> <string name="groups_invitations_response_declined_sent">You declined the group invitation from %s.</string>
<string name="groups_invitations_response_accepted_received">%s accepted your group invitation.</string> <string name="groups_invitations_response_accepted_received">%s accepted the group invitation.</string>
<string name="groups_invitations_response_declined_received">%s declined your group invitation.</string> <string name="groups_invitations_response_declined_received">%s declined the group invitation.</string>
<!-- Forums --> <!-- Forums -->
<string name="no_forums">You don\'t have any forums yet.\n\nWhy don\'t you create a new one yourself by tapping the + icon at the top?\n\nYou can also ask your contacts to share forums with you.</string> <string name="no_forums">You don\'t have any forums yet.\n\nWhy don\'t you create a new one yourself by tapping the + icon at the top?\n\nYou can also ask your contacts to share forums with you.</string>

View File

@@ -80,9 +80,13 @@ public interface ActivityComponent {
void inject(BlogInvitationActivity activity); void inject(BlogInvitationActivity activity);
void inject(CreateGroupActivity activity); void inject(CreateGroupActivity activity);
void inject(GroupActivity activity); void inject(GroupActivity activity);
void inject(GroupInviteActivity activity); void inject(GroupInviteActivity activity);
void inject(GroupInvitationActivity activity); void inject(GroupInvitationActivity activity);
void inject(GroupMemberListActivity activity); void inject(GroupMemberListActivity activity);
void inject(CreateForumActivity activity); void inject(CreateForumActivity activity);
@@ -104,9 +108,11 @@ public interface ActivityComponent {
void inject(BlogFragment fragment); void inject(BlogFragment fragment);
void inject(BlogPostFragment fragment); void inject(BlogPostFragment fragment);
void inject(FeedPostFragment fragment); void inject(FeedPostFragment fragment);
void inject(BlogPostPagerFragment fragment); void inject(BlogPostPagerFragment fragment);
void inject(FeedPostPagerFragment fragment); void inject(FeedPostPagerFragment fragment);
void inject(ReblogFragment fragment); void inject(ReblogFragment fragment);
@@ -124,21 +130,34 @@ public interface ActivityComponent {
void inject(RssFeedManageActivity activity); void inject(RssFeedManageActivity activity);
void inject(EmojiProvider emojiProvider); void inject(EmojiProvider emojiProvider);
void inject(RecentEmojiPageModel recentEmojiPageModel); void inject(RecentEmojiPageModel recentEmojiPageModel);
// Fragments // Fragments
void inject(ContactListFragment fragment); void inject(ContactListFragment fragment);
void inject(CreateGroupFragment fragment); void inject(CreateGroupFragment fragment);
void inject(CreateGroupMessageFragment fragment); void inject(CreateGroupMessageFragment fragment);
void inject(GroupListFragment fragment); void inject(GroupListFragment fragment);
void inject(ForumListFragment fragment); void inject(ForumListFragment fragment);
void inject(FeedFragment fragment); void inject(FeedFragment fragment);
void inject(IntroFragment fragment); void inject(IntroFragment fragment);
void inject(ShowQrCodeFragment fragment); void inject(ShowQrCodeFragment fragment);
void inject(ContactChooserFragment fragment); void inject(ContactChooserFragment fragment);
void inject(ContactSelectorFragment fragment); void inject(ContactSelectorFragment fragment);
void inject(ShareForumMessageFragment fragment); void inject(ShareForumMessageFragment fragment);
void inject(ShareBlogMessageFragment fragment); void inject(ShareBlogMessageFragment fragment);
void inject(IntroductionMessageFragment fragment); void inject(IntroductionMessageFragment fragment);
} }

View File

@@ -1,25 +1,28 @@
package org.briarproject.api.clients; package org.briarproject.api.clients;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.sync.BaseMessageContext; import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
public class BdfMessageContext extends BaseMessageContext { import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class BdfMessageContext {
private final BdfDictionary dictionary; private final BdfDictionary dictionary;
private final Collection<MessageId> dependencies;
public BdfMessageContext(@NotNull BdfDictionary dictionary, public BdfMessageContext(BdfDictionary dictionary,
@NotNull Collection<MessageId> dependencies) { Collection<MessageId> dependencies) {
super(dependencies);
this.dictionary = dictionary; this.dictionary = dictionary;
this.dependencies = dependencies;
} }
public BdfMessageContext(@NotNull BdfDictionary dictionary) { public BdfMessageContext(BdfDictionary dictionary) {
this(dictionary, Collections.<MessageId>emptyList()); this(dictionary, Collections.<MessageId>emptyList());
} }
@@ -27,4 +30,7 @@ public class BdfMessageContext extends BaseMessageContext {
return dictionary; return dictionary;
} }
public Collection<MessageId> getDependencies() {
return dependencies;
}
} }

View File

@@ -5,14 +5,17 @@ import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.InvalidMessageException;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable;
@NotNullByDefault
public interface ClientHelper { public interface ClientHelper {
void addLocalMessage(Message m, BdfDictionary metadata, boolean shared) void addLocalMessage(Message m, BdfDictionary metadata, boolean shared)
@@ -21,14 +24,21 @@ public interface ClientHelper {
void addLocalMessage(Transaction txn, Message m, BdfDictionary metadata, void addLocalMessage(Transaction txn, Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException; boolean shared) throws DbException, FormatException;
Message createMessage(GroupId g, long timestamp, BdfDictionary body)
throws FormatException;
Message createMessage(GroupId g, long timestamp, BdfList body) Message createMessage(GroupId g, long timestamp, BdfList body)
throws FormatException; throws FormatException;
Message createMessageForStoringMetadata(GroupId g);
@Nullable
Message getMessage(MessageId m) throws DbException;
@Nullable
Message getMessage(Transaction txn, MessageId m) throws DbException;
@Nullable
BdfList getMessageAsList(MessageId m) throws DbException, FormatException; BdfList getMessageAsList(MessageId m) throws DbException, FormatException;
@Nullable
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException, BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException; FormatException;
@@ -80,6 +90,8 @@ public interface ClientHelper {
BdfList toList(byte[] b) throws FormatException; BdfList toList(byte[] b) throws FormatException;
BdfList toList(Message m) throws FormatException;
byte[] sign(BdfList toSign, byte[] privateKey) byte[] sign(BdfList toSign, byte[] privateKey)
throws FormatException, GeneralSecurityException; throws FormatException, GeneralSecurityException;

View File

@@ -2,7 +2,6 @@ package org.briarproject.api.clients;
import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.jetbrains.annotations.NotNull;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -13,7 +12,7 @@ public abstract class NamedGroup extends BaseGroup {
private final String name; private final String name;
private final byte[] salt; private final byte[] salt;
public NamedGroup(@NotNull Group group, @NotNull String name, byte[] salt) { public NamedGroup(Group group, String name, byte[] salt) {
super(group); super(group);
this.name = name; this.name = name;
this.salt = salt; this.salt = salt;

View File

@@ -6,6 +6,8 @@ import org.briarproject.api.FormatException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.ConcurrentSkipListMap;
import javax.annotation.Nullable;
public class BdfDictionary extends ConcurrentSkipListMap<String, Object> { public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
public static final Object NULL_VALUE = new Object(); public static final Object NULL_VALUE = new Object();
@@ -39,6 +41,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Boolean getOptionalBoolean(String key) throws FormatException { public Boolean getOptionalBoolean(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -61,6 +64,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Long getOptionalLong(String key) throws FormatException { public Long getOptionalLong(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -87,6 +91,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Double getOptionalDouble(String key) throws FormatException { public Double getOptionalDouble(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -108,6 +113,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public String getOptionalString(String key) throws FormatException { public String getOptionalString(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -128,6 +134,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public byte[] getOptionalRaw(String key) throws FormatException { public byte[] getOptionalRaw(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -149,6 +156,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfList getOptionalList(String key) throws FormatException { public BdfList getOptionalList(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -168,6 +176,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfDictionary getOptionalDictionary(String key) public BdfDictionary getOptionalDictionary(String key)
throws FormatException { throws FormatException {
Object o = get(key); Object o = get(key);

View File

@@ -2,6 +2,7 @@ package org.briarproject.api.data;
import org.briarproject.api.Bytes; import org.briarproject.api.Bytes;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -40,6 +41,7 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Boolean getOptionalBoolean(int index) throws FormatException { public Boolean getOptionalBoolean(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
@@ -65,6 +67,7 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Long getOptionalLong(int index) throws FormatException { public Long getOptionalLong(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
@@ -94,6 +97,7 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Double getOptionalDouble(int index) throws FormatException { public Double getOptionalDouble(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
@@ -118,6 +122,7 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public String getOptionalString(int index) throws FormatException { public String getOptionalString(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
@@ -141,6 +146,7 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public byte[] getOptionalRaw(int index) throws FormatException { public byte[] getOptionalRaw(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
@@ -165,6 +171,7 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfList getOptionalList(int index) throws FormatException { public BdfList getOptionalList(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
@@ -187,6 +194,7 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfDictionary getOptionalDictionary(int index) public BdfDictionary getOptionalDictionary(int index)
throws FormatException { throws FormatException {
if (!isInRange(index)) throw new FormatException(); if (!isInRange(index)) throw new FormatException();

View File

@@ -6,13 +6,12 @@ import org.briarproject.api.sharing.InvitationResponse;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ForumInvitationResponse extends InvitationResponse { public class ForumInvitationResponse extends InvitationResponse {
public ForumInvitationResponse(@NotNull MessageId id, SessionId sessionId, public ForumInvitationResponse(@NotNull MessageId id, SessionId sessionId,
GroupId groupId, ContactId contactId, boolean accept, long time, boolean local, GroupId groupId, ContactId contactId, boolean accept, long time,
boolean sent, boolean seen, boolean read) { boolean local, boolean sent, boolean seen, boolean read) {
super(id, sessionId, groupId, contactId, accept, time, local, sent, super(id, sessionId, groupId, contactId, accept, time, local, sent,
seen, read); seen, read);

View File

@@ -3,10 +3,12 @@ package org.briarproject.api.privategroup;
import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@NotNullByDefault
public interface GroupMessageFactory { public interface GroupMessageFactory {
/** /**

View File

@@ -5,7 +5,6 @@ import org.briarproject.api.identity.Author;
import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sharing.Shareable; import org.briarproject.api.sharing.Shareable;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.jetbrains.annotations.NotNull;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -15,8 +14,7 @@ public class PrivateGroup extends NamedGroup implements Shareable {
private final Author author; private final Author author;
public PrivateGroup(@NotNull Group group, @NotNull String name, public PrivateGroup(Group group, String name, Author author, byte[] salt) {
@NotNull Author author, @NotNull byte[] salt) {
super(group, name, salt); super(group, name, salt);
this.author = author; this.author = author;
} }

View File

@@ -2,21 +2,20 @@ package org.briarproject.api.privategroup;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.jetbrains.annotations.NotNull;
@NotNullByDefault
public interface PrivateGroupFactory { public interface PrivateGroupFactory {
/** /**
* Creates a private group with the given name and author. * Creates a private group with the given name and author.
*/ */
@NotNull
PrivateGroup createPrivateGroup(String name, Author author); PrivateGroup createPrivateGroup(String name, Author author);
/** /**
* Creates a private group with the given name, author and salt. * Creates a private group with the given name, author and salt.
*/ */
@NotNull
PrivateGroup createPrivateGroup(String name, Author author, byte[] salt); PrivateGroup createPrivateGroup(String name, Author author, byte[] salt);
/** /**

View File

@@ -1,19 +0,0 @@
package org.briarproject.api.sync;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public abstract class BaseMessageContext {
private final Collection<MessageId> dependencies;
public BaseMessageContext(@NotNull Collection<MessageId> dependencies) {
this.dependencies = dependencies;
}
public Collection<MessageId> getDependencies() {
return dependencies;
}
}

View File

@@ -1,23 +1,27 @@
package org.briarproject.api.sync; package org.briarproject.api.sync;
import org.briarproject.api.db.Metadata; import org.briarproject.api.db.Metadata;
import org.jetbrains.annotations.NotNull; import org.briarproject.api.nullsafety.NotNullByDefault;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
public class MessageContext extends BaseMessageContext { import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class MessageContext {
private final Metadata metadata; private final Metadata metadata;
private final Collection<MessageId> dependencies;
public MessageContext(@NotNull Metadata metadata, public MessageContext(Metadata metadata,
@NotNull Collection<MessageId> dependencies) { Collection<MessageId> dependencies) {
super(dependencies);
this.metadata = metadata; this.metadata = metadata;
this.dependencies = dependencies;
} }
public MessageContext(@NotNull Metadata metadata) { public MessageContext(Metadata metadata) {
this(metadata, Collections.<MessageId>emptyList()); this(metadata, Collections.<MessageId>emptyList());
} }
@@ -25,4 +29,7 @@ public class MessageContext extends BaseMessageContext {
return metadata; return metadata;
} }
public Collection<MessageId> getDependencies() {
return dependencies;
}
} }

View File

@@ -2,5 +2,7 @@ package org.briarproject.api.sync;
public interface MessageFactory { public interface MessageFactory {
Message createMessage(GroupId groupId, long timestamp, byte[] body); Message createMessage(GroupId g, long timestamp, byte[] body);
Message createMessage(MessageId m, byte[] raw);
} }

View File

@@ -1,10 +1,10 @@
package org.briarproject.clients; package org.briarproject.clients;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.clients.BdfMessageContext;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager.QueueMessageValidator; import org.briarproject.api.clients.MessageQueueManager.QueueMessageValidator;
import org.briarproject.api.clients.QueueMessage; import org.briarproject.api.clients.QueueMessage;
import org.briarproject.api.clients.BdfMessageContext;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.data.MetadataEncoder;
@@ -12,13 +12,15 @@ import org.briarproject.api.db.Metadata;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.InvalidMessageException; import org.briarproject.api.sync.InvalidMessageException;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.ValidationManager.MessageValidator;
import org.briarproject.api.sync.MessageContext; import org.briarproject.api.sync.MessageContext;
import org.briarproject.api.sync.ValidationManager.MessageValidator;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable;
import static org.briarproject.api.clients.QueueMessage.QUEUE_MESSAGE_HEADER_LENGTH; import static org.briarproject.api.clients.QueueMessage.QUEUE_MESSAGE_HEADER_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
@@ -78,7 +80,7 @@ public abstract class BdfMessageValidator implements MessageValidator,
} }
} }
protected void checkLength(String s, int minLength, int maxLength) protected void checkLength(@Nullable String s, int minLength, int maxLength)
throws FormatException { throws FormatException {
if (s != null) { if (s != null) {
int length = StringUtils.toUtf8(s).length; int length = StringUtils.toUtf8(s).length;
@@ -87,12 +89,13 @@ public abstract class BdfMessageValidator implements MessageValidator,
} }
} }
protected void checkLength(String s, int length) throws FormatException { protected void checkLength(@Nullable String s, int length)
throws FormatException {
if (s != null && StringUtils.toUtf8(s).length != length) if (s != null && StringUtils.toUtf8(s).length != length)
throw new FormatException(); throw new FormatException();
} }
protected void checkLength(byte[] b, int minLength, int maxLength) protected void checkLength(@Nullable byte[] b, int minLength, int maxLength)
throws FormatException { throws FormatException {
if (b != null) { if (b != null) {
if (b.length < minLength) throw new FormatException(); if (b.length < minLength) throw new FormatException();
@@ -100,7 +103,8 @@ public abstract class BdfMessageValidator implements MessageValidator,
} }
} }
protected void checkLength(byte[] b, int length) throws FormatException { protected void checkLength(@Nullable byte[] b, int length)
throws FormatException {
if (b != null && b.length != length) throw new FormatException(); if (b != null && b.length != length) throw new FormatException();
} }
@@ -112,11 +116,12 @@ public abstract class BdfMessageValidator implements MessageValidator,
} }
} }
protected void checkSize(BdfList list, int size) throws FormatException { protected void checkSize(@Nullable BdfList list, int size)
throws FormatException {
if (list != null && list.size() != size) throw new FormatException(); if (list != null && list.size() != size) throw new FormatException();
} }
protected void checkSize(BdfDictionary dictionary, int minSize, protected void checkSize(@Nullable BdfDictionary dictionary, int minSize,
int maxSize) throws FormatException { int maxSize) throws FormatException {
if (dictionary != null) { if (dictionary != null) {
if (dictionary.size() < minSize) throw new FormatException(); if (dictionary.size() < minSize) throw new FormatException();
@@ -124,7 +129,7 @@ public abstract class BdfMessageValidator implements MessageValidator,
} }
} }
protected void checkSize(BdfDictionary dictionary, int size) protected void checkSize(@Nullable BdfDictionary dictionary, int size)
throws FormatException { throws FormatException {
if (dictionary != null && dictionary.size() != size) if (dictionary != null && dictionary.size() != size)
throw new FormatException(); throw new FormatException();

View File

@@ -19,6 +19,7 @@ import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata; import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory; import org.briarproject.api.sync.MessageFactory;
@@ -37,28 +38,35 @@ import javax.inject.Inject;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
@NotNullByDefault
class ClientHelperImpl implements ClientHelper { class ClientHelperImpl implements ClientHelper {
/**
* Length in bytes of the random salt used for creating local messages for
* storing metadata.
*/
private static final int SALT_LENGTH = 32;
private final DatabaseComponent db; private final DatabaseComponent db;
private final MessageFactory messageFactory; private final MessageFactory messageFactory;
private final BdfReaderFactory bdfReaderFactory; private final BdfReaderFactory bdfReaderFactory;
private final BdfWriterFactory bdfWriterFactory; private final BdfWriterFactory bdfWriterFactory;
private final MetadataParser metadataParser; private final MetadataParser metadataParser;
private final MetadataEncoder metadataEncoder; private final MetadataEncoder metadataEncoder;
private final CryptoComponent cryptoComponent; private final CryptoComponent crypto;
@Inject @Inject
ClientHelperImpl(DatabaseComponent db, MessageFactory messageFactory, ClientHelperImpl(DatabaseComponent db, MessageFactory messageFactory,
BdfReaderFactory bdfReaderFactory, BdfReaderFactory bdfReaderFactory,
BdfWriterFactory bdfWriterFactory, MetadataParser metadataParser, BdfWriterFactory bdfWriterFactory, MetadataParser metadataParser,
MetadataEncoder metadataEncoder, CryptoComponent cryptoComponent) { MetadataEncoder metadataEncoder, CryptoComponent crypto) {
this.db = db; this.db = db;
this.messageFactory = messageFactory; this.messageFactory = messageFactory;
this.bdfReaderFactory = bdfReaderFactory; this.bdfReaderFactory = bdfReaderFactory;
this.bdfWriterFactory = bdfWriterFactory; this.bdfWriterFactory = bdfWriterFactory;
this.metadataParser = metadataParser; this.metadataParser = metadataParser;
this.metadataEncoder = metadataEncoder; this.metadataEncoder = metadataEncoder;
this.cryptoComponent = cryptoComponent; this.crypto = crypto;
} }
@Override @Override
@@ -81,15 +89,36 @@ class ClientHelperImpl implements ClientHelper {
} }
@Override @Override
public Message createMessage(GroupId g, long timestamp, BdfDictionary body) public Message createMessage(GroupId g, long timestamp, BdfList body)
throws FormatException { throws FormatException {
return messageFactory.createMessage(g, timestamp, toByteArray(body)); return messageFactory.createMessage(g, timestamp, toByteArray(body));
} }
@Override @Override
public Message createMessage(GroupId g, long timestamp, BdfList body) public Message createMessageForStoringMetadata(GroupId g) {
throws FormatException { byte[] salt = new byte[SALT_LENGTH];
return messageFactory.createMessage(g, timestamp, toByteArray(body)); crypto.getSecureRandom().nextBytes(salt);
return messageFactory.createMessage(g, 0, salt);
}
@Override
public Message getMessage(MessageId m) throws DbException {
Message message;
Transaction txn = db.startTransaction(true);
try {
message = getMessage(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return message;
}
@Override
public Message getMessage(Transaction txn, MessageId m) throws DbException {
byte[] raw = db.getRawMessage(txn, m);
if (raw == null) return null;
return messageFactory.createMessage(m, raw);
} }
@Override @Override
@@ -310,13 +339,19 @@ class ClientHelperImpl implements ClientHelper {
return toList(b, 0, b.length); return toList(b, 0, b.length);
} }
@Override
public BdfList toList(Message m) throws FormatException {
byte[] raw = m.getRaw();
return toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
}
@Override @Override
public byte[] sign(BdfList toSign, byte[] privateKey) public byte[] sign(BdfList toSign, byte[] privateKey)
throws FormatException, GeneralSecurityException { throws FormatException, GeneralSecurityException {
Signature signature = cryptoComponent.getSignature(); Signature signature = crypto.getSignature();
KeyParser keyParser = cryptoComponent.getSignatureKeyParser(); KeyParser keyParser = crypto.getSignatureKeyParser();
PrivateKey key = PrivateKey key = keyParser.parsePrivateKey(privateKey);
keyParser.parsePrivateKey(privateKey);
signature.initSign(key); signature.initSign(key);
signature.update(toByteArray(toSign)); signature.update(toByteArray(toSign));
return signature.sign(); return signature.sign();
@@ -326,10 +361,10 @@ class ClientHelperImpl implements ClientHelper {
public void verifySignature(byte[] sig, byte[] publicKey, BdfList signed) public void verifySignature(byte[] sig, byte[] publicKey, BdfList signed)
throws FormatException, GeneralSecurityException { throws FormatException, GeneralSecurityException {
// Parse the public key // Parse the public key
KeyParser keyParser = cryptoComponent.getSignatureKeyParser(); KeyParser keyParser = crypto.getSignatureKeyParser();
PublicKey key = keyParser.parsePublicKey(publicKey); PublicKey key = keyParser.parsePublicKey(publicKey);
// Verify the signature // Verify the signature
Signature signature = cryptoComponent.getSignature(); Signature signature = crypto.getSignature();
signature.initVerify(key); signature.initVerify(key);
signature.update(toByteArray(signed)); signature.update(toByteArray(signed));
if (!signature.verify(sig)) { if (!signature.verify(sig)) {

View File

@@ -1,8 +1,8 @@
package org.briarproject.clients; package org.briarproject.clients;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.ContactGroupFactory; import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.QueueMessageFactory; import org.briarproject.api.clients.QueueMessageFactory;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.data.BdfReaderFactory; import org.briarproject.api.data.BdfReaderFactory;
@@ -33,7 +33,7 @@ public class ClientsModule {
} }
@Provides @Provides
ContactGroupFactory providePrivateGroupFactory(GroupFactory groupFactory, ContactGroupFactory provideContactGroupFactory(GroupFactory groupFactory,
ClientHelper clientHelper) { ClientHelper clientHelper) {
return new ContactGroupFactoryImpl(groupFactory, clientHelper); return new ContactGroupFactoryImpl(groupFactory, clientHelper);
} }

View File

@@ -5,20 +5,23 @@ import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroup;
import org.briarproject.api.privategroup.PrivateGroupFactory; import org.briarproject.api.privategroup.PrivateGroupFactory;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.security.SecureRandom; import java.security.SecureRandom;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
@Immutable
@NotNullByDefault
class PrivateGroupFactoryImpl implements PrivateGroupFactory { class PrivateGroupFactoryImpl implements PrivateGroupFactory {
private final GroupFactory groupFactory; private final GroupFactory groupFactory;
@@ -37,7 +40,6 @@ class PrivateGroupFactoryImpl implements PrivateGroupFactory {
this.random = random; this.random = random;
} }
@NotNull
@Override @Override
public PrivateGroup createPrivateGroup(String name, Author author) { public PrivateGroup createPrivateGroup(String name, Author author) {
int length = StringUtils.toUtf8(name).length; int length = StringUtils.toUtf8(name).length;
@@ -50,7 +52,6 @@ class PrivateGroupFactoryImpl implements PrivateGroupFactory {
return createPrivateGroup(name, author, salt); return createPrivateGroup(name, author, salt);
} }
@NotNull
@Override @Override
public PrivateGroup createPrivateGroup(String name, Author author, public PrivateGroup createPrivateGroup(String name, Author author,
byte[] salt) { byte[] salt) {

View File

@@ -24,14 +24,24 @@ class MessageFactoryImpl implements MessageFactory {
} }
@Override @Override
public Message createMessage(GroupId groupId, long timestamp, byte[] body) { public Message createMessage(GroupId g, long timestamp, byte[] body) {
if (body.length > MAX_MESSAGE_BODY_LENGTH) if (body.length > MAX_MESSAGE_BODY_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length]; byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
System.arraycopy(groupId.getBytes(), 0, raw, 0, UniqueId.LENGTH); System.arraycopy(g.getBytes(), 0, raw, 0, UniqueId.LENGTH);
ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH); ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length); System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
MessageId id = new MessageId(crypto.hash(MessageId.LABEL, raw)); MessageId id = new MessageId(crypto.hash(MessageId.LABEL, raw));
return new Message(id, groupId, timestamp, raw); return new Message(id, g, timestamp, raw);
}
@Override
public Message createMessage(MessageId m, byte[] raw) {
if (raw.length < MESSAGE_HEADER_LENGTH)
throw new IllegalArgumentException();
byte[] groupId = new byte[UniqueId.LENGTH];
System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH);
long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH);
return new Message(m, new GroupId(groupId), timestamp, raw);
} }
} }

View File

@@ -274,7 +274,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
MessageContext context = v.validateMessage(m, g); MessageContext context = v.validateMessage(m, g);
storeMessageContextAsync(m, g.getClientId(), context); storeMessageContextAsync(m, g.getClientId(), context);
} catch (InvalidMessageException e) { } catch (InvalidMessageException e) {
if (LOG.isLoggable(INFO)) LOG.info(e.toString()); if (LOG.isLoggable(INFO))
LOG.log(INFO, e.toString(), e);
Queue<MessageId> invalidate = new LinkedList<MessageId>(); Queue<MessageId> invalidate = new LinkedList<MessageId>();
invalidate.add(m.getId()); invalidate.add(m.getId());
invalidateNextMessageAsync(invalidate); invalidateNextMessageAsync(invalidate);