Interim merge for branch 'master' into crypto-primitives

crypto-primitives
Tal Moran 2015-11-22 15:50:32 +02:00
commit c76724f599
39 changed files with 748 additions and 223 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ out
*.prefs
*.project
*.classpath
bulletin-board-server/local-instances/meerkat.db

View File

@ -57,6 +57,21 @@ dependencies {
/*==== You probably don't have to edit below this line =======*/
// Setup test configuration that can appear as a dependency in
// other subprojects
configurations {
testOutput.extendsFrom (testCompile)
}
task testJar(type: Jar, dependsOn: testClasses) {
classifier = 'tests'
from sourceSets.test.output
}
artifacts {
testOutput testJar
}
// The run task added by the application plugin
// is also of type JavaExec.
tasks.withType(JavaExec) {

1
bulletin-board-server/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/

View File

@ -9,8 +9,10 @@ apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
//apply plugin: 'application'
//apply plugin: 'jetty'
//mainClassName = 'Demo'
//mainClassName = 'SQLiteIntegrationTest'
apply plugin: 'maven-publish'
@ -42,6 +44,8 @@ dependencies {
// Jersey for RESTful API
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
compile 'org.xerial:sqlite-jdbc:3.7.+'
// Logging
compile 'org.slf4j:slf4j-api:1.7.7'
@ -51,6 +55,9 @@ dependencies {
// Google protobufs
compile 'com.google.protobuf:protobuf-java:3.+'
// Depend on test resources from meerkat-common
testCompile project(path: ':meerkat-common', configuration: 'testOutput')
testCompile 'junit:junit:4.+'
runtime 'org.codehaus.groovy:groovy:2.4.+'
@ -61,6 +68,10 @@ test {
exclude '**/*IntegrationTest*'
}
task debugIntegrationTest(type: Test){
include '**/*IntegrationTest*'
debug = true
}
task integrationTest(type: Test) {
include '**/*IntegrationTest*'
@ -68,7 +79,9 @@ task integrationTest(type: Test) {
gretty {
httpPort = 8081
contextPath = '/'
integrationTestTask = 'integrationTest'
loggingLevel = 'TRACE'
}

View File

@ -11,7 +11,7 @@ import javax.servlet.http.HttpServletResponse;
import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.Voting.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.*;
public class BulletinBoardHttpServer extends HttpServlet {

View File

@ -3,8 +3,7 @@ package meerkat.bulletinboard.service;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Voting;
import meerkat.protobuf.Voting.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.*;
import java.util.Arrays;
import java.util.List;
@ -16,7 +15,7 @@ public class HelloProtoBuf {
public Message sayHello() {
BulletinBoardMessage.Builder msg = BulletinBoardMessage.newBuilder();
Voting.UnsignedBulletinBoardMessage.Builder unsigned = Voting.UnsignedBulletinBoardMessage.newBuilder();
UnsignedBulletinBoardMessage.Builder unsigned = UnsignedBulletinBoardMessage.newBuilder();
unsigned.setData(ByteString.copyFromUtf8("Hello World!"));
List<String> tags = Arrays.asList("Greetings", "FirstPrograms");
unsigned.addAllTags(tags);
@ -24,7 +23,7 @@ public class HelloProtoBuf {
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
sig.setData(ByteString.copyFromUtf8("deadbeef"));
msg.setSig(sig);
msg.addSig(sig);
return msg.build();
}

View File

@ -1,5 +1,6 @@
package meerkat.bulletinboard.sqlserver;
import java.util.Arrays;
import java.util.List;
import com.google.protobuf.ProtocolStringList;
@ -11,13 +12,12 @@ import java.sql.SQLException;
import java.sql.Statement;
import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.MessageFilter;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto.Signature;
import meerkat.protobuf.Crypto.SignatureVerificationKey;
import meerkat.protobuf.Voting.BulletinBoardMessage;
import meerkat.crypto.Digest;
import meerkat.crypto.concrete.SHA256Digest;
import meerkat.protobuf.Voting.MessageID;
public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
@ -53,53 +53,109 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
* @return TRUE if the message is authenticated and FALSE otherwise.
*/
private boolean verifyMessage(BulletinBoardMessage msg) {
//TODO: Replace with actual verification.
return true;
}
/**
* This procedure makes sure that all tags in the given list have an entry in the tags list.
* @param tagIterator
* This procedure makes sure that all tags in the given list have an entry in the tags table.
* @param tags
*/
protected abstract void insertNewTags(String[] tags) throws CommunicationException;
protected abstract void insertNewTags(String[] tags) throws SQLException;
/**
* This procedure is used to convert a boolean to a BoolMsg.
* @param b is the boolean to convert.
* @return a ProtoBuf message with boolean payload.
*/
private BoolMsg boolToBoolMsg(boolean b){
return BoolMsg.newBuilder()
.setValue(b)
.build();
}
@Override
public boolean postMessage(BulletinBoardMessage msg) throws CommunicationException {
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
if (!verifyMessage(msg)) {
return false;
return boolToBoolMsg(false);
}
PreparedStatement pstmt;
ResultSet rs;
String sql;
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);
digest.update(msg.getMsg());
msgID = digest.digest();
// Add message to table if needed and store entry number of message.
try {
sql = "INSERT INTO MsgTable (Id, Data, Signature) VALUES(?,?,?)";
pstmt = connection.prepareStatement(sql);
pstmt.setBytes(1, msgID);
pstmt.setBytes(2,msg.getMsg().getData().toByteArray());
pstmt.setBytes(3,msg.getSig().toByteArray());
pstmt.executeUpdate();
sql = "SELECT EntryNum From MsgTable WHERE MsgId = ?";
pstmt = connection.prepareStatement(sql);
pstmt.setBytes(1, msgID);
rs = pstmt.executeQuery();
if (rs.next()){
entryNum = rs.getLong(1);
} else{
sql = "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)";
pstmt = connection.prepareStatement(sql);
pstmt.setBytes(1, msgID);
pstmt.setBytes(2, msg.toByteArray());
pstmt.executeUpdate();
rs = pstmt.getGeneratedKeys();
rs.next();
entryNum = rs.getLong(1);
}
pstmt.close();
} catch (SQLException e) {
throw new CommunicationException("Error inserting into MsgTable: " + e.getMessage());
}
// Retrieve tags and store new ones in tag table.
try {
tagList = msg.getMsg().getTagsList();
tags = new String[tagList.size()];
tags = tagList.toArray(tags);
insertNewTags(tags);
sql = "INSERT INTO MsgTagTable (MsgId, TagId) SELECT (?, TagId) FROM TagTable WHERE tag=?";
} catch (SQLException e) {
throw new CommunicationException(e.getMessage());
}
// Connect message to tags.
try{
sql = "INSERT OR IGNORE INTO MsgTagTable (TagId, EntryNum) SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?";
pstmt = connection.prepareStatement(sql);
pstmt.setLong(1, entryNum);
for (String tag : tags){
pstmt.setBytes(1, msgID);
pstmt.setString(2, tag);
pstmt.addBatch();
}
@ -108,19 +164,43 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
pstmt.close();
} catch (SQLException e) {
throw new CommunicationException("Error accessing DB: " + e.getMessage());
throw new CommunicationException("Error Linking tags: " + e.getMessage());
}
// Retrieve signatures.
signatureList = msg.getSigList();
signatures = new Signature[signatureList.size()];
signatures = signatureList.toArray(signatures);
// Connect message to signatures.
try{
sql = "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)";
pstmt = connection.prepareStatement(sql);
pstmt.setLong(1, entryNum);
for (Signature sig : signatures){
pstmt.setBytes(2, sig.getSignerId().toByteArray());
pstmt.setBytes(3, sig.toByteArray());
pstmt.addBatch();
}
pstmt.executeBatch();
pstmt.close();
} catch (SQLException e) {
throw new CommunicationException("Error Linking tags: " + e.getMessage());
}
return true;
}
@Override
public List<BulletinBoardMessage> readMessages(MessageFilter filter, int max) {
// TODO Auto-generated method stub
return null;
return boolToBoolMsg(true);
}
public void testPrint(){
public String testPrint(){
String s = "";
try {
@ -128,20 +208,30 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
ResultSet rs = statement.executeQuery("select * from MsgTable");
while (rs.next()) {
// read the result set
System.out.println("data = " + rs.getString("Data"));
System.out.println("id = " + rs.getInt("Id"));
s += "entry = " + rs.getInt("EntryNum") + " \n";
s += "id = " + Arrays.toString(rs.getBytes("MsgId")) + " \n";
s += "msg = " + Arrays.toString(rs.getBytes("Msg")) + " \n";
s += "signer ID = " + Arrays.toString(rs.getBytes("SignerId")) + "\t\n<BR>";
}
rs = statement.executeQuery("select * from TagTable");
while (rs.next()) {
// read the result set
s += "Tag = " + rs.getString("Tag") + " \n";
s += "TagId = " + rs.getInt("TagId") + "\t\n<BR>";
}
rs = statement.executeQuery("select * from MsgTagTable");
while (rs.next()) {
// read the result set
System.out.println("MsgId = " + rs.getInt("MsgId"));
System.out.println("TagId = " + rs.getString("TagId"));
s += "MsgId = " + Arrays.toString(rs.getBytes("MsgId")) + " \n";
s += "TagId = " + rs.getInt("TagId") + "\t\n<BR>";
}
} catch(SQLException e){
System.out.println("Error reading from DB");
s += "Error reading from DB";
}
return s;
}
}

View File

@ -2,15 +2,17 @@ package meerkat.bulletinboard.sqlserver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import meerkat.bulletinboard.MessageFilter;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto.Signature;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.Voting.BulletinBoardMessage;
public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
@ -20,20 +22,24 @@ public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
* This procedure initializes:
* 1. The database connection
* 2. The database tables (if they do not yet exist).
* 3.
*/
@Override
public void init() throws CommunicationException {
try{
connection = DriverManager.getConnection("jdbc:sqlite:./local-instances/meerkat.db");
connection = DriverManager.getConnection("jdbc:sqlite:local-instances/meerkat.db");
Statement statement = connection.createStatement();
statement.setQueryTimeout(TIMEOUT);
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER, Id varbinary(1000) UNIQUE, Data varbinary(1000), Signature varbinary(1000), PRIMARY KEY (EntryNum ASC))");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS TagTable (Id int, Tag v archar(50) UNIQUE, PRIMARY KEY (Id ASC))");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTagTable (MsgId varbinary(1000), TagId int, FOREIGN KEY (MsgId) REFERENCES MsgTable(Id), FOREIGN KEY (TagId) REFERENCES TagTable(Id))");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER PRIMARY KEY, MsgId BLOB UNIQUE, Msg BLOB)");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS TagTable (TagId INTEGER PRIMARY KEY, Tag varchar(50) UNIQUE)");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum), FOREIGN KEY (TagId) REFERENCES TagTable(TagId), UNIQUE (EntryNum, TagID))");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum BLOB, SignerId BLOB, Signature BLOB UNIQUE, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
statement.close();
@ -41,18 +47,11 @@ public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
} catch (SQLException e) {
throw new CommunicationException("Couldn't form a connection with the database");
throw new CommunicationException("Couldn't form a connection with the database" + e.getMessage());
}
}
@Override
public List<BulletinBoardMessage> readMessages(MessageFilter filter, int max) {
// TODO Auto-generated method stub
return null;
}
public void close() throws CommunicationException{
@ -66,9 +65,8 @@ public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
}
@Override
protected void insertNewTags(String[] tags) throws CommunicationException {
protected void insertNewTags(String[] tags) throws SQLException {
PreparedStatement pstmt;
String sql;
@ -87,9 +85,178 @@ public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
pstmt.close();
} catch (SQLException e){
throw new CommunicationException("Error adding new tags to table");
throw new SQLException("Error adding new tags to table: " + e.getMessage());
}
}
@Override
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
return super.postMessage(msg);
}
@Override
public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException{
PreparedStatement pstmt;
ResultSet messages, signatures;
long entryNum;
BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder();
BulletinBoardMessage.Builder messageBuilder;
String sql;
String sqlSuffix = "";
List<MessageFilter> filters = filterList.getFilterList();
int i;
boolean tagsRequired = false;
boolean signaturesRequired = false;
boolean isFirstFilter = true;
// Check if Tag/Signature tables are required for filtering purposes.
for (MessageFilter filter : filters){
if (filter.getType() == FilterType.TAG){
tagsRequired = true;
} else if (filter.getType() == FilterType.SIGNER_ID){
signaturesRequired = true;
}
}
sql = "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
if (tagsRequired){
sql += " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum";
sql += " INNER JOIN TagTable ON TagTable.TagId = MsgTagTable.TagId";
}
if (signaturesRequired){
sql += " INNER JOIN SignatureTable ON SignatureTable.EntryNum = MsgTable.EntryNum";
}
// Add conditions.
if (!filters.isEmpty()){
sql += " WHERE";
for (MessageFilter filter : filters){
if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE){
if (isFirstFilter){
isFirstFilter = false;
} else{
sql += " AND";
}
}
switch (filter.getType().getNumber()){
case FilterType.EXACT_ENTRY_VALUE:
sql += " MsgTable.EntryNum = ?";
break;
case FilterType.MAX_ENTRY_VALUE:
sql += " MsgTable.EntryNum <= ?";
break;
case FilterType.MAX_MESSAGES_VALUE:
sqlSuffix += " LIMIT = ?";
break;
case FilterType.MSG_ID_VALUE:
sql += " MsgTableMsgId = ?";
break;
case FilterType.SIGNER_ID_VALUE:
sql += " SignatureTable.SignerId = ?";
break;
case FilterType.TAG_VALUE:
sql += " TagTable.Tag = ?";
break;
}
}
sql += sqlSuffix;
}
// Make query.
try {
pstmt = connection.prepareStatement(sql);
// Specify values for filters.
i = 1;
for (MessageFilter filter : filters){
switch (filter.getType().getNumber()){
case FilterType.EXACT_ENTRY_VALUE: // Go through.
case FilterType.MAX_ENTRY_VALUE:
pstmt.setLong(i, filter.getEntry());
i++;
break;
case FilterType.MSG_ID_VALUE: // Go through.
case FilterType.SIGNER_ID_VALUE:
pstmt.setBytes(i, filter.getId().toByteArray());
i++;
break;
case FilterType.TAG_VALUE:
pstmt.setString(i, filter.getTag());
break;
// The max-messages condition is applied as a suffix. Therefore, it is treated differently.
case FilterType.MAX_MESSAGES_VALUE:
pstmt.setLong(filters.size(), filter.getMaxMessages());
break;
}
}
// Run query.
messages = pstmt.executeQuery();
// Compile list of messages.
sql = "SELECT Signature FROM SignatureTable WHERE EntryNum = ?";
pstmt = connection.prepareStatement(sql);
while (messages.next()){
// Get entry number and retrieve signatures.
entryNum = messages.getLong(1);
pstmt.setLong(1, entryNum);
signatures = pstmt.executeQuery();
// Create message and append signatures.
messageBuilder = BulletinBoardMessage.newBuilder()
.setEntryNum(entryNum)
.setMsg(UnsignedBulletinBoardMessage.parseFrom(messages.getBytes(2)));
while (signatures.next()){
messageBuilder.addSig(Signature.parseFrom(signatures.getBytes(1)));
}
// Finalize message and add to message list.
resultListBuilder.addMessage(messageBuilder.build());
}
pstmt.close();
} catch (SQLException e){
throw new CommunicationException("Error reading messages from DB: " + e.getMessage());
} catch (InvalidProtocolBufferException e) {
throw new CommunicationException("Invalid data from DB: " + e.getMessage());
}
//Combine results and return.
return resultListBuilder.build();
}
}

View File

@ -0,0 +1,63 @@
package meerkat.bulletinboard.webapp;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.BoolMsg;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList;
import meerkat.protobuf.BulletinBoardAPI.MessageFilterList;
import meerkat.rest.Constants;
@Path("/sqlserver")
public class BulletinBoardWebApp implements BulletinBoardServer{
BulletinBoardServer bulletinBoard;
@PostConstruct
@Override
public void init() throws CommunicationException {
bulletinBoard = new SQLiteBulletinBoardServer();
bulletinBoard.init();
}
@Path("postmessage")
@POST
@Consumes(Constants.MEDIATYPE_PROTOBUF)
@Produces(Constants.MEDIATYPE_PROTOBUF)
@Override
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
return bulletinBoard.postMessage(msg);
}
@Path("readmessages")
@POST
@Consumes(Constants.MEDIATYPE_PROTOBUF)
@Produces(Constants.MEDIATYPE_PROTOBUF)
@Override
public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException {
return bulletinBoard.readMessages(filterList);
}
@Override
@PreDestroy
public void close() throws CommunicationException {
bulletinBoard.close();
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public String test() {
return "This BulletinBoard is up and running!\n Please consult the API documents to perform queries.";
}
}

View File

@ -1,22 +1,50 @@
package meerkat.bulletinboard.webapp;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.bulletinboard.service.HelloProtoBuf;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import service.HelloWorldService;
import javax.annotation.PostConstruct;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("/proto")
public class HelloProtoWebApp {
private static HelloProtoBuf helloProtoBuf = new HelloProtoBuf();
private HelloProtoBuf helloProtoBuf;
@GET
@Produces(Constants.MEDIATYPE_PROTOBUF)
public Message hello() {
return helloProtoBuf.sayHello();
}
@PostConstruct
public void init() {
helloProtoBuf = new HelloProtoBuf();
}
@GET
@Produces(Constants.MEDIATYPE_PROTOBUF)
public Message hello() {
byte[] b1 = { (byte) 1, (byte) 2, (byte) 3, (byte) 4 };
byte[] b2 = { (byte) 11, (byte) 12, (byte) 13, (byte) 14 };
byte[] b3 = {(byte) 21, (byte)22, (byte) 23, (byte) 24};
Message msg;
if (helloProtoBuf != null) {
msg = helloProtoBuf.sayHello();
} else {
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTags("Signature")
.addTags("Trustee")
.setData(ByteString.copyFrom(b1)).build())
.addSig(Signature.newBuilder()
.setType(SignatureType.DSA)
.setData(ByteString.copyFrom(b2))
.setSignerId(ByteString.copyFrom(b3)).build())
.build();
}
return msg;
}
}

