diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 6c0b1e2..4edc9f5 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -73,8 +73,7 @@ message EncryptedBallot { message SignedEncryptedBallot { EncryptedBallot encrypted_ballot = 1; - bytes signer_id = 2; - Signature signature = 3; + Signature signature = 2; } message BallotSecrets { diff --git a/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java b/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java new file mode 100644 index 0000000..e0089c8 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java @@ -0,0 +1,46 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.Encryption; +import meerkat.protobuf.Crypto.*; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Random; + +/** + * Created by hai on 07/06/16. + */ +public class ToyEncryption implements Encryption { + + @Override + public RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException { + ByteString cipher = ByteString.copyFromUtf8("Encryption(") + .concat(plaintext.toByteString()) + .concat(ByteString.copyFromUtf8(", Random(")) + .concat(rnd.getData()) + .concat(ByteString.copyFromUtf8("))")); + return RerandomizableEncryptedMessage.newBuilder() + .setData(cipher) + .build(); + } + + @Override + public RerandomizableEncryptedMessage rerandomize + (RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException { + throw new UnsupportedOperationException(); + } + + @Override + public EncryptionRandomness generateRandomness(Random rand) { + ByteBuffer b = ByteBuffer.allocate(4); + b.putInt(rand.nextInt()); + byte[] bArr = b.array(); + ByteString bs = ByteString.copyFrom(bArr); + return EncryptionRandomness.newBuilder() + .setData(bs) + .build(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ToySignature.java b/voting-booth/src/main/java/meerkat/voting/ToySignature.java new file mode 100644 index 0000000..e2473c9 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ToySignature.java @@ -0,0 +1,82 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.crypto.DigitalSignature; +import meerkat.protobuf.Crypto.*; + +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + +/** + * Created by hai on 07/06/16. + */ +public class ToySignature implements DigitalSignature { + + private final ByteString signerID; + private ByteString msgByteString; + + + public ToySignature(String signerID) { + this.signerID = ByteString.copyFromUtf8(signerID); + } + + @Override + public ByteString getSignerID() { + return signerID; + } + + @Override + public void updateContent(Message msg) throws SignatureException { + msgByteString = msg.toByteString(); + } + + @Override + public Signature sign() throws SignatureException { + ByteString signature = ByteString.copyFromUtf8("Signature(") + .concat(msgByteString) + .concat(ByteString.copyFromUtf8(")")); + return Signature.newBuilder() + .setType(SignatureType.ECDSA) + .setData(signature) + .setSignerId(getSignerID()) + .build(); + } + + + @Override + public void loadVerificationCertificates(InputStream certStream) throws CertificateException { + throw new UnsupportedOperationException(); + } + + @Override + public void clearVerificationCertificates() { + throw new UnsupportedOperationException(); + } + + @Override + public void initVerify(Signature sig) throws CertificateException, InvalidKeyException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean verify() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException { + throw new UnsupportedOperationException(); + } + + + @Override + public void clearSigningKey() { + throw new UnsupportedOperationException(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java new file mode 100644 index 0000000..bf466f6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java @@ -0,0 +1,200 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.Encryption; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.*; +import meerkat.voting.controller.selector.SimpleListCategoriesSelector; +import meerkat.voting.output.*; +import meerkat.voting.storage.*; +import meerkat.voting.encryptor.*; +import meerkat.voting.ui.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by hai on 26/04/16. + */ +public class VotingBoothToyRun { + + public static void main(String[] args) { + + Random rand = new Random(); + Encryption enc = new ToyEncryption(); + DigitalSignature sig = new ToySignature("MY_SIGNER_ID"); + + StorageManager storageManager = new StorageManagerMockup(); + SystemConsoleOutputDevice outputDevice = new SystemConsoleOutputDevice(); + VBCryptoManager cryptoManager = new VBCryptoManagerImpl(rand, enc, sig); + SystemConsoleUI ui = new SystemConsoleUI (); + + + VotingBoothImpl controller = new VotingBoothImpl(); + controller.init(outputDevice, cryptoManager, ui, storageManager); + + generateDemoQuestions(controller); + + // create threads + + + Thread controllerThread = new Thread(controller); + controllerThread.setName("Meerkat VB-Controller Thread"); + Thread uiThread = new Thread(ui); + uiThread.setName("Meerkat VB-UI Thread"); + Thread outputThread = new Thread(outputDevice); + uiThread.setName("Meerkat VB-Output Thread"); + + uiThread.start(); + controllerThread.start(); + outputThread.start(); + + } + + + private static void generateDemoQuestions(VotingBoothController controller) { + + List channelChoiceQuestions = generateCahnnelChoiceQuestions(); + controller.setBallotChannelChoiceQuestions(channelChoiceQuestions); + + List allBallotQuestions = generateBallotQuestions(); + controller.setBallotRaceQuestions(allBallotQuestions); + + SimpleCategoriesSelectionData selectionData = generateSelectionData(); + SimpleListCategoriesSelector selector = new SimpleListCategoriesSelector(allBallotQuestions, selectionData); + controller.setChannelQuestionSelector(selector); + } + + + private static List generateCahnnelChoiceQuestions() { + ArrayList channelChoiceQuestions = new ArrayList(); + + String[] ans1 = {"Red", "Blue", "Green"}; + BallotQuestion ccquestion1 = generateBallotQuestion("What is your favorite color?", "Pick one answer", ans1); + channelChoiceQuestions.add(ccquestion1); + + String[] ans2 = {"Yes", "No"}; + BallotQuestion ccquestion2 = generateBallotQuestion("Are you a republican?", "Pick one answer", ans2); + channelChoiceQuestions.add(ccquestion2); + + return channelChoiceQuestions; + } + + + private static List generateBallotQuestions() { + ArrayList allBallotQuestions = new ArrayList(); + + String[] answers1 = {"answer 1", "answer 2", "answer 3", "answer 4"}; + allBallotQuestions.add(generateBallotQuestion("question 1. Asking something...", "Pick one answer", answers1)); + + String[] answers2 = {"Miranda Kerr", "Doutzen Kroes", "Moran Atias", "Roslana Rodina", "Adriana Lima"}; + allBallotQuestions.add(generateBallotQuestion("question 2: Which model do you like", "Mark as many as you want", answers2)); + + allBallotQuestions.add(generateBallotQuestion("question 3. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 4. Asking something...", "Pick one answer", answers1)); + + String[] answers5 = {"Clint Eastwood", "Ninja", "Sonic", "Tai-chi", "Diablo", "Keanu"}; + allBallotQuestions.add(generateBallotQuestion("question 5: Good name for a cat", "Pick the best one", answers5)); + + allBallotQuestions.add(generateBallotQuestion("question 6. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 7. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 8. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 9. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 10. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 11. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 12. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 13. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 14. Asking something...", "Pick one answer", answers1)); + + return allBallotQuestions; + } + + + private static BallotQuestion generateBallotQuestion(String questionStr, String descriptionStr, String[] answers) { + UIElement question = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(questionStr)) + .build(); + + UIElement description = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(descriptionStr)) + .build(); + + BallotQuestion.Builder bqb = BallotQuestion.newBuilder(); + bqb.setIsMandatory(false); + bqb.setQuestion(question); + bqb.setDescription(description); + for (String answerStr : answers) { + UIElement answer = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(answerStr)) + .build(); + bqb.addAnswer(answer); + } + + return bqb.build(); + } + + + private static SimpleCategoriesSelectionData generateSelectionData() { + Category sharedDefaults = Category.newBuilder() + .addQuestionIndex(0) + .addQuestionIndex(5) + .addQuestionIndex(9) + .build(); + + Category cat00 = Category.newBuilder() + .addQuestionIndex(1) + .addQuestionIndex(4) + .addQuestionIndex(6) + .addQuestionIndex(7) + .build(); + + Category cat01 = Category.newBuilder() + .addQuestionIndex(2) + .addQuestionIndex(4) + .addQuestionIndex(8) + .build(); + + Category cat02 = Category.newBuilder() + .addQuestionIndex(3) + .addQuestionIndex(8) + .build(); + + Category cat10 = Category.newBuilder() + .addQuestionIndex(10) + .addQuestionIndex(11) + .build(); + + Category cat11 = Category.newBuilder() + .addQuestionIndex(12) + .addQuestionIndex(13) + .build(); + + CategoryChooser catChooser0 = CategoryChooser.newBuilder() + .addCategory(cat00) + .addCategory(cat01) + .addCategory(cat02) + .build(); + + CategoryChooser catChooser1 = CategoryChooser.newBuilder() + .addCategory(cat10) + .addCategory(cat11) + .build(); + + return SimpleCategoriesSelectionData.newBuilder() + .setSharedDefaults(sharedDefaults) + .addCategoryChooser(catChooser0) + .addCategoryChooser(catChooser1) + .build(); + + } + private static ByteString stringToBytes (String s) { + return ByteString.copyFromUtf8(s); + } + + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index 2d79d33..a9221bf 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -108,6 +108,7 @@ public class VotingBoothImpl implements VotingBoothController { shutDownHasBeenCalled = true; queue.clear(); ui.callShutDown(); + outputDevice.callShutDown(); } private void handleSingleTask (ControllerCommand task) { @@ -122,18 +123,21 @@ public class VotingBoothImpl implements VotingBoothController { if (task instanceof RestartVotingCommand) { doRestartVoting (); } - else if (task instanceof CastCommand) { - doFinalize(false); - } - else if (task instanceof AuditCommand) { - doFinalize(true); - } else if (task instanceof ChannelChoiceCommand) { doChooseChannel(); } else if (task instanceof ChannelDeterminedCommand) { doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); } + else if (task instanceof ChooseFinalizeOptionCommand) { + doChooseFinalizeOption(); + } + else if (task instanceof CastCommand) { + doFinalize(false); + } + else if (task instanceof AuditCommand) { + doFinalize(true); + } else if (task instanceof EncryptAndCommitBallotCommand) { doCommit ((EncryptAndCommitBallotCommand)task); } @@ -213,6 +217,19 @@ public class VotingBoothImpl implements VotingBoothController { } + private void doChooseFinalizeOption() { + if (state.stateIdentifier == VBState.COMMITTING_TO_BALLOT) { + logger.debug("doChooseFinalizeOption"); + state.stateIdentifier = VBState.CAST_OR_AUDIT; + ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue)); + } + else { + logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier); + // ignore this request + } + } private void doCommit (EncryptAndCommitBallotCommand task) { if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); @@ -224,7 +241,7 @@ public class VotingBoothImpl implements VotingBoothController { this.queue)); outputDevice.commitToBallot(state.plaintextBallot, state.signedEncryptedBallot, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { logger.debug("doCommit: current state is " + state.stateIdentifier); @@ -252,15 +269,17 @@ public class VotingBoothImpl implements VotingBoothController { if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); if (auditRequested) { + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); outputDevice.audit(state.secrets, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(), + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); outputDevice.castBallot( - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } } else { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java new file mode 100644 index 0000000..a6eaadf --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java @@ -0,0 +1,34 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.SystemMessages; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class OutputDeviceCommitCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class); + + public OutputDeviceCommitCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Void v) { + logger.debug("callback for output device commit success"); + enqueueCommand(new ChooseFinalizeOptionCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + @Override + public void onFailure(Throwable t) { + logger.error("OutputDeviceCommitCallback got a failure: " + t); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getOutputDeviceFailureMessage())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java similarity index 58% rename from voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java rename to voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java index 2432f49..74a85e0 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java @@ -9,22 +9,24 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class OutputDeviceCallback extends ControllerCallback { - protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class); +public class OutputDeviceFinalizeCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class); - public OutputDeviceCallback(int requestId, - long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + public OutputDeviceFinalizeCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { super(requestId, ballotSerialNumber, controllerQueue); } @Override public void onSuccess(Void v) { + logger.debug("callback for output device finalize success"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } @Override public void onFailure(Throwable t) { - logger.error("WaitForFinishCallback got a failure: " + t); + logger.error("OutputDeviceFinalizeCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), SystemMessages.getOutputDeviceFailureMessage())); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java new file mode 100644 index 0000000..76b0e77 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class ChooseFinalizeOptionCommand extends ControllerCommand { + public ChooseFinalizeOptionCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java index 3f3a1b2..722c24e 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -49,7 +49,6 @@ public class VBCryptoManagerImpl implements VBCryptoManager { SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder() .setEncryptedBallot(encBallot) - .setSignerId(digitalSignature.getSignerID()) .setSignature(digitalSignature.sign()) .build(); diff --git a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index afbe223..97fa7ed 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -37,4 +37,5 @@ public interface BallotOutputDevice { */ public void cancelBallot(FutureCallback callback); + public void callShutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index 5d8446e..614dc40 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -4,22 +4,31 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; import meerkat.protobuf.Crypto.*; import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.LinkedBlockingQueue; + /** * A toy OutputDevice class * outputs everything simply to the System console */ -public class SystemConsoleOutputDevice implements BallotOutputDevice { +public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { private Logger logger; + private LinkedBlockingQueue queue; + private volatile boolean shutDownHasBeenCalled; public SystemConsoleOutputDevice () { logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); logger.info("A SystemConsoleOutputDevice is constructed"); + queue = new LinkedBlockingQueue<>(); + shutDownHasBeenCalled = false; } + /* * Returns the UTF8 decoding of byte-string data */ @@ -27,13 +36,69 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { return data.toStringUtf8(); } + @Override + public void run () { + logger.info("UI starts running"); + while (! wasShutDownCalled()) { + try { + OutputCommand command = queue.take(); + handleSingleCommand(command); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from command queue " + e); + } + } + } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + } + + + private void handleSingleCommand(OutputCommand command) { + if (command instanceof CommitOutputCommand) { + doCommitToBallot((CommitOutputCommand)command); + } + else if (command instanceof AuditOutputCommand) { + doAudit((AuditOutputCommand)command); + } + else if (command instanceof CastOutputCommand) { + doCastBallot((CastOutputCommand)command); + } + else if (command instanceof CancelOutputCommand) { + doCancel((CancelOutputCommand)command); + } + else { + String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " + + command.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + @Override public void commitToBallot(PlaintextBallot plaintextBallot, SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { - logger.debug("entered method commitToBallot"); + logger.debug("Output interface call to commit to ballot"); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + } + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + PlaintextBallot plaintextBallot = command.getPlaintext(); long plaintextSerialNumber = plaintextBallot.getSerialNumber(); System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); + System.out.println(plaintextBallot); + SignedEncryptedBallot signedEncryptedBallot = command.getSignedEncryptedBallot(); long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber(); System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):"); if (plaintextSerialNumber != encryptedSerialNumber) { @@ -42,33 +107,52 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { } ByteString encryptedData = signedEncryptedBallot.getEncryptedBallot().getData().getData(); System.out.println(bytesToString(encryptedData)); - callback.onSuccess(null); + command.getCallback().onSuccess(null); } + @Override public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { - logger.debug("entered method audit"); + logger.debug("an interface call to audit"); + queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + } + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); System.out.println("Auditing"); - printPlaintextBallot (ballotSecrets.getPlaintextBallot()); + BallotSecrets ballotSecrets = command.getBallotSecrets(); printEncryptionRandomness (ballotSecrets.getEncryptionRandomness()); printRandomnessGenerationProof (ballotSecrets.getProof()); - callback.onSuccess(null); + command.getCallback().onSuccess(null); } - private void printPlaintextBallot (PlaintextBallot plaintextBallot) { - long plaintextSerialNumber = plaintextBallot.getSerialNumber(); - System.out.println("Plaintext serial number = " + plaintextSerialNumber); - System.out.println("Answers = "); - for (BallotAnswer ballotAnswer : plaintextBallot.getAnswersList()) { - String printableAnswer = ""; - for (long n : ballotAnswer.getAnswerList()) { - printableAnswer += n + " "; - } - System.out.println(printableAnswer); - } + @Override + public void castBallot(FutureCallback callback) { + logger.debug("an interface call to cast ballot"); + queue.add(new CastOutputCommand((ControllerCallback)callback)); } + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + System.out.println("Ballot finalized for casting!"); + command.getCallback().onSuccess(null); + } + + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("an interface call to cancel the output"); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); + } + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + System.out.println("Ballot cancelled!"); + command.getCallback().onSuccess(null); + } + + private void printEncryptionRandomness (EncryptionRandomness encryptionRandomness) { System.out.println("Encryption Randomness = "); ByteString data = encryptionRandomness.getData(); @@ -81,18 +165,4 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { System.out.println(bytesToString(data)); } - - @Override - public void castBallot(FutureCallback callback) { - logger.debug("entered method castBallot"); - System.out.println("Ballot finalized for casting!"); - callback.onSuccess(null); - } - - @Override - public void cancelBallot(FutureCallback callback) { - logger.debug("entered method cancelBallot"); - System.out.println("Ballot cancelled!"); - callback.onSuccess(null); - } } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java new file mode 100644 index 0000000..2722326 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class AuditOutputCommand extends OutputCommand { + + private final BallotSecrets ballotSecrets; + + public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) { + super(callback); + this.ballotSecrets = ballotSecrets; + } + + public BallotSecrets getBallotSecrets() { + return ballotSecrets; + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java new file mode 100644 index 0000000..0c360d2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CancelOutputCommand extends OutputCommand { + + public CancelOutputCommand(ControllerCallback callback) { + super(callback); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java new file mode 100644 index 0000000..af7ed30 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CastOutputCommand extends OutputCommand { + + public CastOutputCommand(ControllerCallback callback) { + super(callback); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java new file mode 100644 index 0000000..dcd52f6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -0,0 +1,29 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CommitOutputCommand extends OutputCommand { + + private final PlaintextBallot plaintextBallot; + private final SignedEncryptedBallot signedEncryptedBallot; + + public CommitOutputCommand(PlaintextBallot plaintextBallot, + SignedEncryptedBallot signedEncryptedBallot, + ControllerCallback callback) { + super(callback); + this.plaintextBallot = plaintextBallot; + this.signedEncryptedBallot = signedEncryptedBallot; + } + + public PlaintextBallot getPlaintext() { + return plaintextBallot; + } + + public SignedEncryptedBallot getSignedEncryptedBallot() { + return signedEncryptedBallot; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java new file mode 100644 index 0000000..8a7c322 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -0,0 +1,16 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +//TODO: make this class generic +public abstract class OutputCommand { + protected final ControllerCallback callback; + + protected OutputCommand(ControllerCallback callback) { + this.callback = callback; + } + + public ControllerCallback getCallback () { + return this.callback; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index 2f30a80..bc3ac92 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -46,7 +46,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void run () { - logger.info("entered the voting flow"); + logger.info("UI starts running"); while (! wasShutDownCalled()) { try { UICommand command = queue.take();