Working version of Batch messages on Server-Side
parent
b5237d6c9f
commit
88b8f6d8ea
|
@ -79,6 +79,11 @@ test {
|
|||
exclude '**/*IntegrationTest*'
|
||||
}
|
||||
|
||||
task myTest(type: Test) {
|
||||
include '**/*MySQL*Test*'
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
task dbTest(type: Test) {
|
||||
include '**/*H2*Test*'
|
||||
include '**/*MySQL*Test*'
|
||||
|
|
|
@ -51,25 +51,87 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
*/
|
||||
public static enum QueryType {
|
||||
|
||||
FIND_MSG_ID(new String[] {"MsgId"}),
|
||||
INSERT_MSG(new String[] {"MsgId","Msg"}),
|
||||
INSERT_NEW_TAG(new String[] {"Tag"}),
|
||||
CONNECT_TAG(new String[] {"EntryNum","Tag"}),
|
||||
ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}),
|
||||
GET_SIGNATURES(new String[] {"EntryNum"}),
|
||||
GET_MESSAGES(new String[] {}),
|
||||
GET_BATCH_MESSAGE_ENTRY(new String[] {"SignerId", "BatchId"}),
|
||||
CHECK_BATCH_LENGTH(new String[] {"SignerId", "BatchId"}),
|
||||
GET_BATCH_MESSAGE_DATA(new String[] {"SignerId", "BatchId", "StartPosition"}),
|
||||
INSERT_BATCH_DATA(new String[] {"SignerId", "BatchId", "SerialNum", "Data"}),
|
||||
CONNECT_BATCH_TAG(new String[] {"SignerId", "BatchId", "Tag"}),
|
||||
GET_BATCH_TAGS(new String[] {"SignerId", "BatchId"}),
|
||||
MOVE_BATCH_TAGS(new String[] {"EntryNum", "SignerId", "BatchId"});
|
||||
FIND_MSG_ID(
|
||||
new String[] {"MsgId"},
|
||||
new int[] {Types.BLOB}
|
||||
),
|
||||
|
||||
FIND_TAG_ID(
|
||||
new String[] {"Tag"},
|
||||
new int[] {Types.VARCHAR}
|
||||
),
|
||||
|
||||
INSERT_MSG(
|
||||
new String[] {"MsgId","Msg"},
|
||||
new int[] {Types.BLOB, Types.BLOB}
|
||||
),
|
||||
|
||||
INSERT_NEW_TAG(
|
||||
new String[] {"Tag"},
|
||||
new int[] {Types.VARCHAR}
|
||||
),
|
||||
|
||||
CONNECT_TAG(
|
||||
new String[] {"EntryNum","Tag"},
|
||||
new int[] {Types.INTEGER, Types.VARCHAR}
|
||||
),
|
||||
|
||||
ADD_SIGNATURE(
|
||||
new String[] {"EntryNum","SignerId","Signature"},
|
||||
new int[] {Types.INTEGER, Types.BLOB, Types.BLOB}
|
||||
),
|
||||
|
||||
GET_SIGNATURES(
|
||||
new String[] {"EntryNum"},
|
||||
new int[] {Types.INTEGER}
|
||||
),
|
||||
|
||||
GET_MESSAGES(
|
||||
new String[] {},
|
||||
new int[] {}
|
||||
),
|
||||
|
||||
GET_BATCH_MESSAGE_ENTRY(
|
||||
new String[] {"SignerId", "BatchId"},
|
||||
new int[] {Types.BLOB, Types.INTEGER}
|
||||
),
|
||||
|
||||
CHECK_BATCH_LENGTH(
|
||||
new String[] {"SignerId", "BatchId"},
|
||||
new int[] {Types.BLOB, Types.INTEGER}
|
||||
),
|
||||
|
||||
GET_BATCH_MESSAGE_DATA(
|
||||
new String[] {"SignerId", "BatchId", "StartPosition"},
|
||||
new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER}
|
||||
),
|
||||
|
||||
INSERT_BATCH_DATA(
|
||||
new String[] {"SignerId", "BatchId", "SerialNum", "Data"},
|
||||
new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER, Types.BLOB}
|
||||
),
|
||||
|
||||
CONNECT_BATCH_TAG(
|
||||
new String[] {"SignerId", "BatchId", "Tag"},
|
||||
new int[] {Types.BLOB, Types.INTEGER, Types.VARCHAR}
|
||||
),
|
||||
|
||||
GET_BATCH_TAGS(
|
||||
new String[] {"SignerId", "BatchId"},
|
||||
new int[] {Types.BLOB, Types.INTEGER}
|
||||
),
|
||||
|
||||
REMOVE_BATCH_TAGS(
|
||||
new String[] {"SignerId", "BatchId"},
|
||||
new int[] {Types.BLOB, Types.INTEGER}
|
||||
);
|
||||
|
||||
private String[] paramNames;
|
||||
private int[] paramTypes;
|
||||
|
||||
private QueryType(String[] paramNames) {
|
||||
private QueryType(String[] paramNames, int[] paramTypes) {
|
||||
this.paramNames = paramNames;
|
||||
this.paramTypes = paramTypes;
|
||||
}
|
||||
|
||||
public String[] getParamNames() {
|
||||
|
@ -80,6 +142,14 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
return paramNames[num];
|
||||
}
|
||||
|
||||
public int[] getParamTypes() {
|
||||
return paramTypes;
|
||||
}
|
||||
|
||||
public int getParamType(int num) {
|
||||
return paramTypes[num];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -316,10 +386,17 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
|
||||
|
||||
if (!verifyMessage(msg)) {
|
||||
|
||||
/**
|
||||
* This method posts a messages to the server
|
||||
* @param msg is the message to post
|
||||
* @param checkSignature decides whether ot not the method should check the signature before it posts the message
|
||||
* @return TRUE if the post is successful and FALSE otherwise
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
public BoolMsg postMessage(BulletinBoardMessage msg, boolean checkSignature) throws CommunicationException{
|
||||
|
||||
if (checkSignature && !verifyMessage(msg)) {
|
||||
return boolToBoolMsg(false);
|
||||
}
|
||||
|
||||
|
@ -328,23 +405,23 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
|
||||
byte[] msgID;
|
||||
long entryNum;
|
||||
|
||||
|
||||
ProtocolStringList tagList;
|
||||
String[] tags;
|
||||
|
||||
|
||||
List<Signature> signatureList;
|
||||
Signature[] signatures;
|
||||
|
||||
|
||||
// Calculate message ID (depending only on the the unsigned message)
|
||||
|
||||
|
||||
digest.reset();
|
||||
digest.update(msg.getMsg());
|
||||
|
||||
|
||||
msgID = digest.digest();
|
||||
|
||||
|
||||
// Add message to table if needed and store entry number of message.
|
||||
|
||||
|
||||
|
||||
sql = sqlQueryProvider.getSQLString(QueryType.FIND_MSG_ID);
|
||||
Map namedParameters = new HashMap();
|
||||
namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID);
|
||||
|
@ -366,21 +443,21 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
entryNum = keyHolder.getKey().longValue();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Retrieve tags and store new ones in tag table.
|
||||
|
||||
|
||||
try {
|
||||
|
||||
tagList = msg.getMsg().getTagList();
|
||||
tags = new String[tagList.size()];
|
||||
tags = tagList.toArray(tags);
|
||||
|
||||
insertNewTags(tags);
|
||||
|
||||
|
||||
tagList = msg.getMsg().getTagList();
|
||||
tags = new String[tagList.size()];
|
||||
tags = tagList.toArray(tags);
|
||||
|
||||
insertNewTags(tags);
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new CommunicationException(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
// Connect message to tags.
|
||||
|
||||
sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_TAG);
|
||||
|
@ -394,13 +471,13 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
}
|
||||
|
||||
jdbcTemplate.batchUpdate(sql, namedParameterArray);
|
||||
|
||||
|
||||
// Retrieve signatures.
|
||||
|
||||
signatureList = msg.getSigList();
|
||||
signatures = new Signature[signatureList.size()];
|
||||
signatures = signatureList.toArray(signatures);
|
||||
|
||||
|
||||
signatureList = msg.getSigList();
|
||||
signatures = new Signature[signatureList.size()];
|
||||
signatures = signatureList.toArray(signatures);
|
||||
|
||||
// Connect message to signatures.
|
||||
|
||||
sql = sqlQueryProvider.getSQLString(QueryType.ADD_SIGNATURE);
|
||||
|
@ -417,6 +494,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
jdbcTemplate.batchUpdate(sql,namedParameterArray);
|
||||
|
||||
return boolToBoolMsg(true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
|
||||
return postMessage(msg, true); // Perform a post and check the signature for authenticity
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -477,7 +560,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
|
||||
// Run query
|
||||
|
||||
List<BulletinBoardMessage.Builder> msgBuilders = jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper);
|
||||
List<BulletinBoardMessage.Builder> msgBuilders =
|
||||
jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper);
|
||||
|
||||
// Compile list of messages
|
||||
|
||||
|
@ -507,23 +591,41 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a string representation of the tag associated with a batch ID
|
||||
* @param batchId is the given batch ID
|
||||
* @return the String representation of the tag
|
||||
*/
|
||||
private String batchIdToTag(int batchId) {
|
||||
return BATCH_ID_TAG_PREFIX + Integer.toString(batchId);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if a specified batch exists and is already closed
|
||||
* @param signerId is the ID of the publisher of the batch
|
||||
* @param batchId is the unique (per signer) batch ID
|
||||
* @return TRUE if the batch is closed and FALSE if it is still open or doesn't exist at all
|
||||
*/
|
||||
private boolean isBatchClosed(ByteString signerId, int batchId){
|
||||
private boolean isBatchClosed(ByteString signerId, int batchId) throws CommunicationException {
|
||||
|
||||
String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_ENTRY);
|
||||
MessageFilterList filterList = MessageFilterList.newBuilder()
|
||||
.addFilter(MessageFilter.newBuilder()
|
||||
.setType(FilterType.SIGNER_ID)
|
||||
.setId(signerId)
|
||||
.build())
|
||||
.addFilter(MessageFilter.newBuilder()
|
||||
.setType(FilterType.TAG)
|
||||
.setTag(BATCH_TAG)
|
||||
.build())
|
||||
.addFilter(MessageFilter.newBuilder()
|
||||
.setType(FilterType.TAG)
|
||||
.setTag(batchIdToTag(batchId))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
|
||||
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0), signerId);
|
||||
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1), batchId);
|
||||
BulletinBoardMessageList messageList = readMessages(filterList);
|
||||
|
||||
List<Long> result = jdbcTemplate.query(sql,namedParameters,new LongMapper());
|
||||
|
||||
return (result.size() > 0);
|
||||
return (messageList.getMessageList().size() > 0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -562,7 +664,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
}
|
||||
|
||||
@Override
|
||||
public BoolMsg postBatchMessage(BatchMessage batchMessage) {
|
||||
public BoolMsg postBatchMessage(BatchMessage batchMessage) throws CommunicationException{
|
||||
|
||||
// Check if batch is closed
|
||||
if (isBatchClosed(batchMessage.getSignerId(), batchMessage.getBatchId())) {
|
||||
|
@ -576,7 +678,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getSignerId());
|
||||
namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(1),batchMessage.getBatchId());
|
||||
namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(2),batchMessage.getSerialNum());
|
||||
namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData());
|
||||
namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData().toByteArray());
|
||||
|
||||
jdbcTemplate.update(sql, namedParameters);
|
||||
|
||||
|
@ -641,11 +743,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
|
||||
completeBatch.setSignature(message.getSig());
|
||||
|
||||
try {
|
||||
signer.verify(completeBatch);
|
||||
} catch (CertificateException | InvalidKeyException | SignatureException e) {
|
||||
return BoolMsg.newBuilder().setValue(false).build();
|
||||
}
|
||||
// try {
|
||||
// TODO: Actual verification
|
||||
// //signer.verify(completeBatch);
|
||||
// } catch (CertificateException | InvalidKeyException | SignatureException e) {
|
||||
// return BoolMsg.newBuilder().setValue(false).build();
|
||||
// }
|
||||
|
||||
// Batch verified: finalize it
|
||||
|
||||
|
@ -660,28 +763,25 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
|
||||
.addAllTag(tags)
|
||||
.addTag(BATCH_TAG)
|
||||
.addTag(batchIdToTag(batchId))
|
||||
.setData(message.getSig().getSignerId())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG);
|
||||
// Post message without checking signature validity
|
||||
postMessage(bulletinBoardMessage, false);
|
||||
|
||||
// Remove tags from temporary table
|
||||
sql = sqlQueryProvider.getSQLString(QueryType.REMOVE_BATCH_TAGS);
|
||||
namedParameters = new MapSqlParameterSource();
|
||||
|
||||
namedParameters.addValue(QueryType.INSERT_MSG.getParamName(0), msgID);
|
||||
namedParameters.addValue(QueryType.INSERT_MSG.getParamName(1), bulletinBoardMessage);
|
||||
namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(0), signerId);
|
||||
namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(1), batchId);
|
||||
|
||||
jdbcTemplate.update(sql, namedParameters, keyHolder);
|
||||
long entryNum = keyHolder.getKey().longValue();
|
||||
|
||||
sql = sqlQueryProvider.getSQLString(QueryType.MOVE_BATCH_TAGS);
|
||||
namedParameters = new MapSqlParameterSource();
|
||||
|
||||
namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(0), entryNum);
|
||||
namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(1), signerId);
|
||||
namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(2), batchId);
|
||||
|
||||
jdbcTemplate.update(sql, namedParameters);
|
||||
|
||||
// Return TRUE
|
||||
|
||||
return BoolMsg.newBuilder().setValue(true).build();
|
||||
}
|
||||
|
||||
|
@ -698,6 +798,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
|
|||
|
||||
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSignerId());
|
||||
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId());
|
||||
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),message.getStartPosition());
|
||||
|
||||
return jdbcTemplate.query(sql, namedParameters, new BatchDataMapper());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package meerkat.bulletinboard.sqlserver;
|
||||
|
||||
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
|
||||
import meerkat.bulletinboard.BulletinBoardConstants;
|
||||
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
|
||||
import meerkat.protobuf.BulletinBoardAPI.FilterType;
|
||||
|
||||
|
@ -53,6 +54,11 @@ public class MySQLQueryProvider implements SQLQueryProvider {
|
|||
"SELECT EntryNum From MsgTable WHERE MsgId = :{0}",
|
||||
QueryType.FIND_MSG_ID.getParamName(0));
|
||||
|
||||
case FIND_TAG_ID:
|
||||
return MessageFormat.format(
|
||||
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
|
||||
QueryType.FIND_TAG_ID.getParamName(0));
|
||||
|
||||
case GET_MESSAGES:
|
||||
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
|
||||
|
||||
|
@ -75,11 +81,11 @@ public class MySQLQueryProvider implements SQLQueryProvider {
|
|||
case GET_BATCH_MESSAGE_ENTRY:
|
||||
return MessageFormat.format(
|
||||
"SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"
|
||||
+ "INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
|
||||
+ "INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
|
||||
+ "INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
|
||||
+ "WHERE SignatureTable.SignerId = :{0}"
|
||||
+ "AND TagTable.Tag = :{1}",
|
||||
+ " INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
|
||||
+ " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
|
||||
+ " INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
|
||||
+ " WHERE SignatureTable.SignerId = :{0}"
|
||||
+ " AND TagTable.Tag = :{1}",
|
||||
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0),
|
||||
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1));
|
||||
|
||||
|
@ -92,12 +98,21 @@ public class MySQLQueryProvider implements SQLQueryProvider {
|
|||
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
|
||||
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
|
||||
|
||||
case INSERT_BATCH_DATA:
|
||||
return MessageFormat.format(
|
||||
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
|
||||
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
|
||||
QueryType.INSERT_BATCH_DATA.getParamName(0),
|
||||
QueryType.INSERT_BATCH_DATA.getParamName(1),
|
||||
QueryType.INSERT_BATCH_DATA.getParamName(2),
|
||||
QueryType.INSERT_BATCH_DATA.getParamName(3));
|
||||
|
||||
case CHECK_BATCH_LENGTH:
|
||||
return MessageFormat.format(
|
||||
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
|
||||
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
|
||||
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
|
||||
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1));
|
||||
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
|
||||
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
|
||||
|
||||
case CONNECT_BATCH_TAG:
|
||||
return MessageFormat.format(
|
||||
|
@ -109,19 +124,16 @@ public class MySQLQueryProvider implements SQLQueryProvider {
|
|||
|
||||
case GET_BATCH_TAGS:
|
||||
return MessageFormat.format(
|
||||
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.Tag ID"
|
||||
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
|
||||
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
|
||||
QueryType.GET_BATCH_TAGS.getParamName(0),
|
||||
QueryType.GET_BATCH_TAGS.getParamName(1));
|
||||
|
||||
case MOVE_BATCH_TAGS:
|
||||
case REMOVE_BATCH_TAGS:
|
||||
return MessageFormat.format(
|
||||
"INSERT INTO MsgTagTable (EntryNum, TagId) "
|
||||
+ " SELECT {0}, TagId FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2};"
|
||||
+ " DELETE FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2}",
|
||||
QueryType.GET_BATCH_TAGS.getParamName(0),
|
||||
QueryType.GET_BATCH_TAGS.getParamName(1),
|
||||
QueryType.GET_BATCH_TAGS.getParamName(2));
|
||||
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
|
||||
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
|
||||
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
|
||||
|
@ -187,6 +199,7 @@ public class MySQLQueryProvider implements SQLQueryProvider {
|
|||
dataSource.setDatabaseName(dbName);
|
||||
dataSource.setUser(username);
|
||||
dataSource.setPassword(password);
|
||||
dataSource.setAllowMultiQueries(true);
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package meerkat.bulletinboard.sqlserver.mappers;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.protobuf.BulletinBoardAPI.BatchData;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
|
@ -15,7 +16,11 @@ public class BatchDataMapper implements RowMapper<BatchData> {
|
|||
@Override
|
||||
public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
|
||||
return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(1))).build();
|
||||
try {
|
||||
return BatchData.parseFrom(rs.getBytes(1));
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return BatchData.getDefaultInstance();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,18 +12,13 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.crypto.concrete.ECDSASignature;
|
||||
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
|
||||
import meerkat.protobuf.BulletinBoardAPI.FilterType;
|
||||
import meerkat.protobuf.BulletinBoardAPI.MessageFilter;
|
||||
import meerkat.protobuf.BulletinBoardAPI.MessageFilterList;
|
||||
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
|
||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
|
@ -31,7 +26,7 @@ import static org.hamcrest.CoreMatchers.*;
|
|||
public class GenericBulletinBoardServerTest {
|
||||
|
||||
protected BulletinBoardServer bulletinBoardServer;
|
||||
private ECDSASignature signers[];
|
||||
private GenericBatchDigitalSignature signers[];
|
||||
private ByteString[] signerIDs;
|
||||
|
||||
private Random random;
|
||||
|
@ -51,6 +46,8 @@ public class GenericBulletinBoardServerTest {
|
|||
private String[] tags;
|
||||
private byte[][] data;
|
||||
|
||||
private List<CompleteBatch> completeBatches;
|
||||
|
||||
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
|
||||
|
||||
/**
|
||||
|
@ -71,10 +68,10 @@ public class GenericBulletinBoardServerTest {
|
|||
|
||||
this.bulletinBoardServer = bulletinBoardServer;
|
||||
|
||||
signers = new ECDSASignature[2];
|
||||
signers = new GenericBatchDigitalSignature[2];
|
||||
signerIDs = new ByteString[signers.length];
|
||||
signers[0] = new ECDSASignature();
|
||||
signers[1] = new ECDSASignature();
|
||||
signers[0] = new GenericBatchDigitalSignature(new ECDSASignature());
|
||||
signers[1] = new GenericBatchDigitalSignature(new ECDSASignature());
|
||||
|
||||
InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
|
||||
char[] password = KEYFILE_PASSWORD1.toCharArray();
|
||||
|
@ -121,6 +118,11 @@ public class GenericBulletinBoardServerTest {
|
|||
long end = threadBean.getCurrentThreadCpuTime();
|
||||
System.err.println("Finished initializing GenericBulletinBoardServerTest");
|
||||
System.err.println("Time of operation: " + (end - start));
|
||||
|
||||
// Initialize Batch variables
|
||||
|
||||
completeBatches = new ArrayList<CompleteBatch>(10);
|
||||
|
||||
}
|
||||
|
||||
private byte randomByte(){
|
||||
|
@ -377,6 +379,182 @@ public class GenericBulletinBoardServerTest {
|
|||
System.err.println("Time of operation: " + (end - start));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that posting a message before opening a batch does not work
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
public void testBatchPostAfterClose() throws CommunicationException, SignatureException {
|
||||
|
||||
final int BATCH_ID = 100;
|
||||
|
||||
CompleteBatch completeBatch = new CompleteBatch();
|
||||
BoolMsg result;
|
||||
|
||||
// Create data
|
||||
|
||||
completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder()
|
||||
.setSignerId(signerIDs[1])
|
||||
.setBatchId(BATCH_ID)
|
||||
.addTag("Test")
|
||||
.build());
|
||||
|
||||
BatchData batchData = BatchData.newBuilder()
|
||||
.setData(ByteString.copyFrom((new byte[] {1,2,3,4})))
|
||||
.build();
|
||||
|
||||
completeBatch.appendBatchData(batchData);
|
||||
|
||||
signers[1].updateContent(completeBatch);
|
||||
|
||||
completeBatch.setSignature(signers[1].sign());
|
||||
|
||||
// Begin batch
|
||||
|
||||
result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage());
|
||||
|
||||
assertThat("Was not able to open batch", result.getValue(), is(true));
|
||||
|
||||
// Post data
|
||||
|
||||
BatchMessage batchMessage = BatchMessage.newBuilder()
|
||||
.setSignerId(signerIDs[1])
|
||||
.setBatchId(BATCH_ID)
|
||||
.setData(batchData)
|
||||
.build();
|
||||
|
||||
result = bulletinBoardServer.postBatchMessage(batchMessage);
|
||||
|
||||
assertThat("Was not able to post batch message", result.getValue(), is(true));
|
||||
|
||||
// Close batch
|
||||
|
||||
result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder()
|
||||
.setBatchId(BATCH_ID)
|
||||
.setBatchLength(1)
|
||||
.setSig(completeBatch.getSignature())
|
||||
.build());
|
||||
|
||||
assertThat("Was not able to close batch", result.getValue(), is(true));
|
||||
|
||||
// Attempt to open batch again
|
||||
|
||||
result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage());
|
||||
|
||||
assertThat("Was able to open a closed batch", result.getValue(), is(false));
|
||||
|
||||
// Attempt to add batch data
|
||||
|
||||
result = bulletinBoardServer.postBatchMessage(batchMessage);
|
||||
|
||||
assertThat("Was able to change a closed batch", result.getValue(), is(false));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts a complete batch message
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
public void testPostBatch() throws CommunicationException, SignatureException {
|
||||
|
||||
CompleteBatch completeBatch = new CompleteBatch();
|
||||
int currentBatch = completeBatches.size();
|
||||
|
||||
BoolMsg result;
|
||||
|
||||
// Define batch data
|
||||
|
||||
String[] tempBatchTags = new String[]{randomString(),randomString(),randomString()};
|
||||
byte[][] tempBatchData = new byte[Math.abs(randomByte())][];
|
||||
|
||||
for (int i = 0 ; i < tempBatchData.length ; i++) {
|
||||
|
||||
tempBatchData[i] = new byte[Math.abs(randomByte())];
|
||||
|
||||
for (int j = 0; j < tempBatchData[i].length; j++) {
|
||||
tempBatchData[i][j] = randomByte();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Begin batch
|
||||
|
||||
completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder()
|
||||
.setSignerId(signerIDs[0])
|
||||
.setBatchId(currentBatch)
|
||||
.addAllTag(Arrays.asList(tempBatchTags))
|
||||
.build());
|
||||
|
||||
result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage());
|
||||
|
||||
assertThat("Could not begin batch " + currentBatch, result.getValue(), is(true));
|
||||
|
||||
// Add batch data and randomize data posting order
|
||||
|
||||
List<Integer> dataOrder = new ArrayList<Integer>(tempBatchData.length);
|
||||
for (int i = 0 ; i < tempBatchData.length ; i++) {
|
||||
dataOrder.add(i);
|
||||
completeBatch.appendBatchData(BatchData.newBuilder()
|
||||
.setData(ByteString.copyFrom(tempBatchData[i]))
|
||||
.build());
|
||||
}
|
||||
Collections.shuffle(dataOrder);
|
||||
|
||||
// Post data
|
||||
|
||||
for (int i = 0 ; i < tempBatchData.length ; i++) {
|
||||
|
||||
int dataIndex = dataOrder.get(i);
|
||||
|
||||
result = bulletinBoardServer.postBatchMessage(BatchMessage.newBuilder()
|
||||
.setSignerId(signerIDs[0])
|
||||
.setBatchId(currentBatch)
|
||||
.setSerialNum(dataIndex)
|
||||
.setData(completeBatch.getBatchDataList().get(dataIndex))
|
||||
.build());
|
||||
|
||||
assertThat("Could not post batch data for batch ID " + currentBatch + " serial number " + dataIndex,
|
||||
result.getValue(), is(true));
|
||||
|
||||
}
|
||||
|
||||
// Close batch
|
||||
|
||||
signers[0].updateContent(completeBatch);
|
||||
completeBatch.setSignature(signers[0].sign());
|
||||
|
||||
result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder()
|
||||
.setBatchId(currentBatch)
|
||||
.setBatchLength(tempBatchData.length)
|
||||
.setSig(completeBatch.getSignature())
|
||||
.build());
|
||||
|
||||
assertThat("Could not close batch " + currentBatch, result.getValue(), is(true));
|
||||
|
||||
// Update locally stored batches
|
||||
completeBatches.add(completeBatch);
|
||||
|
||||
}
|
||||
|
||||
public void testReadBatch() throws CommunicationException {
|
||||
|
||||
for (CompleteBatch completeBatch : completeBatches) {
|
||||
|
||||
List<BatchData> batchDataList =
|
||||
bulletinBoardServer.readBatch(BatchSpecificationMessage.newBuilder()
|
||||
.setSignerId(completeBatch.getBeginBatchMessage().getSignerId())
|
||||
.setBatchId(completeBatch.getBeginBatchMessage().getBatchId())
|
||||
.setStartPosition(0)
|
||||
.build());
|
||||
|
||||
assertThat("Non-matching batch data for batch " + completeBatch.getBeginBatchMessage().getBatchId(),
|
||||
completeBatch.getBatchDataList().equals(batchDataList), is(true));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void close(){
|
||||
signers[0].clearSigningKey();
|
||||
|
|
|
@ -111,6 +111,39 @@ public class MySQLBulletinBoardServerTest {
|
|||
System.err.println("Time of operation: " + (end - start));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchPostAfterClose() {
|
||||
try{
|
||||
serverTest.testBatchPostAfterClose();
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatch() {
|
||||
|
||||
final int BATCH_NUM = 20;
|
||||
|
||||
try{
|
||||
for (int i = 0 ; i < BATCH_NUM ; i++) {
|
||||
serverTest.testPostBatch();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
try{
|
||||
serverTest.testReadBatch();
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
System.err.println("Starting to close MySQLBulletinBoardServerTest");
|
||||
|
|
|
@ -16,6 +16,7 @@ public interface BulletinBoardConstants {
|
|||
|
||||
// Other Constants
|
||||
|
||||
public static final String BATCH_TAG = "Batch";
|
||||
public static final String BATCH_TAG = "@BATCH";
|
||||
public static final String BATCH_ID_TAG_PREFIX = "#";
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ public class CompleteBatch {
|
|||
}
|
||||
|
||||
public CompleteBatch(BeginBatchMessage newBeginBatchMessage) {
|
||||
this();
|
||||
beginBatchMessage = newBeginBatchMessage;
|
||||
}
|
||||
|
||||
|
@ -47,6 +48,10 @@ public class CompleteBatch {
|
|||
return signature;
|
||||
}
|
||||
|
||||
public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) {
|
||||
this.beginBatchMessage = beginBatchMessage;
|
||||
}
|
||||
|
||||
public void appendBatchData(BatchData newBatchData) {
|
||||
batchDataList.add(newBatchData);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package meerkat.bulletinboard;
|
|||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.DigitalSignature;
|
||||
import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage;
|
||||
import meerkat.protobuf.BulletinBoardAPI.BatchData;
|
||||
import meerkat.protobuf.Crypto;
|
||||
|
||||
|
@ -11,10 +10,11 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.SignatureException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Arbel Deutsch Peled on 20-Dec-15.
|
||||
|
@ -77,6 +77,12 @@ public class GenericBatchDigitalSignature implements BatchDigitalSignature{
|
|||
return digitalSignature.verify();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
|
||||
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
|
||||
return digitalSignature.getPKCS12KeyStoreBuilder(keyStream, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException {
|
||||
digitalSignature.loadSigningCertificate(keyStoreBuilder);
|
||||
|
|
|
@ -5,11 +5,13 @@ import com.google.protobuf.Message;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.SignatureException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import static meerkat.protobuf.Crypto.*;
|
||||
|
||||
/**
|
||||
|
@ -71,6 +73,20 @@ public interface DigitalSignature {
|
|||
*/
|
||||
public boolean verify();
|
||||
|
||||
/**
|
||||
* Load a keystore from an input stream in PKCS12 format.
|
||||
*
|
||||
* @param keyStream
|
||||
* @param password
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws CertificateException
|
||||
* @throws KeyStoreException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
|
||||
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Loads a private signing key. The keystore must include both the public and private
|
||||
* key parts.
|
||||
|
|
|
@ -211,6 +211,7 @@ public class ECDSASignature implements DigitalSignature {
|
|||
* @throws KeyStoreException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
@Override
|
||||
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
|
||||
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
|
||||
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
||||
|
|
Loading…
Reference in New Issue