Added basic Bulletin Board server functionality
parent
aaf26dc2b1
commit
58c1816324
|
@ -6,3 +6,6 @@ out
|
|||
*.ipr
|
||||
*.iws
|
||||
**/*.swp
|
||||
*.prefs
|
||||
*.project
|
||||
*.classpath
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package meerkat.bulletinboard.httpserver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import meerkat.bulletinboard.BulletinBoardServer;
|
||||
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.protobuf.Voting.BulletinBoardMessage;
|
||||
|
||||
public class BulletinBoardHttpServer extends HttpServlet {
|
||||
|
||||
/**
|
||||
* Auto-generated UID.
|
||||
*/
|
||||
private static final long serialVersionUID = -1263665607729456165L;
|
||||
|
||||
BulletinBoardServer bbs;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig config) throws ServletException {
|
||||
//TODO: Make this generic
|
||||
bbs = new SQLiteBulletinBoardServer();
|
||||
|
||||
try {
|
||||
bbs.init();
|
||||
} catch (CommunicationException e) {
|
||||
// TODO Log error
|
||||
throw new ServletException("Servlet failed to initialize: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This procedure handles (POST) requests to post messages to the Bulletin Board.
|
||||
*/
|
||||
@Override
|
||||
protected void doPost( HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
BulletinBoardMessage message;
|
||||
|
||||
try{
|
||||
message = BulletinBoardMessage.newBuilder()
|
||||
.mergeFrom(request.getInputStream())
|
||||
.build();
|
||||
} catch(Exception e){
|
||||
//TODO: Log invalid request
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
bbs.postMessage(message);
|
||||
} catch (CommunicationException e) {
|
||||
// TODO Log DB communication error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This procedure handles (GET) requests which request data from the Bulletin Board.
|
||||
*/
|
||||
@Override
|
||||
protected void doGet( HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
BulletinBoardMessage message;
|
||||
|
||||
try{
|
||||
message = BulletinBoardMessage.newBuilder()
|
||||
.mergeFrom(request.getInputStream())
|
||||
.build();
|
||||
} catch(Exception e){
|
||||
//TODO: Log invalid request
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
bbs.postMessage(message);
|
||||
} catch (CommunicationException e) {
|
||||
// TODO Log DB communication error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
try {
|
||||
bbs.close();
|
||||
} catch (CommunicationException e) {
|
||||
// TODO Log DB communication error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package meerkat.bulletinboard.sqlserver;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.protobuf.ProtocolStringList;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import meerkat.bulletinboard.BulletinBoardServer;
|
||||
import meerkat.bulletinboard.MessageFilter;
|
||||
import meerkat.comm.CommunicationException;
|
||||
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{
|
||||
|
||||
protected Connection connection;
|
||||
|
||||
protected Digest digest;
|
||||
|
||||
protected List<SignatureVerificationKey> trusteeSignatureVerificationArray;
|
||||
protected int minTrusteeSignatures;
|
||||
|
||||
protected List<List<SignatureVerificationKey>> pollingCommitteeSignatureVerificationKeyArray;
|
||||
protected int minCommiteeSignatures;
|
||||
|
||||
/**
|
||||
* This method initializes the signatures but does not implement the DB connection.
|
||||
* Any full (non-abstract) extension of this class should
|
||||
* 1. Establish a DB connection, and
|
||||
* 2. Call this procedure
|
||||
*/
|
||||
@Override
|
||||
public void init() throws CommunicationException {
|
||||
// TODO write signature reading part.
|
||||
|
||||
digest = new SHA256Digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method verifies the authenticity of the received message based on
|
||||
* the stored signatures.
|
||||
*
|
||||
* @param msg
|
||||
* is the message to authenticate (containing the signature).
|
||||
* @return TRUE if the message is authenticated and FALSE otherwise.
|
||||
*/
|
||||
private boolean verifyMessage(BulletinBoardMessage msg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This procedure makes sure that all tags in the given list have an entry in the tags list.
|
||||
* @param tagIterator
|
||||
*/
|
||||
protected abstract void insertNewTags(String[] tags) throws CommunicationException;
|
||||
|
||||
@Override
|
||||
public boolean postMessage(BulletinBoardMessage msg) throws CommunicationException {
|
||||
if (!verifyMessage(msg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PreparedStatement pstmt;
|
||||
String sql;
|
||||
byte[] msgID;
|
||||
|
||||
ProtocolStringList tagList;
|
||||
String[] tags;
|
||||
|
||||
digest.reset();
|
||||
digest.update(msg);
|
||||
|
||||
msgID = digest.digest();
|
||||
|
||||
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();
|
||||
pstmt.close();
|
||||
|
||||
tagList = msg.getMsg().getTagsList();
|
||||
tags = new String[tagList.size()];
|
||||
|
||||
insertNewTags(tags);
|
||||
|
||||
sql = "INSERT INTO MsgTagTable (MsgId, TagId) SELECT (?, TagId) FROM TagTable WHERE tag=?";
|
||||
pstmt = connection.prepareStatement(sql);
|
||||
|
||||
for (String tag : tags){
|
||||
pstmt.setBytes(1, msgID);
|
||||
pstmt.setString(2, tag);
|
||||
pstmt.addBatch();
|
||||
}
|
||||
|
||||
pstmt.executeBatch();
|
||||
pstmt.close();
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new CommunicationException("Error accessing DB: " + e.getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BulletinBoardMessage> readMessages(MessageFilter filter, int max) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public void testPrint(){
|
||||
|
||||
try {
|
||||
|
||||
Statement statement = connection.createStatement();
|
||||
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"));
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
} catch(SQLException e){
|
||||
System.out.println("Error reading from DB");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package meerkat.bulletinboard.sqlserver;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.List;
|
||||
|
||||
import meerkat.bulletinboard.MessageFilter;
|
||||
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.protobuf.Voting.BulletinBoardMessage;
|
||||
|
||||
|
||||
public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
|
||||
|
||||
protected static final int TIMEOUT = 20;
|
||||
|
||||
/**
|
||||
* 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");
|
||||
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.close();
|
||||
|
||||
super.init();
|
||||
|
||||
} catch (SQLException e) {
|
||||
|
||||
throw new CommunicationException("Couldn't form a connection with the database");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<BulletinBoardMessage> readMessages(MessageFilter filter, int max) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public void close() throws CommunicationException{
|
||||
|
||||
try{
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
|
||||
throw new CommunicationException("Couldn't close connection to the database");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void insertNewTags(String[] tags) throws CommunicationException {
|
||||
|
||||
PreparedStatement pstmt;
|
||||
String sql;
|
||||
|
||||
try {
|
||||
|
||||
sql = "INSERT OR IGNORE INTO TagTable(Tag) VALUES (?)";
|
||||
pstmt = connection.prepareStatement(sql);
|
||||
|
||||
for (String tag : tags){
|
||||
pstmt.setString(1, tag);
|
||||
pstmt.addBatch();
|
||||
}
|
||||
|
||||
pstmt.executeBatch();
|
||||
pstmt.close();
|
||||
|
||||
} catch (SQLException e){
|
||||
throw new CommunicationException("Error adding new tags to table");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import meerkat.comm.*;
|
|||
import static meerkat.protobuf.Voting.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by talm on 24/10/15.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package meerkat.bulletinboard;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.protobuf.Voting.BulletinBoardMessage;
|
||||
|
||||
/**
|
||||
* Created by Arbel on 07/11/15.
|
||||
*
|
||||
* This interface refers to a single instance of a Bulletin Board.
|
||||
* An implementation of this interface may use any DB and be hosted on any machine.
|
||||
*/
|
||||
|
||||
public interface BulletinBoardServer{
|
||||
|
||||
/**
|
||||
* This method initializes the server by reading the signature data and storing it.
|
||||
* It also establishes the connection to the DB.
|
||||
* @throws CommunicationException on DB connection error.
|
||||
*/
|
||||
public void init() throws CommunicationException;
|
||||
|
||||
/**
|
||||
* Post a message to bulletin board.
|
||||
* @param msg is the actual (signed) message
|
||||
* @return TRUE if the message has been authenticated and FALSE otherwise.
|
||||
* @throws CommunicationException on DB connection error.
|
||||
*/
|
||||
public boolean 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)
|
||||
* @return
|
||||
*/
|
||||
List<BulletinBoardMessage> readMessages(MessageFilter filter, int max);
|
||||
|
||||
/**
|
||||
* This method closes the connection to the DB.
|
||||
* @throws CommunicationException on DB connection error.
|
||||
*/
|
||||
public void close() throws CommunicationException;
|
||||
}
|
|
@ -9,6 +9,19 @@ package meerkat.bulletinboard;
|
|||
* be efficiently run on the BB database.
|
||||
*
|
||||
*/
|
||||
public interface MessageFilter {
|
||||
|
||||
public abstract class MessageFilter {
|
||||
public enum FilterType{
|
||||
ENTRY_NUM,
|
||||
ID,
|
||||
TAG,
|
||||
SIGNER,
|
||||
TIME
|
||||
}
|
||||
|
||||
FilterType filterType;
|
||||
|
||||
public MessageFilter(FilterType filterType){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,4 +4,33 @@ package meerkat.comm;
|
|||
* Created by talm on 24/10/15.
|
||||
*/
|
||||
public class CommunicationException extends Exception {
|
||||
|
||||
/**
|
||||
* Generated serial.
|
||||
*/
|
||||
|
||||
private static final long serialVersionUID = 2279440129497891293L;
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Default constructor. To be used only if error type is unknown.
|
||||
*/
|
||||
public CommunicationException(){
|
||||
message = "Unknown communication exception";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor enabling specifying of an error message.
|
||||
* @param errorMessage
|
||||
*/
|
||||
public CommunicationException(String errorMessage){
|
||||
message = errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the error message specified.
|
||||
*/
|
||||
public String getMessage(){
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package meerkat.comm;
|
||||
|
||||
/**
|
||||
* Created by talm on 24/10/15.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class MessageID {
|
||||
}
|
||||
|
|
@ -6,8 +6,13 @@ 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 {
|
||||
message UnsignedBulletinBoardMessage {
|
||||
// Optional tags describing message
|
||||
repeated string tags = 1;
|
||||
|
||||
|
|
Loading…
Reference in New Issue