Commit ee7c930c authored by LIly's avatar LIly
Browse files

remove ebcagent

parent 57ef075d
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'
sourceSets {
main {
resources {
srcDirs "src/main/java/resources"
}
}
}
dependencies {
implementation project(path: ':ebcutils')
implementation 'org.apache.commons:commons-lang3:3.4'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'com.jayway.jsonpath:json-path'
}
server.port = 8443
server.ssl.key-store = config/keystore.jks
server.ssl.key-store-password =password
server.ssl.key-password =password
\ No newline at end of file
#Mon Aug 29 13:08:10 CDT 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip
package mpisws;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
@SpringBootApplication
@EnableAutoConfiguration
public class AgentApp {
public static void main(String[] args) {
SpringApplication.run(AgentApp.class, args);
}
}
package mpisws;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.mpisws.database.DBEncounterInfo;
import org.mpisws.embeddedsocial.ESClient;
import org.mpisws.embeddedsocial.ESMessage;
import org.mpisws.helpers.Identifier;
import org.mpisws.messaging.EncounterForwardingMessage;
import org.mpisws.messaging.ReceivedMessageWrapper;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import mpisws.database.AgentDatabase;
import static java.lang.Thread.sleep;
import static org.mpisws.messaging.ReceivedMessageWrapper.MsgTyp.ENCOUNTER_FORWARDING_MESSAGE;
/**
* Created by tslilyai on 2/19/18.
*/
public class AgentForwarder {
private static int loopLimit = 100;
private static int PAGE_SIZE = 20;
private static Set<Integer> receivedMsgs = new HashSet<>();
private static String lastReadCursor;
static List<EncounterForwardingMessage> fwdedMsgs = new ArrayList<>();
public static class RunForwardingCycle implements Runnable {
@Override
public void run() {
while (true) {
if (ESClient.getInstance().getCredentials().getAuth() != null) {
runOneForwardingCycleForNewMessages();
} else {
try {
sleep(1000 * 60 * 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
private static void runOneForwardingCycleForNewMessages() {
String newestCursor = null;
int numLoops = 0;
String continuationCursor = null;
List<EncounterForwardingMessage> msgsToForward = new ArrayList<>();
Pair<String, List<ReceivedMessageWrapper>> nextCursor_newMsgs;
boolean foundLastReadCursor = false;
while (numLoops < loopLimit) {
msgsToForward.clear();
nextCursor_newMsgs = getMsgsPage(continuationCursor);
continuationCursor = nextCursor_newMsgs.getLeft();
// get the messages to forward
for (ReceivedMessageWrapper msg : nextCursor_newMsgs.getRight()) {
if (newestCursor == null) {
newestCursor = msg.getCursor();
}
if (msg.getCursor().compareTo(lastReadCursor) == 0) {
foundLastReadCursor = true;
break;
}
if (msg.getMsgType() == ENCOUNTER_FORWARDING_MESSAGE) {
EncounterForwardingMessage encounterForwardingMessage = msg.getEncounterForwardingMessage();
if (receivedMsgs.contains(encounterForwardingMessage.getMsgText().hashCode())) {
// we've gotten this message before, don't forward again
// TODO this can have false positives?
continue;
} else {
// save a hash of the message
receivedMsgs.add(encounterForwardingMessage.getMsgText().hashCode());
}
msgsToForward.add(encounterForwardingMessage);
}
}
// forward the messages
forwardMessages(msgsToForward, -1);
// save the messages that we've forwarded
fwdedMsgs.addAll(msgsToForward);
if (foundLastReadCursor || nextCursor_newMsgs.getRight().size() < PAGE_SIZE) {
break;
}
numLoops++;
}
// update the last seen (forwarded) message
lastReadCursor = newestCursor;
removeExpired();
}
protected static void forwardMessages(List<EncounterForwardingMessage> msgs, long updatedTime) {
List<ESMessage> msgsToSend = new ArrayList<>();
for (EncounterForwardingMessage encounterForwardingMessage : msgs) {
if (encounterForwardingMessage.shouldBeForwarded()) {
continue;
}
// get the encounters that satisfy the constraint
List<DBEncounterInfo> eids = AgentDatabase.getEncounterInfos(encounterForwardingMessage.getEncounterConstraint(), updatedTime);
// TODO choose at random
eids = (eids.size() < encounterForwardingMessage.getFwdingLimit()) ? eids : eids.subList(0, encounterForwardingMessage.getFwdingLimit());
encounterForwardingMessage.updateForwardConstraint();
// encode the messages to send (with its constraints) and form the message contents
for (int i = 0; i < eids.size(); i++) {
DBEncounterInfo info = eids.get(i);
if (eids.get(i).getOtherTopicHandle() == null) {
// we failed to find the topic handle
continue;
}
msgsToSend.add(new ESMessage(encounterForwardingMessage.toSendMessageText(info.getSs()),
new Identifier(info.getEid()).toString(), info.getOtherTopicHandle(),
true, null, true, -1));
}
}
ESClient.getInstance().sendMsgs(msgsToSend);
}
private static Pair<String, List<ReceivedMessageWrapper>> getMsgsPage(String cursor) {
Pair<String, List<ESMessage>> cursorMessages = ESClient.getInstance().getPageMessages(cursor, PAGE_SIZE);
List receivedMessageWrappers = new ArrayList(cursorMessages.getRight().size());
for (ESMessage msg : cursorMessages.getRight()) {
if (msg == null) continue;
byte[] secret = AgentDatabase.getSharedSecretByEncounterID(msg.getTopicHandle());
if (secret == null) {
continue;
}
ReceivedMessageWrapper receivedMessageWrapper = new ReceivedMessageWrapper(msg, secret);
if (receivedMessageWrapper.getMsgType() == null) {
continue;
} else receivedMessageWrappers.add(receivedMessageWrapper);
}
return new ImmutablePair<String, List<ReceivedMessageWrapper>>(cursorMessages.getLeft(), receivedMessageWrappers);
}
private static void removeExpired() {
Iterator<EncounterForwardingMessage> i = fwdedMsgs.iterator();
while (i.hasNext()) {
EncounterForwardingMessage msg = i.next();
if (msg.expired()) {
receivedMsgs.remove(msg.getMsgText().hashCode());
i.remove();
}
}
}
}
package mpisws;
import org.mpisws.database.DBModel;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedList;
import java.util.List;
import org.mpisws.embeddedsocial.ESClient;
import mpisws.database.AgentDatabase;
import mpisws.database.PLocation;
import mpisws.database.PEncounterEntries;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
/**
* Created by tslilyai on 2/16/18.
*/
@RestController
public class AgentServer {
private ESClient esClient = ESClient.getInstance();
private boolean isAuthenticated() {
// TODO
org.springframework.security.core.Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return true;
}
@RequestMapping(method = PUT, value = "/auth")
public void auth(
@RequestParam(value = "userhandle", defaultValue = "") String userHandle,
@RequestParam(value = "esauth", defaultValue = "") String auth) {
if (esClient.getCredentials().getAuth() != null && !isAuthenticated()) throw new EbCAuthException("Not authenticated");
esClient.setESCredentials(userHandle, auth);
// the database is tied to a particular ES user
AgentDatabase.connectDB();
}
@RequestMapping(method = DELETE, value = "/auth")
public void removeauth() {
if (!isAuthenticated()) throw new EbCAuthException("not authenticated");
esClient.signOut();
AgentDatabase.disconnectDB();
}
@RequestMapping(method = PUT, value = "/database_update")
public void uploaddata(
@RequestParam(value = "updateTime", defaultValue = "") long updateTime,
@RequestParam(value = "secrets", defaultValue = "") String secrets,
@RequestParam(value = "locations", defaultValue = "") String locations) {
if (!isAuthenticated()) throw new EbCAuthException("not authenticated");
String[] secretStrs = secrets.split(",");
String[] locationStrs = locations.split(",");
if (!uploadNewEncounters(updateTime, secretStrs, locationStrs)) {
throw new EbCException("failed to upload new encounters");
}
}
@RequestMapping(method = GET, value = "/database")
public void getEncounters() {
if (!isAuthenticated()) throw new EbCAuthException("not authenticated");
// TODO
}
class EbCException extends RuntimeException {
public EbCException(String msg) {
super(msg);
}
}
@ResponseBody
@ExceptionHandler(EbCException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
private void ebcExceptionHandler(EbCException ex) {
System.out.println(ex.getMessage());
}
class EbCAuthException extends RuntimeException {
public EbCAuthException(String msg) {
super(msg);
}
}
@ResponseBody
@ExceptionHandler(EbCAuthException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
private void ebcAuthExceptionHandler(EbCAuthException ex) {
System.out.println(ex.getMessage());
}
private boolean uploadNewEncounters(
long updateTime,
String[] encodedSecrets,
String[] encodedLocations) {
// TODO encryption
List<DBModel> encounters = new LinkedList<>();
List<DBModel> locations = new LinkedList<>();
List<DBModel> secrets = new LinkedList<>();
for (String locStr : encodedLocations) {
//locations.add(PLocation.fromString(locStr));
}
for (String secStr : encodedSecrets) {
//secrets.add(PEncounterEntries.fromString(secStr));
}
boolean success = AgentDatabase.insertModels(encounters)
&& AgentDatabase.insertModels(locations)
&& AgentDatabase.insertModels(secrets);
// forward "pending" messages to new encounters that match
AgentForwarder.forwardMessages(AgentForwarder.fwdedMsgs, updateTime);
return success;
}
}
package mpisws.database;
import org.mpisws.messaging.constraints.EncounterQueryConstraint;
import org.mpisws.database.DBEncounterInfo;
import org.mpisws.database.DBModel;
import org.mpisws.database.DBValue;
import org.mpisws.database.databaseSchema.DBEncounterEntries;
import org.mpisws.database.databaseSchema.DBLocation;
import org.mpisws.embeddedsocial.ESClient;
import org.mpisws.helpers.Utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* Created by tslilyai on 2/16/18.
*/
public class AgentDatabase {
private static Connection conn;
// specified by the user handle associated with each unique user account
// TODO This means that someone who deletes their account cannot access their encounter database again
private static final String url = "jdbc:sqlite:/sqlite/db/%s.db";
public static final DBEncounterEntries sharedSecrets = DBEncounterEntries.getInstance();
public static final DBLocation locations = DBLocation.getInstance();
public static final List<DBModel> models = new LinkedList<>();
static {
models.add(sharedSecrets);
models.add(locations);
}
public static void connectDB() {
try {
conn = DriverManager.getConnection(String.format(url, ESClient.getInstance().getCredentials().getUserHandle()),
ESClient.getInstance().getCredentials().getUserHandle(),
ESClient.getInstance().getCredentials().getAuth());
System.out.println("Connection to DB SQLites has been established.");
} catch (SQLException e) {
System.out.println("Could not establish DB Connection: " + e.getMessage());
}
}
public static void disconnectDB() {
try{
if (conn != null) {
conn.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
public static void createTables() {
for (DBModel model : models)
try {
final StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE IF NOT EXISTS ").append(model.getTableName()).append(" (");
sb.append(Utils.collectionToStringV2(model.getColumns(), ","));
sb.append(")");
Statement stmt = conn.createStatement();
stmt.execute(sb.toString());
if (stmt != null) { stmt.close(); }
} catch (SQLException e) {
e.printStackTrace();
}
}
public static boolean insertModels(List<DBModel> models) {
try {
DBModel firstModel = models.get(0);
if (firstModel == null) {
return true;
}
final StringBuilder sb = new StringBuilder();
sb.append("REPLACE INTO ").append(firstModel.getTableName()).append(" (");
sb.append(Utils.collectionToStringV2(firstModel.getColumns(), ","));
sb.append(") VALUES (");
for (int i = 0; i < firstModel.getColumns().size(); i++) {
if (i == firstModel.getColumns().size() - 1)
sb.append("?)");
else
sb.append("?,");
}
PreparedStatement stmt = conn.prepareStatement(sb.toString());
for (DBModel model : models) {
if (model == null) {
return true;
}
List<DBValue> values = model.getValues();
DBValue value;
for (int i = 0; i < values.size(); i++) {
value = values.get(i);
switch (value.getValueType()) {
case LONG:
stmt.setLong(i, (Long) value.getValue());
break;
case DOUBLE:
stmt.setDouble(i, (Double) value.getValue());
case BYTES:
stmt.setBytes(i, (byte[]) value.getValue());
break;
case BOOL:
stmt.setBoolean(i, (Boolean) value.getValue());
break;
}
}
stmt.addBatch();
}
stmt.executeBatch();
if (stmt != null) {
stmt.close();
}
return true;
} catch (SQLException e) {
return false;
}
}
public static void dropTables() {
for (DBModel model : models)
try {
Statement stmt = conn.createStatement();
stmt.execute("DROP TABLE " + model.getTableName());
if (stmt != null) { stmt.close(); }
} catch (SQLException e) {
e.printStackTrace();
}
}
public static byte[] getSharedSecretByEncounterID(String msgTopic) {
try {
final StringBuilder sb = new StringBuilder();
sb.append("SELECT " + DBEncounterEntries.getInstance().getTableName() + "." + DBEncounterEntries.Columns.sharedSecret + " FROM ");
sb.append(DBEncounterEntries.getInstance().getTableName() + " ");
sb.append("WHERE HEX(" + DBEncounterEntries.Columns.encounterID + ") = " + msgTopic);
Statement stmt = conn.createStatement();
ResultSet results = stmt.executeQuery(sb.toString());
byte[] ss = null;
if (results.next()) {
ss = results.getBytes(0);
}
if (stmt != null) { stmt.close(); }
return ss;
} catch (SQLException e) {
return null;
}
}
public static List<DBEncounterInfo> getEncounterInfos(EncounterQueryConstraint constraint, long updatedTime) {
try {
Statement stmt = conn.createStatement();
ResultSet results = stmt.executeQuery(constraint.toQueryString(updatedTime));
int pkidCol = results.findColumn(DBEncounterEntries.getInstance().getTableName() + "." + DBEncounterEntries.Columns.encounterPKID);
int eidCol = results.findColumn(DBEncounterEntries.getInstance().getTableName() + "." + DBEncounterEntries.Columns.encounterID);
int ssCol = results.findColumn(DBEncounterEntries.getInstance().getTableName() + "." + DBEncounterEntries.Columns.sharedSecret);
int myTopicHandlCol = results.findColumn(DBEncounterEntries.getInstance().getTableName() + "." + DBEncounterEntries.Columns.myTopicHandle);
int otherTopicHandlCol = results.findColumn(DBEncounterEntries.getInstance().getTableName() + "." + DBEncounterEntries.Columns.myTopicHandle);
int locTimestampCol = results.findColumn(DBLocation.getInstance().getTableName() + "." + DBLocation.Columns.updatedTimestamp);
List<DBEncounterInfo> es = new ArrayList<>();
byte[] curGroupSS = null;
long minTime = -1;
long maxTime = -1;
byte[] ss = null, eid = null;
String myTopicHandle = null, otherTopicHandle = null;
while (results.next()) {
byte[] newGroupSS = results.getBytes(ssCol);
long newTime = results.getLong(locTimestampCol);
if (curGroupSS == null || Arrays.equals(curGroupSS, newGroupSS)) {
curGroupSS = newGroupSS;
eid = results.getBytes(eidCol);
myTopicHandle = results.getString(myTopicHandlCol);
otherTopicHandle = results.getString(otherTopicHandlCol);
minTime = (minTime == -1 || newTime < minTime) ? newTime : minTime;
maxTime = (maxTime == -1 || newTime > maxTime) ? newTime : maxTime;
} else {
es.add(new DBEncounterInfo(results.getLong(pkidCol), eid, ss, maxTime, minTime, myTopicHandle, otherTopicHandle));
// reset
minTime = -1;
maxTime = -1;
curGroupSS = newGroupSS;
}
}
if (stmt != null) {
stmt.close();
}
return es;
} catch (SQLException e) { return null; }
}
}
<
package mpisws.database;
import org.mpisws.database.databaseSchema.DBEncounterEntries;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.mpisws.helpers.Identifier;
public class PEncounterEntries extends DBEncounterEntries {
public PEncounterEntries(long pkid, long encounterPKID, long startTime, long endTime, Identifier sharedSecret, Identifier encounterID,
Identifier myNonce, Identifier myDHPrivKey, Identifier myDHPubKey, Identifier receivedNonce,
boolean postedNonceTopic, boolean shouldPostLink,
String myTopicHandle, String otherTopicHandle) {
super(pkid, encounterPKID, startTime, endTime, sharedSecret.getBytes(), encounterID.getBytes(),
myNonce.getBytes(), myDHPrivKey.getBytes(), myDHPubKey.getBytes(), receivedNonce.getBytes(),
postedNonceTopic, shouldPostLink,
myTopicHandle, otherTopicHandle);
}
public static long extractEncounterPKID(final ResultSet rs) throws SQLException {
return rs.getLong(Columns.encounterPKID);
}
public static byte[] extractSharedSecret(final ResultSet rs) throws SQLException {
return rs.getBytes(Columns.sharedSecret);
}
public static byte[] extractEncounterID(final ResultSet rs) throws SQLException {
return rs.getBytes(Columns.encounterID);
}
public static long extractStartTime(final ResultSet rs) throws SQLException {