diff --git a/polling-station/build.gradle b/polling-station/build.gradle index f397d60..712a36c 100644 --- a/polling-station/build.gradle +++ b/polling-station/build.gradle @@ -13,8 +13,8 @@ apply plugin: 'maven-publish' // Uncomment the lines below to define an application // (this will also allow you to build a "fatCapsule" which includes // the entire application, including all dependencies in a single jar) -//apply plugin: 'application' -//mainClassName='your.main.ApplicationClass' +apply plugin: 'application' +mainClassName='meerkat.pollingstation.PollingStationToyRun' // Is this a snapshot version? @@ -32,7 +32,7 @@ ext { description = "Meerkat polling-station application" // Your project version -version = "0.0" +version = "0.1" version += "${isSnapshot ? '-SNAPSHOT' : ''}" diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java index 391c377..c274794 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java @@ -29,6 +29,7 @@ public class PollingStationToyRun { scanner = new PollingStationWebScanner(0, CONTEXT_PATH); PollingStation.ConnectionServerData serverData = scanner.start(true); + logger.info("Started polling station web scanner on {}", serverData.getServerUrl()); PollingStationMainController controller = new PollingStationMainController(); controller.init(scanner); diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java index 8b459d7..a733867 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java @@ -1,9 +1,13 @@ package meerkat.pollingstation; +import java.io.IOException; +import java.net.*; +import java.nio.channels.ServerSocketChannel; import java.security.InvalidKeyException; import java.security.SecureRandom; import java.security.SignatureException; import java.security.cert.CertificateException; +import java.util.Enumeration; import java.util.List; import java.util.LinkedList; @@ -13,6 +17,7 @@ import meerkat.crypto.DigitalSignature; import meerkat.crypto.concrete.ECDSASignature; import meerkat.protobuf.Crypto; import meerkat.protobuf.PollingStation; +import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.*; @@ -38,6 +43,12 @@ public class PollingStationWebScanner implements PollingStationScanner.PollingSt */ long expectedSerial; + /** + * Context path for servlet + */ + + String contextPath; + /** * Should a newly-connected scanner be verified using the nonce? @@ -108,6 +119,7 @@ public class PollingStationWebScanner implements PollingStationScanner.PollingSt return false; } + expectedSerial = 0; return true; } @@ -116,7 +128,7 @@ public class PollingStationWebScanner implements PollingStationScanner.PollingSt if (verifySignatures) { ByteString scannerID = scannedData.getScannerId(); if (!scannerID.equals(connectedScannerID)) { - logger.warn("Scanner ID doesn't match connection public key"); + logger.error("Scanner ID doesn't match connection public key"); return false; } @@ -124,22 +136,28 @@ public class PollingStationWebScanner implements PollingStationScanner.PollingSt verifier.initVerify(data.getScannerSig()); verifier.updateContent(scannedData); if (!verifier.verify()) { - logger.warn("Bad Signature"); + logger.error("Bad Signature"); return false; } } catch (CertificateException e) { - logger.warn("Certificate Exception: {}", e); + logger.error("Certificate Exception: {}", e); return false; } catch (InvalidKeyException e) { - logger.warn("InvalidKey Exception: {}", e); + logger.error("InvalidKey Exception: {}", e); return false; } catch (SignatureException e) { - logger.warn("Signature Exception: {}", e); + logger.error("Signature Exception: {}", e); return false; } } + if (scannedData.getSerial() != expectedSerial) { + logger.warn("Got scan with serial {}, expecting {}", scannedData.getSerial(), expectedSerial); + } + + expectedSerial = scannedData.getSerial() + 1; + for (FutureCallback callback : callbacks) { callback.onSuccess(scannedData); } @@ -153,7 +171,7 @@ public class PollingStationWebScanner implements PollingStationScanner.PollingSt public PollingStationWebScanner(int port, String contextPath) { - + this.contextPath = contextPath; scanRequestHandler = new ScanRequestHandler(); callbacks = new LinkedList<>(); verifier = new ECDSASignature(); @@ -173,15 +191,64 @@ public class PollingStationWebScanner implements PollingStationScanner.PollingSt } + String getServerURL(Server server) { + + String serverURL = server.getURI().toASCIIString(); + + try { + + Connector connector = server.getConnectors()[0]; + + Object transport = connector.getTransport(); + + if (transport instanceof ServerSocketChannel) { + // We can get better info about the local endpoint + ServerSocketChannel sock = (ServerSocketChannel) transport; + SocketAddress localAddr = null; + localAddr = sock.getLocalAddress(); + if (localAddr instanceof InetSocketAddress) { + InetSocketAddress localInet = (InetSocketAddress) localAddr; + InetAddress hostAddr = localInet.getAddress(); + if (hostAddr.isAnyLocalAddress()) { + Enumeration n = null; + n = NetworkInterface.getNetworkInterfaces(); + while (n.hasMoreElements()) { + NetworkInterface e = n.nextElement(); + if (e.isLoopback() || e.isPointToPoint() || !e.isUp()) + continue; + + Enumeration aList = e.getInetAddresses(); + while (aList.hasMoreElements()) { + InetAddress a = aList.nextElement(); + if (a instanceof Inet4Address) { + serverURL = "http://" + a.getHostAddress() + ":" + localInet.getPort() + + contextPath; + } + } + } + } + } + } + + } catch (SocketException e) { + // Ignore + } catch (IOException e) { + // Ignore + } + + return serverURL; + } + @Override public PollingStation.ConnectionServerData start(boolean verifyScanner) throws Exception { this.verifyNonce = this.verifySignatures = verifyScanner; nonce = new SecureRandom().nextLong(); server.start(); + return PollingStation.ConnectionServerData.newBuilder() .setNonce(nonce) - .setServerUrl(server.getURI().toString()) + .setServerUrl(getServerURL(server)) .build(); }