View File

@ -1,9 +0,0 @@
package service;
public class HelloWorldService {
public String sayHello() {
return "Hello, World!";
}
}

View File

@ -1,16 +0,0 @@
package webapp;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import service.HelloWorldService;
@Path("/hello")
public class HelloWebApp {
private static HelloWorldService helloWorldService = new HelloWorldService();
@GET
public String hello() {
return helloWorldService.sayHello();
}
}

View File

@ -0,0 +1,9 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
message Boolean {
bool value = 1;
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>none</Arg>
</Call>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
<Arg>none</Arg>
</Call>
</Configure>

View File

@ -6,7 +6,7 @@
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>webapp, meerkat</param-value>
<param-value>meerkat</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

View File

@ -1,22 +0,0 @@
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.Test;
public class HelloIntegrationTest {
private static String PROP_GETTY_URL = "gretty.httpBaseURI";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL);
private static String HELLO_URL = BASE_URL + "/hello";
@Test
public void testHello() throws Exception {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(HELLO_URL);
String response = webTarget.request().get(String.class);
System.out.println(response);
assertThat(response, is("Hello, World!"));
}
}

View File

@ -1,6 +1,6 @@
package meerkat.bulletinboard;
import meerkat.protobuf.Voting;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
@ -17,10 +17,10 @@ import static org.hamcrest.MatcherAssert.assertThat;
* Created by talm on 10/11/15.
*/
public class HelloProtoIntegrationTest {
private static String PROP_GETTY_URL = "gretty.httpBaseURI";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL);
private static String HELLO_URL = BASE_URL + "/proto";
private static String DEFAULT_BASE_URL = "http://localhost:8081/";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL, DEFAULT_BASE_URL);
private static String HELLO_URL = "proto";
@Test
public void testHello() throws Exception {
@ -28,8 +28,9 @@ public class HelloProtoIntegrationTest {
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
WebTarget webTarget = client.target(HELLO_URL);
Voting.BulletinBoardMessage response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).get(Voting.BulletinBoardMessage.class);
WebTarget webTarget = client.target(BASE_URL).path(HELLO_URL);
BulletinBoardMessage response = webTarget.request(Constants.MEDIATYPE_PROTOBUF)
.get(BulletinBoardMessage.class);
System.out.println(response.getMsg().getData());

View File

@ -1,41 +0,0 @@
package meerkat.bulletinboard;
import com.google.protobuf.ByteString;
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.Voting.*;
public class SQLiteIntegrationTest {
public static void main(){
byte[] b1 = {(byte) 1, (byte)2, (byte) 3, (byte) 4};
byte[] b2 = {(byte) 11, (byte)12, (byte) 13, (byte) 14};
BulletinBoardMessage msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.setTags(0, "signature")
.setTags(1, "Trustee")
.setData(ByteString.copyFrom(b1))
.build())
.setSig(Signature.newBuilder()
.setType(SignatureType.DSA)
.setData(ByteString.copyFrom(b2))
.build())
.build();
SQLiteBulletinBoardServer bbs = new SQLiteBulletinBoardServer();
try{
bbs.init();
bbs.postMessage(msg);
bbs.testPrint();
bbs.close();
} catch(CommunicationException e){
System.out.println(e.getMessage());
}
}
}

