From c8e747285ca553c197f80bcc3604b576133a0e04 Mon Sep 17 00:00:00 2001 From: Vladimir Eliezer Tokarev Date: Fri, 26 Feb 2016 04:54:39 -0800 Subject: [PATCH] Added the verefication process to the receiving of messages from voter registry --- bulletin-board-server/meerkat | Bin 23552 -> 81920 bytes .../main/java/meerkat/MessageValidator.java | 21 ++++ .../meerkat/Registry/BooleanCallBack.java | 22 +++- .../Registry/CollectionMessagesUtils.java | 29 +++-- .../Registry/RelevantDataCallBack.java | 103 ++++++++++++++---- .../src/main/java/meerkat/SimpleRegistry.java | 32 +++--- .../src/main/java/meerkat/VoterRegistry.java | 1 - .../java/meerkat/VoterRegistryMessage.java | 29 +++-- .../src/test/java/SimpleRegistryTest.java | 64 ++++++----- 9 files changed, 212 insertions(+), 89 deletions(-) create mode 100644 voter-registry/src/main/java/meerkat/MessageValidator.java diff --git a/bulletin-board-server/meerkat b/bulletin-board-server/meerkat index 9709e188fa91b9f4c25f0843276851b6109a34b8..1b73e91920474f1344df3b9508598f00b8544959 100644 GIT binary patch literal 81920 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 SLo5jD#Denp0&|7OYvEre$s0}p diff --git a/voter-registry/src/main/java/meerkat/MessageValidator.java b/voter-registry/src/main/java/meerkat/MessageValidator.java new file mode 100644 index 0000000..5d99279 --- /dev/null +++ b/voter-registry/src/main/java/meerkat/MessageValidator.java @@ -0,0 +1,21 @@ +package meerkat; + +/** + * Provides the validation option for objects + * @param + */ +public interface MessageValidator +{ + /** + * Throws ValidationError when no part of the object is valid else return the valid part + * @param object object which will be checked + * @return T object + */ + T validate(T object) throws ValidationError ; + + class ValidationError extends Exception { + public ValidationError(String message) { + super(message); + } + } +} diff --git a/voter-registry/src/main/java/meerkat/Registry/BooleanCallBack.java b/voter-registry/src/main/java/meerkat/Registry/BooleanCallBack.java index dbf6239..680a652 100644 --- a/voter-registry/src/main/java/meerkat/Registry/BooleanCallBack.java +++ b/voter-registry/src/main/java/meerkat/Registry/BooleanCallBack.java @@ -1,13 +1,18 @@ package meerkat.Registry; +import meerkat.MessageValidator; import meerkat.VoterRegistry; -import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.BulletinBoardClient.ClientCallback; + +/** + * TODO: add logging + */ /** * Created by Vladimir Eliezer Tokarev on 2/19/2016. * Handles the the after post state of VoterRegistry methods (that uses bulletinBoardClient to communicate with the server) */ -public class BooleanCallBack implements BulletinBoardClient.ClientCallback { +public class BooleanCallBack implements ClientCallback, MessageValidator { public VoterRegistry.RegistryCallBack callback; /** @@ -23,7 +28,7 @@ public class BooleanCallBack implements BulletinBoardClient.ClientCallback { * @param msg the message that the bulletinBoardClient passes to the callback */ @Override - public void handleCallback(Object msg) { + public void handleCallback(Boolean msg) { callback.HandleResult(msg); } @@ -35,4 +40,15 @@ public class BooleanCallBack implements BulletinBoardClient.ClientCallback { public void handleFailure(Throwable t) { callback.HandleResult(false); } + + /** + * always return true because there no need to check boolean + * @param object object which will be checked + * @return + * @throws ValidationError + */ + @Override + public Boolean validate(Boolean object) throws ValidationError { + return true; + } } diff --git a/voter-registry/src/main/java/meerkat/Registry/CollectionMessagesUtils.java b/voter-registry/src/main/java/meerkat/Registry/CollectionMessagesUtils.java index 2904050..c52f071 100644 --- a/voter-registry/src/main/java/meerkat/Registry/CollectionMessagesUtils.java +++ b/voter-registry/src/main/java/meerkat/Registry/CollectionMessagesUtils.java @@ -1,7 +1,10 @@ package meerkat.Registry; import meerkat.VoterRegistryMessage; -import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.FilterType; +import meerkat.protobuf.BulletinBoardAPI.MessageFilter; +import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; import java.text.ParseException; import java.util.ArrayList; @@ -10,7 +13,9 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; - +/** + * TODO: add logging to this utils + */ /** * Created by Vladimir Eliezer Tokarev on 1/15/2016. @@ -30,7 +35,7 @@ public abstract class CollectionMessagesUtils { * @return List */ public static List ConvertToVoterRegistryMessages( - List messages){ + List messages){ return messages.stream().map(VoterRegistryMessage::new).collect(Collectors.toList()); } @@ -44,7 +49,8 @@ public abstract class CollectionMessagesUtils { Map groupIdToMessage = new HashMap<>(); // iterate trough all the messages and put into the map the last updated groups actions - for (VoterRegistryMessage message : messages) { + for (int i = 0 ; i < messages.size() ; i++) { + VoterRegistryMessage message = messages.get(i); String groupId = message.GetWantedTagFromBasicMessage(RegistryTags.GROUP_ID_TAG.toString()); VoterRegistryMessage temp = groupIdToMessage.get(groupId); @@ -86,7 +92,8 @@ public abstract class CollectionMessagesUtils { } VoterRegistryMessage LatestMessage = messages.get(0); - for (VoterRegistryMessage message : messages) { + for (int i = 0 ; i < messages.size() ; i++) { + VoterRegistryMessage message = messages.get(i); if (message.GetBasicMessageActionTimestamp().before(LatestMessage.GetBasicMessageActionTimestamp())) { LatestMessage = message; } @@ -100,18 +107,16 @@ public abstract class CollectionMessagesUtils { * @param tags the tags based on which the messages will be filtered * @return MessageFilterList. */ - public static BulletinBoardAPI.MessageFilterList GetRelevantMessagesFilters(List tags) { - BulletinBoardAPI.MessageFilterList.Builder filters = BulletinBoardAPI.MessageFilterList.newBuilder(); + public static MessageFilterList GenerateFiltersFromTags(List tags) { + MessageFilterList.Builder filters = MessageFilterList.newBuilder(); if (tags.isEmpty()){ return filters.build(); } - for (String tag : tags) { - BulletinBoardAPI.MessageFilter.Builder filter = - BulletinBoardAPI.MessageFilter.newBuilder().setTag(tag) - .setType(BulletinBoardAPI.FilterType.TAG); - + for (int i = 0 ;i < tags.size() ; i++) { + String tag = tags.get(i); + MessageFilter.Builder filter = MessageFilter.newBuilder().setTag(tag).setType(FilterType.TAG); filters.addFilter(filter); } return filters.build(); diff --git a/voter-registry/src/main/java/meerkat/Registry/RelevantDataCallBack.java b/voter-registry/src/main/java/meerkat/Registry/RelevantDataCallBack.java index 6442b27..c6cff8f 100644 --- a/voter-registry/src/main/java/meerkat/Registry/RelevantDataCallBack.java +++ b/voter-registry/src/main/java/meerkat/Registry/RelevantDataCallBack.java @@ -1,29 +1,54 @@ package meerkat.Registry; -import meerkat.VoterRegistry; +import meerkat.MessageValidator; +import meerkat.VoterRegistry.RegistryCallBack; import meerkat.VoterRegistryMessage; -import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.BulletinBoardClient.ClientCallback; +import meerkat.crypto.DigitalSignature; import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.Crypto; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.SignatureException; +import java.security.cert.CertificateException; import java.text.ParseException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import static meerkat.Registry.CollectionMessagesUtils.*; +/** + * TODO : add logging + */ + /** * Created by Vladimir Eliezer Tokarev on 2/19/2016. * Object that handles the GetGroups or the GetPersonIDDetails of the simpleRegistry */ -public class RelevantDataCallBack implements BulletinBoardClient.ClientCallback> { - public VoterRegistry.RegistryCallBack callback; +public class RelevantDataCallBack implements ClientCallback>, MessageValidator> { + public RegistryCallBack callback; + protected DigitalSignature validator; + protected Crypto.Signature signature; + protected InputStream certificateStream; + /** * Init BooleanCallBack * @param callback voter registry callback object + * @param validator DigitalSignature object + * @param signature Crypto.Signature object */ - public RelevantDataCallBack(VoterRegistry.RegistryCallBack callback) { + public RelevantDataCallBack(RegistryCallBack callback, + DigitalSignature validator, + Crypto.Signature signature, + InputStream certificateStream) { this.callback = callback; + this.validator = validator; + this.signature = signature; + this.certificateStream = certificateStream; } /** @@ -31,8 +56,10 @@ public class RelevantDataCallBack implements BulletinBoardClient.ClientCallback< * @param msg List * @return true if the messages are with GROUP_ID_TAG tags */ - private boolean isAddToGroupsList(List msg) { - for (String tag : msg.get(0).getMsg().getTagList()) { + private boolean isAddToGroupsList(List msg) { + List tags = msg.get(0).getMsg().getTagList(); + for (int i = 0 ;i < tags.size(); i++) { + String tag = tags.get(i); if(tag.contains(RegistryTags.GROUP_ID_TAG.toString())) { return true; @@ -49,24 +76,20 @@ public class RelevantDataCallBack implements BulletinBoardClient.ClientCallback< * @param msg List */ @Override - public void handleCallback(List msg) { - List messages = ConvertToVoterRegistryMessages(msg); - - if(isAddToGroupsList(msg)){ - try { + public void handleCallback(List msg) { + try { + List messages = ConvertToVoterRegistryMessages(validate(msg)); + if(isAddToGroupsList(msg)) { Map map = GetLatestGroupsActions(messages); List groupsOfUser = GetListOfGroupIds(map); callback.HandleResult(groupsOfUser); - } catch (ParseException e) { - callback.HandleResult(null); } - } - try { - callback.HandleResult(CollectionMessagesUtils.GetLatestMessage(messages)); - } catch (ParseException e) { - e.printStackTrace(); - } catch (CollectionMessagesUtils.EmptyListException e) { - e.printStackTrace(); + else { + callback.HandleResult(GetLatestMessage(messages)); + } + } catch (ValidationError | ParseException | EmptyListException validationError) { + callback.HandleResult(null); + validationError.printStackTrace(); } } @@ -78,4 +101,42 @@ public class RelevantDataCallBack implements BulletinBoardClient.ClientCallback< public void handleFailure(Throwable t) { callback.HandleResult(null); } + + /** + * verify that the message is valid + * @param message BulletinBoardMessage instance + * @return true if the message is valid else false + */ + private boolean VerifyMessage(BulletinBoardAPI.UnsignedBulletinBoardMessage message) + { + try { + validator.loadVerificationCertificates(certificateStream); + validator.initVerify(signature); + validator.updateContent(message); + return validator.verify(); + } catch (CertificateException | InvalidKeyException | SignatureException e) { + e.printStackTrace(); + return false; + } + } + + /** + * Gets all the valid messages from the list of bulletin board messages + * @param object object which will be checked + * @return List + * @throws ValidationError + */ + @Override + public List validate(List object) throws ValidationError { + List verifiedMessages = new ArrayList<>(); + for (int i = 0 ; i < object.size() ; i++) + { + BulletinBoardMessage message = object.get(i); + if(VerifyMessage(message.getMsg())) + { + verifiedMessages.add(message); + } + } + return verifiedMessages; + } } diff --git a/voter-registry/src/main/java/meerkat/SimpleRegistry.java b/voter-registry/src/main/java/meerkat/SimpleRegistry.java index 556fdd6..e04dd66 100644 --- a/voter-registry/src/main/java/meerkat/SimpleRegistry.java +++ b/voter-registry/src/main/java/meerkat/SimpleRegistry.java @@ -7,6 +7,7 @@ import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage; import meerkat.protobuf.Crypto; +import java.io.InputStream; import java.security.SignatureException; import java.util.ArrayList; import java.util.List; @@ -17,12 +18,17 @@ import java.util.List; */ public class SimpleRegistry implements VoterRegistry{ - protected DigitalSignature signatory; + protected DigitalSignature signer; protected BulletinBoardClient bulletinBoardClient ; + protected Crypto.Signature signature; + protected InputStream certificateStream; - public SimpleRegistry(DigitalSignature signatory, BulletinBoardClient communicator) { - this.signatory = signatory; + public SimpleRegistry(DigitalSignature signer, + BulletinBoardClient communicator, + InputStream certificateStream) { + this.signer = signer; this.bulletinBoardClient = communicator; + this.certificateStream = certificateStream; } /** @@ -34,15 +40,11 @@ public class SimpleRegistry implements VoterRegistry{ */ private BulletinBoardMessage CreateBulletinBoardMessage(UnsignedBulletinBoardMessage basicMessage) { try { - BulletinBoardMessage.Builder bulletinBoardMessage = - BulletinBoardMessage.newBuilder(); + BulletinBoardMessage.Builder bulletinBoardMessage = BulletinBoardMessage.newBuilder(); - signatory.updateContent(basicMessage); - - Crypto.Signature signature = signatory.sign(); - bulletinBoardMessage.addSig(signature); - - bulletinBoardMessage.setMsg(basicMessage); + signer.updateContent(basicMessage); + signature = signer.sign(); + bulletinBoardMessage.setMsg(basicMessage).addSig(signature); return bulletinBoardMessage.build(); } catch (SignatureException e) { @@ -98,8 +100,8 @@ public class SimpleRegistry implements VoterRegistry{ List GroupsActionsTags = new ArrayList() {{ add(RegistryTags.GROUP_ID_TAG + groupID.getId()); }}; - bulletinBoardClient.readMessages(CollectionMessagesUtils.GetRelevantMessagesFilters(GroupsActionsTags), - new RelevantDataCallBack(callback)); + bulletinBoardClient.readMessages(CollectionMessagesUtils.GenerateFiltersFromTags(GroupsActionsTags), + new RelevantDataCallBack(callback, signer, signature, certificateStream)); } public void GetPersonIDDetails(RegistryMessages.VoterID voterID, RegistryCallBack callback) { @@ -107,7 +109,7 @@ public class SimpleRegistry implements VoterRegistry{ add(RegistryTags.ID_TAG + voterID.getId()); add(RegistryTags.VOTER_ENTRY_TAG.toString()); }}; - bulletinBoardClient.readMessages(CollectionMessagesUtils.GetRelevantMessagesFilters(GroupsActionsTags), - new RelevantDataCallBack(callback)); + bulletinBoardClient.readMessages(CollectionMessagesUtils.GenerateFiltersFromTags(GroupsActionsTags), + new RelevantDataCallBack(callback, signer, signature, certificateStream)); } } diff --git a/voter-registry/src/main/java/meerkat/VoterRegistry.java b/voter-registry/src/main/java/meerkat/VoterRegistry.java index 32c5dbe..9160d32 100644 --- a/voter-registry/src/main/java/meerkat/VoterRegistry.java +++ b/voter-registry/src/main/java/meerkat/VoterRegistry.java @@ -11,7 +11,6 @@ public interface VoterRegistry { * This interface will handle the end of methods of RegistryInstance */ interface RegistryCallBack { - boolean ActionSucceed = false; void HandleResult(T result); } diff --git a/voter-registry/src/main/java/meerkat/VoterRegistryMessage.java b/voter-registry/src/main/java/meerkat/VoterRegistryMessage.java index 5252159..51910f3 100644 --- a/voter-registry/src/main/java/meerkat/VoterRegistryMessage.java +++ b/voter-registry/src/main/java/meerkat/VoterRegistryMessage.java @@ -1,11 +1,18 @@ package meerkat; -import meerkat.protobuf.BulletinBoardAPI; import meerkat.Registry.AccurateTimestamp; import meerkat.Registry.RegistryTags; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage; import java.sql.Timestamp; import java.text.ParseException; +import java.util.List; + + +/** + * TODO: add logging + */ /** * Created by Vladimir Eliezer Tokarev on 1/15.2016 @@ -13,11 +20,11 @@ import java.text.ParseException; */ public class VoterRegistryMessage { - public BulletinBoardAPI.UnsignedBulletinBoardMessage base; + public UnsignedBulletinBoardMessage base; - public VoterRegistryMessage(BulletinBoardAPI.BulletinBoardMessage message) { - BulletinBoardAPI.UnsignedBulletinBoardMessage.Builder unsignedBase = - BulletinBoardAPI.UnsignedBulletinBoardMessage.newBuilder().addAllTag(message.getMsg().getTagList()); + public VoterRegistryMessage(BulletinBoardMessage message) { + UnsignedBulletinBoardMessage.Builder unsignedBase = + UnsignedBulletinBoardMessage.newBuilder().addAllTag(message.getMsg().getTagList()); unsignedBase.setData(message.getMsg().getData()); base = unsignedBase.build(); } @@ -29,7 +36,9 @@ public class VoterRegistryMessage { * @return string */ public String GetWantedTagFromBasicMessage(String tagName) { - for (String tag : base.getTagList()) { + List tags = base.getTagList(); + for (int i = 0 ; i < tags.size() ; i++) { + String tag = tags.get(i); if (tag.contains(tagName)) { return tag; } @@ -44,7 +53,9 @@ public class VoterRegistryMessage { * @throws ParseException */ public Timestamp GetBasicMessageActionTimestamp() throws ParseException { - for (String tag : base.getTagList()) { + List tags = base.getTagList(); + for (int i = 0 ; i < tags.size() ; i++) { + String tag = tags.get(i); if (tag.contains(RegistryTags.ACTION_TIMESTAMP_TAG.toString())) { String[] tagParts = tag.split(" "); @@ -62,7 +73,9 @@ public class VoterRegistryMessage { * @return true when ADD_TO_GROUP_TAG exist else false */ public boolean IsGroupAdding() { - for (String tag : base.getTagList()) { + List tags = base.getTagList(); + for (int i = 0 ; i < tags.size() ; i++) { + String tag = tags.get(i); if (tag.contains(RegistryTags.ADD_TO_GROUP_TAG.toString())) { return true; } diff --git a/voter-registry/src/test/java/SimpleRegistryTest.java b/voter-registry/src/test/java/SimpleRegistryTest.java index fb1a251..97c5412 100644 --- a/voter-registry/src/test/java/SimpleRegistryTest.java +++ b/voter-registry/src/test/java/SimpleRegistryTest.java @@ -1,5 +1,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import junit.framework.TestCase; +import meerkat.Registry.CollectionMessagesUtils; +import meerkat.Registry.RegistryTags; import meerkat.RegistryMessages; import meerkat.SimpleRegistry; import meerkat.VoterRegistry; @@ -7,10 +9,9 @@ import meerkat.VoterRegistryMessage; import meerkat.bulletinboard.BulletinBoardClient; import meerkat.bulletinboard.ThreadedBulletinBoardClient; import meerkat.crypto.concrete.ECDSASignature; -import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; import meerkat.protobuf.Voting; -import meerkat.Registry.CollectionMessagesUtils; -import meerkat.Registry.RegistryTags; import java.io.InputStream; import java.math.BigInteger; @@ -26,10 +27,9 @@ import static meerkat.Registry.CollectionMessagesUtils.ConvertToVoterRegistryMes * TODO: add logs prints for the tests to be clear what they are */ - /** * Created by Vladimir Eliezer Tokarev on 1/16/2016. - * Tests the Simple meerkat.Registry contents + * Tests the Simple Registry contents * NOTE: for most of this tests to pass there should run BulletinBoardServer * that should be reachable on BULLETIN_BOARD_SERVER_ADDRESS */ @@ -37,8 +37,11 @@ public class SimpleRegistryTest extends TestCase { private ECDSASignature signer; private BulletinBoardClient bulletinBoardClient; + private InputStream certStream; private SecureRandom random = new SecureRandom(); + public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; public static String KEYFILE_PASSWORD = "secret"; Semaphore jobSemaphore; @@ -59,11 +62,11 @@ public class SimpleRegistryTest extends TestCase { } } - public class DummyBulletinBoardCallBackHandler implements BulletinBoardClient.ClientCallback> { - public List messages; + public class DummyBulletinBoardCallBackHandler implements BulletinBoardClient.ClientCallback> { + public List messages; @Override - public void handleCallback(List msg) + public void handleCallback(List msg) { messages = msg; jobSemaphore.release(); @@ -76,10 +79,11 @@ public class SimpleRegistryTest extends TestCase { } } + private void createCertificateStream() + { + this.certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + } - /** - * Creates the communication object (the bulletinBoardClient) - */ private void CommunicatorSetup() { bulletinBoardClient = new ThreadedBulletinBoardClient(); String BULLETIN_BOARD_SERVER_ADDRESS = "http://localhost:8081"; @@ -89,9 +93,6 @@ public class SimpleRegistryTest extends TestCase { .build()); } - /** - * Creates the signer object which is the ECDSASignature - */ private void SetSigner(){ try { signer = new ECDSASignature(); @@ -100,6 +101,7 @@ public class SimpleRegistryTest extends TestCase { KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); signer.loadSigningCertificate(keyStore); + keyStream.close(); } catch (Exception e){ @@ -113,6 +115,7 @@ public class SimpleRegistryTest extends TestCase { public void setUp() { SetSigner(); CommunicatorSetup(); + createCertificateStream(); jobSemaphore = new Semaphore(0); } @@ -121,7 +124,7 @@ public class SimpleRegistryTest extends TestCase { */ public void testSimpleRegistryCreation() { try { - new SimpleRegistry(signer, bulletinBoardClient); + new SimpleRegistry(signer, bulletinBoardClient, certStream); } catch (Exception e) { assert false : "While creating the SimpleRegistry exception have been thrown " + e; } @@ -137,10 +140,12 @@ public class SimpleRegistryTest extends TestCase { { int counter = 0 ; - for (VoterRegistryMessage message :messages) { + for (int i = 0 ; i < messages.size() ; i++) { + VoterRegistryMessage message = messages.get(i); int wantedTagsCounter = 0; - for (String tag : tags) { + for (int j = 0 ;j < tags.size() ; j++) { + String tag = tags.get(j); if(message.GetWantedTagFromBasicMessage(tag)!=null){ wantedTagsCounter++; } @@ -154,7 +159,6 @@ public class SimpleRegistryTest extends TestCase { return counter; } - /** * Test that add voter creates new correct bulletin board message and adds the voter */ @@ -166,14 +170,14 @@ public class SimpleRegistryTest extends TestCase { RegistryMessages.VoterInfo voterInfo = RegistryMessages.VoterInfo.newBuilder(). setId(RegistryMessages.VoterID.newBuilder().setId(id)).setInfo(data).build(); - SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient); + SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient, certStream); registry.AddVoter(voterInfo, handler); jobSemaphore.acquire(); assertEquals(1, handler.counter ); List tags = new ArrayList(){{ add(RegistryTags.VOTER_ENTRY_TAG.toString());}}; - BulletinBoardAPI.MessageFilterList filters = CollectionMessagesUtils.GetRelevantMessagesFilters(tags); + MessageFilterList filters = CollectionMessagesUtils.GenerateFiltersFromTags(tags); DummyBulletinBoardCallBackHandler bulletinHandler = new DummyBulletinBoardCallBackHandler(); bulletinBoardClient.readMessages(filters, bulletinHandler); @@ -194,14 +198,14 @@ public class SimpleRegistryTest extends TestCase { String id = new BigInteger(130, random).toString(32); RegistryMessages.VoterID voterInfo = RegistryMessages.VoterID.newBuilder().setId(id).build(); - SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient); + SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient, certStream); registry.SetVoted(voterInfo, handler); jobSemaphore.acquire(); assertEquals(1, handler.counter ); List tags = new ArrayList(){{ add(RegistryTags.VOTE_ACTION_TAG.toString());}}; - BulletinBoardAPI.MessageFilterList filters = CollectionMessagesUtils.GetRelevantMessagesFilters(tags); + MessageFilterList filters = CollectionMessagesUtils.GenerateFiltersFromTags(tags); DummyBulletinBoardCallBackHandler bulletinHandler = new DummyBulletinBoardCallBackHandler(); bulletinBoardClient.readMessages(filters, bulletinHandler); @@ -224,7 +228,7 @@ public class SimpleRegistryTest extends TestCase { .setVoterId(RegistryMessages.VoterID.newBuilder().setId(voterId)) .setGroupId(RegistryMessages.GroupID.newBuilder().setId(groupId)).build(); - SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient); + SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient, certStream); registry.AddToGroup(voterInfo, handler); jobSemaphore.acquire(); @@ -232,7 +236,7 @@ public class SimpleRegistryTest extends TestCase { List tags = new ArrayList(){{ add(RegistryTags.GROUP_ACTION_TAG .toString() + RegistryTags.ADD_TO_GROUP_TAG.toString());}}; - BulletinBoardAPI.MessageFilterList filters = CollectionMessagesUtils.GetRelevantMessagesFilters(tags); + MessageFilterList filters = CollectionMessagesUtils.GenerateFiltersFromTags(tags); DummyBulletinBoardCallBackHandler bulletinHandler = new DummyBulletinBoardCallBackHandler(); bulletinBoardClient.readMessages(filters, bulletinHandler); @@ -249,7 +253,7 @@ public class SimpleRegistryTest extends TestCase { * Test that remove from group creates correct bulletin board message and removes the user from a group */ public void testGetGroups() throws InvalidProtocolBufferException, InterruptedException { - DummyRegistryCallBackHandler> handler = + DummyRegistryCallBackHandler> handler = new DummyRegistryCallBackHandler<>(); String voterId = new BigInteger(130, random).toString(32); @@ -258,7 +262,9 @@ public class SimpleRegistryTest extends TestCase { .setVoterId(RegistryMessages.VoterID.newBuilder().setId(voterId)) .setGroupId(RegistryMessages.GroupID.newBuilder().setId(groupId)).build(); - SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient); + this.certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + + SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient,certStream); registry.AddToGroup(voterInfo, handler); jobSemaphore.acquire(); @@ -267,7 +273,7 @@ public class SimpleRegistryTest extends TestCase { DummyRegistryCallBackHandler> groupsHandler = new DummyRegistryCallBackHandler<>(); registry.GetGroups(RegistryMessages.GroupID.newBuilder().setId(groupId).build(), groupsHandler); - jobSemaphore.acquire(); + jobSemaphore.acquire(1); List userGroups = groupsHandler.data; assert userGroups.contains(RegistryTags.GROUP_ID_TAG + groupId) : "The simple voter registry object does not retrieved right user groups"; @@ -277,7 +283,7 @@ public class SimpleRegistryTest extends TestCase { * Test that the personal data outputted about the user is right */ public void testGetPersonalIDDetails() throws InvalidProtocolBufferException, InterruptedException { - DummyRegistryCallBackHandler> handler = + DummyRegistryCallBackHandler> handler = new DummyRegistryCallBackHandler<>(); String id = new BigInteger(130, random).toString(32); @@ -285,7 +291,7 @@ public class SimpleRegistryTest extends TestCase { RegistryMessages.VoterInfo voterInfo = RegistryMessages.VoterInfo.newBuilder(). setId(RegistryMessages.VoterID.newBuilder().setId(id)).setInfo(data).build(); - SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient); + SimpleRegistry registry = new SimpleRegistry(signer, bulletinBoardClient, certStream); registry.AddVoter(voterInfo, handler); jobSemaphore.acquire();