More refactoring for scannerAPI
parent
7e4260b8d5
commit
cb1d2343c4
|
@ -2,7 +2,6 @@ package meerkat.pollingstation;
|
|||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import meerkat.pollingstation.controller.PollingStationControllerInterface;
|
||||
import meerkat.pollingstation.controller.callbacks.ScanDataCallback;
|
||||
import meerkat.pollingstation.controller.commands.PollingStationCommand;
|
||||
import meerkat.pollingstation.controller.commands.ReceivedScanCommand;
|
||||
import meerkat.protobuf.PollingStation;
|
||||
|
@ -26,7 +25,7 @@ public class PollingStationMainController implements PollingStationControllerInt
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(PollingStationScanner.Consumer server) {
|
||||
public void init(PollingStationScanner.PollingStationServer server) {
|
||||
server.subscribe(new FutureCallback<PollingStation.ScannedData>() {
|
||||
@Override
|
||||
public void onSuccess(PollingStation.ScannedData result) {
|
||||
|
|
|
@ -6,7 +6,8 @@ package meerkat.pollingstation;
|
|||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.protobuf.BoolValue;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.crypto.DigitalSignature;
|
||||
import meerkat.crypto.concrete.ECDSASignature;
|
||||
import meerkat.protobuf.PollingStation;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
@ -16,24 +17,25 @@ import javax.ws.rs.POST;
|
|||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import java.io.IOException;
|
||||
|
||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_CONNECT_PATH;
|
||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
|
||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH;
|
||||
import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF;
|
||||
|
||||
/**
|
||||
* Implements a Web-App interface for {@link meerkat.pollingstation.PollingStationScanner.Producer}
|
||||
* Implements a Web-App interface for {@link PollingStationScanner.ScannerClient}
|
||||
* This class depends on {@link meerkat.pollingstation.PollingStationWebScanner} and works in conjunction with it
|
||||
*/
|
||||
@Path("/")
|
||||
public class PollingStationScannerWebApp implements PollingStationScanner.Producer {
|
||||
|
||||
public class PollingStationScannerWebApp implements PollingStationScanner.PollingStationWebAPI {
|
||||
@Context
|
||||
ServletContext servletContext;
|
||||
|
||||
Iterable<FutureCallback<PollingStation.ScannedData>> callbacks;
|
||||
final static BoolValue trueValue = BoolValue.newBuilder().setValue(true).build();
|
||||
final static BoolValue falseValue = BoolValue.newBuilder().setValue(false).build();
|
||||
|
||||
PollingStationWebScanner.ScanRequestHandler requestHandler;
|
||||
|
||||
|
||||
/**
|
||||
* This method is called by the Jetty engine when instantiating the servlet
|
||||
|
@ -44,7 +46,7 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc
|
|||
Object context = servletContext.getAttribute(PollingStationWebScanner.CALLBACKS_ATTRIBUTE_NAME);
|
||||
|
||||
try {
|
||||
callbacks = (Iterable<FutureCallback<PollingStation.ScannedData>>) context;
|
||||
requestHandler = (PollingStationWebScanner.ScanRequestHandler) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw e;
|
||||
}
|
||||
|
@ -57,7 +59,7 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc
|
|||
@Produces(MEDIATYPE_PROTOBUF)
|
||||
@Override
|
||||
public BoolValue connect(PollingStation.ConnectionClientData clientData) {
|
||||
return null;
|
||||
return requestHandler.handleConnection(clientData) ? trueValue : falseValue;
|
||||
}
|
||||
|
||||
@POST
|
||||
|
@ -65,22 +67,8 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc
|
|||
@Consumes(MEDIATYPE_PROTOBUF)
|
||||
@Produces(MEDIATYPE_PROTOBUF)
|
||||
@Override
|
||||
public BoolValue newScan(PollingStation.ScannedData scannedData) {
|
||||
|
||||
boolean handled = false;
|
||||
|
||||
// TODO:
|
||||
for (FutureCallback<PollingStation.ScannedData> callback : callbacks){
|
||||
|
||||
callback.onSuccess(scannedData);
|
||||
handled = true;
|
||||
|
||||
}
|
||||
|
||||
return BoolValue.newBuilder()
|
||||
.setValue(handled)
|
||||
.build();
|
||||
|
||||
public BoolValue newScan(PollingStation.SignedScannedData scannerData) {
|
||||
return requestHandler.handleRequest(scannerData) ? trueValue : falseValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory;
|
|||
public class PollingStationToyRun {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private static PollingStationScanner.Consumer scanner;
|
||||
private static PollingStationScanner.PollingStationServer scanner;
|
||||
private static final String CONTEXT_PATH = "/scan";
|
||||
private static final int PORT = 8080;
|
||||
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
package meerkat.pollingstation;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.crypto.DigitalSignature;
|
||||
import meerkat.crypto.concrete.ECDSASignature;
|
||||
import meerkat.protobuf.PollingStation;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.*;
|
||||
|
@ -14,28 +20,128 @@ import org.glassfish.jersey.server.ResourceConfig;
|
|||
|
||||
import meerkat.protobuf.PollingStation.ScannedData;
|
||||
import meerkat.rest.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Created by Arbel on 05/05/2016.
|
||||
*/
|
||||
|
||||
public class PollingStationWebScanner implements PollingStationScanner.Consumer {
|
||||
|
||||
public class PollingStationWebScanner implements PollingStationScanner.PollingStationServer {
|
||||
public final static String CALLBACKS_ATTRIBUTE_NAME = "controller";
|
||||
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* Expected serial number for next scan
|
||||
*/
|
||||
long expectedSerial;
|
||||
|
||||
|
||||
/**
|
||||
* Should a newly-connected scanner be verified using the nonce?
|
||||
*/
|
||||
boolean verifyNonce;
|
||||
|
||||
/**
|
||||
* Should every scan's signature be verified?
|
||||
*/
|
||||
boolean verifySignatures;
|
||||
|
||||
|
||||
/**
|
||||
* The nonce we use to verify a new scanner connection.
|
||||
*/
|
||||
long nonce;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DigitalSignature verifier;
|
||||
|
||||
private final Server server;
|
||||
|
||||
private final List<FutureCallback<ScannedData>> callbacks;
|
||||
boolean verifyScanner;
|
||||
byte nonce[];
|
||||
|
||||
public class ScanRequestHandler {
|
||||
private ScanRequestHandler() { }
|
||||
|
||||
boolean handleConnection(PollingStation.ConnectionClientData data) {
|
||||
if (verifyNonce) {
|
||||
if (data.getNonce() != nonce) {
|
||||
|
||||
logger.warn("Received scanner connection with bad nonce!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (verifySignatures) {
|
||||
try {
|
||||
if (data.getIdCase() != PollingStation.ConnectionClientData.IdCase.SCANNERPK)
|
||||
throw new CertificateException("Connection request doesn't include certificate!");
|
||||
|
||||
verifier.loadVerificationCertificate(data.getScannerPK());
|
||||
} catch (CertificateException e) {
|
||||
logger.warn("Scanner connection with bad certificate: {}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean handleRequest(PollingStation.SignedScannedData data) {
|
||||
ScannedData scannedData = data.getData();
|
||||
if (verifySignatures) {
|
||||
ByteString scannerID = scannedData.getScannerId();
|
||||
if (!scannerID.equals(verifier.getSignerID())) {
|
||||
logger.warn("Scanner ID doesn't match connection public key");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
verifier.initVerify(data.getScannerSig());
|
||||
verifier.updateContent(scannedData);
|
||||
if (!verifier.verify()) {
|
||||
logger.warn("Bad Signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (CertificateException e) {
|
||||
logger.warn("Certificate Exception: {}", e);
|
||||
return false;
|
||||
} catch (InvalidKeyException e) {
|
||||
logger.warn("InvalidKey Exception: {}", e);
|
||||
return false;
|
||||
} catch (SignatureException e) {
|
||||
logger.warn("Signature Exception: {}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (FutureCallback<ScannedData> callback : callbacks) {
|
||||
callback.onSuccess(scannedData);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ScanRequestHandler scanRequestHandler;
|
||||
|
||||
|
||||
public PollingStationWebScanner(int port, String contextPath) {
|
||||
|
||||
scanRequestHandler = new ScanRequestHandler();
|
||||
callbacks = new LinkedList<>();
|
||||
verifier = new ECDSASignature();
|
||||
|
||||
server = new Server(port);
|
||||
|
||||
ServletContextHandler servletContextHandler = new ServletContextHandler(server, contextPath);
|
||||
servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, (Iterable<FutureCallback<ScannedData>>) callbacks);
|
||||
servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, callbacks);
|
||||
|
||||
ResourceConfig resourceConfig = new ResourceConfig(PollingStationScannerWebApp.class);
|
||||
resourceConfig.register(ProtobufMessageBodyReader.class);
|
||||
|
@ -50,10 +156,8 @@ public class PollingStationWebScanner implements PollingStationScanner.Consumer
|
|||
|
||||
@Override
|
||||
public PollingStation.ConnectionServerData start(boolean verifyScanner) throws Exception {
|
||||
this.verifyScanner = verifyScanner;
|
||||
nonce = new byte[32];
|
||||
new SecureRandom().nextBytes(nonce);
|
||||
|
||||
this.verifyNonce = this.verifySignatures = verifyScanner;
|
||||
nonce = new SecureRandom().nextLong();
|
||||
|
||||
server.start();
|
||||
return null;
|
||||
|
|
|
@ -15,8 +15,6 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
|||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.glassfish.jersey.servlet.ServletContainer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
@ -24,7 +22,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
|||
/**
|
||||
* Created by Laura on 3/20/2017.
|
||||
*/
|
||||
public class ReceiverScanHandler implements PollingStationScanner.Consumer, Runnable {
|
||||
public class ReceiverScanHandler implements PollingStationScanner.PollingStationServer, Runnable {
|
||||
|
||||
public final static String CALLBACKS_ATTRIBUTE_NAME = "controller";
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package meerkat.pollingstation;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.protobuf.BoolValue;
|
||||
import meerkat.pollingstation.controller.callbacks.ScanCallback;
|
||||
import meerkat.pollingstation.controller.callbacks.ScanDataCallback;
|
||||
|
@ -23,11 +22,11 @@ import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB
|
|||
import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF;
|
||||
|
||||
/**
|
||||
* Implements a Web-App interface for {@link meerkat.pollingstation.PollingStationScanner.Producer}
|
||||
* Implements a Web-App interface for {@link PollingStationScanner.ScannerClient}
|
||||
* This class depends on {@link meerkat.pollingstation.ReceiverScanHandler} and works in conjunction with it
|
||||
*/
|
||||
@Path("/")
|
||||
public class ReceiverWebAPI implements PollingStationScanner.Producer {
|
||||
public class ReceiverWebAPI implements PollingStationScanner.ScannerClient {
|
||||
|
||||
@Context
|
||||
ServletContext servletContext;
|
||||
|
|
|
@ -11,7 +11,7 @@ public interface PollingStationControllerInterface extends Runnable {
|
|||
* (see VotingBoothController)
|
||||
*/
|
||||
// TODO: 4/16/2017 complete with proper arguments and exceptions
|
||||
public void init(PollingStationScanner.Consumer server);
|
||||
public void init(PollingStationScanner.PollingStationServer server);
|
||||
|
||||
/**
|
||||
* an asynchronous call from Admin Console (If there is such one implemented) to shut down the system
|
||||
|
|
|
@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
*/
|
||||
public class PollingStationWebScannerTest {
|
||||
|
||||
private PollingStationScanner.Consumer scanner;
|
||||
private PollingStationScanner.PollingStationServer scanner;
|
||||
private static final String ADDRESS = "http://localhost";
|
||||
private static final String SUB_ADDRESS = "";
|
||||
private static final int PORT = 8080;
|
||||
|
|
|
@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
*/
|
||||
public class ReceiverTest {
|
||||
|
||||
private PollingStationScanner.Consumer scanner;
|
||||
private PollingStationScanner.PollingStationServer scanner;
|
||||
private static final String ADDRESS = "http://localhost";
|
||||
private static final String SUB_ADDRESS = "";
|
||||
private static final int PORT = 8080;
|
||||
|
|
|
@ -5,20 +5,12 @@ import com.google.protobuf.ByteString;
|
|||
import meerkat.protobuf.PollingStation;
|
||||
import meerkat.protobuf.PollingStation.ErrorMsg;
|
||||
import meerkat.protobuf.PollingStation.ScannedData;
|
||||
import meerkat.rest.Constants;
|
||||
import meerkat.rest.ProtobufMessageBodyReader;
|
||||
import meerkat.rest.ProtobufMessageBodyWriter;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
|
||||
|
@ -28,7 +20,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
|
||||
public class Receiver_ClientTest {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private PollingStationScanner.Consumer scanner;
|
||||
private PollingStationScanner.PollingStationServer scanner;
|
||||
private static final String CONTEXT_PATH = "/scan";
|
||||
|
||||
private Semaphore semaphore;
|
||||
|
@ -94,7 +86,7 @@ public class Receiver_ClientTest {
|
|||
|
||||
scanner.subscribe(new ScanHandler(scannedData));
|
||||
|
||||
PollingStationScanner.Producer scannerClient = new ScannerClientAPI()
|
||||
PollingStationScanner.ScannerClient scannerClient = new ScannerClientAPI()
|
||||
|
||||
ScannerClientAPI(PSC_URL + POLLING_STATION_WEB_SCANNER_SCAN_PATH);
|
||||
scannerClient.newScan(scannedData, null);
|
||||
|
|
|
@ -15,7 +15,7 @@ public interface PollingStationScanner {
|
|||
/**
|
||||
* An interface for processing scans (Polling Station side)
|
||||
*/
|
||||
public interface Consumer {
|
||||
public interface PollingStationServer {
|
||||
|
||||
/**
|
||||
* Sets up the connection to the scanner and begins receiving scans.
|
||||
|
@ -40,10 +40,11 @@ public interface PollingStationScanner {
|
|||
public void subscribe(FutureCallback<ScannedData> scanCallback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An interface for submitting scanned data (scanner side)
|
||||
* An interface for handling the WebAPI (on the polling-station side)
|
||||
*/
|
||||
public interface Producer {
|
||||
public interface PollingStationWebAPI {
|
||||
|
||||
/**
|
||||
* Connect to the polling station server.
|
||||
|
@ -54,11 +55,43 @@ public interface PollingStationScanner {
|
|||
|
||||
/**
|
||||
* Sends a scan to all subscribers
|
||||
* @param scannedData contains the scanned data
|
||||
* @return a BoolValue containing TRUE iff the scanned data has been sent to at least one subscriber
|
||||
* @param scannedData contains the scanned data.
|
||||
* This can be either a ScannedBallot or a ScanError;
|
||||
* On the client side, this method can be called without setting
|
||||
* the signature field.
|
||||
* @return true iff the scanned data has been sent to at least one subscriber
|
||||
*/
|
||||
public BoolValue newScan(ScannedData scannedData);
|
||||
|
||||
public BoolValue newScan(SignedScannedData scannedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for submitting scanned data (scanner side)
|
||||
*/
|
||||
public interface ScannerClient {
|
||||
|
||||
/**
|
||||
* Connect to the polling station server.
|
||||
* The client data contains the scanner ID and optional verification data.
|
||||
* @return
|
||||
*/
|
||||
public boolean connect(ConnectionServerData serverData);
|
||||
|
||||
/**
|
||||
* Sends a scan to all subscribers
|
||||
* @param scannedBallot contains the scanned data.
|
||||
* This can be either a ScannedBallot or a ScanError;
|
||||
* @return true iff the scanned data has been sent to at least one subscriber
|
||||
*/
|
||||
public boolean newScan(ScannedBallot scannedBallot);
|
||||
|
||||
/**
|
||||
* Report a scan error to all subscribers
|
||||
* @param scanError
|
||||
* @return
|
||||
*/
|
||||
public boolean reportError(ScanError scanError);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,64 +1,137 @@
|
|||
package meerkat.pollingstation;
|
||||
|
||||
import com.google.protobuf.BoolValue;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.crypto.DigitalSignatureGenerator;
|
||||
import meerkat.protobuf.PollingStation;
|
||||
import meerkat.rest.Constants;
|
||||
import meerkat.rest.ProtobufMessageBodyReader;
|
||||
import meerkat.rest.ProtobufMessageBodyWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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;
|
||||
import java.security.SignatureException;
|
||||
|
||||
/**
|
||||
* Created by Laura on 3/20/2017.
|
||||
*/
|
||||
public class ScannerClientAPI implements PollingStationScanner.Producer {
|
||||
private Client client;
|
||||
private WebTarget webTarget;
|
||||
|
||||
public ScannerClientAPI(String url) {
|
||||
client = ClientBuilder.newClient();
|
||||
client.register(ProtobufMessageBodyReader.class);
|
||||
client.register(ProtobufMessageBodyWriter.class);
|
||||
webTarget = client.target(url);
|
||||
}
|
||||
public class ScannerClientAPI implements PollingStationScanner.ScannerClient {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
DigitalSignatureGenerator signer;
|
||||
ByteString scannerID;
|
||||
Client client;
|
||||
WebTarget webTarget;
|
||||
|
||||
/**
|
||||
* Sends the scanned data to the polling station server
|
||||
* @param scannedData
|
||||
* @return boolean value: true if the data was sent successfully, false otherwise
|
||||
* Serial number of request (zeroed on new connection to server)
|
||||
*/
|
||||
@Override
|
||||
public BoolValue newScan(PollingStation.ScannedData scannedData) {
|
||||
long serial;
|
||||
|
||||
Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF),
|
||||
);
|
||||
BoolValue res = response.readEntity(BoolValue.class);
|
||||
response.close();
|
||||
return res.getValue();
|
||||
|
||||
protected ScannerClientAPI() {
|
||||
this.signer = null;
|
||||
this.scannerID = null;
|
||||
this.client = ClientBuilder.newClient();
|
||||
this.client.register(ProtobufMessageBodyReader.class);
|
||||
this.client.register(ProtobufMessageBodyWriter.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for client that doesn't use signatures.
|
||||
* @param scannerId
|
||||
*/
|
||||
public ScannerClientAPI(byte[] scannerId) {
|
||||
this();
|
||||
ByteString.copyFrom(scannerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for client that signs messages.
|
||||
* @param signer
|
||||
*/
|
||||
public ScannerClientAPI(DigitalSignatureGenerator signer) {
|
||||
this();
|
||||
assert (signer != null && signer.getSignerID() != null); // Use the default constructor instead
|
||||
|
||||
this.signer = signer;
|
||||
this.scannerID = signer.getSignerID();
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
client.close();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoolValue connect(PollingStation.ConnectionClientData clientData) {
|
||||
return null;
|
||||
public boolean connect(PollingStation.ConnectionServerData serverData) {
|
||||
serial = 0;
|
||||
webTarget = client.target(serverData.getServerUrl());
|
||||
PollingStation.ConnectionClientData.Builder clientData = PollingStation.ConnectionClientData.newBuilder()
|
||||
.setNonce(serverData.getNonce());
|
||||
|
||||
if (signer != null) {
|
||||
clientData.setScannerPK(signer.getSignerPublicKey());
|
||||
} else {
|
||||
clientData.setScannerId(scannerID);
|
||||
}
|
||||
|
||||
Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF)
|
||||
.post(Entity.entity(clientData.build(), Constants.MEDIATYPE_PROTOBUF));
|
||||
BoolValue res = response.readEntity(BoolValue.class);
|
||||
response.close();
|
||||
return res.getValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
boolean sendScannedData(PollingStation.ScannedData.Builder scannedData) {
|
||||
|
||||
scannedData.setSerial(serial++)
|
||||
.setScannerId(scannerID);
|
||||
|
||||
PollingStation.SignedScannedData.Builder signedDataBuilder = PollingStation.SignedScannedData.newBuilder()
|
||||
.setData(scannedData);
|
||||
|
||||
if (signer != null) {
|
||||
try {
|
||||
signer.updateContent(scannedData.build());
|
||||
|
||||
signedDataBuilder.setScannerSig(signer.sign());
|
||||
} catch (SignatureException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF)
|
||||
.post(Entity.entity(signedDataBuilder.build(), Constants.MEDIATYPE_PROTOBUF));
|
||||
BoolValue res = response.readEntity(BoolValue.class);
|
||||
response.close();
|
||||
return res.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the scanned data to the polling station server
|
||||
* @param scannedBallot
|
||||
* @return boolean value: true if the data was sent successfully, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean newScan(PollingStation.ScannedBallot scannedBallot) {
|
||||
PollingStation.ScannedData.Builder scannedData = PollingStation.ScannedData.newBuilder()
|
||||
.setBallot(scannedBallot);
|
||||
|
||||
return sendScannedData(scannedData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg, Crypto.Signature errorMsgSignature) {
|
||||
return null;
|
||||
public boolean reportError(PollingStation.ScanError scanError) {
|
||||
PollingStation.ScannedData.Builder scannedData = PollingStation.ScannedData.newBuilder()
|
||||
.setError(scanError);
|
||||
|
||||
return sendScannedData(scannedData);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,27 +8,32 @@ import "meerkat/crypto.proto";
|
|||
import "meerkat/voting.proto";
|
||||
|
||||
|
||||
|
||||
|
||||
// Data sent (out-of-band) by the server that the client will require to set up a connection
|
||||
message ConnectionServerData {
|
||||
// Web-API URL for the server
|
||||
string server_url = 1;
|
||||
|
||||
// random nonce used for verification of the client.
|
||||
bytes nonce = 2;
|
||||
uint64 nonce = 2;
|
||||
}
|
||||
|
||||
// Data sent by the client in order to set up a connection
|
||||
message ConnectionClientData {
|
||||
// Key used to identify the client
|
||||
SignatureVerificationKey scannerPK = 1;
|
||||
|
||||
oneof id {
|
||||
// Unique ID of the scanner (if not using signatures)
|
||||
bytes scannerId = 1;
|
||||
|
||||
// Public Key used to sign future reports
|
||||
// If this is set, the ID is the certificate fingerprint.
|
||||
SignatureVerificationKey scannerPK = 2;
|
||||
}
|
||||
|
||||
// Nonce sent by connection-server
|
||||
bytes nonce = 2;
|
||||
// (used to verify pairing)
|
||||
uint64 nonce = 3;
|
||||
}
|
||||
|
||||
|
||||
message ScannedBallot {
|
||||
bytes channel = 1;
|
||||
|
||||
|
@ -41,6 +46,7 @@ message ScanError {
|
|||
string msg = 1;
|
||||
}
|
||||
|
||||
|
||||
// Container for scanned data
|
||||
message ScannedData {
|
||||
oneof data {
|
||||
|
@ -49,6 +55,10 @@ message ScannedData {
|
|||
}
|
||||
uint64 serial = 4; // Serial number of the message
|
||||
bytes scannerId = 5; // hash of the scannerPK
|
||||
Signature scannerSig = 6; // signature on the serialzed form of data.
|
||||
}
|
||||
|
||||
message SignedScannedData {
|
||||
ScannedData data = 1;
|
||||
Signature scannerSig = 2; // signature on the serialzed form of data.
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.concurrent.Semaphore;
|
|||
*/
|
||||
public class PollingStationServerToyRun {
|
||||
|
||||
private PollingStationScanner.Consumer scanner;
|
||||
private PollingStationScanner.PollingStationServer scanner;
|
||||
private static final String ADDRESS = "http://localhost";
|
||||
private static final String SUB_ADDRESS = "";
|
||||
private static final int PORT = 8080;
|
||||
|
|
|
@ -32,7 +32,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
|
||||
public class NetworkVirtualPrinterTest {
|
||||
|
||||
private PollingStationScanner.Consumer scanner;
|
||||
private PollingStationScanner.PollingStationServer scanner;
|
||||
private static final String ADDRESS = "http://localhost";
|
||||
private static final String SUB_ADDRESS = "";
|
||||
private static final int PORT = 8080;
|
||||
|
|
Loading…
Reference in New Issue