View File

@ -0,0 +1,173 @@
package meerkat.bulletinboard;
import com.google.protobuf.ByteString;
import com.google.protobuf.TextFormat;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
import org.junit.Before;
import org.junit.Test;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
public class SQLiteServerIntegrationTest {
private static String PROP_GETTY_URL = "gretty.httpBaseURI";
private static String DEFAULT_BASE_URL = "localhost:8081";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL, DEFAULT_BASE_URL);
private static String SQL_SERVER_POST = "sqlserver/postmessage";
private static String SQL_SERVER_GET = "sqlserver/readmessages";
Client client;
// Connection connection;
@Before
public void setup() throws Exception {
client = ClientBuilder.newClient();
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
}
@Test
public void testPost() throws Exception {
byte[] b1 = {(byte) 1, (byte) 2, (byte) 3, (byte) 4};
byte[] b2 = {(byte) 11, (byte) 12, (byte) 13, (byte) 14};
byte[] b3 = {(byte) 21, (byte) 22, (byte) 23, (byte) 24};
byte[] b4 = {(byte) 4, (byte) 5, (byte) 100, (byte) -50, (byte) 0};
WebTarget webTarget;
Response response;
BoolMsg bool;
BulletinBoardMessage msg;
MessageFilterList filterList;
BulletinBoardMessageList msgList;
// try{
// connection = DriverManager.getConnection("jdbc:sqlite:d:/arbel/projects/meerkat-java/bulletin-board-server/local-instances/meerkat.db");
// } catch (SQLException e) {
// System.err.println(e.getMessage());
// assert false;
// }
// Test writing mechanism
System.err.println("******** Testing: " + SQL_SERVER_POST);
webTarget = client.target(BASE_URL).path(SQL_SERVER_POST);
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTags("Signature")
.addTags("Trustee")
.setData(ByteString.copyFrom(b1))
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.DSA)
.setData(ByteString.copyFrom(b2))
.setSignerId(ByteString.copyFrom(b3))
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.ECDSA)
.setData(ByteString.copyFrom(b3))
.setSignerId(ByteString.copyFrom(b2))
.build())
.build();
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
System.err.println(response);
bool = response.readEntity(BoolMsg.class);
assert bool.getValue();
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTags("Vote")
.addTags("Trustee")
.setData(ByteString.copyFrom(b4))
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.ECDSA)
.setData(ByteString.copyFrom(b4))
.setSignerId(ByteString.copyFrom(b2))
.build())
.build();
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
System.err.println(response);
bool = response.readEntity(BoolMsg.class);
assert bool.getValue();
// Test reading mechanism
System.err.println("******** Testing: " + SQL_SERVER_GET);
webTarget = client.target(BASE_URL).path(SQL_SERVER_GET);
filterList = MessageFilterList.newBuilder()
.addFilter(
MessageFilter.newBuilder()
.setType(FilterType.TAG)
.setTag("Vote")
.build()
)
.build();
// String sql = "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable INNER JOIN SignatureTable ON SignatureTable.EntryNum = MsgTable.EntryNum WHERE SignatureTable.SignerId = ?";
// PreparedStatement pstmt = connection.prepareStatement(sql);
// int i=1;
// for (MessageFilter filter : filterList.getFilterList()){
//
// switch (filter.getType().getNumber()){
//
// case FilterType.EXACT_ENTRY_VALUE: // Go through.
// case FilterType.MAX_ENTRY_VALUE:
// pstmt.setLong(i, filter.getEntry());
// i++;
// break;
//
// case FilterType.MSG_ID_VALUE: // Go through.
// case FilterType.SIGNER_ID_VALUE:
// pstmt.setBytes(i, filter.getId().toByteArray());
// i++;
// break;
//
// case FilterType.TAG_VALUE:
// pstmt.setString(i, filter.getTag());
// break;
//
// // The max-messages condition is applied as a suffix. Therefore, it is treated differently.
// case FilterType.MAX_MESSAGES_VALUE:
// pstmt.setLong(filterList.getFilterList().size(), filter.getMaxMessages());
// break;
//
// }
// }
// ResultSet rs = pstmt.executeQuery();
//
// i = 0;
// while (rs.next()){
// i++;
// assert rs.getBytes(2)
// }
// System.err.println("Local DB size = " + i);
// pstmt.close();
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
System.err.println(response);
msgList = response.readEntity(BulletinBoardMessageList.class);
System.err.println("List size: " + msgList.getMessageCount());
System.err.println("This is the list:");
System.err.println(TextFormat.printToString(msgList));
assert msgList.getMessageCount() == 1;
}
}

1
meerkat-common/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/

View File

@ -59,6 +59,23 @@ dependencies {
/*==== You probably don't have to edit below this line =======*/
// Setup test configuration that can appear as a dependency in
// other subprojects
configurations {
testOutput.extendsFrom (testCompile)
}
task testJar(type: Jar, dependsOn: testClasses) {
classifier = 'tests'
from sourceSets.test.output
}
artifacts {
testOutput testJar
}
// The run task added by the application plugin
// is also of type JavaExec.
tasks.withType(JavaExec) {

View File

@ -1,5 +1,5 @@
import com.google.protobuf.ByteString;
import static meerkat.protobuf.Voting.*;
import static meerkat.protobuf.BulletinBoardAPI.*;
import java.io.IOException;
/**

View File

@ -1,7 +1,7 @@
package meerkat.bulletinboard;
import meerkat.comm.*;
import static meerkat.protobuf.Voting.*;
import static meerkat.protobuf.BulletinBoardAPI.*;
import java.util.List;

View File

@ -1,9 +1,7 @@
package meerkat.bulletinboard;
import java.util.List;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.Voting.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.*;
/**
* Created by Arbel on 07/11/15.
@ -24,18 +22,17 @@ public interface BulletinBoardServer{
/**
* Post a message to bulletin board.
* @param msg is the actual (signed) message
* @return TRUE if the message has been authenticated and FALSE otherwise.
* @return TRUE if the message has been authenticated and FALSE otherwise (in ProtoBuf form).
* @throws CommunicationException on DB connection error.
*/
public boolean postMessage(BulletinBoardMessage msg) throws CommunicationException;
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException;
/**
* Read all messages posted matching the given filter.
* @param filter return only messages that match the filter (null means no filtering).
* @param max maximum number of messages to return (0=no limit)
* @param filter return only messages that match the filter (empty list means no filtering).
* @return
*/
List<BulletinBoardMessage> readMessages(MessageFilter filter, int max);
BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException;
/**
* This method closes the connection to the DB.

View File

@ -1,27 +0,0 @@
package meerkat.bulletinboard;
/**
* Created by talm on 25/10/15.
*
* A filter for messages (run on the BB server side).
*
* TODO: define a limited filter language (e.g., by tag, by signer, by time, etc.) that can
* be efficiently run on the BB database.
*
*/
public abstract class MessageFilter {
public enum FilterType{
ENTRY_NUM,
ID,
TAG,
SIGNER,
TIME
}
FilterType filterType;
public MessageFilter(FilterType filterType){
}
}

View File

@ -17,7 +17,7 @@ import static meerkat.protobuf.Crypto.*;
/**
* Created by talm on 25/10/15.
*
* Sign and verifyarrays of messages
* Sign and verify arrays of messages
*/
public interface DigitalSignature {
final public static String CERTIFICATE_ENCODING_X509 = "X.509";

View File

@ -0,0 +1,73 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto';
message BoolMsg {
bool value = 1;
}
message MessageID {
// The ID of a message for unique retrieval.
// Note that it is assumed that this ID is a function of the message itself.
bytes ID = 1;
}
message UnsignedBulletinBoardMessage {
// Optional tags describing message
repeated string tags = 1;
// The actual content of the message
bytes data = 2;
}
message BulletinBoardMessage {
// Serial entry number of message in database
int64 entryNum = 1;
// Unsigned raw data of message
UnsignedBulletinBoardMessage msg = 2;
// Signature of message (and tags), excluding the entry number.
repeated meerkat.Signature sig = 3;
}
message BulletinBoardMessageList {
repeated BulletinBoardMessage message = 1;
}
enum FilterType {
MSG_ID = 0; // Match exact message ID
EXACT_ENTRY = 1; // Match exact entry number in database (chronological)
MAX_ENTRY = 2; // Find all entries in database up to specified entry number (chronological)
SIGNER_ID = 3; // Find all entries in database that correspond to specific signature (signer)
TAG = 4; // Find all entries in database that have a specific tag
MAX_MESSAGES = 5; // Return at most some specified number of messages
}
message MessageFilter {
FilterType type = 1;
oneof filter{
bytes id = 2;
int64 entry = 3;
string tag = 4;
int64 maxMessages = 5;
}
}
message MessageFilterList {
// Combination of filters.
// To be implemented using intersection ("AND") operations.
repeated MessageFilter filter = 1;
}

View File

@ -6,28 +6,6 @@ import 'meerkat/crypto.proto';
option java_package = "meerkat.protobuf";
message MessageID {
// The ID of a message for unique retrieval.
// Note that it is assumed that this ID is a function of the message itself.
bytes ID = 1;
}
message UnsignedBulletinBoardMessage {
// Optional tags describing message
repeated string tags = 1;
// The actual content of the message
bytes data = 2;
}
message BulletinBoardMessage {
UnsignedBulletinBoardMessage msg = 1;
// Signature of message (and tags)
meerkat.Signature sig = 2;
}
// A ballot question. This is an opaque
// data type that is parsed by the UI to display
// the question.

View File

@ -2,7 +2,7 @@ package meerkat.crypto.concrete;
import com.google.protobuf.ByteString;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Voting;
import meerkat.protobuf.BulletinBoardAPI.*;
import org.junit.Test;
import java.io.ByteArrayInputStream;
@ -149,13 +149,13 @@ public class TestECDSASignature {
signer.loadSigningCertificate(keyStore);
Voting.UnsignedBulletinBoardMessage.Builder unsignedMsgBuilder = Voting.UnsignedBulletinBoardMessage.newBuilder();
UnsignedBulletinBoardMessage.Builder unsignedMsgBuilder = UnsignedBulletinBoardMessage.newBuilder();
unsignedMsgBuilder.setData(ByteString.copyFromUtf8(HELLO_WORLD));
unsignedMsgBuilder.addTags("Tag1");
unsignedMsgBuilder.addTags("Tag2");
unsignedMsgBuilder.addTags("Tag3");
Voting.UnsignedBulletinBoardMessage usMsg = unsignedMsgBuilder.build();
UnsignedBulletinBoardMessage usMsg = unsignedMsgBuilder.build();
signer.updateContent(usMsg);
Crypto.Signature sig = signer.sign();

View File

@ -0,0 +1 @@
0D r=¥|n“Ò2ɪ‰!S»®[gCŸ$ä°Ž/ Ê”(Âò½ ^esüHLŸ½o,oV®”§ce²p0(èXÆ]&@

1
restful-api-common/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/